Переглянути джерело

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

Jaskar 6 роки тому
батько
коміт
ac493ef42d
82 змінених файлів з 187619 додано та 186265 видалено
  1. 21445 21330
      Playground/babylon.d.txt
  2. 6 5
      Viewer/src/configuration/renderOnlyLoader.ts
  3. 2 1
      Viewer/src/templating/templateManager.ts
  4. 22241 22122
      dist/preview release/babylon.d.ts
  5. 2 2
      dist/preview release/babylon.js
  6. 1693 1422
      dist/preview release/babylon.max.js
  7. 1 1
      dist/preview release/babylon.max.js.map
  8. 58132 57875
      dist/preview release/babylon.module.d.ts
  9. 22241 22122
      dist/preview release/documentation.d.ts
  10. 4 4
      dist/preview release/gui/babylon.gui.js
  11. 1 1
      dist/preview release/gui/babylon.gui.js.map
  12. 1 1
      dist/preview release/gui/babylon.gui.module.d.ts
  13. 7 7
      dist/preview release/inspector/babylon.inspector.bundle.max.js
  14. 1 1
      dist/preview release/inspector/babylon.inspector.bundle.max.js.map
  15. 9 3
      dist/preview release/loaders/babylon.glTF2FileLoader.js
  16. 1 1
      dist/preview release/loaders/babylon.glTF2FileLoader.js.map
  17. 1 1
      dist/preview release/loaders/babylon.glTF2FileLoader.min.js
  18. 9 3
      dist/preview release/loaders/babylon.glTFFileLoader.js
  19. 1 1
      dist/preview release/loaders/babylon.glTFFileLoader.js.map
  20. 1 1
      dist/preview release/loaders/babylon.glTFFileLoader.min.js
  21. 9 3
      dist/preview release/loaders/babylonjs.loaders.js
  22. 1 1
      dist/preview release/loaders/babylonjs.loaders.js.map
  23. 2 2
      dist/preview release/loaders/babylonjs.loaders.min.js
  24. 1 1
      dist/preview release/packagesSizeBaseLine.json
  25. 58132 57875
      dist/preview release/viewer/babylon.module.d.ts
  26. 80 52
      dist/preview release/viewer/babylon.viewer.js
  27. 2 2
      dist/preview release/viewer/babylon.viewer.max.js
  28. 4 3
      dist/preview release/what's new.md
  29. 1 1
      gui/src/2D/adtInstrumentation.ts
  30. 2 0
      loaders/src/glTF/2.0/Extensions/KHR_materials_pbrSpecularGlossiness.ts
  31. 1 0
      loaders/src/glTF/2.0/Extensions/KHR_materials_unlit.ts
  32. 2324 2322
      loaders/src/glTF/2.0/glTFLoader.ts
  33. 2 3
      src/Behaviors/Cameras/framingBehavior.ts
  34. 2 2
      src/Cameras/XR/webXRCamera.ts
  35. 14 1
      src/Cameras/XR/webXRControllerModelLoader.ts
  36. 2 2
      src/Cameras/XR/webXRControllerTeleportation.ts
  37. 1 1
      src/Cameras/XR/webXRExperienceHelper.ts
  38. 1 1
      src/Cameras/XR/webXRSessionManager.ts
  39. 5 1
      src/Cameras/camera.ts
  40. 3 3
      src/Engines/Extensions/engine.cubeTexture.ts
  41. 2 2
      src/Engines/Extensions/engine.webVR.ts
  42. 4 4
      src/Engines/Processors/shaderCodeNode.ts
  43. 2 2
      src/Engines/Processors/shaderProcessor.ts
  44. 220 80
      src/Engines/engine.ts
  45. 12 0
      src/Engines/engineStore.ts
  46. 3 13
      src/Engines/nullEngine.ts
  47. 2 2
      src/Gamepads/gamepadManager.ts
  48. 1 1
      src/Instrumentation/engineInstrumentation.ts
  49. 2 1
      src/Instrumentation/sceneInstrumentation.ts
  50. 2 2
      src/Layers/effectLayer.ts
  51. 3 3
      src/Layers/glowLayer.ts
  52. 2 3
      src/Layers/highlightLayer.ts
  53. 5 5
      src/LibDeclarations/webxr.d.ts
  54. 3 2
      src/Loading/Plugins/babylonFileLoader.ts
  55. 2 1
      src/Loading/sceneLoader.ts
  56. 3 4
      src/Materials/Textures/renderTargetTexture.ts
  57. 3 3
      src/Materials/effect.ts
  58. 79 0
      src/Maths/math.functions.ts
  59. 11 0
      src/Maths/math.ts
  60. 2 1
      src/Meshes/abstractMesh.ts
  61. 2 1
      src/Meshes/geometry.ts
  62. 2 2
      src/Meshes/subMesh.ts
  63. 20 0
      src/Misc/customAnimationFrameRequester.ts
  64. 16 0
      src/Misc/fileRequest.ts
  65. 370 0
      src/Misc/fileTools.ts
  66. 108 0
      src/Misc/gradients.ts
  67. 6 0
      src/Misc/index.ts
  68. 30 0
      src/Misc/loadFileError.ts
  69. 169 0
      src/Misc/perfCounter.ts
  70. 1 2
      src/Misc/promise.ts
  71. 22 0
      src/Misc/retryStrategy.ts
  72. 24 0
      src/Misc/stringTools.ts
  73. 64 919
      src/Misc/tools.ts
  74. 1 1
      src/Particles/IParticleSystem.ts
  75. 1 1
      src/Particles/baseParticleSystem.ts
  76. 4 3
      src/Particles/gpuParticleSystem.ts
  77. 1 1
      src/Particles/particle.ts
  78. 14 13
      src/Particles/particleSystem.ts
  79. 5 6
      src/PostProcesses/postProcess.ts
  80. 2 3
      src/node.ts
  81. 5 3
      src/scene.ts
  82. 1 1
      tests/validation/config.json

Різницю між файлами не показано, бо вона завелика
+ 21445 - 21330
Playground/babylon.d.txt


+ 6 - 5
Viewer/src/configuration/renderOnlyLoader.ts

@@ -3,9 +3,10 @@ import { ViewerConfiguration } from './configuration';
 import { processConfigurationCompatibility } from './configurationCompatibility';
 
 import { deepmerge } from '../helper';
-import { IFileRequest, Tools } from 'babylonjs/Misc/tools';
+import { Tools } from 'babylonjs/Misc/tools';
 import { extendedConfiguration } from './types/extended';
 import { renderOnlyDefaultConfiguration } from './types/renderOnlyDefault';
+import { IFileRequest } from 'babylonjs/Misc/fileRequest';
 
 /**
  * The configuration loader will load the configuration object from any source and will use the defined mapper to
@@ -23,7 +24,7 @@ export class RenderOnlyConfigurationLoader {
         this._loadRequests = [];
     }
 
-    private _getConfigurationTypeExcludeTemplate (types: string): ViewerConfiguration {
+    private _getConfigurationTypeExcludeTemplate(types: string): ViewerConfiguration {
         let config: ViewerConfiguration = {};
         let typesSeparated = types.split(",");
         typesSeparated.forEach((type) => {
@@ -45,7 +46,7 @@ export class RenderOnlyConfigurationLoader {
         return config;
     };
 
-    protected getExtendedConfig(type:string|undefined){
+    protected getExtendedConfig(type: string | undefined) {
         return this._getConfigurationTypeExcludeTemplate(type || "extended");
     }
 
@@ -61,7 +62,7 @@ export class RenderOnlyConfigurationLoader {
 
         let loadedConfig: ViewerConfiguration = deepmerge({}, initConfig);
         this._processInitialConfiguration(loadedConfig);
-        
+
         let extendedConfiguration = this.getExtendedConfig(loadedConfig.extends);
 
         if (loadedConfig.configuration) {
@@ -160,5 +161,5 @@ export class RenderOnlyConfigurationLoader {
             this._loadRequests.push(fileRequest);
         });
     }
-    
+
 }

+ 2 - 1
Viewer/src/templating/templateManager.ts

@@ -1,11 +1,12 @@
 import { Observable } from 'babylonjs/Misc/observable';
-import { IFileRequest, Tools } from 'babylonjs/Misc/tools';
+import { Tools } from 'babylonjs/Misc/tools';
 import { isUrl, camelToKebab, kebabToCamel } from '../helper';
 
 import * as Handlebars from 'handlebars/dist/handlebars';
 import { EventManager } from './eventManager';
 import { ITemplateConfiguration } from '../configuration/interfaces';
 import { deepmerge } from '../helper/';
+import { IFileRequest } from 'babylonjs/Misc/fileRequest';
 
 /**
  * The object sent when an event is triggered

Різницю між файлами не показано, бо вона завелика
+ 22241 - 22122
dist/preview release/babylon.d.ts


Різницю між файлами не показано, бо вона завелика
+ 2 - 2
dist/preview release/babylon.js


Різницю між файлами не показано, бо вона завелика
+ 1693 - 1422
dist/preview release/babylon.max.js


Різницю між файлами не показано, бо вона завелика
+ 1 - 1
dist/preview release/babylon.max.js.map


Різницю між файлами не показано, бо вона завелика
+ 58132 - 57875
dist/preview release/babylon.module.d.ts


Різницю між файлами не показано, бо вона завелика
+ 22241 - 22122
dist/preview release/documentation.d.ts


+ 4 - 4
dist/preview release/gui/babylon.gui.js

@@ -355,8 +355,8 @@ module.exports = g;
 "use strict";
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "AdvancedDynamicTextureInstrumentation", function() { return AdvancedDynamicTextureInstrumentation; });
-/* harmony import */ var babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! babylonjs/Misc/tools */ "babylonjs/Maths/math");
-/* harmony import */ var babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_0__);
+/* harmony import */ var babylonjs_Misc_perfCounter__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! babylonjs/Misc/perfCounter */ "babylonjs/Maths/math");
+/* harmony import */ var babylonjs_Misc_perfCounter__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_perfCounter__WEBPACK_IMPORTED_MODULE_0__);
 
 /**
  * This class can be used to get instrumentation data from a AdvancedDynamicTexture object
@@ -374,9 +374,9 @@ var AdvancedDynamicTextureInstrumentation = /** @class */ (function () {
     texture) {
         this.texture = texture;
         this._captureRenderTime = false;
-        this._renderTime = new babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_0__["PerfCounter"]();
+        this._renderTime = new babylonjs_Misc_perfCounter__WEBPACK_IMPORTED_MODULE_0__["PerfCounter"]();
         this._captureLayoutTime = false;
-        this._layoutTime = new babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_0__["PerfCounter"]();
+        this._layoutTime = new babylonjs_Misc_perfCounter__WEBPACK_IMPORTED_MODULE_0__["PerfCounter"]();
         // Observers
         this._onBeginRenderObserver = null;
         this._onEndRenderObserver = null;

Різницю між файлами не показано, бо вона завелика
+ 1 - 1
dist/preview release/gui/babylon.gui.js.map


+ 1 - 1
dist/preview release/gui/babylon.gui.module.d.ts

@@ -3012,7 +3012,7 @@ declare module "babylonjs-gui/2D/controls/index" {
     export * from "babylonjs-gui/2D/controls/statics";
 }
 declare module "babylonjs-gui/2D/adtInstrumentation" {
-    import { PerfCounter } from "babylonjs/Misc/tools";
+    import { PerfCounter } from "babylonjs/Misc/perfCounter";
     import { IDisposable } from "babylonjs/scene";
     import { AdvancedDynamicTexture } from "babylonjs-gui/2D/advancedDynamicTexture";
     /**

+ 7 - 7
dist/preview release/inspector/babylon.inspector.bundle.max.js

@@ -7,7 +7,7 @@
 		exports["babylonjs-inspector"] = factory(require("babylonjs-gui"), require("babylonjs-loaders"), require("babylonjs-serializers"), require("babylonjs"));
 	else
 		root["INSPECTOR"] = factory(root["BABYLON"]["GUI"], root["BABYLON"], root["BABYLON"], root["BABYLON"]);
-})((typeof self !== "undefined" ? self : typeof global !== "undefined" ? global : this), function(__WEBPACK_EXTERNAL_MODULE_babylonjs_gui_2D_adtInstrumentation__, __WEBPACK_EXTERNAL_MODULE_babylonjs_loaders_glTF_index__, __WEBPACK_EXTERNAL_MODULE_babylonjs_serializers_glTF_2_0_index__, __WEBPACK_EXTERNAL_MODULE_babylonjs_Misc_observable__) {
+})((typeof self !== "undefined" ? self : typeof global !== "undefined" ? global : this), function(__WEBPACK_EXTERNAL_MODULE_babylonjs_gui_2D_controls_image__, __WEBPACK_EXTERNAL_MODULE_babylonjs_loaders_glTF_index__, __WEBPACK_EXTERNAL_MODULE_babylonjs_serializers_glTF_2_0_index__, __WEBPACK_EXTERNAL_MODULE_babylonjs_Misc_observable__) {
 return /******/ (function(modules) { // webpackBootstrap
 /******/ 	// The module cache
 /******/ 	var installedModules = {};
@@ -36157,7 +36157,7 @@ __webpack_require__.r(__webpack_exports__);
 /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var _lineContainerComponent__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../../../lineContainerComponent */ "./components/actionTabs/lineContainerComponent.tsx");
 /* harmony import */ var _lines_textLineComponent__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../../../lines/textLineComponent */ "./components/actionTabs/lines/textLineComponent.tsx");
-/* harmony import */ var babylonjs_gui_2D_controls_control__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! babylonjs-gui/2D/controls/control */ "babylonjs-gui/2D/adtInstrumentation");
+/* harmony import */ var babylonjs_gui_2D_controls_control__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! babylonjs-gui/2D/controls/control */ "babylonjs-gui/2D/controls/image");
 /* harmony import */ var babylonjs_gui_2D_controls_control__WEBPACK_IMPORTED_MODULE_4___default = /*#__PURE__*/__webpack_require__.n(babylonjs_gui_2D_controls_control__WEBPACK_IMPORTED_MODULE_4__);
 /* harmony import */ var _lines_sliderLineComponent__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ../../../lines/sliderLineComponent */ "./components/actionTabs/lines/sliderLineComponent.tsx");
 /* harmony import */ var _lines_floatLineComponent__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ../../../lines/floatLineComponent */ "./components/actionTabs/lines/floatLineComponent.tsx");
@@ -36462,7 +36462,7 @@ __webpack_require__.r(__webpack_exports__);
 /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var _commonControlPropertyGridComponent__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./commonControlPropertyGridComponent */ "./components/actionTabs/tabs/propertyGrids/gui/commonControlPropertyGridComponent.tsx");
 /* harmony import */ var _lineContainerComponent__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../../../lineContainerComponent */ "./components/actionTabs/lineContainerComponent.tsx");
-/* harmony import */ var babylonjs_gui_2D_controls_image__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! babylonjs-gui/2D/controls/image */ "babylonjs-gui/2D/adtInstrumentation");
+/* harmony import */ var babylonjs_gui_2D_controls_image__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! babylonjs-gui/2D/controls/image */ "babylonjs-gui/2D/controls/image");
 /* harmony import */ var babylonjs_gui_2D_controls_image__WEBPACK_IMPORTED_MODULE_4___default = /*#__PURE__*/__webpack_require__.n(babylonjs_gui_2D_controls_image__WEBPACK_IMPORTED_MODULE_4__);
 /* harmony import */ var _lines_floatLineComponent__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ../../../lines/floatLineComponent */ "./components/actionTabs/lines/floatLineComponent.tsx");
 /* harmony import */ var _lines_checkBoxLineComponent__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ../../../lines/checkBoxLineComponent */ "./components/actionTabs/lines/checkBoxLineComponent.tsx");
@@ -36876,7 +36876,7 @@ __webpack_require__.r(__webpack_exports__);
 /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react */ "../../node_modules/react/index.js");
 /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var _commonControlPropertyGridComponent__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./commonControlPropertyGridComponent */ "./components/actionTabs/tabs/propertyGrids/gui/commonControlPropertyGridComponent.tsx");
-/* harmony import */ var babylonjs_gui_2D_controls_textBlock__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! babylonjs-gui/2D/controls/textBlock */ "babylonjs-gui/2D/adtInstrumentation");
+/* harmony import */ var babylonjs_gui_2D_controls_textBlock__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! babylonjs-gui/2D/controls/textBlock */ "babylonjs-gui/2D/controls/image");
 /* harmony import */ var babylonjs_gui_2D_controls_textBlock__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(babylonjs_gui_2D_controls_textBlock__WEBPACK_IMPORTED_MODULE_3__);
 /* harmony import */ var _lineContainerComponent__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../../../lineContainerComponent */ "./components/actionTabs/lineContainerComponent.tsx");
 /* harmony import */ var _lines_textInputLineComponent__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ../../../lines/textInputLineComponent */ "./components/actionTabs/lines/textInputLineComponent.tsx");
@@ -38013,7 +38013,7 @@ __webpack_require__.r(__webpack_exports__);
 /* harmony import */ var _lines_optionsLineComponent__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! ../../../lines/optionsLineComponent */ "./components/actionTabs/lines/optionsLineComponent.tsx");
 /* harmony import */ var _lines_fileButtonLineComponent__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! ../../../lines/fileButtonLineComponent */ "./components/actionTabs/lines/fileButtonLineComponent.tsx");
 /* harmony import */ var _lines_valueLineComponent__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! ../../../lines/valueLineComponent */ "./components/actionTabs/lines/valueLineComponent.tsx");
-/* harmony import */ var babylonjs_gui_2D_adtInstrumentation__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(/*! babylonjs-gui/2D/adtInstrumentation */ "babylonjs-gui/2D/adtInstrumentation");
+/* harmony import */ var babylonjs_gui_2D_adtInstrumentation__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(/*! babylonjs-gui/2D/adtInstrumentation */ "babylonjs-gui/2D/controls/image");
 /* harmony import */ var babylonjs_gui_2D_adtInstrumentation__WEBPACK_IMPORTED_MODULE_12___default = /*#__PURE__*/__webpack_require__.n(babylonjs_gui_2D_adtInstrumentation__WEBPACK_IMPORTED_MODULE_12__);
 /* harmony import */ var _customPropertyGridComponent__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(/*! ../customPropertyGridComponent */ "./components/actionTabs/tabs/propertyGrids/customPropertyGridComponent.tsx");
 
@@ -42703,14 +42703,14 @@ var Tools = /** @class */ (function () {
 
 /***/ }),
 
-/***/ "babylonjs-gui/2D/adtInstrumentation":
+/***/ "babylonjs-gui/2D/controls/image":
 /*!************************************************************************************************************************!*\
   !*** external {"root":["BABYLON","GUI"],"commonjs":"babylonjs-gui","commonjs2":"babylonjs-gui","amd":"babylonjs-gui"} ***!
   \************************************************************************************************************************/
 /*! no static exports found */
 /***/ (function(module, exports) {
 
-module.exports = __WEBPACK_EXTERNAL_MODULE_babylonjs_gui_2D_adtInstrumentation__;
+module.exports = __WEBPACK_EXTERNAL_MODULE_babylonjs_gui_2D_controls_image__;
 
 /***/ }),
 

Різницю між файлами не показано, бо вона завелика
+ 1 - 1
dist/preview release/inspector/babylon.inspector.bundle.max.js.map


+ 9 - 3
dist/preview release/loaders/babylon.glTF2FileLoader.js

@@ -567,11 +567,13 @@ var KHR_materials_pbrSpecularGlossiness = /** @class */ (function () {
         babylonMaterial.microSurface = properties.glossinessFactor == undefined ? 1 : properties.glossinessFactor;
         if (properties.diffuseTexture) {
             promises.push(this._loader.loadTextureInfoAsync(context + "/diffuseTexture", properties.diffuseTexture, function (texture) {
+                texture.name = babylonMaterial.name + " (Diffuse)";
                 babylonMaterial.albedoTexture = texture;
             }));
         }
         if (properties.specularGlossinessTexture) {
             promises.push(this._loader.loadTextureInfoAsync(context + "/specularGlossinessTexture", properties.specularGlossinessTexture, function (texture) {
+                texture.name = babylonMaterial.name + " (Specular Glossiness)";
                 babylonMaterial.reflectivityTexture = texture;
             }));
             babylonMaterial.reflectivityTexture.hasAlpha = true;
@@ -644,6 +646,7 @@ var KHR_materials_unlit = /** @class */ (function () {
             }
             if (properties.baseColorTexture) {
                 promises.push(this._loader.loadTextureInfoAsync(context + "/baseColorTexture", properties.baseColorTexture, function (texture) {
+                    texture.name = babylonMaterial.name + " (Base Color)";
                     babylonMaterial.albedoTexture = texture;
                 }));
             }
@@ -1426,6 +1429,7 @@ __webpack_require__.r(__webpack_exports__);
 
 
 
+
 /**
  * Helper class for working with arrays when loading the glTF asset
  */
@@ -2746,11 +2750,13 @@ var GLTFLoader = /** @class */ (function () {
             babylonMaterial.roughness = properties.roughnessFactor == undefined ? 1 : properties.roughnessFactor;
             if (properties.baseColorTexture) {
                 promises.push(this.loadTextureInfoAsync(context + "/baseColorTexture", properties.baseColorTexture, function (texture) {
+                    texture.name = babylonMaterial.name + " (Base Color)";
                     babylonMaterial.albedoTexture = texture;
                 }));
             }
             if (properties.metallicRoughnessTexture) {
                 promises.push(this.loadTextureInfoAsync(context + "/metallicRoughnessTexture", properties.metallicRoughnessTexture, function (texture) {
+                    texture.name = babylonMaterial.name + " (Metallic Roughness)";
                     babylonMaterial.metallicTexture = texture;
                 }));
                 babylonMaterial.useMetallnessFromMetallicTextureBlue = true;
@@ -2861,6 +2867,7 @@ var GLTFLoader = /** @class */ (function () {
         }
         if (material.normalTexture) {
             promises.push(this.loadTextureInfoAsync(context + "/normalTexture", material.normalTexture, function (texture) {
+                texture.name = babylonMaterial.name + " (Normal)";
                 babylonMaterial.bumpTexture = texture;
             }));
             babylonMaterial.invertNormalMapX = !this._babylonScene.useRightHandedSystem;
@@ -2872,6 +2879,7 @@ var GLTFLoader = /** @class */ (function () {
         }
         if (material.occlusionTexture) {
             promises.push(this.loadTextureInfoAsync(context + "/occlusionTexture", material.occlusionTexture, function (texture) {
+                texture.name = babylonMaterial.name + " (Occlusion)";
                 babylonMaterial.ambientTexture = texture;
             }));
             babylonMaterial.useAmbientInGrayScale = true;
@@ -2881,6 +2889,7 @@ var GLTFLoader = /** @class */ (function () {
         }
         if (material.emissiveTexture) {
             promises.push(this.loadTextureInfoAsync(context + "/emissiveTexture", material.emissiveTexture, function (texture) {
+                texture.name = babylonMaterial.name + " (Emissive)";
                 babylonMaterial.emissiveTexture = texture;
             }));
         }
@@ -2942,9 +2951,6 @@ var GLTFLoader = /** @class */ (function () {
         var texture = ArrayItem.Get(context + "/index", this._gltf.textures, textureInfo.index);
         var promise = this._loadTextureAsync("/textures/" + textureInfo.index, texture, function (babylonTexture) {
             babylonTexture.coordinatesIndex = textureInfo.texCoord || 0;
-            if (texture.name) {
-                babylonTexture.name = texture.name;
-            }
             GLTFLoader.AddPointerMetadata(babylonTexture, context);
             _this._parent.onTextureLoadedObservable.notifyObservers(babylonTexture);
             assign(babylonTexture);

Різницю між файлами не показано, бо вона завелика
+ 1 - 1
dist/preview release/loaders/babylon.glTF2FileLoader.js.map


Різницю між файлами не показано, бо вона завелика
+ 1 - 1
dist/preview release/loaders/babylon.glTF2FileLoader.min.js


+ 9 - 3
dist/preview release/loaders/babylon.glTFFileLoader.js

@@ -3116,11 +3116,13 @@ var KHR_materials_pbrSpecularGlossiness = /** @class */ (function () {
         babylonMaterial.microSurface = properties.glossinessFactor == undefined ? 1 : properties.glossinessFactor;
         if (properties.diffuseTexture) {
             promises.push(this._loader.loadTextureInfoAsync(context + "/diffuseTexture", properties.diffuseTexture, function (texture) {
+                texture.name = babylonMaterial.name + " (Diffuse)";
                 babylonMaterial.albedoTexture = texture;
             }));
         }
         if (properties.specularGlossinessTexture) {
             promises.push(this._loader.loadTextureInfoAsync(context + "/specularGlossinessTexture", properties.specularGlossinessTexture, function (texture) {
+                texture.name = babylonMaterial.name + " (Specular Glossiness)";
                 babylonMaterial.reflectivityTexture = texture;
             }));
             babylonMaterial.reflectivityTexture.hasAlpha = true;
@@ -3193,6 +3195,7 @@ var KHR_materials_unlit = /** @class */ (function () {
             }
             if (properties.baseColorTexture) {
                 promises.push(this._loader.loadTextureInfoAsync(context + "/baseColorTexture", properties.baseColorTexture, function (texture) {
+                    texture.name = babylonMaterial.name + " (Base Color)";
                     babylonMaterial.albedoTexture = texture;
                 }));
             }
@@ -3975,6 +3978,7 @@ __webpack_require__.r(__webpack_exports__);
 
 
 
+
 /**
  * Helper class for working with arrays when loading the glTF asset
  */
@@ -5295,11 +5299,13 @@ var GLTFLoader = /** @class */ (function () {
             babylonMaterial.roughness = properties.roughnessFactor == undefined ? 1 : properties.roughnessFactor;
             if (properties.baseColorTexture) {
                 promises.push(this.loadTextureInfoAsync(context + "/baseColorTexture", properties.baseColorTexture, function (texture) {
+                    texture.name = babylonMaterial.name + " (Base Color)";
                     babylonMaterial.albedoTexture = texture;
                 }));
             }
             if (properties.metallicRoughnessTexture) {
                 promises.push(this.loadTextureInfoAsync(context + "/metallicRoughnessTexture", properties.metallicRoughnessTexture, function (texture) {
+                    texture.name = babylonMaterial.name + " (Metallic Roughness)";
                     babylonMaterial.metallicTexture = texture;
                 }));
                 babylonMaterial.useMetallnessFromMetallicTextureBlue = true;
@@ -5410,6 +5416,7 @@ var GLTFLoader = /** @class */ (function () {
         }
         if (material.normalTexture) {
             promises.push(this.loadTextureInfoAsync(context + "/normalTexture", material.normalTexture, function (texture) {
+                texture.name = babylonMaterial.name + " (Normal)";
                 babylonMaterial.bumpTexture = texture;
             }));
             babylonMaterial.invertNormalMapX = !this._babylonScene.useRightHandedSystem;
@@ -5421,6 +5428,7 @@ var GLTFLoader = /** @class */ (function () {
         }
         if (material.occlusionTexture) {
             promises.push(this.loadTextureInfoAsync(context + "/occlusionTexture", material.occlusionTexture, function (texture) {
+                texture.name = babylonMaterial.name + " (Occlusion)";
                 babylonMaterial.ambientTexture = texture;
             }));
             babylonMaterial.useAmbientInGrayScale = true;
@@ -5430,6 +5438,7 @@ var GLTFLoader = /** @class */ (function () {
         }
         if (material.emissiveTexture) {
             promises.push(this.loadTextureInfoAsync(context + "/emissiveTexture", material.emissiveTexture, function (texture) {
+                texture.name = babylonMaterial.name + " (Emissive)";
                 babylonMaterial.emissiveTexture = texture;
             }));
         }
@@ -5491,9 +5500,6 @@ var GLTFLoader = /** @class */ (function () {
         var texture = ArrayItem.Get(context + "/index", this._gltf.textures, textureInfo.index);
         var promise = this._loadTextureAsync("/textures/" + textureInfo.index, texture, function (babylonTexture) {
             babylonTexture.coordinatesIndex = textureInfo.texCoord || 0;
-            if (texture.name) {
-                babylonTexture.name = texture.name;
-            }
             GLTFLoader.AddPointerMetadata(babylonTexture, context);
             _this._parent.onTextureLoadedObservable.notifyObservers(babylonTexture);
             assign(babylonTexture);

Різницю між файлами не показано, бо вона завелика
+ 1 - 1
dist/preview release/loaders/babylon.glTFFileLoader.js.map


Різницю між файлами не показано, бо вона завелика
+ 1 - 1
dist/preview release/loaders/babylon.glTFFileLoader.min.js


+ 9 - 3
dist/preview release/loaders/babylonjs.loaders.js

@@ -4458,11 +4458,13 @@ var KHR_materials_pbrSpecularGlossiness = /** @class */ (function () {
         babylonMaterial.microSurface = properties.glossinessFactor == undefined ? 1 : properties.glossinessFactor;
         if (properties.diffuseTexture) {
             promises.push(this._loader.loadTextureInfoAsync(context + "/diffuseTexture", properties.diffuseTexture, function (texture) {
+                texture.name = babylonMaterial.name + " (Diffuse)";
                 babylonMaterial.albedoTexture = texture;
             }));
         }
         if (properties.specularGlossinessTexture) {
             promises.push(this._loader.loadTextureInfoAsync(context + "/specularGlossinessTexture", properties.specularGlossinessTexture, function (texture) {
+                texture.name = babylonMaterial.name + " (Specular Glossiness)";
                 babylonMaterial.reflectivityTexture = texture;
             }));
             babylonMaterial.reflectivityTexture.hasAlpha = true;
@@ -4535,6 +4537,7 @@ var KHR_materials_unlit = /** @class */ (function () {
             }
             if (properties.baseColorTexture) {
                 promises.push(this._loader.loadTextureInfoAsync(context + "/baseColorTexture", properties.baseColorTexture, function (texture) {
+                    texture.name = babylonMaterial.name + " (Base Color)";
                     babylonMaterial.albedoTexture = texture;
                 }));
             }
@@ -5317,6 +5320,7 @@ __webpack_require__.r(__webpack_exports__);
 
 
 
+
 /**
  * Helper class for working with arrays when loading the glTF asset
  */
@@ -6637,11 +6641,13 @@ var GLTFLoader = /** @class */ (function () {
             babylonMaterial.roughness = properties.roughnessFactor == undefined ? 1 : properties.roughnessFactor;
             if (properties.baseColorTexture) {
                 promises.push(this.loadTextureInfoAsync(context + "/baseColorTexture", properties.baseColorTexture, function (texture) {
+                    texture.name = babylonMaterial.name + " (Base Color)";
                     babylonMaterial.albedoTexture = texture;
                 }));
             }
             if (properties.metallicRoughnessTexture) {
                 promises.push(this.loadTextureInfoAsync(context + "/metallicRoughnessTexture", properties.metallicRoughnessTexture, function (texture) {
+                    texture.name = babylonMaterial.name + " (Metallic Roughness)";
                     babylonMaterial.metallicTexture = texture;
                 }));
                 babylonMaterial.useMetallnessFromMetallicTextureBlue = true;
@@ -6752,6 +6758,7 @@ var GLTFLoader = /** @class */ (function () {
         }
         if (material.normalTexture) {
             promises.push(this.loadTextureInfoAsync(context + "/normalTexture", material.normalTexture, function (texture) {
+                texture.name = babylonMaterial.name + " (Normal)";
                 babylonMaterial.bumpTexture = texture;
             }));
             babylonMaterial.invertNormalMapX = !this._babylonScene.useRightHandedSystem;
@@ -6763,6 +6770,7 @@ var GLTFLoader = /** @class */ (function () {
         }
         if (material.occlusionTexture) {
             promises.push(this.loadTextureInfoAsync(context + "/occlusionTexture", material.occlusionTexture, function (texture) {
+                texture.name = babylonMaterial.name + " (Occlusion)";
                 babylonMaterial.ambientTexture = texture;
             }));
             babylonMaterial.useAmbientInGrayScale = true;
@@ -6772,6 +6780,7 @@ var GLTFLoader = /** @class */ (function () {
         }
         if (material.emissiveTexture) {
             promises.push(this.loadTextureInfoAsync(context + "/emissiveTexture", material.emissiveTexture, function (texture) {
+                texture.name = babylonMaterial.name + " (Emissive)";
                 babylonMaterial.emissiveTexture = texture;
             }));
         }
@@ -6833,9 +6842,6 @@ var GLTFLoader = /** @class */ (function () {
         var texture = ArrayItem.Get(context + "/index", this._gltf.textures, textureInfo.index);
         var promise = this._loadTextureAsync("/textures/" + textureInfo.index, texture, function (babylonTexture) {
             babylonTexture.coordinatesIndex = textureInfo.texCoord || 0;
-            if (texture.name) {
-                babylonTexture.name = texture.name;
-            }
             GLTFLoader.AddPointerMetadata(babylonTexture, context);
             _this._parent.onTextureLoadedObservable.notifyObservers(babylonTexture);
             assign(babylonTexture);

Різницю між файлами не показано, бо вона завелика
+ 1 - 1
dist/preview release/loaders/babylonjs.loaders.js.map


Різницю між файлами не показано, бо вона завелика
+ 2 - 2
dist/preview release/loaders/babylonjs.loaders.min.js


+ 1 - 1
dist/preview release/packagesSizeBaseLine.json

@@ -1 +1 @@
-{"engineOnly":252171,"sceneOnly":510337,"minGridMaterial":639247,"minStandardMaterial":765316}
+{"engineOnly":166401,"sceneOnly":510917,"minGridMaterial":639821,"minStandardMaterial":765892}

Різницю між файлами не показано, бо вона завелика
+ 58132 - 57875
dist/preview release/viewer/babylon.module.d.ts


Різницю між файлами не показано, бо вона завелика
+ 80 - 52
dist/preview release/viewer/babylon.viewer.js


Різницю між файлами не показано, бо вона завелика
+ 2 - 2
dist/preview release/viewer/babylon.viewer.max.js


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

@@ -24,8 +24,8 @@
 - Added startAndReleaseDragOnPointerEvents property to pointerDragBehavior which can be set to false for custom drag triggering ([TrevorDev](https://github.com/TrevorDev))
 - Effect renderer to render one or multiple shader effects to a texture ([TrevorDev](https://github.com/TrevorDev))
 - Added url parameters to web request modifiers ([PierreLeBlond](https://github.com/PierreLeBlond))
-- WebXR updated to spec as of July 9th ([TrevorDev](https://github.com/TrevorDev))
-- WebXR webVR parity helpers ([TrevorDev](https://github.com/TrevorDev))
+- WebXR updated to spec as of July 10th ([TrevorDev](https://github.com/TrevorDev))
+- WebXR webVR parity helpers (Vive, WMR, Oculus Rift) ([TrevorDev](https://github.com/TrevorDev))
 
 ### Engine
 - Morph targets now can morph UV channel as well ([Deltakosh](https://github.com/deltakosh/))
@@ -93,9 +93,10 @@
 - Fix bug when adding and removing observers in quick succession ([sable](https://github.com/thscott))
 - Cannon and Ammo forceUpdate will no longer cause an unexpected exception ([TrevorDev](https://github.com/TrevorDev))
 - Loading the same multi-material twice and disposing one should not impact the other ([TrevorDev](https://github.com/TrevorDev))
-- GLTF loader should now preserve the texture naming ([Drigax](https://github.com/Drigax))
 - GLTF exporter should no longer duplicate exported texture data ([Drigax](https://github.com/Drigax))
 - Avoid exception when disposing of Ammo cloth physics ([TrevorDev](https://github.com/TrevorDev))
 
 ## Breaking changes
 - Setting mesh.scaling to a new vector will no longer automatically call forceUpdate (this should be done manually when needed) ([TrevorDev](https://github.com/TrevorDev))
+- `Tools.ExtractMinAndMaxIndexed` and `Tools.ExtractMinAndMax` are now ambiant functions (available on `BABYLON.extractMinAndMaxIndexed` and `BABYLON.extractMinAndMax`) ([Deltakosh](https://github.com/deltakosh/))
+- `Tools.QueueNewFrame` was removed in favor of `Engine.QueueNewFrame` ([Deltakosh](https://github.com/deltakosh/))

+ 1 - 1
gui/src/2D/adtInstrumentation.ts

@@ -1,7 +1,7 @@
 
 import { Nullable } from "babylonjs/types";
 import { Observer } from "babylonjs/Misc/observable";
-import { PerfCounter } from "babylonjs/Misc/tools";
+import { PerfCounter } from "babylonjs/Misc/perfCounter";
 import { IDisposable } from "babylonjs/scene";
 
 import { AdvancedDynamicTexture } from "./advancedDynamicTexture";

+ 2 - 0
loaders/src/glTF/2.0/Extensions/KHR_materials_pbrSpecularGlossiness.ts

@@ -73,12 +73,14 @@ export class KHR_materials_pbrSpecularGlossiness implements IGLTFLoaderExtension
 
         if (properties.diffuseTexture) {
             promises.push(this._loader.loadTextureInfoAsync(`${context}/diffuseTexture`, properties.diffuseTexture, (texture) => {
+                texture.name = `${babylonMaterial.name} (Diffuse)`;
                 babylonMaterial.albedoTexture = texture;
             }));
         }
 
         if (properties.specularGlossinessTexture) {
             promises.push(this._loader.loadTextureInfoAsync(`${context}/specularGlossinessTexture`, properties.specularGlossinessTexture, (texture) => {
+                texture.name = `${babylonMaterial.name} (Specular Glossiness)`;
                 babylonMaterial.reflectivityTexture = texture;
             }));
 

+ 1 - 0
loaders/src/glTF/2.0/Extensions/KHR_materials_unlit.ts

@@ -58,6 +58,7 @@ export class KHR_materials_unlit implements IGLTFLoaderExtension {
 
             if (properties.baseColorTexture) {
                 promises.push(this._loader.loadTextureInfoAsync(`${context}/baseColorTexture`, properties.baseColorTexture, (texture) => {
+                    texture.name = `${babylonMaterial.name} (Base Color)`;
                     babylonMaterial.albedoTexture = texture;
                 }));
             }

Різницю між файлами не показано, бо вона завелика
+ 2324 - 2322
loaders/src/glTF/2.0/glTFLoader.ts


+ 2 - 3
src/Behaviors/Cameras/framingBehavior.ts

@@ -4,7 +4,6 @@ import { ArcRotateCamera } from "../../Cameras/arcRotateCamera";
 import { ExponentialEase, EasingFunction } from "../../Animations/easing";
 import { Nullable } from "../../types";
 import { PointerInfoPre, PointerEventTypes } from "../../Events/pointerEvents";
-import { Tools } from "../../Misc/tools";
 import { PrecisionDate } from "../../Misc/precisionDate";
 import { Observer } from "../../Misc/observable";
 import { AbstractMesh } from "../../Meshes/abstractMesh";
@@ -293,8 +292,8 @@ export class FramingBehavior implements Behavior<ArcRotateCamera> {
 
         for (let i = 0; i < meshes.length; i++) {
             let boundingInfo = meshes[i].getHierarchyBoundingVectors(true);
-            Tools.CheckExtends(boundingInfo.min, min, max);
-            Tools.CheckExtends(boundingInfo.max, min, max);
+            Vector3.CheckExtends(boundingInfo.min, min, max);
+            Vector3.CheckExtends(boundingInfo.max, min, max);
         }
 
         this.zoomOnBoundingInfo(min, max, focusOnOriginXZ, onAnimationEnd);

+ 2 - 2
src/Cameras/XR/webXRCamera.ts

@@ -21,7 +21,7 @@ export class WebXRCamera extends FreeCamera {
         super(name, Vector3.Zero(), scene);
 
         // Initial camera configuration
-        this.minZ = 0;
+        this.minZ = 0.1;
         this.rotationQuaternion = new Quaternion();
         this.cameraRigMode = Camera.RIG_MODE_CUSTOM;
         this.updateUpVectorFromRotation = true;
@@ -31,7 +31,7 @@ export class WebXRCamera extends FreeCamera {
     private _updateNumberOfRigCameras(viewCount = 1) {
         while (this.rigCameras.length < viewCount) {
             var newCamera = new TargetCamera("view: " + this.rigCameras.length, Vector3.Zero(), this.getScene());
-            newCamera.minZ = 0;
+            newCamera.minZ = 0.1;
             newCamera.parent = this;
             newCamera.rotationQuaternion = new Quaternion();
             newCamera.updateUpVectorFromRotation = true;

+ 14 - 1
src/Cameras/XR/webXRControllerModelLoader.ts

@@ -2,6 +2,7 @@ import { Quaternion } from '../../Maths/math';
 import { WindowsMotionController } from '../../Gamepads/Controllers/windowsMotionController';
 import { OculusTouchController } from '../../Gamepads/Controllers/oculusTouchController';
 import { WebXRInput } from './webXRInput';
+import { ViveController } from '../../Gamepads/Controllers/viveController';
 
 /**
  * Loads a controller model and adds it as a child of the WebXRControllers grip when the controller is created
@@ -13,7 +14,19 @@ export class WebXRControllerModelLoader {
      */
     constructor(input: WebXRInput) {
         input.onControllerAddedObservable.add((c) => {
-            if (c.inputSource.gamepad && c.inputSource.gamepad.id === "oculus-touch") {
+            if (c.inputSource.gamepad && c.inputSource.gamepad.id === "htc-vive") {
+                let controllerModel = new ViveController(c.inputSource.gamepad);
+                controllerModel.hand = c.inputSource.handedness;
+                controllerModel.isXR = true;
+                controllerModel.initControllerMesh(c.grip!.getScene(), (m) => {
+                    m.isPickable = false;
+                    m.getChildMeshes(false).forEach((m) => {
+                        m.isPickable = false;
+                    });
+                    controllerModel.mesh!.parent = c.grip!;
+                    controllerModel.mesh!.rotationQuaternion = Quaternion.FromEulerAngles(0, Math.PI, 0);
+                });
+            } else if (c.inputSource.gamepad && c.inputSource.gamepad.id === "oculus-touch") {
                 let controllerModel = new OculusTouchController(c.inputSource.gamepad);
                 controllerModel.hand = c.inputSource.handedness;
                 controllerModel.isXR = true;

+ 2 - 2
src/Cameras/XR/webXRControllerTeleportation.ts

@@ -100,7 +100,7 @@ export class WebXRControllerTeleportation {
                 }
 
                 if (c.inputSource.gamepad) {
-                    if (c.inputSource.gamepad.axes[1]) {
+                    if (c.inputSource.gamepad.axes[1] !== undefined) {
                         // Forward teleportation
                         if (c.inputSource.gamepad.axes[1] < -0.7) {
                             forwardReadyToTeleport = true;
@@ -145,7 +145,7 @@ export class WebXRControllerTeleportation {
                         }
                     }
 
-                    if (c.inputSource.gamepad.axes[0]) {
+                    if (c.inputSource.gamepad.axes[0] !== undefined) {
                         if (c.inputSource.gamepad.axes[0] < -0.7) {
                             leftReadyToTeleport = true;
                         }else {

+ 1 - 1
src/Cameras/XR/webXRExperienceHelper.ts

@@ -123,7 +123,7 @@ export class WebXRExperienceHelper implements IDisposable {
         }).then(() => {
             return outputCanvas.initializeXRLayerAsync(this.sessionManager.session);
         }).then(() => {
-            return this.sessionManager.updateRenderStateAsync({baseLayer: outputCanvas.xrLayer});
+            return this.sessionManager.updateRenderStateAsync({depthFar: this.camera.maxZ, depthNear: this.camera.minZ, baseLayer: outputCanvas.xrLayer!});
         }).then(() => {
             return this.sessionManager.startRenderingToXRAsync();
         }).then(() => {

+ 1 - 1
src/Cameras/XR/webXRSessionManager.ts

@@ -102,7 +102,7 @@ export class WebXRSessionManager implements IDisposable {
      * @param state state to set
      * @returns a promise that resolves once the render state has been updated
      */
-    public updateRenderStateAsync(state: any) {
+    public updateRenderStateAsync(state: XRRenderState) {
         if (state.baseLayer) {
             this.baseLayer = state.baseLayer;
         }

+ 5 - 1
src/Cameras/camera.ts

@@ -230,11 +230,15 @@ export class Camera extends Node {
     /**
      * Defines the list of custom render target which are rendered to and then used as the input to this camera's render. Eg. display another camera view on a TV in the main scene
      * This is pretty helpfull if you wish to make a camera render to a texture you could reuse somewhere
-     * else in the scene.
+     * else in the scene. (Eg. security camera)
+     *
+     * To change the final output target of the camera, camera.outputRenderTarget should be used instead (eg. webXR renders to a render target corrisponding to an HMD)
      */
     public customRenderTargets = new Array<RenderTargetTexture>();
     /**
      * When set, the camera will render to this render target instead of the default canvas
+     *
+     * If the desire is to use the output of a camera as a texture in the scene consider using camera.customRenderTargets instead
      */
     public outputRenderTarget: Nullable<RenderTargetTexture> = null;
 

+ 3 - 3
src/Engines/Extensions/engine.cubeTexture.ts

@@ -5,7 +5,7 @@ import { Nullable } from '../../types';
 import { Scene } from '../../scene';
 import { IInternalTextureLoader } from '../../Materials/Textures/internalTextureLoader';
 import { WebRequest } from '../../Misc/webRequest';
-import { Tools } from '../../Misc/tools';
+import { FileTools } from '../../Misc/fileTools';
 
 declare module "../../Engines/engine" {
     export interface Engine {
@@ -191,7 +191,7 @@ Engine.prototype._partialLoadImg = function(url: string, index: number, loadedIm
         }
     };
 
-    img = Tools.LoadImage(url, onload, onerror, scene ? scene.offlineProvider : null);
+    img = FileTools.LoadImage(url, onload, onerror, scene ? scene.offlineProvider : null);
     if (scene) {
         scene._addPendingData(img);
     }
@@ -268,7 +268,7 @@ Engine.prototype.createCubeTexture = function(rootUrl: string, scene: Nullable<S
         }
 
         this._cascadeLoadImgs(scene, (imgs) => {
-            var width = this.needPOTTextures ? Tools.GetExponentOfTwo(imgs[0].width, this._caps.maxCubemapTextureSize) : imgs[0].width;
+            var width = this.needPOTTextures ? Engine.GetExponentOfTwo(imgs[0].width, this._caps.maxCubemapTextureSize) : imgs[0].width;
             var height = width;
 
             this._prepareWorkingCanvas();

+ 2 - 2
src/Engines/Extensions/engine.webVR.ts

@@ -133,7 +133,7 @@ Engine.prototype.initWebVRAsync = function(): Promise<IDisplayChangedEventArgs>
         this._onVrDisplayDisconnect = () => {
             this._vrDisplay.cancelAnimationFrame(this._frameHandler);
             this._vrDisplay = undefined;
-            this._frameHandler = Tools.QueueNewFrame(this._bindedRenderFunction);
+            this._frameHandler = Engine.QueueNewFrame(this._bindedRenderFunction);
             notifyObservers();
         };
         this._onVrDisplayPresentChange = () => {
@@ -266,5 +266,5 @@ Engine.prototype.isVRPresenting = function() {
 };
 
 Engine.prototype._requestVRFrame = function() {
-    this._frameHandler = Tools.QueueNewFrame(this._bindedRenderFunction, this._vrDisplay);
+    this._frameHandler = Engine.QueueNewFrame(this._bindedRenderFunction, this._vrDisplay);
 };

+ 4 - 4
src/Engines/Processors/shaderCodeNode.ts

@@ -1,5 +1,5 @@
 import { ProcessingOptions } from './shaderProcessingOptions';
-import { Tools } from '../../Misc/tools';
+import { StringTools } from '../../Misc/stringTools';
 
 /** @hidden */
 export class ShaderCodeNode {
@@ -18,11 +18,11 @@ export class ShaderCodeNode {
             let value: string = this.line;
             let processor = options.processor;
             if (processor) {
-                if (processor.attributeProcessor && Tools.StartsWith(this.line, "attribute")) {
+                if (processor.attributeProcessor && StringTools.StartsWith(this.line, "attribute")) {
                     value = processor.attributeProcessor(this.line);
-                } else if (processor.varyingProcessor && Tools.StartsWith(this.line, "varying")) {
+                } else if (processor.varyingProcessor && StringTools.StartsWith(this.line, "varying")) {
                     value = processor.varyingProcessor(this.line, options.isFragment);
-                } else if ((processor.uniformProcessor || processor.uniformBufferProcessor) && Tools.StartsWith(this.line, "uniform")) {
+                } else if ((processor.uniformProcessor || processor.uniformBufferProcessor) && StringTools.StartsWith(this.line, "uniform")) {
                     let regex = /uniform (.+) (.+)/;
 
                     if (regex.test(this.line)) { // uniform

+ 2 - 2
src/Engines/Processors/shaderProcessor.ts

@@ -1,4 +1,3 @@
-import { Tools } from '../../Misc/tools';
 import { ShaderCodeNode } from './shaderCodeNode';
 import { ShaderCodeCursor } from './shaderCodeCursor';
 import { ShaderCodeConditionNode } from './shaderCodeConditionNode';
@@ -9,6 +8,7 @@ import { ShaderDefineAndOperator } from './Expressions/Operators/shaderDefineAnd
 import { ShaderDefineExpression } from './Expressions/shaderDefineExpression';
 import { ShaderDefineArithmeticOperator } from './Expressions/Operators/shaderDefineArithmeticOperator';
 import { ProcessingOptions } from './shaderProcessingOptions';
+import { FileTools } from '../../Misc/fileTools';
 
 /** @hidden */
 export class ShaderProcessor {
@@ -331,7 +331,7 @@ export class ShaderProcessor {
             } else {
                 var includeShaderUrl = options.shadersRepository + "ShadersInclude/" + includeFile + ".fx";
 
-                Tools.LoadFile(includeShaderUrl, (fileContent) => {
+                FileTools.LoadFile(includeShaderUrl, (fileContent) => {
                     options.includesShadersStore[includeFile] = fileContent as string;
                     this._ProcessIncludes(<string>returnValue, options, callback);
                 });

+ 220 - 80
src/Engines/engine.ts

@@ -1,13 +1,8 @@
 import { Observer, Observable } from "../Misc/observable";
 import { PerformanceMonitor } from "../Misc/performanceMonitor";
 import { StringDictionary } from "../Misc/stringDictionary";
-import { PromisePolyfill } from "../Misc/promise";
-import { Tools, ICustomAnimationFrameRequester, PerfCounter, IFileRequest } from "../Misc/tools";
-import { Nullable, FloatArray, DataArray, IndicesArray } from "../types";
-import { Camera } from "../Cameras/camera";
+import { Nullable, FloatArray, DataArray, IndicesArray, float } from "../types";
 import { Scene } from "../scene";
-import { Matrix, Color3, Color4, Viewport, Vector4 } from "../Maths/math";
-import { Scalar } from "../Maths/math.scalar";
 import { VertexBuffer } from "../Meshes/buffer";
 import { UniformBuffer } from "../Materials/uniformBuffer";
 import { Effect, EffectCreationOptions, EffectFallbacks } from "../Materials/effect";
@@ -32,6 +27,10 @@ import { DataBuffer } from '../Meshes/dataBuffer';
 import { WebGLDataBuffer } from '../Meshes/WebGL/webGLDataBuffer';
 import { IShaderProcessor } from './Processors/iShaderProcessor';
 import { WebGL2ShaderProcessor } from './WebGL/webGL2ShaderProcessors';
+import { PerfCounter } from '../Misc/perfCounter';
+import { IFileRequest } from '../Misc/fileRequest';
+import { ICustomAnimationFrameRequester } from '../Misc/customAnimationFrameRequester';
+import { FileTools } from '../Misc/fileTools';
 
 declare type Material = import("../Materials/material").Material;
 declare type PostProcess = import("../PostProcesses/postProcess").PostProcess;
@@ -40,6 +39,36 @@ declare type VideoTexture = import("../Materials/Textures/videoTexture").VideoTe
 declare type RenderTargetTexture = import("../Materials/Textures/renderTargetTexture").RenderTargetTexture;
 
 /**
+ * @hidden
+ */
+export interface IColor4Like {
+    r: float;
+    g: float;
+    b: float;
+    a: float;
+}
+
+/**
+ * @hidden
+ */
+export interface IViewportLike {
+    x: float;
+    y: float;
+    width: float;
+    height: float;
+}
+
+/**
+ * Defines the interface used by objects containing a viewport (like a camera)
+ */
+interface IViewportOwnerLike {
+    /**
+     * Gets or sets the viewport
+     */
+    viewport: IViewportLike;
+}
+
+/**
  * Keeps track of all the buffer info used in engine.
  */
 class BufferPointer {
@@ -847,7 +876,7 @@ export class Engine {
     private _compiledEffects: { [key: string]: Effect } = {};
     private _vertexAttribArraysEnabled: boolean[] = [];
     /** @hidden */
-    protected _cachedViewport: Nullable<Viewport>;
+    protected _cachedViewport: Nullable<IViewportLike>;
     private _cachedVertexArrayObject: Nullable<WebGLVertexArrayObject>;
     /** @hidden */
     protected _cachedVertexBuffers: any;
@@ -915,7 +944,7 @@ export class Engine {
     /**
      * Gets the current viewport
      */
-    public get currentViewport(): Nullable<Viewport> {
+    public get currentViewport(): Nullable<IViewportLike> {
         return this._cachedViewport;
     }
 
@@ -968,9 +997,6 @@ export class Engine {
      */
     constructor(canvasOrContext: Nullable<HTMLCanvasElement | WebGLRenderingContext>, antialias?: boolean, options?: EngineOptions, adaptToDeviceRatio: boolean = false) {
 
-        // Register promises
-        PromisePolyfill.Apply();
-
         let canvas: Nullable<HTMLCanvasElement> = null;
         Engine.Instances.push(this);
 
@@ -1210,7 +1236,7 @@ export class Engine {
 
                 // Pointer lock
                 if (this.isFullscreen && this._pointerLockRequested && canvas) {
-                    Tools.RequestPointerlock(canvas);
+                    Engine._RequestPointerlock(canvas);
                 }
             };
 
@@ -1638,12 +1664,12 @@ export class Engine {
 
     /**
      * Gets current aspect ratio
-     * @param camera defines the camera to use to get the aspect ratio
+     * @param viewportOwner defines the camera to use to get the aspect ratio
      * @param useScreen defines if screen size must be used (or the current render target if any)
      * @returns a number defining the aspect ratio
      */
-    public getAspectRatio(camera: Camera, useScreen = false): number {
-        var viewport = camera.viewport;
+    public getAspectRatio(viewportOwner: IViewportOwnerLike, useScreen = false): number {
+        var viewport = viewportOwner.viewport;
         return (this.getRenderWidth(useScreen) * viewport.width) / (this.getRenderHeight(useScreen) * viewport.height);
     }
 
@@ -2010,12 +2036,12 @@ export class Engine {
         if (this._activeRenderLoops.length > 0) {
             // Register new frame
             if (this.customAnimationFrameRequester) {
-                this.customAnimationFrameRequester.requestID = Tools.QueueNewFrame(this.customAnimationFrameRequester.renderFunction || this._bindedRenderFunction, this.customAnimationFrameRequester);
+                this.customAnimationFrameRequester.requestID = Engine.QueueNewFrame(this.customAnimationFrameRequester.renderFunction || this._bindedRenderFunction, this.customAnimationFrameRequester);
                 this._frameHandler = this.customAnimationFrameRequester.requestID;
             } else if (this.isVRPresenting()) {
                 this._requestVRFrame();
             } else {
-                this._frameHandler = Tools.QueueNewFrame(this._bindedRenderFunction);
+                this._frameHandler = Engine.QueueNewFrame(this._bindedRenderFunction);
             }
         } else {
             this._renderingQueueLaunched = false;
@@ -2036,7 +2062,7 @@ export class Engine {
         if (!this._renderingQueueLaunched) {
             this._renderingQueueLaunched = true;
             this._bindedRenderFunction = this._renderLoop.bind(this);
-            this._frameHandler = Tools.QueueNewFrame(this._bindedRenderFunction);
+            this._frameHandler = Engine.QueueNewFrame(this._bindedRenderFunction);
         }
     }
 
@@ -2060,7 +2086,7 @@ export class Engine {
         if (!this.isFullscreen) {
             this._pointerLockRequested = requestPointerLock;
             if (this._renderingCanvas) {
-                Tools.RequestFullscreen(this._renderingCanvas);
+                Engine._RequestFullscreen(this._renderingCanvas);
             }
         }
     }
@@ -2070,7 +2096,7 @@ export class Engine {
      */
     public exitFullscreen(): void {
         if (this.isFullscreen) {
-            Tools.ExitFullscreen();
+            Engine._ExitFullscreen();
         }
     }
 
@@ -2079,7 +2105,7 @@ export class Engine {
      */
     public enterPointerlock(): void {
         if (this._renderingCanvas) {
-            Tools.RequestPointerlock(this._renderingCanvas);
+            Engine._RequestPointerlock(this._renderingCanvas);
         }
     }
 
@@ -2087,7 +2113,7 @@ export class Engine {
      * Exits Pointerlock mode
      */
     public exitPointerlock(): void {
-        Tools.ExitPointerlock();
+        Engine._ExitPointerlock();
     }
 
     /**
@@ -2097,7 +2123,7 @@ export class Engine {
      * @param depth defines if the depth buffer must be cleared
      * @param stencil defines if the stencil buffer must be cleared
      */
-    public clear(color: Nullable<Color4>, backBuffer: boolean, depth: boolean, stencil: boolean = false): void {
+    public clear(color: Nullable<IColor4Like>, backBuffer: boolean, depth: boolean, stencil: boolean = false): void {
         this.applyStates();
 
         var mode = 0;
@@ -2124,7 +2150,7 @@ export class Engine {
      * @param height defines the height of the clear rectangle
      * @param clearColor defines the clear color
      */
-    public scissorClear(x: number, y: number, width: number, height: number, clearColor: Color4): void {
+    public scissorClear(x: number, y: number, width: number, height: number, clearColor: IColor4Like): void {
         this.enableScissor(x, y, width, height);
         this.clear(clearColor, true, true, true);
         this.disableScissor();
@@ -2154,7 +2180,7 @@ export class Engine {
         gl.disable(gl.SCISSOR_TEST);
     }
 
-    private _viewportCached = new Vector4(0, 0, 0, 0);
+    private _viewportCached = { x: 0, y: 0, z: 0, w: 0 };
 
     /** @hidden */
     public _viewport(x: number, y: number, width: number, height: number): void {
@@ -2177,7 +2203,7 @@ export class Engine {
      * @param requiredWidth defines the width required for rendering. If not provided the rendering canvas' width is used
      * @param requiredHeight defines the height required for rendering. If not provided the rendering canvas' height is used
      */
-    public setViewport(viewport: Viewport, requiredWidth?: number, requiredHeight?: number): void {
+    public setViewport(viewport: IViewportLike, requiredWidth?: number, requiredHeight?: number): void {
         var width = requiredWidth || this.getRenderWidth();
         var height = requiredHeight || this.getRenderHeight();
         var x = viewport.x || 0;
@@ -2196,7 +2222,7 @@ export class Engine {
      * @param height defines the height of the viewport (in screen space)
      * @return the current viewport Object (if any) that is being replaced by this call. You can restore this viewport later on to go back to the original state
      */
-    public setDirectViewport(x: number, y: number, width: number, height: number): Nullable<Viewport> {
+    public setDirectViewport(x: number, y: number, width: number, height: number): Nullable<IViewportLike> {
         let currentViewport = this._cachedViewport;
         this._cachedViewport = null;
 
@@ -3652,19 +3678,6 @@ export class Engine {
     }
 
     /**
-     * Set the value of an uniform to a matrix
-     * @param uniform defines the webGL uniform location where to store the value
-     * @param matrix defines the matrix to store
-     */
-    public setMatrix(uniform: Nullable<WebGLUniformLocation>, matrix: Matrix): void {
-        if (!uniform) {
-            return;
-        }
-
-        this._gl.uniformMatrix4fv(uniform, false, matrix.toArray() as Float32Array);
-    }
-
-    /**
      * Set the value of an uniform to a matrix (3x3)
      * @param uniform defines the webGL uniform location where to store the value
      * @param matrix defines the Float32Array representing the 3x3 matrix to store
@@ -3775,38 +3788,11 @@ export class Engine {
     }
 
     /**
-     * Set the value of an uniform to a Color3
-     * @param uniform defines the webGL uniform location where to store the value
-     * @param color3 defines the color to store
-     */
-    public setColor3(uniform: Nullable<WebGLUniformLocation>, color3: Color3): void {
-        if (!uniform) {
-            return;
-        }
-
-        this._gl.uniform3f(uniform, color3.r, color3.g, color3.b);
-    }
-
-    /**
-     * Set the value of an uniform to a Color3 and an alpha value
-     * @param uniform defines the webGL uniform location where to store the value
-     * @param color3 defines the color to store
-     * @param alpha defines the alpha component to store
-     */
-    public setColor4(uniform: Nullable<WebGLUniformLocation>, color3: Color3, alpha: number): void {
-        if (!uniform) {
-            return;
-        }
-
-        this._gl.uniform4f(uniform, color3.r, color3.g, color3.b, alpha);
-    }
-
-    /**
      * Sets a Color4 on a uniform variable
      * @param uniform defines the uniform location
      * @param color4 defines the value to be set
      */
-    public setDirectColor4(uniform: Nullable<WebGLUniformLocation>, color4: Color4): void {
+    public setDirectColor4(uniform: Nullable<WebGLUniformLocation>, color4: IColor4Like): void {
         if (!uniform) {
             return;
         }
@@ -4247,7 +4233,6 @@ export class Engine {
                     // Add Back
                     customFallback = true;
                     excludeLoaders.push(loader);
-                    Tools.Warn((loader.constructor as any).name + " failed when trying to load " + texture.url + ", falling back to the next supported loader");
                     this.createTexture(urlArg, noMipmap, texture.invertY, scene, samplingMode, null, onError, buffer, texture, undefined, undefined, excludeLoaders);
                     return;
                 }
@@ -4257,8 +4242,8 @@ export class Engine {
                 if (onLoadObserver) {
                     texture.onLoadedObservable.remove(onLoadObserver);
                 }
-                if (Tools.UseFallbackTexture) {
-                    this.createTexture(Tools.fallbackTexture, noMipmap, texture.invertY, scene, samplingMode, null, onError, buffer, texture);
+                if (EngineStore.UseFallbackTexture) {
+                    this.createTexture(EngineStore.FallbackTexture, noMipmap, texture.invertY, scene, samplingMode, null, onError, buffer, texture);
                     return;
                 }
             }
@@ -4348,11 +4333,11 @@ export class Engine {
                 if (buffer instanceof HTMLImageElement) {
                     onload(buffer);
                 } else {
-                    Tools.LoadImage(url, onload, onInternalError, scene ? scene.offlineProvider : null);
+                    FileTools.LoadImage(url, onload, onInternalError, scene ? scene.offlineProvider : null);
                 }
             }
             else if (typeof buffer === "string" || buffer instanceof ArrayBuffer || buffer instanceof Blob) {
-                Tools.LoadImage(buffer, onload, onInternalError, scene ? scene.offlineProvider : null);
+                FileTools.LoadImage(buffer, onload, onInternalError, scene ? scene.offlineProvider : null);
             }
             else {
                 onload(<HTMLImageElement>buffer);
@@ -4473,8 +4458,8 @@ export class Engine {
         texture.baseHeight = height;
 
         if (generateMipMaps) {
-            width = this.needPOTTextures ? Tools.GetExponentOfTwo(width, this._caps.maxTextureSize) : width;
-            height = this.needPOTTextures ? Tools.GetExponentOfTwo(height, this._caps.maxTextureSize) : height;
+            width = this.needPOTTextures ? Engine.GetExponentOfTwo(width, this._caps.maxTextureSize) : width;
+            height = this.needPOTTextures ? Engine.GetExponentOfTwo(height, this._caps.maxTextureSize) : height;
         }
 
         //  this.resetTextureCache();
@@ -5018,8 +5003,8 @@ export class Engine {
             target = gl.TEXTURE_CUBE_MAP_POSITIVE_X + faceIndex;
         }
 
-        const lodMaxWidth = Math.round(Scalar.Log2(texture.width));
-        const lodMaxHeight = Math.round(Scalar.Log2(texture.height));
+        const lodMaxWidth = Math.round(Math.log(texture.width) * Math.LOG2E);
+        const lodMaxHeight = Math.round(Math.log(texture.height) * Math.LOG2E);
         const width = useTextureWidthAndHeight ? texture.width : Math.pow(2, Math.max(lodMaxWidth - lod, 0));
         const height = useTextureWidthAndHeight ? texture.height : Math.pow(2, Math.max(lodMaxHeight - lod, 0));
 
@@ -5138,8 +5123,8 @@ export class Engine {
     private _prepareWebGLTexture(texture: InternalTexture, scene: Nullable<Scene>, width: number, height: number, invertY: boolean, noMipmap: boolean, isCompressed: boolean,
         processFunction: (width: number, height: number, continuationCallback: () => void) => boolean, samplingMode: number = Engine.TEXTURE_TRILINEAR_SAMPLINGMODE): void {
         var maxTextureSize = this.getCaps().maxTextureSize;
-        var potWidth = Math.min(maxTextureSize, this.needPOTTextures ? Tools.GetExponentOfTwo(width, maxTextureSize) : width);
-        var potHeight = Math.min(maxTextureSize, this.needPOTTextures ? Tools.GetExponentOfTwo(height, maxTextureSize) : height);
+        var potWidth = Math.min(maxTextureSize, this.needPOTTextures ? Engine.GetExponentOfTwo(width, maxTextureSize) : width);
+        var potHeight = Math.min(maxTextureSize, this.needPOTTextures ? Engine.GetExponentOfTwo(height, maxTextureSize) : height);
 
         var gl = this._gl;
         if (!gl) {
@@ -6392,7 +6377,7 @@ export class Engine {
 
     /** @hidden */
     public _loadFile(url: string, onSuccess: (data: string | ArrayBuffer, responseURL?: string) => void, onProgress?: (data: any) => void, offlineProvider?: IOfflineProvider, useArrayBuffer?: boolean, onError?: (request?: WebRequest, exception?: any) => void): IFileRequest {
-        let request = Tools.LoadFile(url, onSuccess, onProgress, offlineProvider, useArrayBuffer, onError);
+        let request = FileTools.LoadFile(url, onSuccess, onProgress, offlineProvider, useArrayBuffer, onError);
         this._activeRequests.push(request);
         request.onCompleteObservable.add((request) => {
             this._activeRequests.splice(this._activeRequests.indexOf(request), 1);
@@ -6428,4 +6413,159 @@ export class Engine {
             return false;
         }
     }
+
+    /**
+     * Find the next highest power of two.
+     * @param x Number to start search from.
+     * @return Next highest power of two.
+     */
+    public static CeilingPOT(x: number): number {
+        x--;
+        x |= x >> 1;
+        x |= x >> 2;
+        x |= x >> 4;
+        x |= x >> 8;
+        x |= x >> 16;
+        x++;
+        return x;
+    }
+
+    /**
+     * Find the next lowest power of two.
+     * @param x Number to start search from.
+     * @return Next lowest power of two.
+     */
+    public static FloorPOT(x: number): number {
+        x = x | (x >> 1);
+        x = x | (x >> 2);
+        x = x | (x >> 4);
+        x = x | (x >> 8);
+        x = x | (x >> 16);
+        return x - (x >> 1);
+    }
+
+    /**
+     * Find the nearest power of two.
+     * @param x Number to start search from.
+     * @return Next nearest power of two.
+     */
+    public static NearestPOT(x: number): number {
+        var c = Engine.CeilingPOT(x);
+        var f = Engine.FloorPOT(x);
+        return (c - x) > (x - f) ? f : c;
+    }
+
+    /**
+     * Get the closest exponent of two
+     * @param value defines the value to approximate
+     * @param max defines the maximum value to return
+     * @param mode defines how to define the closest value
+     * @returns closest exponent of two of the given value
+     */
+    public static GetExponentOfTwo(value: number, max: number, mode = Constants.SCALEMODE_NEAREST): number {
+        let pot;
+
+        switch (mode) {
+            case Constants.SCALEMODE_FLOOR:
+                pot = Engine.FloorPOT(value);
+                break;
+            case Constants.SCALEMODE_NEAREST:
+                pot = Engine.NearestPOT(value);
+                break;
+            case Constants.SCALEMODE_CEILING:
+            default:
+                pot = Engine.CeilingPOT(value);
+                break;
+        }
+
+        return Math.min(pot, max);
+    }
+
+    /**
+     * Queue a new function into the requested animation frame pool (ie. this function will be executed byt the browser for the next frame)
+     * @param func - the function to be called
+     * @param requester - the object that will request the next frame. Falls back to window.
+     * @returns frame number
+     */
+    public static QueueNewFrame(func: () => void, requester?: any): number {
+        if (!DomManagement.IsWindowObjectExist()) {
+            return setTimeout(func, 16);
+        }
+
+        if (!requester) {
+            requester = window;
+        }
+
+        if (requester.requestAnimationFrame) {
+            return requester.requestAnimationFrame(func);
+        }
+        else if (requester.msRequestAnimationFrame) {
+            return requester.msRequestAnimationFrame(func);
+        }
+        else if (requester.webkitRequestAnimationFrame) {
+            return requester.webkitRequestAnimationFrame(func);
+        }
+        else if (requester.mozRequestAnimationFrame) {
+            return requester.mozRequestAnimationFrame(func);
+        }
+        else if (requester.oRequestAnimationFrame) {
+            return requester.oRequestAnimationFrame(func);
+        }
+        else {
+            return window.setTimeout(func, 16);
+        }
+    }
+
+    /**
+     * Ask the browser to promote the current element to pointerlock mode
+     * @param element defines the DOM element to promote
+     */
+    static _RequestPointerlock(element: HTMLElement): void {
+        element.requestPointerLock = element.requestPointerLock || (<any>element).msRequestPointerLock || (<any>element).mozRequestPointerLock || (<any>element).webkitRequestPointerLock;
+        if (element.requestPointerLock) {
+            element.requestPointerLock();
+        }
+    }
+
+    /**
+     * Asks the browser to exit pointerlock mode
+     */
+    static _ExitPointerlock(): void {
+        let anyDoc = document as any;
+        document.exitPointerLock = document.exitPointerLock || anyDoc.msExitPointerLock || anyDoc.mozExitPointerLock || anyDoc.webkitExitPointerLock;
+
+        if (document.exitPointerLock) {
+            document.exitPointerLock();
+        }
+    }
+
+    /**
+     * Ask the browser to promote the current element to fullscreen rendering mode
+     * @param element defines the DOM element to promote
+     */
+    static _RequestFullscreen(element: HTMLElement): void {
+        var requestFunction = element.requestFullscreen || (<any>element).msRequestFullscreen || (<any>element).webkitRequestFullscreen || (<any>element).mozRequestFullScreen;
+        if (!requestFunction) { return; }
+        requestFunction.call(element);
+    }
+
+    /**
+     * Asks the browser to exit fullscreen mode
+     */
+    static _ExitFullscreen(): void {
+        let anyDoc = document as any;
+
+        if (document.exitFullscreen) {
+            document.exitFullscreen();
+        }
+        else if (anyDoc.mozCancelFullScreen) {
+            anyDoc.mozCancelFullScreen();
+        }
+        else if (anyDoc.webkitCancelFullScreen) {
+            anyDoc.webkitCancelFullScreen();
+        }
+        else if (anyDoc.msCancelFullScreen) {
+            anyDoc.msCancelFullScreen();
+        }
+    }
 }

+ 12 - 0
src/Engines/engineStore.ts

@@ -31,4 +31,16 @@ export class EngineStore {
     public static get LastCreatedScene(): Nullable<Scene> {
         return this._LastCreatedScene;
     }
+
+    /**
+     * Gets or sets a global variable indicating if fallback texture must be used when a texture cannot be loaded
+     * @ignorenaming
+     */
+    public static UseFallbackTexture = true;
+
+    /**
+     * Texture content used if a texture cannot loaded
+     * @ignorenaming
+     */
+    public static FallbackTexture = "";
 }

+ 3 - 13
src/Engines/nullEngine.ts

@@ -1,8 +1,7 @@
 import { Logger } from "../Misc/logger";
 import { Nullable, FloatArray, IndicesArray } from "../types";
 import { Scene } from "../scene";
-import { Matrix, Color3, Color4, Viewport } from "../Maths/math";
-import { Engine, EngineCapabilities } from "../Engines/engine";
+import { Engine, EngineCapabilities, IViewportLike, IColor4Like } from "../Engines/engine";
 import { RenderTargetCreationOptions } from "../Materials/Textures/renderTargetCreationOptions";
 import { VertexBuffer } from "../Meshes/buffer";
 import { InternalTexture } from "../Materials/Textures/internalTexture";
@@ -158,7 +157,7 @@ export class NullEngine extends Engine {
         return buffer;
     }
 
-    public clear(color: Color4, backBuffer: boolean, depth: boolean, stencil: boolean = false): void {
+    public clear(color: IColor4Like, backBuffer: boolean, depth: boolean, stencil: boolean = false): void {
     }
 
     public getRenderWidth(useScreen = false): number {
@@ -177,7 +176,7 @@ export class NullEngine extends Engine {
         return this._options.renderHeight;
     }
 
-    public setViewport(viewport: Viewport, requiredWidth?: number, requiredHeight?: number): void {
+    public setViewport(viewport: IViewportLike, requiredWidth?: number, requiredHeight?: number): void {
         this._cachedViewport = viewport;
     }
 
@@ -252,9 +251,6 @@ export class NullEngine extends Engine {
     public setMatrices(uniform: WebGLUniformLocation, matrices: Float32Array): void {
     }
 
-    public setMatrix(uniform: WebGLUniformLocation, matrix: Matrix): void {
-    }
-
     public setMatrix3x3(uniform: WebGLUniformLocation, matrix: Float32Array): void {
     }
 
@@ -276,12 +272,6 @@ export class NullEngine extends Engine {
     public setFloat4(uniform: WebGLUniformLocation, x: number, y: number, z: number, w: number): void {
     }
 
-    public setColor3(uniform: WebGLUniformLocation, color3: Color3): void {
-    }
-
-    public setColor4(uniform: WebGLUniformLocation, color3: Color3, alpha: number): void {
-    }
-
     public setAlphaMode(mode: number, noDepthWriteChange: boolean = false): void {
         if (this._alphaMode === mode) {
             return;

+ 2 - 2
src/Gamepads/gamepadManager.ts

@@ -1,4 +1,3 @@
-import { Tools } from "../Misc/tools";
 import { Observable } from "../Misc/observable";
 import { DomManagement } from "../Misc/domManagement";
 import { Nullable } from "../types";
@@ -9,6 +8,7 @@ import { _DepthCullingState, _StencilState, _AlphaState } from "../States/index"
 import { PoseEnabledControllerHelper } from "../Gamepads/Controllers/poseEnabledController";
 import { Xbox360Pad } from "./xboxGamepad";
 import { Gamepad, GenericPad } from "./gamepad";
+import { Engine } from '../Engines/engine';
 /**
  * Manager for handling gamepads
  */
@@ -211,7 +211,7 @@ export class GamepadManager {
         }
 
         if (this._isMonitoring && !this._scene) {
-            Tools.QueueNewFrame(() => { this._checkGamepadsStatus(); });
+            Engine.QueueNewFrame(() => { this._checkGamepadsStatus(); });
         }
     }
 

+ 1 - 1
src/Instrumentation/engineInstrumentation.ts

@@ -1,5 +1,5 @@
 import { Observer } from "../Misc/observable";
-import { PerfCounter } from "../Misc/tools";
+import { PerfCounter } from "../Misc/perfCounter";
 import { Nullable } from "../types";
 import { IDisposable } from "../scene";
 import { Engine } from "../Engines/engine";

+ 2 - 1
src/Instrumentation/sceneInstrumentation.ts

@@ -1,10 +1,11 @@
-import { Tools, PerfCounter } from "../Misc/tools";
+import { Tools } from "../Misc/tools";
 import { Observer } from "../Misc/observable";
 import { Nullable } from "../types";
 import { Camera } from "../Cameras/camera";
 import { Scene, IDisposable } from "../scene";
 import { _TimeToken } from "../Instrumentation/timeToken";
 import { _DepthCullingState, _StencilState, _AlphaState } from "../States/index";
+import { PerfCounter } from '../Misc/perfCounter';
 /**
  * This class can be used to get instrumentation data from a Babylon engine
  * @see http://doc.babylonjs.com/how_to/optimizing_your_scene#sceneinstrumentation

+ 2 - 2
src/Layers/effectLayer.ts

@@ -298,8 +298,8 @@ export abstract class EffectLayer {
             this._mainTextureDesiredSize.width = this._engine.getRenderWidth() * this._effectLayerOptions.mainTextureRatio;
             this._mainTextureDesiredSize.height = this._engine.getRenderHeight() * this._effectLayerOptions.mainTextureRatio;
 
-            this._mainTextureDesiredSize.width = this._engine.needPOTTextures ? Tools.GetExponentOfTwo(this._mainTextureDesiredSize.width, this._maxSize) : this._mainTextureDesiredSize.width;
-            this._mainTextureDesiredSize.height = this._engine.needPOTTextures ? Tools.GetExponentOfTwo(this._mainTextureDesiredSize.height, this._maxSize) : this._mainTextureDesiredSize.height;
+            this._mainTextureDesiredSize.width = this._engine.needPOTTextures ? Engine.GetExponentOfTwo(this._mainTextureDesiredSize.width, this._maxSize) : this._mainTextureDesiredSize.width;
+            this._mainTextureDesiredSize.height = this._engine.needPOTTextures ? Engine.GetExponentOfTwo(this._mainTextureDesiredSize.height, this._maxSize) : this._mainTextureDesiredSize.height;
         }
 
         this._mainTextureDesiredSize.width = Math.floor(this._mainTextureDesiredSize.width);

+ 3 - 3
src/Layers/glowLayer.ts

@@ -1,5 +1,4 @@
 import { serialize, SerializationHelper } from "../Misc/decorators";
-import { Tools } from "../Misc/tools";
 import { Nullable } from "../types";
 import { Camera } from "../Cameras/camera";
 import { Scene } from "../scene";
@@ -18,6 +17,7 @@ import { EffectLayer } from "./effectLayer";
 import { AbstractScene } from "../abstractScene";
 import { Constants } from "../Engines/constants";
 import { _TypeStore } from '../Misc/typeStore';
+import { Engine } from '../Engines/engine';
 
 import "../Shaders/glowMapMerge.fragment";
 import "../Shaders/glowMapMerge.vertex";
@@ -222,8 +222,8 @@ export class GlowLayer extends EffectLayer {
     protected _createTextureAndPostProcesses(): void {
         var blurTextureWidth = this._mainTextureDesiredSize.width;
         var blurTextureHeight = this._mainTextureDesiredSize.height;
-        blurTextureWidth = this._engine.needPOTTextures ? Tools.GetExponentOfTwo(blurTextureWidth, this._maxSize) : blurTextureWidth;
-        blurTextureHeight = this._engine.needPOTTextures ? Tools.GetExponentOfTwo(blurTextureHeight, this._maxSize) : blurTextureHeight;
+        blurTextureWidth = this._engine.needPOTTextures ? Engine.GetExponentOfTwo(blurTextureWidth, this._maxSize) : blurTextureWidth;
+        blurTextureHeight = this._engine.needPOTTextures ? Engine.GetExponentOfTwo(blurTextureHeight, this._maxSize) : blurTextureHeight;
 
         var textureType = 0;
         if (this._engine.getCaps().textureHalfFloatRender) {

+ 2 - 3
src/Layers/highlightLayer.ts

@@ -1,6 +1,5 @@
 import { serialize, SerializationHelper } from "../Misc/decorators";
 import { Observer, Observable } from "../Misc/observable";
-import { Tools } from "../Misc/tools";
 import { Nullable } from "../types";
 import { Camera } from "../Cameras/camera";
 import { Scene } from "../scene";
@@ -326,8 +325,8 @@ export class HighlightLayer extends EffectLayer {
     protected _createTextureAndPostProcesses(): void {
         var blurTextureWidth = this._mainTextureDesiredSize.width * this._options.blurTextureSizeRatio;
         var blurTextureHeight = this._mainTextureDesiredSize.height * this._options.blurTextureSizeRatio;
-        blurTextureWidth = this._engine.needPOTTextures ? Tools.GetExponentOfTwo(blurTextureWidth, this._maxSize) : blurTextureWidth;
-        blurTextureHeight = this._engine.needPOTTextures ? Tools.GetExponentOfTwo(blurTextureHeight, this._maxSize) : blurTextureHeight;
+        blurTextureWidth = this._engine.needPOTTextures ? Engine.GetExponentOfTwo(blurTextureWidth, this._maxSize) : blurTextureWidth;
+        blurTextureHeight = this._engine.needPOTTextures ? Engine.GetExponentOfTwo(blurTextureHeight, this._maxSize) : blurTextureHeight;
 
         var textureType = 0;
         if (this._engine.getCaps().textureHalfFloatRender) {

+ 5 - 5
src/LibDeclarations/webxr.d.ts

@@ -40,10 +40,10 @@ interface XRSpace extends EventTarget {
 }
 
 interface XRRenderState {
-    depthNear: number ;
-    depthFar: number ;
-    inlineVerticalFieldOfView: number | undefined;
-    baseLayer: XRWebGLLayer | undefined;
+    depthNear?: number;
+    depthFar?: number;
+    inlineVerticalFieldOfView?: number;
+    baseLayer?: XRWebGLLayer;
 }
 
 interface XRInputSource {
@@ -58,7 +58,7 @@ interface XRInputSource {
 interface XRSession {
     addEventListener: Function;
     requestReferenceSpace(type: XRReferenceSpaceType): Promise<XRReferenceSpace>;
-    updateRenderState(XRRenderStateInit: any): Promise<void>;
+    updateRenderState(XRRenderStateInit: XRRenderState): Promise<void>;
     requestAnimationFrame: Function;
     end(): Promise<void>;
     renderState: XRRenderState;

+ 3 - 2
src/Loading/Plugins/babylonFileLoader.ts

@@ -29,6 +29,7 @@ import { AmmoJSPlugin } from "../../Physics/Plugins/ammoJSPlugin";
 import { ReflectionProbe } from "../../Probes/reflectionProbe";
 import { _TypeStore } from '../../Misc/typeStore';
 import { Tools } from '../../Misc/tools';
+import { StringTools } from '../../Misc/stringTools';
 
 /** @hidden */
 export var _BabylonLoaderRegistered = true;
@@ -125,7 +126,7 @@ var loadAssetContainer = (scene: Scene, data: string, rootUrl: string, onError?:
                 }
                 scene.environmentTexture = hdrTexture;
             } else {
-                if (Tools.EndsWith(parsedData.environmentTexture, ".env")) {
+                if (StringTools.EndsWith(parsedData.environmentTexture, ".env")) {
                     var compressedTexture = new CubeTexture((parsedData.environmentTexture.match(/https?:\/\//g) ? "" : rootUrl) + parsedData.environmentTexture, scene);
                     if (parsedData.environmentTextureRotationY) {
                         compressedTexture.rotationY = parsedData.environmentTextureRotationY;
@@ -744,7 +745,7 @@ SceneLoader.RegisterPlugin({
                     }
                     scene.environmentTexture = hdrTexture;
                 } else {
-                    if (Tools.EndsWith(parsedData.environmentTexture, ".env")) {
+                    if (StringTools.EndsWith(parsedData.environmentTexture, ".env")) {
                         var compressedTexture = new CubeTexture(rootUrl + parsedData.environmentTexture, scene);
                         if (parsedData.environmentTextureRotationY) {
                             compressedTexture.rotationY = parsedData.environmentTextureRotationY;

+ 2 - 1
src/Loading/sceneLoader.ts

@@ -1,4 +1,4 @@
-import { IFileRequest, Tools } from "../Misc/tools";
+import { Tools } from "../Misc/tools";
 import { Observable } from "../Misc/observable";
 import { FilesInputStore } from "../Misc/filesInputStore";
 import { Nullable } from "../types";
@@ -16,6 +16,7 @@ import { Skeleton } from "../Bones/skeleton";
 import { Logger } from "../Misc/logger";
 import { Constants } from "../Engines/constants";
 import { SceneLoaderFlags } from "./sceneLoaderFlags";
+import { IFileRequest } from '../Misc/fileRequest';
 /**
  * Class used to represent data loading progression
  */

+ 3 - 4
src/Materials/Textures/renderTargetTexture.ts

@@ -17,8 +17,7 @@ import { Constants } from "../../Engines/constants";
 
 import "../../Engines/Extensions/engine.renderTarget";
 import { InstancedMesh } from '../../Meshes/instancedMesh';
-
-declare type Engine = import("../../Engines/engine").Engine;
+import { Engine } from '../../Engines/engine';
 
 /**
  * This Helps creating a texture that will be created from a camera in your scene.
@@ -734,10 +733,10 @@ export class RenderTargetTexture extends Texture {
     private _bestReflectionRenderTargetDimension(renderDimension: number, scale: number): number {
         let minimum = 128;
         let x = renderDimension * scale;
-        let curved = Tools.NearestPOT(x + (minimum * minimum / (minimum + x)));
+        let curved = Engine.NearestPOT(x + (minimum * minimum / (minimum + x)));
 
         // Ensure we don't exceed the render dimension (while staying POT)
-        return Math.min(Tools.FloorPOT(renderDimension), curved);
+        return Math.min(Engine.FloorPOT(renderDimension), curved);
     }
 
     /**

+ 3 - 3
src/Materials/effect.ts

@@ -1194,7 +1194,7 @@ export class Effect implements IDisposable {
      */
     public setMatrix(uniformName: string, matrix: Matrix): Effect {
         if (this._cacheMatrix(uniformName, matrix)) {
-            this._engine.setMatrix(this._uniforms[uniformName], matrix);
+            this._engine.setMatrices(this._uniforms[uniformName], matrix.toArray() as Float32Array);
         }
         return this;
     }
@@ -1356,7 +1356,7 @@ export class Effect implements IDisposable {
     public setColor3(uniformName: string, color3: Color3): Effect {
 
         if (this._cacheFloat3(uniformName, color3.r, color3.g, color3.b)) {
-            this._engine.setColor3(this._uniforms[uniformName], color3);
+            this._engine.setFloat3(this._uniforms[uniformName], color3.r, color3.g, color3.b);
         }
         return this;
     }
@@ -1370,7 +1370,7 @@ export class Effect implements IDisposable {
      */
     public setColor4(uniformName: string, color3: Color3, alpha: number): Effect {
         if (this._cacheFloat4(uniformName, color3.r, color3.g, color3.b, alpha)) {
-            this._engine.setColor4(this._uniforms[uniformName], color3, alpha);
+            this._engine.setFloat4(this._uniforms[uniformName], color3.r, color3.g, color3.b, alpha);
         }
         return this;
     }

+ 79 - 0
src/Maths/math.functions.ts

@@ -0,0 +1,79 @@
+import { FloatArray, Nullable, IndicesArray } from '../types';
+import { Vector2, Vector3 } from './math';
+
+/**
+ * Extracts minimum and maximum values from a list of indexed positions
+ * @param positions defines the positions to use
+ * @param indices defines the indices to the positions
+ * @param indexStart defines the start index
+ * @param indexCount defines the end index
+ * @param bias defines bias value to add to the result
+ * @return minimum and maximum values
+ */
+export function extractMinAndMaxIndexed(positions: FloatArray, indices: IndicesArray, indexStart: number, indexCount: number, bias: Nullable<Vector2> = null): { minimum: Vector3; maximum: Vector3 } {
+    var minimum = new Vector3(Number.MAX_VALUE, Number.MAX_VALUE, Number.MAX_VALUE);
+    var maximum = new Vector3(-Number.MAX_VALUE, -Number.MAX_VALUE, -Number.MAX_VALUE);
+
+    for (var index = indexStart; index < indexStart + indexCount; index++) {
+        const offset = indices[index] * 3;
+        const x = positions[offset];
+        const y = positions[offset + 1];
+        const z = positions[offset + 2];
+        minimum.minimizeInPlaceFromFloats(x, y, z);
+        maximum.maximizeInPlaceFromFloats(x, y, z);
+    }
+
+    if (bias) {
+        minimum.x -= minimum.x * bias.x + bias.y;
+        minimum.y -= minimum.y * bias.x + bias.y;
+        minimum.z -= minimum.z * bias.x + bias.y;
+        maximum.x += maximum.x * bias.x + bias.y;
+        maximum.y += maximum.y * bias.x + bias.y;
+        maximum.z += maximum.z * bias.x + bias.y;
+    }
+
+    return {
+        minimum: minimum,
+        maximum: maximum
+    };
+}
+
+/**
+ * Extracts minimum and maximum values from a list of positions
+ * @param positions defines the positions to use
+ * @param start defines the start index in the positions array
+ * @param count defines the number of positions to handle
+ * @param bias defines bias value to add to the result
+ * @param stride defines the stride size to use (distance between two positions in the positions array)
+ * @return minimum and maximum values
+ */
+export function extractMinAndMax(positions: FloatArray, start: number, count: number, bias: Nullable<Vector2> = null, stride?: number): { minimum: Vector3; maximum: Vector3 } {
+    var minimum = new Vector3(Number.MAX_VALUE, Number.MAX_VALUE, Number.MAX_VALUE);
+    var maximum = new Vector3(-Number.MAX_VALUE, -Number.MAX_VALUE, -Number.MAX_VALUE);
+
+    if (!stride) {
+        stride = 3;
+    }
+
+    for (var index = start, offset = start * stride; index < start + count; index++ , offset += stride) {
+        const x = positions[offset];
+        const y = positions[offset + 1];
+        const z = positions[offset + 2];
+        minimum.minimizeInPlaceFromFloats(x, y, z);
+        maximum.maximizeInPlaceFromFloats(x, y, z);
+    }
+
+    if (bias) {
+        minimum.x -= minimum.x * bias.x + bias.y;
+        minimum.y -= minimum.y * bias.x + bias.y;
+        minimum.z -= minimum.z * bias.x + bias.y;
+        maximum.x += maximum.x * bias.x + bias.y;
+        maximum.y += maximum.y * bias.x + bias.y;
+        maximum.z += maximum.z * bias.x + bias.y;
+    }
+
+    return {
+        minimum: minimum,
+        maximum: maximum
+    };
+}

+ 11 - 0
src/Maths/math.ts

@@ -2560,6 +2560,17 @@ export class Vector3 {
     }
 
     /**
+     * Checks if a given vector is inside a specific range
+     * @param v defines the vector to test
+     * @param min defines the minimum range
+     * @param max defines the maximum range
+     */
+    public static CheckExtends(v: Vector3, min: Vector3, max: Vector3): void {
+        min.minimizeInPlace(v);
+        max.maximizeInPlace(v);
+    }
+
+    /**
      * Returns a new Vector3 located for "amount" (float) on the Hermite interpolation spline defined by the vectors "value1", "tangent1", "value2", "tangent2"
      * @param value1 defines the first control point
      * @param tangent1 defines the first tangent vector

+ 2 - 1
src/Meshes/abstractMesh.ts

@@ -24,6 +24,7 @@ import { AbstractActionManager } from '../Actions/abstractActionManager';
 import { _MeshCollisionData } from '../Collisions/meshCollisionData';
 import { _DevTools } from '../Misc/devTools';
 import { RawTexture } from '../Materials/Textures/rawTexture';
+import { extractMinAndMax } from '../Maths/math.functions';
 
 declare type Ray = import("../Culling/ray").Ray;
 declare type Collider = import("../Collisions/collider").Collider;
@@ -1142,7 +1143,7 @@ export class AbstractMesh extends TransformNode implements IDisposable, ICullabl
     /** @hidden */
     public _refreshBoundingInfo(data: Nullable<FloatArray>, bias: Nullable<Vector2>): void {
         if (data) {
-            var extend = Tools.ExtractMinAndMax(data, 0, this.getTotalVertices(), bias);
+            var extend = extractMinAndMax(data, 0, this.getTotalVertices(), bias);
             if (this._boundingInfo) {
                 this._boundingInfo.reConstruct(extend.minimum, extend.maximum);
             }

+ 2 - 1
src/Meshes/geometry.ts

@@ -13,6 +13,7 @@ import { Constants } from "../Engines/constants";
 import { Tools } from "../Misc/tools";
 import { Tags } from "../Misc/tags";
 import { DataBuffer } from './dataBuffer';
+import { extractMinAndMax } from '../Maths/math.functions';
 
 declare type Mesh = import("../Meshes/mesh").Mesh;
 
@@ -693,7 +694,7 @@ export class Geometry implements IGetSetVerticesData {
             data = this.getVerticesData(VertexBuffer.PositionKind)!;
         }
 
-        this._extend = Tools.ExtractMinAndMax(data, 0, this._totalVertices, this.boundingBias, 3);
+        this._extend = extractMinAndMax(data, 0, this._totalVertices, this.boundingBias, 3);
     }
 
     private _applyToMesh(mesh: Mesh): void {

+ 2 - 2
src/Meshes/subMesh.ts

@@ -1,4 +1,3 @@
-import { Tools } from "../Misc/tools";
 import { Nullable, IndicesArray, DeepImmutable, FloatArray } from "../types";
 import { Matrix, Vector3, Plane } from "../Maths/math";
 import { Engine } from "../Engines/engine";
@@ -8,6 +7,7 @@ import { ICullable, BoundingInfo } from "../Culling/boundingInfo";
 import { Effect } from "../Materials/effect";
 import { Constants } from "../Engines/constants";
 import { DataBuffer } from './dataBuffer';
+import { extractMinAndMaxIndexed } from '../Maths/math.functions';
 
 declare type Collider = import("../Collisions/collider").Collider;
 declare type Material = import("../Materials/material").Material;
@@ -235,7 +235,7 @@ export class SubMesh extends BaseSubMesh implements ICullable {
             //the rendering mesh's bounding info can be used, it is the standard submesh for all indices.
             extend = { minimum: boundingInfo.minimum.clone(), maximum: boundingInfo.maximum.clone() };
         } else {
-            extend = Tools.ExtractMinAndMaxIndexed(data, indices, this.indexStart, this.indexCount, this._renderingMesh.geometry.boundingBias);
+            extend = extractMinAndMaxIndexed(data, indices, this.indexStart, this.indexCount, this._renderingMesh.geometry.boundingBias);
         }
 
         if (this._boundingInfo) {

+ 20 - 0
src/Misc/customAnimationFrameRequester.ts

@@ -0,0 +1,20 @@
+
+/**
+ * Interface for any object that can request an animation frame
+ */
+export interface ICustomAnimationFrameRequester {
+    /**
+     * This function will be called when the render loop is ready. If this is not populated, the engine's renderloop function will be called
+     */
+    renderFunction?: Function;
+    /**
+     * Called to request the next frame to render to
+     * @see https://developer.mozilla.org/en-US/docs/Web/API/window/requestAnimationFrame
+     */
+    requestAnimationFrame: Function;
+    /**
+     * You can pass this value to cancelAnimationFrame() to cancel the refresh callback request
+     * @see https://developer.mozilla.org/en-US/docs/Web/API/window/requestAnimationFrame#Return_value
+     */
+    requestID?: number;
+}

+ 16 - 0
src/Misc/fileRequest.ts

@@ -0,0 +1,16 @@
+import { Observable } from './observable';
+
+/**
+ * File request interface
+ */
+export interface IFileRequest {
+    /**
+     * Raised when the request is complete (success or error).
+     */
+    onCompleteObservable: Observable<IFileRequest>;
+
+    /**
+     * Aborts the request for a file.
+     */
+    abort: () => void;
+}

+ 370 - 0
src/Misc/fileTools.ts

@@ -0,0 +1,370 @@
+import { WebRequest } from './webRequest';
+import { LoadFileError } from './loadFileError';
+import { DomManagement } from './domManagement';
+import { Nullable } from '../types';
+import { IOfflineProvider } from '../Offline/IOfflineProvider';
+import { IFileRequest } from './fileRequest';
+import { Observable } from './observable';
+import { FilesInputStore } from './filesInputStore';
+import { RetryStrategy } from './retryStrategy';
+
+/**
+ * @hidden
+ */
+export class FileTools {
+    /**
+     * Gets or sets the retry strategy to apply when an error happens while loading an asset
+     */
+    public static DefaultRetryStrategy = RetryStrategy.ExponentialBackoff();
+
+    /**
+     * Gets or sets the base URL to use to load assets
+     */
+    public static BaseUrl = "";
+
+    /**
+     * Default behaviour for cors in the application.
+     * It can be a string if the expected behavior is identical in the entire app.
+     * Or a callback to be able to set it per url or on a group of them (in case of Video source for instance)
+     */
+    public static CorsBehavior: string | ((url: string | string[]) => string) = "anonymous";
+
+    /**
+     * Gets or sets a function used to pre-process url before using them to load assets
+     */
+    public static PreprocessUrl = (url: string) => {
+        return url;
+    }
+
+    /**
+     * Removes unwanted characters from an url
+     * @param url defines the url to clean
+     * @returns the cleaned url
+     */
+    private static _CleanUrl(url: string): string {
+        url = url.replace(/#/mg, "%23");
+        return url;
+    }
+
+    /**
+     * Sets the cors behavior on a dom element. This will add the required Tools.CorsBehavior to the element.
+     * @param url define the url we are trying
+     * @param element define the dom element where to configure the cors policy
+     */
+    public static SetCorsBehavior(url: string | string[], element: { crossOrigin: string | null }): void {
+        if (url && url.indexOf("data:") === 0) {
+            return;
+        }
+
+        if (this.CorsBehavior) {
+            if (typeof (this.CorsBehavior) === 'string' || this.CorsBehavior instanceof String) {
+                element.crossOrigin = <string>this.CorsBehavior;
+            }
+            else {
+                var result = this.CorsBehavior(url);
+                if (result) {
+                    element.crossOrigin = result;
+                }
+            }
+        }
+    }
+
+    /**
+     * Loads an image as an HTMLImageElement.
+     * @param input url string, ArrayBuffer, or Blob to load
+     * @param onLoad callback called when the image successfully loads
+     * @param onError callback called when the image fails to load
+     * @param offlineProvider offline provider for caching
+     * @returns the HTMLImageElement of the loaded image
+     */
+    public static LoadImage(input: string | ArrayBuffer | Blob, onLoad: (img: HTMLImageElement) => void, onError: (message?: string, exception?: any) => void, offlineProvider: Nullable<IOfflineProvider>): HTMLImageElement {
+        let url: string;
+        let usingObjectURL = false;
+
+        if (input instanceof ArrayBuffer) {
+            url = URL.createObjectURL(new Blob([input]));
+            usingObjectURL = true;
+        }
+        else if (input instanceof Blob) {
+            url = URL.createObjectURL(input);
+            usingObjectURL = true;
+        }
+        else {
+            url = this._CleanUrl(input);
+            url = this.PreprocessUrl(input);
+        }
+
+        var img = new Image();
+        this.SetCorsBehavior(url, img);
+
+        const loadHandler = () => {
+            img.removeEventListener("load", loadHandler);
+            img.removeEventListener("error", errorHandler);
+
+            onLoad(img);
+
+            // Must revoke the URL after calling onLoad to avoid security exceptions in
+            // certain scenarios (e.g. when hosted in vscode).
+            if (usingObjectURL && img.src) {
+                URL.revokeObjectURL(img.src);
+            }
+        };
+
+        const errorHandler = (err: any) => {
+            img.removeEventListener("load", loadHandler);
+            img.removeEventListener("error", errorHandler);
+
+            if (onError) {
+                onError("Error while trying to load image: " + input, err);
+            }
+
+            if (usingObjectURL && img.src) {
+                URL.revokeObjectURL(img.src);
+            }
+        };
+
+        img.addEventListener("load", loadHandler);
+        img.addEventListener("error", errorHandler);
+
+        var noOfflineSupport = () => {
+            img.src = url;
+        };
+
+        var loadFromOfflineSupport = () => {
+            if (offlineProvider) {
+                offlineProvider.loadImage(url, img);
+            }
+        };
+
+        if (url.substr(0, 5) !== "data:" && offlineProvider && offlineProvider.enableTexturesOffline) {
+            offlineProvider.open(loadFromOfflineSupport, noOfflineSupport);
+        }
+        else {
+            if (url.indexOf("file:") !== -1) {
+                var textureName = decodeURIComponent(url.substring(5).toLowerCase());
+                if (FilesInputStore.FilesToLoad[textureName]) {
+                    try {
+                        var blobURL;
+                        try {
+                            blobURL = URL.createObjectURL(FilesInputStore.FilesToLoad[textureName]);
+                        }
+                        catch (ex) {
+                            // Chrome doesn't support oneTimeOnly parameter
+                            blobURL = URL.createObjectURL(FilesInputStore.FilesToLoad[textureName]);
+                        }
+                        img.src = blobURL;
+                        usingObjectURL = true;
+                    }
+                    catch (e) {
+                        img.src = "";
+                    }
+                    return img;
+                }
+            }
+
+            noOfflineSupport();
+        }
+
+        return img;
+    }
+
+    /**
+     * Loads a file
+     * @param fileToLoad defines the file to load
+     * @param callback defines the callback to call when data is loaded
+     * @param progressCallBack defines the callback to call during loading process
+     * @param useArrayBuffer defines a boolean indicating that data must be returned as an ArrayBuffer
+     * @returns a file request object
+     */
+    public static ReadFile(fileToLoad: File, callback: (data: any) => void, progressCallBack?: (ev: ProgressEvent) => any, useArrayBuffer?: boolean): IFileRequest {
+        let reader = new FileReader();
+        let request: IFileRequest = {
+            onCompleteObservable: new Observable<IFileRequest>(),
+            abort: () => reader.abort(),
+        };
+
+        reader.onloadend = (e) => request.onCompleteObservable.notifyObservers(request);
+        reader.onerror = (e) => {
+            callback(JSON.stringify({ autoClear: true, clearColor: [1, 0, 0], ambientColor: [0, 0, 0], gravity: [0, -9.807, 0], meshes: [], cameras: [], lights: [] }));
+        };
+        reader.onload = (e) => {
+            //target doesn't have result from ts 1.3
+            callback((<any>e.target)['result']);
+        };
+        if (progressCallBack) {
+            reader.onprogress = progressCallBack;
+        }
+        if (!useArrayBuffer) {
+            // Asynchronous read
+            reader.readAsText(fileToLoad);
+        }
+        else {
+            reader.readAsArrayBuffer(fileToLoad);
+        }
+
+        return request;
+    }
+
+    /**
+     * Loads a file
+     * @param url url string, ArrayBuffer, or Blob to load
+     * @param onSuccess callback called when the file successfully loads
+     * @param onProgress callback called while file is loading (if the server supports this mode)
+     * @param offlineProvider defines the offline provider for caching
+     * @param useArrayBuffer defines a boolean indicating that date must be returned as ArrayBuffer
+     * @param onError callback called when the file fails to load
+     * @returns a file request object
+     */
+    public static LoadFile(url: string, onSuccess: (data: string | ArrayBuffer, responseURL?: string) => void, onProgress?: (data: any) => void, offlineProvider?: IOfflineProvider, useArrayBuffer?: boolean, onError?: (request?: WebRequest, exception?: any) => void): IFileRequest {
+        url = this._CleanUrl(url);
+
+        url = this.PreprocessUrl(url);
+
+        // If file and file input are set
+        if (url.indexOf("file:") !== -1) {
+            const fileName = decodeURIComponent(url.substring(5).toLowerCase());
+            if (FilesInputStore.FilesToLoad[fileName]) {
+                return this.ReadFile(FilesInputStore.FilesToLoad[fileName], onSuccess, onProgress, useArrayBuffer);
+            }
+        }
+
+        const loadUrl = this.BaseUrl + url;
+
+        let aborted = false;
+        const fileRequest: IFileRequest = {
+            onCompleteObservable: new Observable<IFileRequest>(),
+            abort: () => aborted = true,
+        };
+
+        const requestFile = () => {
+            let request = new WebRequest();
+            let retryHandle: Nullable<number> = null;
+
+            fileRequest.abort = () => {
+                aborted = true;
+
+                if (request.readyState !== (XMLHttpRequest.DONE || 4)) {
+                    request.abort();
+                }
+
+                if (retryHandle !== null) {
+                    clearTimeout(retryHandle);
+                    retryHandle = null;
+                }
+            };
+
+            const retryLoop = (retryIndex: number) => {
+                request.open('GET', loadUrl);
+
+                if (useArrayBuffer) {
+                    request.responseType = "arraybuffer";
+                }
+
+                if (onProgress) {
+                    request.addEventListener("progress", onProgress);
+                }
+
+                const onLoadEnd = () => {
+                    request.removeEventListener("loadend", onLoadEnd);
+                    fileRequest.onCompleteObservable.notifyObservers(fileRequest);
+                    fileRequest.onCompleteObservable.clear();
+                };
+
+                request.addEventListener("loadend", onLoadEnd);
+
+                const onReadyStateChange = () => {
+                    if (aborted) {
+                        return;
+                    }
+
+                    // In case of undefined state in some browsers.
+                    if (request.readyState === (XMLHttpRequest.DONE || 4)) {
+                        // Some browsers have issues where onreadystatechange can be called multiple times with the same value.
+                        request.removeEventListener("readystatechange", onReadyStateChange);
+
+                        if ((request.status >= 200 && request.status < 300) || (request.status === 0 && (!DomManagement.IsWindowObjectExist() || this.IsFileURL()))) {
+                            onSuccess(!useArrayBuffer ? request.responseText : <ArrayBuffer>request.response, request.responseURL);
+                            return;
+                        }
+
+                        let retryStrategy = this.DefaultRetryStrategy;
+                        if (retryStrategy) {
+                            let waitTime = retryStrategy(loadUrl, request, retryIndex);
+                            if (waitTime !== -1) {
+                                // Prevent the request from completing for retry.
+                                request.removeEventListener("loadend", onLoadEnd);
+                                request = new WebRequest();
+                                retryHandle = setTimeout(() => retryLoop(retryIndex + 1), waitTime);
+                                return;
+                            }
+                        }
+
+                        let e = new LoadFileError("Error status: " + request.status + " " + request.statusText + " - Unable to load " + loadUrl, request);
+                        if (onError) {
+                            onError(request, e);
+                        } else {
+                            throw e;
+                        }
+                    }
+                };
+
+                request.addEventListener("readystatechange", onReadyStateChange);
+
+                request.send();
+            };
+
+            retryLoop(0);
+        };
+
+        // Caching all files
+        if (offlineProvider && offlineProvider.enableSceneOffline) {
+            const noOfflineSupport = (request?: any) => {
+                if (request && request.status > 400) {
+                    if (onError) {
+                        onError(request);
+                    }
+                } else {
+                    if (!aborted) {
+                        requestFile();
+                    }
+                }
+            };
+
+            const loadFromOfflineSupport = () => {
+                // TODO: database needs to support aborting and should return a IFileRequest
+                if (aborted) {
+                    return;
+                }
+
+                if (offlineProvider) {
+                    offlineProvider.loadFile(url, (data) => {
+                        if (!aborted) {
+                            onSuccess(data);
+                        }
+
+                        fileRequest.onCompleteObservable.notifyObservers(fileRequest);
+                    }, onProgress ? (event) => {
+                        if (!aborted) {
+                            onProgress(event);
+                        }
+                    } : undefined, noOfflineSupport, useArrayBuffer);
+                }
+            };
+
+            offlineProvider.open(loadFromOfflineSupport, noOfflineSupport);
+        }
+        else {
+            requestFile();
+        }
+
+        return fileRequest;
+    }
+
+    /**
+     * Checks if the loaded document was accessed via `file:`-Protocol.
+     * @returns boolean
+     */
+    public static IsFileURL(): boolean {
+        return location.protocol === "file:";
+    }
+}

+ 108 - 0
src/Misc/gradients.ts

@@ -0,0 +1,108 @@
+import { Color3, Color4 } from '../Maths/math';
+
+/** Interface used by value gradients (color, factor, ...) */
+export interface IValueGradient {
+    /**
+     * Gets or sets the gradient value (between 0 and 1)
+     */
+    gradient: number;
+}
+
+/** Class used to store color4 gradient */
+export class ColorGradient implements IValueGradient {
+    /**
+     * Gets or sets the gradient value (between 0 and 1)
+     */
+    public gradient: number;
+    /**
+     * Gets or sets first associated color
+     */
+    public color1: Color4;
+    /**
+     * Gets or sets second associated color
+     */
+    public color2?: Color4;
+
+    /**
+     * Will get a color picked randomly between color1 and color2.
+     * If color2 is undefined then color1 will be used
+     * @param result defines the target Color4 to store the result in
+     */
+    public getColorToRef(result: Color4) {
+        if (!this.color2) {
+            result.copyFrom(this.color1);
+            return;
+        }
+
+        Color4.LerpToRef(this.color1, this.color2, Math.random(), result);
+    }
+}
+
+/** Class used to store color 3 gradient */
+export class Color3Gradient implements IValueGradient {
+    /**
+     * Gets or sets the gradient value (between 0 and 1)
+     */
+    public gradient: number;
+    /**
+     * Gets or sets the associated color
+     */
+    public color: Color3;
+}
+
+/** Class used to store factor gradient */
+export class FactorGradient implements IValueGradient {
+    /**
+     * Gets or sets the gradient value (between 0 and 1)
+     */
+    public gradient: number;
+    /**
+     * Gets or sets first associated factor
+     */
+    public factor1: number;
+    /**
+     * Gets or sets second associated factor
+     */
+    public factor2?: number;
+
+    /**
+     * Will get a number picked randomly between factor1 and factor2.
+     * If factor2 is undefined then factor1 will be used
+     * @returns the picked number
+     */
+    public getFactor(): number {
+        if (this.factor2 === undefined) {
+            return this.factor1;
+        }
+
+        return this.factor1 + ((this.factor2 - this.factor1) * Math.random());
+    }
+}
+
+/**
+ * Helper used to simplify some generic gradient tasks
+ */
+export class GradientHelper {
+    /**
+     * Gets the current gradient from an array of IValueGradient
+     * @param ratio defines the current ratio to get
+     * @param gradients defines the array of IValueGradient
+     * @param updateFunc defines the callback function used to get the final value from the selected gradients
+     */
+    public static GetCurrentGradient(ratio: number, gradients: IValueGradient[], updateFunc: (current: IValueGradient, next: IValueGradient, scale: number) => void) {
+        for (var gradientIndex = 0; gradientIndex < gradients.length - 1; gradientIndex++) {
+            let currentGradient = gradients[gradientIndex];
+            let nextGradient = gradients[gradientIndex + 1];
+
+            if (ratio >= currentGradient.gradient && ratio <= nextGradient.gradient) {
+                let scale = (ratio - currentGradient.gradient) / (nextGradient.gradient - currentGradient.gradient);
+                updateFunc(currentGradient, nextGradient, scale);
+                return;
+            }
+        }
+
+        // Use last index if over
+        const lastIndex = gradients.length - 1;
+        updateFunc(gradients[lastIndex], gradients[lastIndex], 1.0);
+    }
+}

+ 6 - 0
src/Misc/index.ts

@@ -33,3 +33,9 @@ export * from "./typeStore";
 export * from "./webRequest";
 export * from "./iInspectable";
 export * from "./brdfTextureTools";
+export * from "./gradients";
+export * from "./perfCounter";
+export * from "./fileRequest";
+export * from "./customAnimationFrameRequester";
+export * from "./retryStrategy";
+export * from "./loadFileError";

+ 30 - 0
src/Misc/loadFileError.ts

@@ -0,0 +1,30 @@
+import { WebRequest } from './webRequest';
+
+/**
+ * @ignore
+ * Application error to support additional information when loading a file
+ */
+export class LoadFileError extends Error {
+    // See https://stackoverflow.com/questions/12915412/how-do-i-extend-a-host-object-e-g-error-in-typescript
+    // and https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work
+
+    // Polyfill for Object.setPrototypeOf if necessary.
+    private static _setPrototypeOf: (o: any, proto: object | null) => any =
+        (Object as any).setPrototypeOf || ((o, proto) => { o.__proto__ = proto; return o; });
+
+    /**
+     * Creates a new LoadFileError
+     * @param message defines the message of the error
+     * @param request defines the optional web request
+     */
+    constructor(
+        message: string,
+        /** defines the optional web request */
+        public request?: WebRequest
+    ) {
+        super(message);
+        this.name = "LoadFileError";
+
+        LoadFileError._setPrototypeOf(this, LoadFileError.prototype);
+    }
+}

+ 169 - 0
src/Misc/perfCounter.ts

@@ -0,0 +1,169 @@
+import { PrecisionDate } from './precisionDate';
+
+/**
+ * This class is used to track a performance counter which is number based.
+ * The user has access to many properties which give statistics of different nature.
+ *
+ * The implementer can track two kinds of Performance Counter: time and count.
+ * For time you can optionally call fetchNewFrame() to notify the start of a new frame to monitor, then call beginMonitoring() to start and endMonitoring() to record the lapsed time. endMonitoring takes a newFrame parameter for you to specify if the monitored time should be set for a new frame or accumulated to the current frame being monitored.
+ * For count you first have to call fetchNewFrame() to notify the start of a new frame to monitor, then call addCount() how many time required to increment the count value you monitor.
+ */
+export class PerfCounter {
+    /**
+     * Gets or sets a global boolean to turn on and off all the counters
+     */
+    public static Enabled = true;
+
+    /**
+     * Returns the smallest value ever
+     */
+    public get min(): number {
+        return this._min;
+    }
+
+    /**
+     * Returns the biggest value ever
+     */
+    public get max(): number {
+        return this._max;
+    }
+
+    /**
+     * Returns the average value since the performance counter is running
+     */
+    public get average(): number {
+        return this._average;
+    }
+
+    /**
+     * Returns the average value of the last second the counter was monitored
+     */
+    public get lastSecAverage(): number {
+        return this._lastSecAverage;
+    }
+
+    /**
+     * Returns the current value
+     */
+    public get current(): number {
+        return this._current;
+    }
+
+    /**
+     * Gets the accumulated total
+     */
+    public get total(): number {
+        return this._totalAccumulated;
+    }
+
+    /**
+     * Gets the total value count
+     */
+    public get count(): number {
+        return this._totalValueCount;
+    }
+
+    /**
+     * Creates a new counter
+     */
+    constructor() {
+        this._startMonitoringTime = 0;
+        this._min = 0;
+        this._max = 0;
+        this._average = 0;
+        this._lastSecAverage = 0;
+        this._current = 0;
+        this._totalValueCount = 0;
+        this._totalAccumulated = 0;
+        this._lastSecAccumulated = 0;
+        this._lastSecTime = 0;
+        this._lastSecValueCount = 0;
+    }
+
+    /**
+     * Call this method to start monitoring a new frame.
+     * This scenario is typically used when you accumulate monitoring time many times for a single frame, you call this method at the start of the frame, then beginMonitoring to start recording and endMonitoring(false) to accumulated the recorded time to the PerfCounter or addCount() to accumulate a monitored count.
+     */
+    public fetchNewFrame() {
+        this._totalValueCount++;
+        this._current = 0;
+        this._lastSecValueCount++;
+    }
+
+    /**
+     * Call this method to monitor a count of something (e.g. mesh drawn in viewport count)
+     * @param newCount the count value to add to the monitored count
+     * @param fetchResult true when it's the last time in the frame you add to the counter and you wish to update the statistics properties (min/max/average), false if you only want to update statistics.
+     */
+    public addCount(newCount: number, fetchResult: boolean) {
+        if (!PerfCounter.Enabled) {
+            return;
+        }
+        this._current += newCount;
+        if (fetchResult) {
+            this._fetchResult();
+        }
+    }
+
+    /**
+     * Start monitoring this performance counter
+     */
+    public beginMonitoring() {
+        if (!PerfCounter.Enabled) {
+            return;
+        }
+        this._startMonitoringTime = PrecisionDate.Now;
+    }
+
+    /**
+     * Compute the time lapsed since the previous beginMonitoring() call.
+     * @param newFrame true by default to fetch the result and monitor a new frame, if false the time monitored will be added to the current frame counter
+     */
+    public endMonitoring(newFrame: boolean = true) {
+        if (!PerfCounter.Enabled) {
+            return;
+        }
+
+        if (newFrame) {
+            this.fetchNewFrame();
+        }
+
+        let currentTime = PrecisionDate.Now;
+        this._current = currentTime - this._startMonitoringTime;
+
+        if (newFrame) {
+            this._fetchResult();
+        }
+    }
+
+    private _fetchResult() {
+        this._totalAccumulated += this._current;
+        this._lastSecAccumulated += this._current;
+
+        // Min/Max update
+        this._min = Math.min(this._min, this._current);
+        this._max = Math.max(this._max, this._current);
+        this._average = this._totalAccumulated / this._totalValueCount;
+
+        // Reset last sec?
+        let now = PrecisionDate.Now;
+        if ((now - this._lastSecTime) > 1000) {
+            this._lastSecAverage = this._lastSecAccumulated / this._lastSecValueCount;
+            this._lastSecTime = now;
+            this._lastSecAccumulated = 0;
+            this._lastSecValueCount = 0;
+        }
+    }
+
+    private _startMonitoringTime: number;
+    private _min: number;
+    private _max: number;
+    private _average: number;
+    private _current: number;
+    private _totalValueCount: number;
+    private _totalAccumulated: number;
+    private _lastSecAverage: number;
+    private _lastSecAccumulated: number;
+    private _lastSecTime: number;
+    private _lastSecValueCount: number;
+}

+ 1 - 2
src/Misc/promise.ts

@@ -1,5 +1,4 @@
 import { Nullable } from "../types";
-import { Tools } from "./tools";
 
 enum PromiseStates {
     Pending,
@@ -70,7 +69,7 @@ class InternalPromise<T> {
         newPromise._parent = this;
 
         if (this._state !== PromiseStates.Pending) {
-            Tools.SetImmediate(() => {
+            setTimeout(() => {
                 if (this._state === PromiseStates.Fulfilled || this._rejectWasConsumed) {
                     let returnedValue = newPromise._resolve(this._result);
 

+ 22 - 0
src/Misc/retryStrategy.ts

@@ -0,0 +1,22 @@
+import { WebRequest } from './webRequest';
+
+/**
+ * Class used to define a retry strategy when error happens while loading assets
+ */
+export class RetryStrategy {
+    /**
+     * Function used to defines an exponential back off strategy
+     * @param maxRetries defines the maximum number of retries (3 by default)
+     * @param baseInterval defines the interval between retries
+     * @returns the strategy function to use
+     */
+    public static ExponentialBackoff(maxRetries = 3, baseInterval = 500) {
+        return (url: string, request: WebRequest, retryIndex: number): number => {
+            if (request.status !== 0 || retryIndex >= maxRetries || url.indexOf("file:") !== -1) {
+                return -1;
+            }
+
+            return Math.pow(2, retryIndex) * baseInterval;
+        };
+    }
+}

+ 24 - 0
src/Misc/stringTools.ts

@@ -0,0 +1,24 @@
+/**
+ * Helper to manipulate strings
+ */
+export class StringTools {
+    /**
+     * Checks for a matching suffix at the end of a string (for ES5 and lower)
+     * @param str Source string
+     * @param suffix Suffix to search for in the source string
+     * @returns Boolean indicating whether the suffix was found (true) or not (false)
+     */
+    public static EndsWith(str: string, suffix: string): boolean {
+        return str.indexOf(suffix, str.length - suffix.length) !== -1;
+    }
+
+    /**
+     * Checks for a matching suffix at the beginning of a string (for ES5 and lower)
+     * @param str Source string
+     * @param suffix Suffix to search for in the source string
+     * @returns Boolean indicating whether the suffix was found (true) or not (false)
+     */
+    public static StartsWith(str: string, suffix: string): boolean {
+        return str.indexOf(suffix) === 0;
+    }
+}

Різницю між файлами не показано, бо вона завелика
+ 64 - 919
src/Misc/tools.ts


+ 1 - 1
src/Particles/IParticleSystem.ts

@@ -5,7 +5,7 @@ import { BaseTexture } from "../Materials/Textures/baseTexture";
 import { Texture } from "../Materials/Textures/texture";
 import { BoxParticleEmitter, IParticleEmitterType, PointParticleEmitter, HemisphericParticleEmitter, SphereParticleEmitter, SphereDirectedParticleEmitter, CylinderParticleEmitter, ConeParticleEmitter } from "../Particles/EmitterTypes/index";
 import { Scene } from "../scene";
-import { ColorGradient, FactorGradient, Color3Gradient } from "../Misc/tools";
+import { ColorGradient, FactorGradient, Color3Gradient } from "../Misc/gradients";
 
 declare type Animation = import("../Animations/animation").Animation;
 

+ 1 - 1
src/Particles/baseParticleSystem.ts

@@ -5,7 +5,7 @@ import { ImageProcessingConfiguration, ImageProcessingConfigurationDefines } fro
 import { ProceduralTexture } from "../Materials/Textures/Procedurals/proceduralTexture";
 import { RawTexture } from "../Materials/Textures/rawTexture";
 import { Scene } from "../scene";
-import { ColorGradient, FactorGradient, Color3Gradient, IValueGradient } from "../Misc/tools";
+import { ColorGradient, FactorGradient, Color3Gradient, IValueGradient } from "../Misc/gradients";
 import { BoxParticleEmitter, IParticleEmitterType, PointParticleEmitter, HemisphericParticleEmitter, SphereParticleEmitter, SphereDirectedParticleEmitter, CylinderParticleEmitter, CylinderDirectedParticleEmitter, ConeParticleEmitter } from "../Particles/EmitterTypes/index";
 import { Constants } from "../Engines/constants";
 import { Texture } from '../Materials/Textures/texture';

+ 4 - 3
src/Particles/gpuParticleSystem.ts

@@ -1,5 +1,6 @@
 import { Nullable, float } from "../types";
-import { IAnimatable, Tools, IValueGradient, ColorGradient, FactorGradient, Color3Gradient } from "../Misc/tools";
+import { IAnimatable } from "../Misc/tools";
+import { FactorGradient, ColorGradient, Color3Gradient, IValueGradient, GradientHelper } from "../Misc/gradients";
 import { Observable } from "../Misc/observable";
 import { Color4, Color3, Vector3, Matrix, Tmp } from "../Maths/math";
 import { Scalar } from "../Maths/math.scalar";
@@ -1105,7 +1106,7 @@ export class GPUParticleSystem extends BaseParticleSystem implements IDisposable
         for (var x = 0; x < this._rawTextureWidth; x++) {
             var ratio = x / this._rawTextureWidth;
 
-            Tools.GetCurrentGradient(ratio, factorGradients, (currentGradient, nextGradient, scale) => {
+            GradientHelper.GetCurrentGradient(ratio, factorGradients, (currentGradient, nextGradient, scale) => {
                 data[x] = Scalar.Lerp((<FactorGradient>currentGradient).factor1, (<FactorGradient>nextGradient).factor1, scale);
             });
         }
@@ -1144,7 +1145,7 @@ export class GPUParticleSystem extends BaseParticleSystem implements IDisposable
         for (var x = 0; x < this._rawTextureWidth; x++) {
             var ratio = x / this._rawTextureWidth;
 
-            Tools.GetCurrentGradient(ratio, this._colorGradients, (currentGradient, nextGradient, scale) => {
+            GradientHelper.GetCurrentGradient(ratio, this._colorGradients, (currentGradient, nextGradient, scale) => {
 
                 Color4.LerpToRef((<ColorGradient>currentGradient).color1, (<ColorGradient>nextGradient).color1, scale, tmpColor);
                 data[x * 4] = tmpColor.r * 255;

+ 1 - 1
src/Particles/particle.ts

@@ -4,7 +4,7 @@ import { Scalar } from "../Maths/math.scalar";
 import { AbstractMesh } from "../Meshes/abstractMesh";
 import { ParticleSystem } from "./particleSystem";
 import { SubEmitter } from "./subEmitter";
-import { ColorGradient, FactorGradient } from "../Misc/tools";
+import { ColorGradient, FactorGradient } from "../Misc/gradients";
 /**
  * A particle represents one of the element emitted by a particle system.
  * This is mainly define by its coordinates, direction, velocity and age.

+ 14 - 13
src/Particles/particleSystem.ts

@@ -1,5 +1,6 @@
 import { Nullable } from "../types";
-import { IAnimatable, Tools, FactorGradient, ColorGradient, Color3Gradient } from "../Misc/tools";
+import { IAnimatable } from "../Misc/tools";
+import { FactorGradient, ColorGradient, Color3Gradient, GradientHelper } from "../Misc/gradients";
 import { Observable, Observer } from "../Misc/observable";
 import { Color4, Color3, Vector3, Matrix, Tmp, ISize, Vector4 } from "../Maths/math";
 import { Scalar } from "../Maths/math.scalar";
@@ -254,7 +255,7 @@ export class ParticleSystem extends BaseParticleSystem implements IDisposable, I
 
                 // Color
                 if (this._colorGradients && this._colorGradients.length > 0) {
-                    Tools.GetCurrentGradient(ratio, this._colorGradients, (currentGradient, nextGradient, scale) => {
+                    GradientHelper.GetCurrentGradient(ratio, this._colorGradients, (currentGradient, nextGradient, scale) => {
                         if (currentGradient !== particle._currentColorGradient) {
                             particle._currentColor1.copyFrom(particle._currentColor2);
                             (<ColorGradient>nextGradient).getColorToRef(particle._currentColor2);
@@ -274,7 +275,7 @@ export class ParticleSystem extends BaseParticleSystem implements IDisposable, I
 
                 // Angular speed
                 if (this._angularSpeedGradients && this._angularSpeedGradients.length > 0) {
-                    Tools.GetCurrentGradient(ratio, this._angularSpeedGradients, (currentGradient, nextGradient, scale) => {
+                    GradientHelper.GetCurrentGradient(ratio, this._angularSpeedGradients, (currentGradient, nextGradient, scale) => {
                         if (currentGradient !== particle._currentAngularSpeedGradient) {
                             particle._currentAngularSpeed1 = particle._currentAngularSpeed2;
                             particle._currentAngularSpeed2 = (<FactorGradient>nextGradient).getFactor();
@@ -290,7 +291,7 @@ export class ParticleSystem extends BaseParticleSystem implements IDisposable, I
 
                 /// Velocity
                 if (this._velocityGradients && this._velocityGradients.length > 0) {
-                    Tools.GetCurrentGradient(ratio, this._velocityGradients, (currentGradient, nextGradient, scale) => {
+                    GradientHelper.GetCurrentGradient(ratio, this._velocityGradients, (currentGradient, nextGradient, scale) => {
                         if (currentGradient !== particle._currentVelocityGradient) {
                             particle._currentVelocity1 = particle._currentVelocity2;
                             particle._currentVelocity2 = (<FactorGradient>nextGradient).getFactor();
@@ -304,7 +305,7 @@ export class ParticleSystem extends BaseParticleSystem implements IDisposable, I
 
                 /// Limit velocity
                 if (this._limitVelocityGradients && this._limitVelocityGradients.length > 0) {
-                    Tools.GetCurrentGradient(ratio, this._limitVelocityGradients, (currentGradient, nextGradient, scale) => {
+                    GradientHelper.GetCurrentGradient(ratio, this._limitVelocityGradients, (currentGradient, nextGradient, scale) => {
                         if (currentGradient !== particle._currentLimitVelocityGradient) {
                             particle._currentLimitVelocity1 = particle._currentLimitVelocity2;
                             particle._currentLimitVelocity2 = (<FactorGradient>nextGradient).getFactor();
@@ -322,7 +323,7 @@ export class ParticleSystem extends BaseParticleSystem implements IDisposable, I
 
                 /// Drag
                 if (this._dragGradients && this._dragGradients.length > 0) {
-                    Tools.GetCurrentGradient(ratio, this._dragGradients, (currentGradient, nextGradient, scale) => {
+                    GradientHelper.GetCurrentGradient(ratio, this._dragGradients, (currentGradient, nextGradient, scale) => {
                         if (currentGradient !== particle._currentDragGradient) {
                             particle._currentDrag1 = particle._currentDrag2;
                             particle._currentDrag2 = (<FactorGradient>nextGradient).getFactor();
@@ -358,7 +359,7 @@ export class ParticleSystem extends BaseParticleSystem implements IDisposable, I
 
                 // Size
                 if (this._sizeGradients && this._sizeGradients.length > 0) {
-                    Tools.GetCurrentGradient(ratio, this._sizeGradients, (currentGradient, nextGradient, scale) => {
+                    GradientHelper.GetCurrentGradient(ratio, this._sizeGradients, (currentGradient, nextGradient, scale) => {
                         if (currentGradient !== particle._currentSizeGradient) {
                             particle._currentSize1 = particle._currentSize2;
                             particle._currentSize2 = (<FactorGradient>nextGradient).getFactor();
@@ -371,7 +372,7 @@ export class ParticleSystem extends BaseParticleSystem implements IDisposable, I
                 // Remap data
                 if (this._useRampGradients) {
                     if (this._colorRemapGradients && this._colorRemapGradients.length > 0) {
-                        Tools.GetCurrentGradient(ratio, this._colorRemapGradients, (currentGradient, nextGradient, scale) => {
+                        GradientHelper.GetCurrentGradient(ratio, this._colorRemapGradients, (currentGradient, nextGradient, scale) => {
                             let min = Scalar.Lerp((<FactorGradient>currentGradient).factor1, (<FactorGradient>nextGradient).factor1, scale);
                             let max = Scalar.Lerp((<FactorGradient>currentGradient).factor2!, (<FactorGradient>nextGradient).factor2!, scale);
 
@@ -381,7 +382,7 @@ export class ParticleSystem extends BaseParticleSystem implements IDisposable, I
                     }
 
                     if (this._alphaRemapGradients && this._alphaRemapGradients.length > 0) {
-                        Tools.GetCurrentGradient(ratio, this._alphaRemapGradients, (currentGradient, nextGradient, scale) => {
+                        GradientHelper.GetCurrentGradient(ratio, this._alphaRemapGradients, (currentGradient, nextGradient, scale) => {
                             let min = Scalar.Lerp((<FactorGradient>currentGradient).factor1, (<FactorGradient>nextGradient).factor1, scale);
                             let max = Scalar.Lerp((<FactorGradient>currentGradient).factor2!, (<FactorGradient>nextGradient).factor2!, scale);
 
@@ -737,7 +738,7 @@ export class ParticleSystem extends BaseParticleSystem implements IDisposable, I
         for (var x = 0; x < this._rawTextureWidth; x++) {
             var ratio = x / this._rawTextureWidth;
 
-            Tools.GetCurrentGradient(ratio, this._rampGradients, (currentGradient, nextGradient, scale) => {
+            GradientHelper.GetCurrentGradient(ratio, this._rampGradients, (currentGradient, nextGradient, scale) => {
 
                 Color3.LerpToRef((<Color3Gradient>currentGradient).color, (<Color3Gradient>nextGradient).color, scale, tmpColor);
                 data[x * 4] = tmpColor.r * 255;
@@ -1321,7 +1322,7 @@ export class ParticleSystem extends BaseParticleSystem implements IDisposable, I
             // Life time
             if (this.targetStopDuration && this._lifeTimeGradients && this._lifeTimeGradients.length > 0) {
                 let ratio = Scalar.Clamp(this._actualFrame / this.targetStopDuration);
-                Tools.GetCurrentGradient(ratio, this._lifeTimeGradients, (currentGradient, nextGradient) => {
+                GradientHelper.GetCurrentGradient(ratio, this._lifeTimeGradients, (currentGradient, nextGradient) => {
                     let factorGradient1 = (<FactorGradient>currentGradient);
                     let factorGradient2 = (<FactorGradient>nextGradient);
                     let lifeTime1 = factorGradient1.getFactor();
@@ -1353,7 +1354,7 @@ export class ParticleSystem extends BaseParticleSystem implements IDisposable, I
             // Adjust scale by start size
             if (this._startSizeGradients && this._startSizeGradients[0] && this.targetStopDuration) {
                 const ratio = this._actualFrame / this.targetStopDuration;
-                Tools.GetCurrentGradient(ratio, this._startSizeGradients, (currentGradient, nextGradient, scale) => {
+                GradientHelper.GetCurrentGradient(ratio, this._startSizeGradients, (currentGradient, nextGradient, scale) => {
                     if (currentGradient !== this._currentStartSizeGradient) {
                         this._currentStartSize1 = this._currentStartSize2;
                         this._currentStartSize2 = (<FactorGradient>nextGradient).getFactor();
@@ -1615,7 +1616,7 @@ export class ParticleSystem extends BaseParticleSystem implements IDisposable, I
 
             if (this._emitRateGradients && this._emitRateGradients.length > 0 && this.targetStopDuration) {
                 const ratio = this._actualFrame / this.targetStopDuration;
-                Tools.GetCurrentGradient(ratio, this._emitRateGradients, (currentGradient, nextGradient, scale) => {
+                GradientHelper.GetCurrentGradient(ratio, this._emitRateGradients, (currentGradient, nextGradient, scale) => {
                     if (currentGradient !== this._currentEmitRateGradient) {
                         this._currentEmitRate1 = this._currentEmitRate2;
                         this._currentEmitRate2 = (<FactorGradient>nextGradient).getFactor();

+ 5 - 6
src/PostProcesses/postProcess.ts

@@ -1,5 +1,4 @@
 import { Nullable } from "../types";
-import { Tools } from "../Misc/tools";
 import { SmartArray } from "../Misc/smartArray";
 import { Observable, Observer } from "../Misc/observable";
 import { Color4, Vector2 } from "../Maths/math";
@@ -8,11 +7,11 @@ import { Effect } from "../Materials/effect";
 import { Constants } from "../Engines/constants";
 import "../Shaders/postprocess.vertex";
 import { IInspectable } from '../Misc/iInspectable';
+import { Engine } from '../Engines/engine';
 
-declare type Scene  = import("../scene").Scene;
+declare type Scene = import("../scene").Scene;
 declare type InternalTexture = import("../Materials/Textures/internalTexture").InternalTexture;
 declare type WebVRFreeCamera = import("../Cameras/VR/webVRCamera").WebVRFreeCamera;
-declare type Engine = import("../Engines/engine").Engine;
 declare type Animation = import("../Animations/animation").Animation;
 
 /**
@@ -98,7 +97,7 @@ export class PostProcess {
      * | 3     | SCALEMODE_CEILING                   | [engine.scalemode_ceiling](http://doc.babylonjs.com/api/classes/babylon.engine#scalemode_ceiling) |
      *
      */
-    public scaleMode = Constants.SCALEMODE_FLOOR;
+    public scaleMode = Engine.SCALEMODE_FLOOR;
     /**
     * Force textures to be a power of two (default: false)
     */
@@ -464,11 +463,11 @@ export class PostProcess {
 
             if (this.renderTargetSamplingMode === Constants.TEXTURE_TRILINEAR_SAMPLINGMODE || this.alwaysForcePOT) {
                 if (!(<PostProcessOptions>this._options).width) {
-                    desiredWidth = engine.needPOTTextures ? Tools.GetExponentOfTwo(desiredWidth, maxSize, this.scaleMode) : desiredWidth;
+                    desiredWidth = engine.needPOTTextures ? Engine.GetExponentOfTwo(desiredWidth, maxSize, this.scaleMode) : desiredWidth;
                 }
 
                 if (!(<PostProcessOptions>this._options).height) {
-                    desiredHeight = engine.needPOTTextures ? Tools.GetExponentOfTwo(desiredHeight, maxSize, this.scaleMode) : desiredHeight;
+                    desiredHeight = engine.needPOTTextures ? Engine.GetExponentOfTwo(desiredHeight, maxSize, this.scaleMode) : desiredHeight;
                 }
             }
 

+ 2 - 3
src/node.ts

@@ -9,7 +9,6 @@ import { EngineStore } from "./Engines/engineStore";
 import { _DevTools } from './Misc/devTools';
 import { AbstractActionManager } from './Actions/abstractActionManager';
 import { IInspectable } from './Misc/iInspectable';
-import { Tools } from './Misc/tools';
 
 declare type Animatable = import("./Animations/animatable").Animatable;
 declare type AnimationPropertiesOverride = import("./Animations/animationPropertiesOverride").AnimationPropertiesOverride;
@@ -830,8 +829,8 @@ export class Node implements IBehaviorAware<Node> {
                 var minBox = boundingBox.minimumWorld;
                 var maxBox = boundingBox.maximumWorld;
 
-                Tools.CheckExtends(minBox, min, max);
-                Tools.CheckExtends(maxBox, min, max);
+                Vector3.CheckExtends(minBox, min, max);
+                Vector3.CheckExtends(maxBox, min, max);
             }
         }
 

+ 5 - 3
src/scene.ts

@@ -1,5 +1,5 @@
 import { Nullable } from "./types";
-import { IAnimatable, IFileRequest, Tools, PerfCounter } from "./Misc/tools";
+import { IAnimatable, Tools } from "./Misc/tools";
 import { PrecisionDate } from "./Misc/precisionDate";
 import { Observable, Observer } from "./Misc/observable";
 import { SmartArrayNoDuplicate, SmartArray, ISmartArrayLike } from "./Misc/smartArray";
@@ -47,6 +47,8 @@ import { AbstractActionManager } from './Actions/abstractActionManager';
 import { _DevTools } from './Misc/devTools';
 import { WebRequest } from './Misc/webRequest';
 import { InputManager } from './Inputs/scene.inputManager';
+import { PerfCounter } from './Misc/perfCounter';
+import { IFileRequest } from './Misc/fileRequest';
 
 declare type Ray = import("./Culling/ray").Ray;
 declare type TrianglePickingPredicate = import("./Culling/ray").TrianglePickingPredicate;
@@ -4156,8 +4158,8 @@ export class Scene extends AbstractScene implements IAnimatable {
             var minBox = boundingInfo.boundingBox.minimumWorld;
             var maxBox = boundingInfo.boundingBox.maximumWorld;
 
-            Tools.CheckExtends(minBox, min, max);
-            Tools.CheckExtends(maxBox, min, max);
+            Vector3.CheckExtends(minBox, min, max);
+            Vector3.CheckExtends(maxBox, min, max);
         });
 
         return {

+ 1 - 1
tests/validation/config.json

@@ -237,7 +237,7 @@
         },
         {
             "title": "Fresnel",
-            "playgroundId": "#603JUZ#0",
+            "playgroundId": "#603JUZ#1",
             "referenceImage": "fresnel.png"
         },
         {