浏览代码

Merge remote-tracking branch 'upstream/master'

MackeyK24 6 年之前
父节点
当前提交
36b265e885
共有 78 个文件被更改,包括 2862 次插入2072 次删除
  1. 122 121
      Playground/babylon.d.txt
  2. 265 0
      Tools/Gulp/helpers/gulp-karmaJunitPlugin.js
  3. 36 0
      Tools/Gulp/tasks/gulpTasks-tests.js
  4. 10 0
      Viewer/tests/karma.conf.js
  5. 10 0
      Viewer/tests/validation/karma.conf.js
  6. 49 17
      azure-pipelines.yml
  7. 119 122
      dist/preview release/babylon.d.ts
  8. 2 2
      dist/preview release/babylon.js
  9. 672 554
      dist/preview release/babylon.max.js
  10. 1 1
      dist/preview release/babylon.max.js.map
  11. 247 248
      dist/preview release/babylon.module.d.ts
  12. 39 39
      dist/preview release/gui/babylon.gui.js
  13. 1 1
      dist/preview release/gui/babylon.gui.js.map
  14. 1 1
      dist/preview release/inspector/babylon.inspector.bundle.js
  15. 7 8
      dist/preview release/inspector/babylon.inspector.bundle.max.js
  16. 1 1
      dist/preview release/inspector/babylon.inspector.bundle.max.js.map
  17. 13 6
      dist/preview release/loaders/babylon.glTF2FileLoader.js
  18. 1 1
      dist/preview release/loaders/babylon.glTF2FileLoader.js.map
  19. 1 1
      dist/preview release/loaders/babylon.glTF2FileLoader.min.js
  20. 13 6
      dist/preview release/loaders/babylon.glTFFileLoader.js
  21. 1 1
      dist/preview release/loaders/babylon.glTFFileLoader.js.map
  22. 2 2
      dist/preview release/loaders/babylon.glTFFileLoader.min.js
  23. 3 1
      dist/preview release/loaders/babylonjs.loaders.d.ts
  24. 13 6
      dist/preview release/loaders/babylonjs.loaders.js
  25. 1 1
      dist/preview release/loaders/babylonjs.loaders.js.map
  26. 2 2
      dist/preview release/loaders/babylonjs.loaders.min.js
  27. 7 2
      dist/preview release/loaders/babylonjs.loaders.module.d.ts
  28. 1 1
      dist/preview release/packagesSizeBaseLine.json
  29. 247 248
      dist/preview release/viewer/babylon.module.d.ts
  30. 1 48
      dist/preview release/viewer/babylon.viewer.d.ts
  31. 32 36
      dist/preview release/viewer/babylon.viewer.js
  32. 2 2
      dist/preview release/viewer/babylon.viewer.max.js
  33. 2 49
      dist/preview release/viewer/babylon.viewer.module.d.ts
  34. 7 2
      dist/preview release/viewer/babylonjs.loaders.module.d.ts
  35. 10 3
      dist/preview release/what's new.md
  36. 0 1
      inspector/src/components/actionTabs/tabs/statisticsTabComponent.tsx
  37. 11 7
      loaders/src/glTF/2.0/Extensions/KHR_draco_mesh_compression.ts
  38. 7 0
      loaders/src/glTF/2.0/glTFLoader.ts
  39. 3 3
      package.json
  40. 1 1
      readme.md
  41. 91 0
      sandbox/debug.html
  42. 10 1
      sandbox/index.js
  43. 1 1
      src/Actions/actionEvent.ts
  44. 1 1
      src/Animations/animatable.ts
  45. 81 43
      src/Animations/runtimeAnimation.ts
  46. 52 19
      src/Cameras/arcRotateCamera.ts
  47. 38 0
      src/Debug/physicsViewer.ts
  48. 22 130
      src/Engines/engine.ts
  49. 0 8
      src/Instrumentation/sceneInstrumentation.ts
  50. 1 1
      src/Lights/shadowLight.ts
  51. 0 1
      src/Materials/Textures/index.ts
  52. 3 17
      src/Materials/Textures/internalTexture.ts
  53. 0 30
      src/Materials/Textures/internalTextureTracker.ts
  54. 65 5
      src/Maths/math.ts
  55. 7 3
      src/Meshes/Builders/groundBuilder.ts
  56. 2 1
      src/Meshes/Builders/icoSphereBuilder.ts
  57. 2 1
      src/Meshes/Builders/latheBuilder.ts
  58. 2 1
      src/Meshes/Builders/planeBuilder.ts
  59. 5 4
      src/Meshes/Builders/polygonBuilder.ts
  60. 2 1
      src/Meshes/Builders/polyhedronBuilder.ts
  61. 1 1
      src/Meshes/Builders/shapeBuilder.ts
  62. 1 1
      src/Meshes/Builders/tubeBuilder.ts
  63. 237 122
      src/Meshes/Compression/dracoCompression.ts
  64. 8 0
      src/Meshes/abstractMesh.ts
  65. 15 15
      src/Meshes/meshBuilder.ts
  66. 3 1
      src/Meshes/meshSimplification.ts
  67. 183 115
      src/Meshes/transformNode.ts
  68. 2 1
      src/Misc/dds.ts
  69. 11 0
      src/Misc/tools.ts
  70. 3 0
      src/Physics/Plugins/ammoJSPlugin.ts
  71. 6 0
      src/node.ts
  72. 3 0
      src/scene.ts
  73. 10 0
      tests/modules/karma.conf.js
  74. 4 0
      tests/modules/tests.json
  75. 10 0
      tests/unit/karma.conf.js
  76. 4 0
      tests/validation/integration.js
  77. 12 2
      tests/validation/karma.conf.js
  78. 1 1
      tests/validation/validation.js

+ 122 - 121
Playground/babylon.d.txt

@@ -267,7 +267,7 @@ declare module BABYLON {
      * Constant used to define the minimal number value in Babylon.js
      * Constant used to define the minimal number value in Babylon.js
      * @ignorenaming
      * @ignorenaming
      */
      */
-    export const Epsilon = 0.001;
+    let Epsilon: number;
     /**
     /**
      * Class used to hold a RBG color
      * Class used to hold a RBG color
      */
      */
@@ -2937,6 +2937,14 @@ declare module BABYLON {
          */
          */
         setTranslationFromFloats(x: number, y: number, z: number): Matrix;
         setTranslationFromFloats(x: number, y: number, z: number): Matrix;
         /**
         /**
+         * Adds the translation vector (using 3 floats) in the current matrix
+         * @param x defines the 1st component of the translation
+         * @param y defines the 2nd component of the translation
+         * @param z defines the 3rd component of the translation
+         * @returns the current updated matrix
+         */
+        addTranslationFromFloats(x: number, y: number, z: number): Matrix;
+        /**
          * Inserts the translation vector in the current matrix
          * Inserts the translation vector in the current matrix
          * @param vector3 defines the translation to insert
          * @param vector3 defines the translation to insert
          * @returns the current updated matrix
          * @returns the current updated matrix
@@ -3255,6 +3263,14 @@ declare module BABYLON {
          */
          */
         static RotationAxisToRef(axis: DeepImmutable<Vector3>, angle: number, result: Matrix): void;
         static RotationAxisToRef(axis: DeepImmutable<Vector3>, angle: number, result: Matrix): void;
         /**
         /**
+         * Takes normalised vectors and returns a rotation matrix to align "from" with "to".
+         * Taken from http://www.iquilezles.org/www/articles/noacos/noacos.htm
+         * @param from defines the vector to align
+         * @param to defines the vector to align to
+         * @param result defines the target matrix
+         */
+        static RotationAlignToRef(from: DeepImmutable<Vector3>, to: DeepImmutable<Vector3>, result: Matrix): void;
+        /**
          * Creates a rotation matrix
          * Creates a rotation matrix
          * @param yaw defines the yaw angle in radians (Y axis)
          * @param yaw defines the yaw angle in radians (Y axis)
          * @param pitch defines the pitch angle in radians (X axis)
          * @param pitch defines the pitch angle in radians (X axis)
@@ -6134,38 +6150,10 @@ declare module BABYLON {
 }
 }
 declare module BABYLON {
 declare module BABYLON {
     /**
     /**
-     * Internal interface used to track InternalTexture already bound to the GL context
-     */
-    export interface IInternalTextureTracker {
-        /**
-         * Gets or set the previous tracker in the list
-         */
-        previous: Nullable<IInternalTextureTracker>;
-        /**
-         * Gets or set the next tracker in the list
-         */
-        next: Nullable<IInternalTextureTracker>;
-    }
-    /**
-     * Internal class used by the engine to get list of InternalTexture already bound to the GL context
-     */
-    export class DummyInternalTextureTracker {
-        /**
-         * Gets or set the previous tracker in the list
-         */
-        previous: Nullable<IInternalTextureTracker>;
-        /**
-         * Gets or set the next tracker in the list
-         */
-        next: Nullable<IInternalTextureTracker>;
-    }
-}
-declare module BABYLON {
-    /**
      * Class used to store data associated with WebGL texture data for the engine
      * Class used to store data associated with WebGL texture data for the engine
      * This class should not be used directly
      * This class should not be used directly
      */
      */
-    export class InternalTexture implements IInternalTextureTracker {
+    export class InternalTexture {
         /** hidden */
private static _UpdateRGBDAsync: (internalTexture: InternalTexture, data: ArrayBufferView[][], sphericalPolynomial: SphericalPolynomial | null, lodScale: number, lodOffset: number) => Promise<void>;
         /** hidden */
private static _UpdateRGBDAsync: (internalTexture: InternalTexture, data: ArrayBufferView[][], sphericalPolynomial: SphericalPolynomial | null, lodScale: number, lodOffset: number) => Promise<void>;
         /**
         /**
          * The source of the texture data is unknown
          * The source of the texture data is unknown
@@ -6291,17 +6279,8 @@ declare module BABYLON {
          * Gets a boolean indicating if the texture is inverted on Y axis
          * Gets a boolean indicating if the texture is inverted on Y axis
          */
          */
         invertY: boolean;
         invertY: boolean;
-        /**
-         * Gets or set the previous tracker in the list
-         */
-        previous: Nullable<IInternalTextureTracker>;
-        /**
-         * Gets or set the next tracker in the list
-         */
-        next: Nullable<IInternalTextureTracker>;
         /** @hidden */
invertVScale: boolean;
         /** @hidden */
invertVScale: boolean;
-        /** @hidden */
initialSlot: number;
-        /** @hidden */
designatedSlot: number;
+        /** @hidden */
associatedChannel: number;
         /** @hidden */
dataSource: number;
         /** @hidden */
dataSource: number;
         /** @hidden */
buffer: Nullable<string | ArrayBuffer | HTMLImageElement | Blob>;
         /** @hidden */
buffer: Nullable<string | ArrayBuffer | HTMLImageElement | Blob>;
         /** @hidden */
bufferView: Nullable<ArrayBufferView>;
         /** @hidden */
bufferView: Nullable<ArrayBufferView>;
@@ -7419,6 +7398,7 @@ declare module BABYLON {
         private _up;
         private _up;
         private _right;
         private _right;
         private _rightInverted;
         private _rightInverted;
+        private _usePivotMatrix;
         private _position;
         private _position;
         private _rotation;
         private _rotation;
         private _rotationQuaternion;
         private _rotationQuaternion;
@@ -7462,8 +7442,6 @@ declare module BABYLON {
         private _pivotMatrix;
         private _pivotMatrix;
         private _pivotMatrixInverse;
         private _pivotMatrixInverse;
         protected _postMultiplyPivotMatrix: boolean;
         protected _postMultiplyPivotMatrix: boolean;
-        private _tempMatrix;
-        private _tempMatrix2;
         protected _isWorldMatrixFrozen: boolean;
         protected _isWorldMatrixFrozen: boolean;
         /** @hidden */
indexInSceneTransformNodesArray: number;
         /** @hidden */
indexInSceneTransformNodesArray: number;
         /**
         /**
@@ -18081,6 +18059,8 @@ declare module BABYLON {
          * The previous ratio of the runtime animation
          * The previous ratio of the runtime animation
          */
          */
         private _previousRatio;
         private _previousRatio;
+        private _enableBlending;
+        private _correctLoopMode;
         /**
         /**
          * Gets the current frame of the runtime animation
          * Gets the current frame of the runtime animation
          */
          */
@@ -23647,6 +23627,10 @@ declare module BABYLON {
          */
          */
         alwaysSelectAsActiveMesh: boolean;
         alwaysSelectAsActiveMesh: boolean;
         /**
         /**
+         * Gets or sets a boolean indicating that the bounding info does not need to be kept in sync (for performance reason)
+         */
+        doNotSyncBoundingInfo: boolean;
+        /**
          * Gets or sets the current action manager
          * Gets or sets the current action manager
          * @see http://doc.babylonjs.com/how_to/how_to_use_actions
          * @see http://doc.babylonjs.com/how_to/how_to_use_actions
          */
          */
@@ -26800,12 +26784,6 @@ declare module BABYLON {
         /** @hidden */
badOS: boolean;
         /** @hidden */
badOS: boolean;
         /** @hidden */
badDesktopOS: boolean;
         /** @hidden */
badDesktopOS: boolean;
         /**
         /**
-         * Gets or sets a value indicating if we want to disable texture binding optimization.
-         * This could be required on some buggy drivers which wants to have textures bound in a progressive order.
-         * By default Babylon.js will try to let textures bound where they are and only update the samplers to point where the texture is
-         */
-        disableTextureBindingOptimization: boolean;
-        /**
          * Gets the audio engine
          * Gets the audio engine
          * @see http://doc.babylonjs.com/how_to/playing_sounds_and_music
          * @see http://doc.babylonjs.com/how_to/playing_sounds_and_music
          * @ignorenaming
          * @ignorenaming
@@ -26853,7 +26831,6 @@ declare module BABYLON {
         private _colorWrite;
         private _colorWrite;
         private _loadingScreen;
         private _loadingScreen;
         /** @hidden */
drawCalls: PerfCounter;
         /** @hidden */
drawCalls: PerfCounter;
-        /** @hidden */
textureCollisions: PerfCounter;
         private _glVersion;
         private _glVersion;
         private _glRenderer;
         private _glRenderer;
         private _glVendor;
         private _glVendor;
@@ -26936,8 +26913,6 @@ declare module BABYLON {
         private _currentInstanceLocations;
         private _currentInstanceLocations;
         private _currentInstanceBuffers;
         private _currentInstanceBuffers;
         private _textureUnits;
         private _textureUnits;
-        private _firstBoundInternalTextureTracker;
-        private _lastBoundInternalTextureTracker;
         private _workingCanvas;
         private _workingCanvas;
         private _workingContext;
         private _workingContext;
         private _rescalePostProcess;
         private _rescalePostProcess;
@@ -28181,10 +28156,6 @@ declare module BABYLON {
          * @param effect defines the effect to bind
          * @param effect defines the effect to bind
          */
          */
         bindSamplers(effect: Effect): void;
         bindSamplers(effect: Effect): void;
-        private _moveBoundTextureOnTop;
-        private _getCorrectTextureChannel;
-        private _linkTrackers;
-        private _removeDesignatedSlot;
         private _activateCurrentTexture;
         private _activateCurrentTexture;
         /** @hidden */
bindTextureDirectly(target: number, texture: Nullable<InternalTexture>, forTextureDataUpdate?: boolean, force?: boolean): boolean;
         /** @hidden */
bindTextureDirectly(target: number, texture: Nullable<InternalTexture>, forTextureDataUpdate?: boolean, force?: boolean): boolean;
         /** @hidden */
bindTexture(channel: number, texture: Nullable<InternalTexture>): void;
         /** @hidden */
bindTexture(channel: number, texture: Nullable<InternalTexture>): void;
@@ -30582,6 +30553,12 @@ declare module BABYLON {
         */
         */
         static DecodeBase64(uri: string): ArrayBuffer;
         static DecodeBase64(uri: string): ArrayBuffer;
         /**
         /**
+         * Gets the absolute url.
+         * @param url the input url
+         * @return the absolute url
+         */
+        static GetAbsoluteUrl(url: string): string;
+        /**
          * No log
          * No log
          */
          */
         static readonly NoneLogLevel: number;
         static readonly NoneLogLevel: number;
@@ -34311,6 +34288,19 @@ declare module BABYLON {
          * Define the current local position of the camera in the scene
          * Define the current local position of the camera in the scene
          */
          */
         position: Vector3;
         position: Vector3;
+        protected _upVector: Vector3;
+        protected _upToYMatrix: Matrix;
+        protected _YToUpMatrix: Matrix;
+        /**
+         * The vector the camera should consider as up. (default is Vector3(0, 1, 0) as returned by Vector3.Up())
+         * Setting this will copy the given vector to the camera's upVector, and set rotation matrices to and from Y up.
+         * DO NOT set the up vector using copyFrom or copyFromFloats, as this bypasses setting the above matrices.
+         */
+        upVector: Vector3;
+        /**
+         * Sets the Y-up to camera up-vector rotation matrix, and the up-vector to Y-up rotation matrix.
+         */
+        setMatUp(): void;
         /**
         /**
          * Current inertia value on the longitudinal axis.
          * Current inertia value on the longitudinal axis.
          * The bigger this number the longer it will take for the camera to stop.
          * The bigger this number the longer it will take for the camera to stop.
@@ -34525,8 +34515,6 @@ declare module BABYLON {
         protected _collisionTriggered: boolean;
         protected _collisionTriggered: boolean;
         protected _targetBoundingCenter: Nullable<Vector3>;
         protected _targetBoundingCenter: Nullable<Vector3>;
         private _computationVector;
         private _computationVector;
-        private _tempAxisVector;
-        private _tempAxisRotationMatrix;
         /**
         /**
          * Instantiates a new ArcRotateCamera in a given scene
          * Instantiates a new ArcRotateCamera in a given scene
          * @param name Defines the name of the camera
          * @param name Defines the name of the camera
@@ -34845,7 +34833,7 @@ declare module BABYLON {
             backUVs?: Vector4;
             backUVs?: Vector4;
             updatable?: boolean;
             updatable?: boolean;
             sourcePlane?: Plane;
             sourcePlane?: Plane;
-        }, scene: Scene): Mesh;
+        }, scene?: Nullable<Scene>): Mesh;
     }
     }
 }
 }
 declare module BABYLON {
 declare module BABYLON {
@@ -38544,7 +38532,7 @@ declare module BABYLON {
                 h: number;
                 h: number;
             };
             };
             updatable?: boolean;
             updatable?: boolean;
-        }, scene: Scene): Mesh;
+        }, scene?: Nullable<Scene>): Mesh;
         /**
         /**
          * Creates a ground mesh from a height map
          * Creates a ground mesh from a height map
          * * The parameter `url` sets the URL of the height map image resource.
          * * The parameter `url` sets the URL of the height map image resource.
@@ -38574,7 +38562,7 @@ declare module BABYLON {
             alphaFilter?: number;
             alphaFilter?: number;
             updatable?: boolean;
             updatable?: boolean;
             onReady?: (mesh: GroundMesh) => void;
             onReady?: (mesh: GroundMesh) => void;
-        }, scene: Scene): GroundMesh;
+        }, scene?: Nullable<Scene>): GroundMesh;
     }
     }
 }
 }
 declare module BABYLON {
 declare module BABYLON {
@@ -40203,6 +40191,7 @@ declare module BABYLON.Debug {
         private _utilityLayer;
         private _utilityLayer;
         private _debugBoxMesh;
         private _debugBoxMesh;
         private _debugSphereMesh;
         private _debugSphereMesh;
+        private _debugCylinderMesh;
         private _debugMaterial;
         private _debugMaterial;
         private _debugMeshMeshes;
         private _debugMeshMeshes;
         /**
         /**
@@ -40227,6 +40216,7 @@ declare module BABYLON.Debug {
         private _getDebugMaterial;
         private _getDebugMaterial;
         private _getDebugBoxMesh;
         private _getDebugBoxMesh;
         private _getDebugSphereMesh;
         private _getDebugSphereMesh;
+        private _getDebugCylinderMesh;
         private _getDebugMeshMesh;
         private _getDebugMeshMesh;
         private _getDebugMesh;
         private _getDebugMesh;
         /** Releases all resources */
         /** Releases all resources */
@@ -41783,7 +41773,7 @@ declare module BABYLON {
             sideOrientation?: number;
             sideOrientation?: number;
             frontUVs?: Vector4;
             frontUVs?: Vector4;
             backUVs?: Vector4;
             backUVs?: Vector4;
-        }, scene: Scene): Mesh;
+        }, scene?: Nullable<Scene>): Mesh;
     }
     }
 }
 }
 declare module BABYLON {
 declare module BABYLON {
@@ -45678,10 +45668,6 @@ declare module BABYLON {
          */
          */
         readonly drawCallsCounter: PerfCounter;
         readonly drawCallsCounter: PerfCounter;
         /**
         /**
-         * Gets the perf counter used for texture collisions
-         */
-        readonly textureCollisionsCounter: PerfCounter;
-        /**
          * Instantiates a new scene instrumentation.
          * Instantiates a new scene instrumentation.
          * This class can be used to get instrumentation data from a Babylon engine
          * This class can be used to get instrumentation data from a Babylon engine
          * @see http://doc.babylonjs.com/how_to/optimizing_your_scene#sceneinstrumentation
          * @see http://doc.babylonjs.com/how_to/optimizing_your_scene#sceneinstrumentation
@@ -47432,7 +47418,7 @@ declare module BABYLON {
             backUVs?: Vector4;
             backUVs?: Vector4;
             instance?: Mesh;
             instance?: Mesh;
             invertUV?: boolean;
             invertUV?: boolean;
-        }, scene: Scene): Mesh;
+        }, scene?: Nullable<Scene>): Mesh;
         private static _ExtrudeShapeGeneric;
         private static _ExtrudeShapeGeneric;
     }
     }
 }
 }
@@ -48533,6 +48519,31 @@ declare module BABYLON {
 }
 }
 declare module BABYLON {
 declare module BABYLON {
     /**
     /**
+     * Helper class to push actions to a pool of workers.
+     */
+    export class WorkerPool implements IDisposable {
+        private _workerInfos;
+        private _pendingActions;
+        /**
+         * Constructor
+         * @param workers Array of workers to use for actions
+         */
+        constructor(workers: Array<Worker>);
+        /**
+         * Terminates all workers and clears any pending actions.
+         */
+        dispose(): void;
+        /**
+         * Pushes an action to the worker pool. If all the workers are active, the action will be
+         * pended until a worker has completed its action.
+         * @param action The action to perform. Call onComplete when the action is complete.
+         */
+        push(action: (worker: Worker, onComplete: () => void) => void): void;
+        private _execute;
+    }
+}
+declare module BABYLON {
+    /**
      * Configuration for Draco compression
      * Configuration for Draco compression
      */
      */
     export interface IDracoCompressionConfiguration {
     export interface IDracoCompressionConfiguration {
@@ -48593,7 +48604,7 @@ declare module BABYLON {
      * @see https://www.babylonjs-playground.com/#N3EK4B#0
      * @see https://www.babylonjs-playground.com/#N3EK4B#0
      */
      */
     export class DracoCompression implements IDisposable {
     export class DracoCompression implements IDisposable {
-        private static _DecoderModulePromise;
+        private _workerPoolPromise;
         /**
         /**
          * The configuration. Defaults to the following urls:
          * The configuration. Defaults to the following urls:
          * - wasmUrl: "https://preview.babylonjs.com/draco_wasm_wrapper_gltf.js"
          * - wasmUrl: "https://preview.babylonjs.com/draco_wasm_wrapper_gltf.js"
@@ -48606,25 +48617,38 @@ declare module BABYLON {
          */
          */
         static readonly DecoderAvailable: boolean;
         static readonly DecoderAvailable: boolean;
         /**
         /**
+         * Default number of workers to create when creating the draco compression object.
+         */
+        static DefaultNumWorkers: number;
+        private static GetDefaultNumWorkers;
+        /**
          * Constructor
          * Constructor
+         * @param numWorkers The number of workers for async operations
          */
          */
-        constructor();
+        constructor(numWorkers?: number);
         /**
         /**
          * Stop all async operations and release resources.
          * Stop all async operations and release resources.
          */
          */
         dispose(): void;
         dispose(): void;
         /**
         /**
-         * Decode Draco compressed mesh data to vertex data.
-         * @param data The ArrayBuffer or ArrayBufferView for the Draco compression data
-         * @param attributes A map of attributes from vertex buffer kinds to Draco unique ids
-         * @returns A promise that resolves with the decoded vertex data
+         * Returns a promise that resolves when ready. Call this manually to ensure draco compression is ready before use.
+         * @returns a promise that resolves when ready
          */
          */
+        whenReadyAsync(): Promise<void>;
+        /**
+          * Decode Draco compressed mesh data to vertex data.
+          * @param data The ArrayBuffer or ArrayBufferView for the Draco compression data
+          * @param attributes A map of attributes from vertex buffer kinds to Draco unique ids
+          * @returns A promise that resolves with the decoded vertex data
+          */
         decodeMeshAsync(data: ArrayBuffer | ArrayBufferView, attributes: {
         decodeMeshAsync(data: ArrayBuffer | ArrayBufferView, attributes: {
             [kind: string]: number;
             [kind: string]: number;
         }): Promise<VertexData>;
         }): Promise<VertexData>;
-        private static _GetDecoderModule;
-        private static _LoadScriptAsync;
-        private static _LoadFileAsync;
+        /**
+         * The worker function that gets converted to a blob url to pass into a worker.
+         */
+        private static _Worker;
+        private _loadDecoderWasmBinaryAsync;
     }
     }
 }
 }
 declare module BABYLON {
 declare module BABYLON {
@@ -48962,7 +48986,7 @@ declare module BABYLON {
             sideOrientation?: number;
             sideOrientation?: number;
             frontUVs?: Vector4;
             frontUVs?: Vector4;
             backUVs?: Vector4;
             backUVs?: Vector4;
-        }, scene: Scene, earcutInjection?: any): Mesh;
+        }, scene?: Nullable<Scene>, earcutInjection?: any): Mesh;
         /**
         /**
          * Creates an extruded polygon mesh, with depth in the Y direction.
          * Creates an extruded polygon mesh, with depth in the Y direction.
          * * You can set different colors and different images to the top, bottom and extruded side by using the parameters `faceColors` (an array of 3 Color3 elements) and `faceUV` (an array of 3 Vector4 elements)
          * * You can set different colors and different images to the top, bottom and extruded side by using the parameters `faceColors` (an array of 3 Color3 elements) and `faceUV` (an array of 3 Vector4 elements)
@@ -48983,7 +49007,7 @@ declare module BABYLON {
             sideOrientation?: number;
             sideOrientation?: number;
             frontUVs?: Vector4;
             frontUVs?: Vector4;
             backUVs?: Vector4;
             backUVs?: Vector4;
-        }, scene: Scene, earcutInjection?: any): Mesh;
+        }, scene?: Nullable<Scene>, earcutInjection?: any): Mesh;
     }
     }
 }
 }
 declare module BABYLON {
 declare module BABYLON {
@@ -49024,7 +49048,7 @@ declare module BABYLON {
             backUVs?: Vector4;
             backUVs?: Vector4;
             cap?: number;
             cap?: number;
             invertUV?: boolean;
             invertUV?: boolean;
-        }, scene: Scene): Mesh;
+        }, scene?: Nullable<Scene>): Mesh;
     }
     }
 }
 }
 declare module BABYLON {
 declare module BABYLON {
@@ -49069,7 +49093,7 @@ declare module BABYLON {
             backUVs?: Vector4;
             backUVs?: Vector4;
             instance?: Mesh;
             instance?: Mesh;
             invertUV?: boolean;
             invertUV?: boolean;
-        }, scene: Scene): Mesh;
+        }, scene?: Nullable<Scene>): Mesh;
     }
     }
 }
 }
 declare module BABYLON {
 declare module BABYLON {
@@ -49103,7 +49127,7 @@ declare module BABYLON {
             frontUVs?: Vector4;
             frontUVs?: Vector4;
             backUVs?: Vector4;
             backUVs?: Vector4;
             updatable?: boolean;
             updatable?: boolean;
-        }, scene: Scene): Mesh;
+        }, scene?: Nullable<Scene>): Mesh;
     }
     }
 }
 }
 declare module BABYLON {
 declare module BABYLON {
@@ -49193,7 +49217,7 @@ declare module BABYLON {
             frontUVs?: Vector4;
             frontUVs?: Vector4;
             backUVs?: Vector4;
             backUVs?: Vector4;
             updatable?: boolean;
             updatable?: boolean;
-        }, scene: any): Mesh;
+        }, scene?: Nullable<Scene>): Mesh;
         /**
         /**
          * Creates a plane polygonal mesh.  By default, this is a disc
          * Creates a plane polygonal mesh.  By default, this is a disc
          * * The parameter `radius` sets the radius size (float) of the polygon (default 0.5)
          * * The parameter `radius` sets the radius size (float) of the polygon (default 0.5)
@@ -49243,7 +49267,7 @@ declare module BABYLON {
             frontUVs?: Vector4;
             frontUVs?: Vector4;
             backUVs?: Vector4;
             backUVs?: Vector4;
             updatable?: boolean;
             updatable?: boolean;
-        }, scene: Scene): Mesh;
+        }, scene?: Nullable<Scene>): Mesh;
         /**
         /**
          * Creates a ribbon mesh. The ribbon is a parametric shape.  It has no predefined shape. Its final shape will depend on the input parameters
          * Creates a ribbon mesh. The ribbon is a parametric shape.  It has no predefined shape. Its final shape will depend on the input parameters
          * * The parameter `pathArray` is a required array of paths, what are each an array of successive Vector3. The pathArray parameter depicts the ribbon geometry
          * * The parameter `pathArray` is a required array of paths, what are each an array of successive Vector3. The pathArray parameter depicts the ribbon geometry
@@ -49324,7 +49348,7 @@ declare module BABYLON {
             sideOrientation?: number;
             sideOrientation?: number;
             frontUVs?: Vector4;
             frontUVs?: Vector4;
             backUVs?: Vector4;
             backUVs?: Vector4;
-        }, scene: any): Mesh;
+        }, scene?: Nullable<Scene>): Mesh;
         /**
         /**
          * Creates a torus mesh
          * Creates a torus mesh
          * * The parameter `diameter` sets the diameter size (float) of the torus (default 1)
          * * The parameter `diameter` sets the diameter size (float) of the torus (default 1)
@@ -49347,7 +49371,7 @@ declare module BABYLON {
             sideOrientation?: number;
             sideOrientation?: number;
             frontUVs?: Vector4;
             frontUVs?: Vector4;
             backUVs?: Vector4;
             backUVs?: Vector4;
-        }, scene: any): Mesh;
+        }, scene?: Nullable<Scene>): Mesh;
         /**
         /**
          * Creates a torus knot mesh
          * Creates a torus knot mesh
          * * The parameter `radius` sets the global radius size (float) of the torus knot (default 2)
          * * The parameter `radius` sets the global radius size (float) of the torus knot (default 2)
@@ -49374,7 +49398,7 @@ declare module BABYLON {
             sideOrientation?: number;
             sideOrientation?: number;
             frontUVs?: Vector4;
             frontUVs?: Vector4;
             backUVs?: Vector4;
             backUVs?: Vector4;
-        }, scene: any): Mesh;
+        }, scene?: Nullable<Scene>): Mesh;
         /**
         /**
          * Creates a line system mesh. A line system is a pool of many lines gathered in a single mesh
          * Creates a line system mesh. A line system is a pool of many lines gathered in a single mesh
          * * A line system mesh is considered as a parametric shape since it has no predefined original shape. Its shape is determined by the passed array of lines as an input parameter
          * * A line system mesh is considered as a parametric shape since it has no predefined original shape. Its shape is determined by the passed array of lines as an input parameter
@@ -49520,7 +49544,7 @@ declare module BABYLON {
             backUVs?: Vector4;
             backUVs?: Vector4;
             instance?: Mesh;
             instance?: Mesh;
             invertUV?: boolean;
             invertUV?: boolean;
-        }, scene: Scene): Mesh;
+        }, scene?: Nullable<Scene>): Mesh;
         /**
         /**
          * Creates lathe mesh.
          * Creates lathe mesh.
          * The lathe is a shape with a symetry axis : a 2D model shape is rotated around this axis to design the lathe
          * The lathe is a shape with a symetry axis : a 2D model shape is rotated around this axis to design the lathe
@@ -49554,7 +49578,7 @@ declare module BABYLON {
             backUVs?: Vector4;
             backUVs?: Vector4;
             cap?: number;
             cap?: number;
             invertUV?: boolean;
             invertUV?: boolean;
-        }, scene: Scene): Mesh;
+        }, scene?: Nullable<Scene>): Mesh;
         /**
         /**
          * Creates a plane mesh
          * Creates a plane mesh
          * * The parameter `size` sets the size (float) of both sides of the plane at once (default 1)
          * * The parameter `size` sets the size (float) of both sides of the plane at once (default 1)
@@ -49578,7 +49602,7 @@ declare module BABYLON {
             backUVs?: Vector4;
             backUVs?: Vector4;
             updatable?: boolean;
             updatable?: boolean;
             sourcePlane?: Plane;
             sourcePlane?: Plane;
-        }, scene: Scene): Mesh;
+        }, scene?: Nullable<Scene>): Mesh;
         /**
         /**
          * Creates a ground mesh
          * Creates a ground mesh
          * * The parameters `width` and `height` (floats, default 1) set the width and height sizes of the ground
          * * The parameters `width` and `height` (floats, default 1) set the width and height sizes of the ground
@@ -49597,7 +49621,7 @@ declare module BABYLON {
             subdivisionsX?: number;
             subdivisionsX?: number;
             subdivisionsY?: number;
             subdivisionsY?: number;
             updatable?: boolean;
             updatable?: boolean;
-        }, scene: any): Mesh;
+        }, scene?: Nullable<Scene>): Mesh;
         /**
         /**
          * Creates a tiled ground mesh
          * Creates a tiled ground mesh
          * * The parameters `xmin` and `xmax` (floats, default -1 and 1) set the ground minimum and maximum X coordinates
          * * The parameters `xmin` and `xmax` (floats, default -1 and 1) set the ground minimum and maximum X coordinates
@@ -49625,7 +49649,7 @@ declare module BABYLON {
                 h: number;
                 h: number;
             };
             };
             updatable?: boolean;
             updatable?: boolean;
-        }, scene: Scene): Mesh;
+        }, scene?: Nullable<Scene>): Mesh;
         /**
         /**
          * Creates a ground mesh from a height map
          * Creates a ground mesh from a height map
          * * The parameter `url` sets the URL of the height map image resource.
          * * The parameter `url` sets the URL of the height map image resource.
@@ -49655,7 +49679,7 @@ declare module BABYLON {
             alphaFilter?: number;
             alphaFilter?: number;
             updatable?: boolean;
             updatable?: boolean;
             onReady?: (mesh: GroundMesh) => void;
             onReady?: (mesh: GroundMesh) => void;
-        }, scene: Scene): GroundMesh;
+        }, scene?: Nullable<Scene>): GroundMesh;
         /**
         /**
          * Creates a polygon mesh
          * Creates a polygon mesh
          * The polygon's shape will depend on the input parameters and is constructed parallel to a ground mesh
          * The polygon's shape will depend on the input parameters and is constructed parallel to a ground mesh
@@ -49680,7 +49704,7 @@ declare module BABYLON {
             sideOrientation?: number;
             sideOrientation?: number;
             frontUVs?: Vector4;
             frontUVs?: Vector4;
             backUVs?: Vector4;
             backUVs?: Vector4;
-        }, scene: Scene, earcutInjection?: any): Mesh;
+        }, scene?: Nullable<Scene>, earcutInjection?: any): Mesh;
         /**
         /**
          * Creates an extruded polygon mesh, with depth in the Y direction.
          * Creates an extruded polygon mesh, with depth in the Y direction.
          * * You can set different colors and different images to the top, bottom and extruded side by using the parameters `faceColors` (an array of 3 Color3 elements) and `faceUV` (an array of 3 Vector4 elements)
          * * You can set different colors and different images to the top, bottom and extruded side by using the parameters `faceColors` (an array of 3 Color3 elements) and `faceUV` (an array of 3 Vector4 elements)
@@ -49701,7 +49725,7 @@ declare module BABYLON {
             sideOrientation?: number;
             sideOrientation?: number;
             frontUVs?: Vector4;
             frontUVs?: Vector4;
             backUVs?: Vector4;
             backUVs?: Vector4;
-        }, scene: Scene, earcutInjection?: any): Mesh;
+        }, scene?: Nullable<Scene>, earcutInjection?: any): Mesh;
         /**
         /**
          * Creates a tube mesh.
          * Creates a tube mesh.
          * The tube is a parametric shape. It has no predefined shape. Its final shape will depend on the input parameters
          * The tube is a parametric shape. It has no predefined shape. Its final shape will depend on the input parameters
@@ -49739,7 +49763,7 @@ declare module BABYLON {
             backUVs?: Vector4;
             backUVs?: Vector4;
             instance?: Mesh;
             instance?: Mesh;
             invertUV?: boolean;
             invertUV?: boolean;
-        }, scene: Scene): Mesh;
+        }, scene?: Nullable<Scene>): Mesh;
         /**
         /**
          * Creates a polyhedron mesh
          * Creates a polyhedron mesh
          * * The parameter `type` (positive integer, max 14, default 0) sets the polyhedron type to build among the 15 embbeded types. Please refer to the type sheet in the tutorial to choose the wanted type
          * * The parameter `type` (positive integer, max 14, default 0) sets the polyhedron type to build among the 15 embbeded types. Please refer to the type sheet in the tutorial to choose the wanted type
@@ -49773,7 +49797,7 @@ declare module BABYLON {
             sideOrientation?: number;
             sideOrientation?: number;
             frontUVs?: Vector4;
             frontUVs?: Vector4;
             backUVs?: Vector4;
             backUVs?: Vector4;
-        }, scene: Scene): Mesh;
+        }, scene?: Nullable<Scene>): Mesh;
         /**
         /**
          * Creates a decal mesh.
          * Creates a decal mesh.
          * A decal is a mesh usually applied as a model onto the surface of another mesh. So don't forget the parameter `sourceMesh` depicting the decal
          * A decal is a mesh usually applied as a model onto the surface of another mesh. So don't forget the parameter `sourceMesh` depicting the decal
@@ -55216,31 +55240,6 @@ declare module BABYLON {
 }
 }
 declare module BABYLON {
 declare module BABYLON {
     /**
     /**
-     * Helper class to push actions to a pool of workers.
-     */
-    export class WorkerPool implements IDisposable {
-        private _workerInfos;
-        private _pendingActions;
-        /**
-         * Constructor
-         * @param workers Array of workers to use for actions
-         */
-        constructor(workers: Array<Worker>);
-        /**
-         * Terminates all workers and clears any pending actions.
-         */
-        dispose(): void;
-        /**
-         * Pushes an action to the worker pool. If all the workers are active, the action will be
-         * pended until a worker has completed its action.
-         * @param action The action to perform. Call onComplete when the action is complete.
-         */
-        push(action: (worker: Worker, onComplete: () => void) => void): void;
-        private _execute;
-    }
-}
-declare module BABYLON {
-    /**
      * Class containing a set of static utilities functions for screenshots
      * Class containing a set of static utilities functions for screenshots
      */
      */
     export class ScreenshotTools {
     export class ScreenshotTools {
@@ -60819,10 +60818,12 @@ declare module BABYLON.GLTF2.Loader.Extensions {
     export class KHR_draco_mesh_compression implements IGLTFLoaderExtension {
     export class KHR_draco_mesh_compression implements IGLTFLoaderExtension {
         /** The name of this extension. */
         /** The name of this extension. */
         readonly name: string;
         readonly name: string;
+        /** The draco compression used to decode vertex data. */
+        dracoCompression?: DracoCompression;
         /** Defines whether this extension is enabled. */
         /** Defines whether this extension is enabled. */
         enabled: boolean;
         enabled: boolean;
         private _loader;
         private _loader;
-        private _dracoCompression?;
+        private _dracoCompressionOwned;
         /** @hidden */
         /** @hidden */
         constructor(loader: GLTFLoader);
         constructor(loader: GLTFLoader);
         /** @hidden */
         /** @hidden */

+ 265 - 0
Tools/Gulp/helpers/gulp-karmaJunitPlugin.js

@@ -0,0 +1,265 @@
+var os = require('os')
+var path = require('path')
+var fs = require('fs')
+var builder = require('xmlbuilder')
+
+/* XML schemas supported by the reporter: 'xmlVersion' in karma.conf.js,
+   'XMLconfigValue' as variable here.
+   0 = "old", original XML format. For example, SonarQube versions prior to 6.2
+   1 = first amended version. Compatible with SonarQube starting from 6.2
+*/
+
+// concatenate test suite(s) and test description by default
+function defaultNameFormatter (browser, result) {
+  return result.suite.join(' ') + ' ' + result.description
+}
+
+var JUnitReporter = function (baseReporterDecorator, config, logger, helper, formatError) {
+  var log = logger.create('reporter.junit')
+  var reporterConfig = config.junitReporter || {}
+  // All reporterConfig.something are for reading flags from the Karma config file
+  var pkgName = reporterConfig.suite || ''
+  var outputDir = reporterConfig.outputDir
+  var outputFile = reporterConfig.outputFile
+  var useBrowserName = reporterConfig.useBrowserName
+  var nameFormatter = reporterConfig.nameFormatter || defaultNameFormatter
+  var classNameFormatter = reporterConfig.classNameFormatter
+  var properties = reporterConfig.properties
+  // The below two variables have to do with adding support for new SonarQube XML format
+  var XMLconfigValue = reporterConfig.xmlVersion
+  var NEWXML
+  // We need one global variable for the tag <file> to be visible to functions
+  var exposee
+  var suites = []
+  var pendingFileWritings = 0
+  var fileWritingFinished = function () {}
+  var allMessages = []
+
+  // The NEWXML is just sugar, a flag. Remove it when there are more than 2
+  // supported XML output formats.
+  if (!XMLconfigValue) {
+    XMLconfigValue = 0
+    NEWXML = false
+  } else {
+    // Slack behavior: "If defined, assume to be 1" since we have only two formats now
+    XMLconfigValue = 1
+    NEWXML = true
+  }
+
+  if (outputDir == null) {
+    outputDir = '.'
+  }
+
+  outputDir = helper.normalizeWinPath(path.resolve(config.basePath, outputDir)) + path.sep
+
+  if (typeof useBrowserName === 'undefined') {
+    useBrowserName = true
+  }
+
+  baseReporterDecorator(this)
+
+  this.adapters = [
+    function (msg) {
+      allMessages.push(msg)
+    }
+  ]
+
+  // Creates the outermost XML element: <unitTest>
+  var initializeXmlForBrowser = function (browser) {
+    var timestamp = (new Date()).toISOString().substr(0, 19)
+    var suite
+    if (NEWXML) {
+      suite = suites[browser.id] = builder.create('unitTest')
+      suite.att('version', '1')
+      exposee = suite.ele('file', {'path': 'fixedString'})
+    } else {
+      suite = suites[browser.id] = builder.create('testsuite')
+      suite.att('name', pkgName)
+      .att('package', pkgName)
+      .att('timestamp', timestamp)
+      .att('id', 'MYTESTMYTEST')
+      .att('hostname', os.hostname())
+      var propertiesElement = suite.ele('properties')
+      propertiesElement.ele('property', {name: 'browser.fullName', value: browser.fullName})
+
+      // add additional properties passed in through the config
+      for (var property in properties) {
+        if (properties.hasOwnProperty(property)) {
+          propertiesElement.ele('property', {name: property, value: properties[property]})
+        }
+      }
+    }
+  }
+
+  // This function takes care of writing the XML into a file
+  var writeXmlForBrowser = function (browser) {
+    // Define the file name using rules
+    var safeBrowserName = browser.name.replace(/ /g, '_')
+    var newOutputFile
+    if (outputFile && path.isAbsolute(outputFile)) {
+      newOutputFile = outputFile
+    } else if (outputFile != null) {
+      var dir = useBrowserName ? path.join(outputDir, safeBrowserName)
+                               : outputDir
+      newOutputFile = path.join(dir, outputFile)
+    } else if (useBrowserName) {
+      newOutputFile = path.join(outputDir, 'TESTS-' + safeBrowserName + '.xml')
+    } else {
+      newOutputFile = path.join(outputDir, 'TESTS.xml')
+    }
+
+    var xmlToOutput = suites[browser.id]
+
+    if (!xmlToOutput) {
+      return // don't die if browser didn't start
+    }
+
+    pendingFileWritings++
+    helper.mkdirIfNotExists(path.dirname(newOutputFile), function () {
+      fs.writeFile(newOutputFile, xmlToOutput.end({pretty: true}), function (err) {
+        if (err) {
+          log.warn('Cannot write JUnit xml\n\t' + err.message)
+        } else {
+          log.debug('JUnit results written to "%s".', newOutputFile)
+        }
+
+        if (!--pendingFileWritings) {
+          fileWritingFinished()
+        }
+      })
+    })
+  }
+
+  // Return a 'safe' name for test. This will be the name="..." content in XML.
+  var getClassName = function (browser, result) {
+    var name = ''
+    // configuration tells whether to use browser name at all
+    if (useBrowserName) {
+      name += browser.name
+        .replace(/ /g, '_')
+        .replace(/\./g, '_') + '.'
+    }
+    if (pkgName) {
+      name += '.'
+    }
+    if (result.suite && result.suite.length > 0) {
+      name += result.suite.join(' ')
+    }
+    return name
+  }
+
+  // "run_start" - a test run is beginning for all browsers
+  this.onRunStart = function (browsers) {
+    // TODO(vojta): remove once we don't care about Karma 0.10
+    browsers.forEach(initializeXmlForBrowser)
+  }
+
+  // "browser_start" - a test run is beginning in _this_ browser
+  this.onBrowserStart = function (browser) {
+    initializeXmlForBrowser(browser)
+  }
+
+  // "browser_complete" - a test run has completed in _this_ browser
+  // writes the XML to file and releases memory
+  this.onBrowserComplete = function (browser) {
+    var suite = suites[browser.id]
+    var result = browser.lastResult
+    if (!suite || !result) {
+      return // don't die if browser didn't start
+    }
+
+    if (!NEWXML) {
+      suite.att('tests', result.total ? result.total : 0)
+      suite.att('errors', result.disconnected || result.error ? 1 : 0)
+      suite.att('failures', result.failed ? result.failed : 0)
+      suite.att('time', (result.netTime || 0) / 1000)
+      suite.ele('system-out').dat(allMessages.join() + '\n')
+      suite.ele('system-err')
+    }
+
+    writeXmlForBrowser(browser)
+
+    // Release memory held by the test suite.
+    suites[browser.id] = null
+  }
+
+  // "run_complete" - a test run has completed on all browsers
+  this.onRunComplete = function () {
+    allMessages.length = 0
+  }
+
+  // --------------------------------------------
+  // | Producing XML for individual testCase    |
+  // --------------------------------------------
+  this.specSuccess = this.specSkipped = this.specFailure = function (browser, result) {
+    var testsuite = suites[browser.id]
+    var validMilliTime
+    var spec
+
+    if (!testsuite) {
+      return
+    }
+
+    // New in the XSD schema: only name and duration. classname is obsoleted
+    if (NEWXML) {
+      if (!result.time || result.time === 0) {
+        validMilliTime = 1
+      } else {
+        validMilliTime = result.time
+      }
+    }
+
+    // create the tag for a new test case
+    /*
+    if (NEWXML) {
+      spec = testsuite.ele('testCase', {
+      name: nameFormatter(browser, result),
+      duration: validMilliTime })
+    }
+    */
+
+    if (NEWXML) {
+      spec = exposee.ele('testCase', {
+        name: nameFormatter(browser, result),
+        duration: validMilliTime })
+    } else {
+      // old XML format. Code as-was
+      spec = testsuite.ele('testcase', {
+        name: nameFormatter(browser, result),
+        time: ((result.time || 0) / 1000),
+        classname: (typeof classNameFormatter === 'function' ? classNameFormatter : getClassName)(browser, result)
+      })
+    }
+
+    if (result.skipped) {
+      spec.ele('skipped')
+    }
+
+    if (!result.success) {
+      result.log.forEach(function (err) {
+        if (!NEWXML) {
+          spec.ele('failure', {type: ''}, formatError(err))
+        } else {
+        // In new XML format, an obligatory 'message' attribute in failure
+          spec.ele('failure', {message: formatError(err)})
+        }
+      })
+    }
+  }
+
+  // wait for writing all the xml files, before exiting
+  this.onExit = function (done) {
+    if (pendingFileWritings) {
+      fileWritingFinished = done
+    } else {
+      done()
+    }
+  }
+}
+
+JUnitReporter.$inject = ['baseReporterDecorator', 'config', 'logger', 'helper', 'formatError']
+
+// PUBLISH DI MODULE
+module.exports = {
+  'reporter:junit': ['type', JUnitReporter]
+}

+ 36 - 0
Tools/Gulp/tasks/gulpTasks-tests.js

@@ -42,6 +42,32 @@ gulp.task("tests-validation-virtualscreen", function(done) {
 });
 });
 
 
 /**
 /**
+ * Launches the KARMA validation tests in ff or virtual screen ff on travis for a quick analysis during the build.
+ */
+gulp.task("tests-validation-virtualscreenWebGL1", function(done) {
+    var kamaServerOptions = {
+        configFile: rootDir + "tests/validation/karma.conf.js",
+        singleRun: true,
+        browsers: ['Firefox'],
+        client: {
+            args: ["--disableWebGL2Support"]
+        },
+        junitReporter: {
+            outputDir: '.temp/testResults', // results will be saved as $outputDir/$browserName.xml
+            outputFile: 'ValidationTests1.xml', // if included, results will be saved as $outputDir/$browserName/$outputFile
+            suite: 'Validation Tests WebGL1', // suite will become the package name attribute in xml testsuite element
+            useBrowserName: false, // add browser name to report and classes names
+            nameFormatter: undefined, // function (browser, result) to customize the name attribute in xml testcase element
+            classNameFormatter: undefined, // function (browser, result) to customize the classname attribute in xml testcase element
+            properties: {} // key value pair of properties to add to the <properties> section of the report
+        }
+    };
+
+    var server = new karmaServer(kamaServerOptions, done);
+    server.start();
+});
+
+/**
  * Launches the KARMA validation tests in browser stack for remote and cross devices validation tests.
  * Launches the KARMA validation tests in browser stack for remote and cross devices validation tests.
  */
  */
 gulp.task("tests-validation-browserstack", function(done) {
 gulp.task("tests-validation-browserstack", function(done) {
@@ -309,6 +335,16 @@ gulp.task("tests-modules", function() {
                 return new Promise(function(resolve, reject) {
                 return new Promise(function(resolve, reject) {
                     var kamaServerOptions = {
                     var kamaServerOptions = {
                         configFile: rootDir + "tests/modules/karma.conf.js",
                         configFile: rootDir + "tests/modules/karma.conf.js",
+
+                        junitReporter: {
+                            outputDir: '.temp/testResults', // results will be saved as $outputDir/$browserName.xml
+                            outputFile:  test.reportName + '.xml', // if included, results will be saved as $outputDir/$browserName/$outputFile
+                            suite: test.displayName, // suite will become the package name attribute in xml testsuite element
+                            useBrowserName: false, // add browser name to report and classes names
+                            nameFormatter: undefined, // function (browser, result) to customize the name attribute in xml testcase element
+                            classNameFormatter: undefined, // function (browser, result) to customize the classname attribute in xml testcase element
+                            properties: {} // key value pair of properties to add to the <properties> section of the report
+                        },
                     };
                     };
 
 
                     var server = new karmaServer(kamaServerOptions, (err) => {
                     var server = new karmaServer(kamaServerOptions, (err) => {

+ 10 - 0
Viewer/tests/karma.conf.js

@@ -36,6 +36,16 @@ module.exports = function (config) {
 
 
         reporters: ['progress', 'junit'],
         reporters: ['progress', 'junit'],
 
 
+        plugins: [
+            'karma-mocha',
+            'karma-chai',
+            'karma-sinon',
+            'karma-chrome-launcher',
+            'karma-firefox-launcher',
+
+            require('../../Tools/Gulp/helpers/gulp-karmaJunitPlugin')
+        ],
+
         junitReporter: {
         junitReporter: {
             outputDir: '../.temp/testResults', // results will be saved as $outputDir/$browserName.xml
             outputDir: '../.temp/testResults', // results will be saved as $outputDir/$browserName.xml
             outputFile: 'ViewerUnitTests.xml', // if included, results will be saved as $outputDir/$browserName/$outputFile
             outputFile: 'ViewerUnitTests.xml', // if included, results will be saved as $outputDir/$browserName/$outputFile

+ 10 - 0
Viewer/tests/validation/karma.conf.js

@@ -36,6 +36,16 @@ module.exports = function (config) {
 
 
         reporters: ['progress', 'junit'],
         reporters: ['progress', 'junit'],
 
 
+        plugins: [
+            'karma-mocha',
+            'karma-chai',
+            'karma-sinon',
+            'karma-chrome-launcher',
+            'karma-firefox-launcher',
+
+            require('../../../Tools/Gulp/helpers/gulp-karmaJunitPlugin')
+        ],
+
         junitReporter: {
         junitReporter: {
             outputDir: '../.temp/testResults', // results will be saved as $outputDir/$browserName.xml
             outputDir: '../.temp/testResults', // results will be saved as $outputDir/$browserName.xml
             outputFile: 'ViewerValidationTests.xml', // if included, results will be saved as $outputDir/$browserName/$outputFile
             outputFile: 'ViewerValidationTests.xml', // if included, results will be saved as $outputDir/$browserName/$outputFile

+ 49 - 17
azure-pipelines.yml

@@ -57,7 +57,7 @@ jobs:
     displayName: 'Full Lint'
     displayName: 'Full Lint'
 
 
 - job: Build
 - job: Build
-  displayName: '4. Build'
+  displayName: '4. Build and Unit Tests'
   pool:
   pool:
     vmImage: 'Ubuntu-16.04'
     vmImage: 'Ubuntu-16.04'
     demands: npm
     demands: npm
@@ -70,9 +70,17 @@ jobs:
   - script: 'gulp typescript-all'
   - script: 'gulp typescript-all'
     workingDirectory: Tools/Gulp
     workingDirectory: Tools/Gulp
     displayName: 'Typescript all'
     displayName: 'Typescript all'
+  - script: 'gulp tests-babylon-unit'
+    workingDirectory: Tools/Gulp
+    displayName: 'Unit Tests'
+  - task: PublishTestResults@2
+    condition: succeededOrFailed()
+    inputs:
+      testRunner: JUnit
+      testResultsFiles: '.temp/testResults/UnitTests.xml'
 
 
-- job: Tests
-  displayName: '5. Core Tests'
+- job: TestsWebGL1
+  displayName: '5. Validation Tests WebGL1'
   pool:
   pool:
     vmImage: 'Ubuntu-16.04'
     vmImage: 'Ubuntu-16.04'
     demands: npm
     demands: npm
@@ -85,14 +93,33 @@ jobs:
   - script: 'gulp typescript-all'
   - script: 'gulp typescript-all'
     workingDirectory: Tools/Gulp
     workingDirectory: Tools/Gulp
     displayName: 'Typescript all'
     displayName: 'Typescript all'
-  - script: 'gulp tests-babylon-unit'
+  - script: |
+      export DISPLAY=:99
+      Xvfb :99 -screen 0 1024x768x24 > /dev/null 2>&1 &
+      sleep 3 # give xvfb some time to start
+      gulp tests-validation-virtualscreenWebGL1
     workingDirectory: Tools/Gulp
     workingDirectory: Tools/Gulp
-    displayName: 'Unit Tests'
+    displayName: 'Visual Tests'
   - task: PublishTestResults@2
   - task: PublishTestResults@2
     condition: succeededOrFailed()
     condition: succeededOrFailed()
     inputs:
     inputs:
       testRunner: JUnit
       testRunner: JUnit
-      testResultsFiles: '.temp/testResults/UnitTests.xml'
+      testResultsFiles: '.temp/testResults/ValidationTests1.xml'
+
+- job: TestsWebGL2
+  displayName: '6. Validation Tests WebGL2'
+  pool:
+    vmImage: 'Ubuntu-16.04'
+    demands: npm
+  steps:
+  - task: Npm@1
+    displayName: 'npm install'
+    inputs:
+      workingDir: Tools/Gulp
+      verbose: false
+  - script: 'gulp typescript-all'
+    workingDirectory: Tools/Gulp
+    displayName: 'Typescript all'
   - script: |
   - script: |
       export DISPLAY=:99
       export DISPLAY=:99
       Xvfb :99 -screen 0 1024x768x24 > /dev/null 2>&1 &
       Xvfb :99 -screen 0 1024x768x24 > /dev/null 2>&1 &
@@ -104,17 +131,17 @@ jobs:
     condition: succeededOrFailed()
     condition: succeededOrFailed()
     inputs:
     inputs:
       testRunner: JUnit
       testRunner: JUnit
-      testResultsFiles: '.temp/testResults/ValidationTests.xml'
-  - script: 'gulp tests-validation-browserstack'
-    workingDirectory: Tools/Gulp
-    displayName: 'Browser Stack Tests'
-    env:
-      TRAVIS_BUILD_NUMBER: $(Build.BuildNumber)
-      BROWSER_STACK_USERNAME: $(babylon.browserStack.userName)
-      BROWSER_STACK_ACCESS_KEY: $(babylon.browserStack.userToken)
+      testResultsFiles: '.temp/testResults/ValidationTests2.xml'
+  # - script: 'gulp tests-validation-browserstack'
+  #   workingDirectory: Tools/Gulp
+  #   displayName: 'Browser Stack Tests'
+  #   env:
+  #     TRAVIS_BUILD_NUMBER: $(Build.BuildNumber)
+  #     BROWSER_STACK_USERNAME: $(babylon.browserStack.userName)
+  #     BROWSER_STACK_ACCESS_KEY: $(babylon.browserStack.userToken)
 
 
 - job: ModuleTests
 - job: ModuleTests
-  displayName: '6. Module Tests'
+  displayName: '7. Module Tests'
   pool:
   pool:
     vmImage: 'Ubuntu-16.04'
     vmImage: 'Ubuntu-16.04'
     demands: npm
     demands: npm
@@ -140,10 +167,15 @@ jobs:
     condition: succeededOrFailed()
     condition: succeededOrFailed()
     inputs:
     inputs:
       testRunner: JUnit
       testRunner: JUnit
-      testResultsFiles: '.temp/testResults/ModuleTests.xml'
+      testResultsFiles: '.temp/testResults/ModuleTestsVanilla.xml'
+  - task: PublishTestResults@2
+    condition: succeededOrFailed()
+    inputs:
+      testRunner: JUnit
+      testResultsFiles: '.temp/testResults/ModuleTestsWebpack.xml'
 
 
 - job: ViewerTests
 - job: ViewerTests
-  displayName: '7. Viewer Tests'
+  displayName: '8. Viewer Tests'
   pool:
   pool:
     vmImage: 'Ubuntu-16.04'
     vmImage: 'Ubuntu-16.04'
     demands: npm
     demands: npm

+ 119 - 122
dist/preview release/babylon.d.ts

@@ -267,7 +267,7 @@ declare module BABYLON {
      * Constant used to define the minimal number value in Babylon.js
      * Constant used to define the minimal number value in Babylon.js
      * @ignorenaming
      * @ignorenaming
      */
      */
-    export const Epsilon = 0.001;
+    let Epsilon: number;
     /**
     /**
      * Class used to hold a RBG color
      * Class used to hold a RBG color
      */
      */
@@ -2939,6 +2939,14 @@ declare module BABYLON {
          */
          */
         setTranslationFromFloats(x: number, y: number, z: number): Matrix;
         setTranslationFromFloats(x: number, y: number, z: number): Matrix;
         /**
         /**
+         * Adds the translation vector (using 3 floats) in the current matrix
+         * @param x defines the 1st component of the translation
+         * @param y defines the 2nd component of the translation
+         * @param z defines the 3rd component of the translation
+         * @returns the current updated matrix
+         */
+        addTranslationFromFloats(x: number, y: number, z: number): Matrix;
+        /**
          * Inserts the translation vector in the current matrix
          * Inserts the translation vector in the current matrix
          * @param vector3 defines the translation to insert
          * @param vector3 defines the translation to insert
          * @returns the current updated matrix
          * @returns the current updated matrix
@@ -3257,6 +3265,14 @@ declare module BABYLON {
          */
          */
         static RotationAxisToRef(axis: DeepImmutable<Vector3>, angle: number, result: Matrix): void;
         static RotationAxisToRef(axis: DeepImmutable<Vector3>, angle: number, result: Matrix): void;
         /**
         /**
+         * Takes normalised vectors and returns a rotation matrix to align "from" with "to".
+         * Taken from http://www.iquilezles.org/www/articles/noacos/noacos.htm
+         * @param from defines the vector to align
+         * @param to defines the vector to align to
+         * @param result defines the target matrix
+         */
+        static RotationAlignToRef(from: DeepImmutable<Vector3>, to: DeepImmutable<Vector3>, result: Matrix): void;
+        /**
          * Creates a rotation matrix
          * Creates a rotation matrix
          * @param yaw defines the yaw angle in radians (Y axis)
          * @param yaw defines the yaw angle in radians (Y axis)
          * @param pitch defines the pitch angle in radians (X axis)
          * @param pitch defines the pitch angle in radians (X axis)
@@ -6158,38 +6174,10 @@ declare module BABYLON {
 }
 }
 declare module BABYLON {
 declare module BABYLON {
     /**
     /**
-     * Internal interface used to track InternalTexture already bound to the GL context
-     */
-    export interface IInternalTextureTracker {
-        /**
-         * Gets or set the previous tracker in the list
-         */
-        previous: Nullable<IInternalTextureTracker>;
-        /**
-         * Gets or set the next tracker in the list
-         */
-        next: Nullable<IInternalTextureTracker>;
-    }
-    /**
-     * Internal class used by the engine to get list of InternalTexture already bound to the GL context
-     */
-    export class DummyInternalTextureTracker {
-        /**
-         * Gets or set the previous tracker in the list
-         */
-        previous: Nullable<IInternalTextureTracker>;
-        /**
-         * Gets or set the next tracker in the list
-         */
-        next: Nullable<IInternalTextureTracker>;
-    }
-}
-declare module BABYLON {
-    /**
      * Class used to store data associated with WebGL texture data for the engine
      * Class used to store data associated with WebGL texture data for the engine
      * This class should not be used directly
      * This class should not be used directly
      */
      */
-    export class InternalTexture implements IInternalTextureTracker {
+    export class InternalTexture {
         /** hidden */
         /** hidden */
         static _UpdateRGBDAsync: (internalTexture: InternalTexture, data: ArrayBufferView[][], sphericalPolynomial: SphericalPolynomial | null, lodScale: number, lodOffset: number) => Promise<void>;
         static _UpdateRGBDAsync: (internalTexture: InternalTexture, data: ArrayBufferView[][], sphericalPolynomial: SphericalPolynomial | null, lodScale: number, lodOffset: number) => Promise<void>;
         /**
         /**
@@ -6316,20 +6304,10 @@ declare module BABYLON {
          * Gets a boolean indicating if the texture is inverted on Y axis
          * Gets a boolean indicating if the texture is inverted on Y axis
          */
          */
         invertY: boolean;
         invertY: boolean;
-        /**
-         * Gets or set the previous tracker in the list
-         */
-        previous: Nullable<IInternalTextureTracker>;
-        /**
-         * Gets or set the next tracker in the list
-         */
-        next: Nullable<IInternalTextureTracker>;
         /** @hidden */
         /** @hidden */
         _invertVScale: boolean;
         _invertVScale: boolean;
         /** @hidden */
         /** @hidden */
-        _initialSlot: number;
-        /** @hidden */
-        _designatedSlot: number;
+        _associatedChannel: number;
         /** @hidden */
         /** @hidden */
         _dataSource: number;
         _dataSource: number;
         /** @hidden */
         /** @hidden */
@@ -7502,6 +7480,7 @@ declare module BABYLON {
         private _up;
         private _up;
         private _right;
         private _right;
         private _rightInverted;
         private _rightInverted;
+        private _usePivotMatrix;
         private _position;
         private _position;
         private _rotation;
         private _rotation;
         private _rotationQuaternion;
         private _rotationQuaternion;
@@ -7547,8 +7526,6 @@ declare module BABYLON {
         private _pivotMatrix;
         private _pivotMatrix;
         private _pivotMatrixInverse;
         private _pivotMatrixInverse;
         protected _postMultiplyPivotMatrix: boolean;
         protected _postMultiplyPivotMatrix: boolean;
-        private _tempMatrix;
-        private _tempMatrix2;
         protected _isWorldMatrixFrozen: boolean;
         protected _isWorldMatrixFrozen: boolean;
         /** @hidden */
         /** @hidden */
         _indexInSceneTransformNodesArray: number;
         _indexInSceneTransformNodesArray: number;
@@ -18357,6 +18334,8 @@ declare module BABYLON {
          * The previous ratio of the runtime animation
          * The previous ratio of the runtime animation
          */
          */
         private _previousRatio;
         private _previousRatio;
+        private _enableBlending;
+        private _correctLoopMode;
         /**
         /**
          * Gets the current frame of the runtime animation
          * Gets the current frame of the runtime animation
          */
          */
@@ -24026,6 +24005,10 @@ declare module BABYLON {
          */
          */
         alwaysSelectAsActiveMesh: boolean;
         alwaysSelectAsActiveMesh: boolean;
         /**
         /**
+         * Gets or sets a boolean indicating that the bounding info does not need to be kept in sync (for performance reason)
+         */
+        doNotSyncBoundingInfo: boolean;
+        /**
          * Gets or sets the current action manager
          * Gets or sets the current action manager
          * @see http://doc.babylonjs.com/how_to/how_to_use_actions
          * @see http://doc.babylonjs.com/how_to/how_to_use_actions
          */
          */
@@ -27251,12 +27234,6 @@ declare module BABYLON {
         /** @hidden */
         /** @hidden */
         _badDesktopOS: boolean;
         _badDesktopOS: boolean;
         /**
         /**
-         * Gets or sets a value indicating if we want to disable texture binding optimization.
-         * This could be required on some buggy drivers which wants to have textures bound in a progressive order.
-         * By default Babylon.js will try to let textures bound where they are and only update the samplers to point where the texture is
-         */
-        disableTextureBindingOptimization: boolean;
-        /**
          * Gets the audio engine
          * Gets the audio engine
          * @see http://doc.babylonjs.com/how_to/playing_sounds_and_music
          * @see http://doc.babylonjs.com/how_to/playing_sounds_and_music
          * @ignorenaming
          * @ignorenaming
@@ -27305,8 +27282,6 @@ declare module BABYLON {
         private _loadingScreen;
         private _loadingScreen;
         /** @hidden */
         /** @hidden */
         _drawCalls: PerfCounter;
         _drawCalls: PerfCounter;
-        /** @hidden */
-        _textureCollisions: PerfCounter;
         private _glVersion;
         private _glVersion;
         private _glRenderer;
         private _glRenderer;
         private _glVendor;
         private _glVendor;
@@ -27389,8 +27364,6 @@ declare module BABYLON {
         private _currentInstanceLocations;
         private _currentInstanceLocations;
         private _currentInstanceBuffers;
         private _currentInstanceBuffers;
         private _textureUnits;
         private _textureUnits;
-        private _firstBoundInternalTextureTracker;
-        private _lastBoundInternalTextureTracker;
         private _workingCanvas;
         private _workingCanvas;
         private _workingContext;
         private _workingContext;
         private _rescalePostProcess;
         private _rescalePostProcess;
@@ -28652,10 +28625,6 @@ declare module BABYLON {
          * @param effect defines the effect to bind
          * @param effect defines the effect to bind
          */
          */
         bindSamplers(effect: Effect): void;
         bindSamplers(effect: Effect): void;
-        private _moveBoundTextureOnTop;
-        private _getCorrectTextureChannel;
-        private _linkTrackers;
-        private _removeDesignatedSlot;
         private _activateCurrentTexture;
         private _activateCurrentTexture;
         /** @hidden */
         /** @hidden */
         _bindTextureDirectly(target: number, texture: Nullable<InternalTexture>, forTextureDataUpdate?: boolean, force?: boolean): boolean;
         _bindTextureDirectly(target: number, texture: Nullable<InternalTexture>, forTextureDataUpdate?: boolean, force?: boolean): boolean;
@@ -31112,6 +31081,12 @@ declare module BABYLON {
         */
         */
         static DecodeBase64(uri: string): ArrayBuffer;
         static DecodeBase64(uri: string): ArrayBuffer;
         /**
         /**
+         * Gets the absolute url.
+         * @param url the input url
+         * @return the absolute url
+         */
+        static GetAbsoluteUrl(url: string): string;
+        /**
          * No log
          * No log
          */
          */
         static readonly NoneLogLevel: number;
         static readonly NoneLogLevel: number;
@@ -34906,6 +34881,19 @@ declare module BABYLON {
          * Define the current local position of the camera in the scene
          * Define the current local position of the camera in the scene
          */
          */
         position: Vector3;
         position: Vector3;
+        protected _upVector: Vector3;
+        protected _upToYMatrix: Matrix;
+        protected _YToUpMatrix: Matrix;
+        /**
+         * The vector the camera should consider as up. (default is Vector3(0, 1, 0) as returned by Vector3.Up())
+         * Setting this will copy the given vector to the camera's upVector, and set rotation matrices to and from Y up.
+         * DO NOT set the up vector using copyFrom or copyFromFloats, as this bypasses setting the above matrices.
+         */
+        upVector: Vector3;
+        /**
+         * Sets the Y-up to camera up-vector rotation matrix, and the up-vector to Y-up rotation matrix.
+         */
+        setMatUp(): void;
         /**
         /**
          * Current inertia value on the longitudinal axis.
          * Current inertia value on the longitudinal axis.
          * The bigger this number the longer it will take for the camera to stop.
          * The bigger this number the longer it will take for the camera to stop.
@@ -35124,8 +35112,6 @@ declare module BABYLON {
         protected _collisionTriggered: boolean;
         protected _collisionTriggered: boolean;
         protected _targetBoundingCenter: Nullable<Vector3>;
         protected _targetBoundingCenter: Nullable<Vector3>;
         private _computationVector;
         private _computationVector;
-        private _tempAxisVector;
-        private _tempAxisRotationMatrix;
         /**
         /**
          * Instantiates a new ArcRotateCamera in a given scene
          * Instantiates a new ArcRotateCamera in a given scene
          * @param name Defines the name of the camera
          * @param name Defines the name of the camera
@@ -35453,7 +35439,7 @@ declare module BABYLON {
             backUVs?: Vector4;
             backUVs?: Vector4;
             updatable?: boolean;
             updatable?: boolean;
             sourcePlane?: Plane;
             sourcePlane?: Plane;
-        }, scene: Scene): Mesh;
+        }, scene?: Nullable<Scene>): Mesh;
     }
     }
 }
 }
 declare module BABYLON {
 declare module BABYLON {
@@ -39169,7 +39155,7 @@ declare module BABYLON {
                 h: number;
                 h: number;
             };
             };
             updatable?: boolean;
             updatable?: boolean;
-        }, scene: Scene): Mesh;
+        }, scene?: Nullable<Scene>): Mesh;
         /**
         /**
          * Creates a ground mesh from a height map
          * Creates a ground mesh from a height map
          * * The parameter `url` sets the URL of the height map image resource.
          * * The parameter `url` sets the URL of the height map image resource.
@@ -39199,7 +39185,7 @@ declare module BABYLON {
             alphaFilter?: number;
             alphaFilter?: number;
             updatable?: boolean;
             updatable?: boolean;
             onReady?: (mesh: GroundMesh) => void;
             onReady?: (mesh: GroundMesh) => void;
-        }, scene: Scene): GroundMesh;
+        }, scene?: Nullable<Scene>): GroundMesh;
     }
     }
 }
 }
 declare module BABYLON {
 declare module BABYLON {
@@ -40846,6 +40832,7 @@ declare module BABYLON.Debug {
         private _utilityLayer;
         private _utilityLayer;
         private _debugBoxMesh;
         private _debugBoxMesh;
         private _debugSphereMesh;
         private _debugSphereMesh;
+        private _debugCylinderMesh;
         private _debugMaterial;
         private _debugMaterial;
         private _debugMeshMeshes;
         private _debugMeshMeshes;
         /**
         /**
@@ -40870,6 +40857,7 @@ declare module BABYLON.Debug {
         private _getDebugMaterial;
         private _getDebugMaterial;
         private _getDebugBoxMesh;
         private _getDebugBoxMesh;
         private _getDebugSphereMesh;
         private _getDebugSphereMesh;
+        private _getDebugCylinderMesh;
         private _getDebugMeshMesh;
         private _getDebugMeshMesh;
         private _getDebugMesh;
         private _getDebugMesh;
         /** Releases all resources */
         /** Releases all resources */
@@ -42445,7 +42433,7 @@ declare module BABYLON {
             sideOrientation?: number;
             sideOrientation?: number;
             frontUVs?: Vector4;
             frontUVs?: Vector4;
             backUVs?: Vector4;
             backUVs?: Vector4;
-        }, scene: Scene): Mesh;
+        }, scene?: Nullable<Scene>): Mesh;
     }
     }
 }
 }
 declare module BABYLON {
 declare module BABYLON {
@@ -46353,10 +46341,6 @@ declare module BABYLON {
          */
          */
         readonly drawCallsCounter: PerfCounter;
         readonly drawCallsCounter: PerfCounter;
         /**
         /**
-         * Gets the perf counter used for texture collisions
-         */
-        readonly textureCollisionsCounter: PerfCounter;
-        /**
          * Instantiates a new scene instrumentation.
          * Instantiates a new scene instrumentation.
          * This class can be used to get instrumentation data from a Babylon engine
          * This class can be used to get instrumentation data from a Babylon engine
          * @see http://doc.babylonjs.com/how_to/optimizing_your_scene#sceneinstrumentation
          * @see http://doc.babylonjs.com/how_to/optimizing_your_scene#sceneinstrumentation
@@ -48114,7 +48098,7 @@ declare module BABYLON {
             backUVs?: Vector4;
             backUVs?: Vector4;
             instance?: Mesh;
             instance?: Mesh;
             invertUV?: boolean;
             invertUV?: boolean;
-        }, scene: Scene): Mesh;
+        }, scene?: Nullable<Scene>): Mesh;
         private static _ExtrudeShapeGeneric;
         private static _ExtrudeShapeGeneric;
     }
     }
 }
 }
@@ -49222,6 +49206,31 @@ declare module BABYLON {
 }
 }
 declare module BABYLON {
 declare module BABYLON {
     /**
     /**
+     * Helper class to push actions to a pool of workers.
+     */
+    export class WorkerPool implements IDisposable {
+        private _workerInfos;
+        private _pendingActions;
+        /**
+         * Constructor
+         * @param workers Array of workers to use for actions
+         */
+        constructor(workers: Array<Worker>);
+        /**
+         * Terminates all workers and clears any pending actions.
+         */
+        dispose(): void;
+        /**
+         * Pushes an action to the worker pool. If all the workers are active, the action will be
+         * pended until a worker has completed its action.
+         * @param action The action to perform. Call onComplete when the action is complete.
+         */
+        push(action: (worker: Worker, onComplete: () => void) => void): void;
+        private _execute;
+    }
+}
+declare module BABYLON {
+    /**
      * Configuration for Draco compression
      * Configuration for Draco compression
      */
      */
     export interface IDracoCompressionConfiguration {
     export interface IDracoCompressionConfiguration {
@@ -49282,7 +49291,7 @@ declare module BABYLON {
      * @see https://www.babylonjs-playground.com/#N3EK4B#0
      * @see https://www.babylonjs-playground.com/#N3EK4B#0
      */
      */
     export class DracoCompression implements IDisposable {
     export class DracoCompression implements IDisposable {
-        private static _DecoderModulePromise;
+        private _workerPoolPromise;
         /**
         /**
          * The configuration. Defaults to the following urls:
          * The configuration. Defaults to the following urls:
          * - wasmUrl: "https://preview.babylonjs.com/draco_wasm_wrapper_gltf.js"
          * - wasmUrl: "https://preview.babylonjs.com/draco_wasm_wrapper_gltf.js"
@@ -49295,25 +49304,38 @@ declare module BABYLON {
          */
          */
         static readonly DecoderAvailable: boolean;
         static readonly DecoderAvailable: boolean;
         /**
         /**
+         * Default number of workers to create when creating the draco compression object.
+         */
+        static DefaultNumWorkers: number;
+        private static GetDefaultNumWorkers;
+        /**
          * Constructor
          * Constructor
+         * @param numWorkers The number of workers for async operations
          */
          */
-        constructor();
+        constructor(numWorkers?: number);
         /**
         /**
          * Stop all async operations and release resources.
          * Stop all async operations and release resources.
          */
          */
         dispose(): void;
         dispose(): void;
         /**
         /**
-         * Decode Draco compressed mesh data to vertex data.
-         * @param data The ArrayBuffer or ArrayBufferView for the Draco compression data
-         * @param attributes A map of attributes from vertex buffer kinds to Draco unique ids
-         * @returns A promise that resolves with the decoded vertex data
+         * Returns a promise that resolves when ready. Call this manually to ensure draco compression is ready before use.
+         * @returns a promise that resolves when ready
          */
          */
+        whenReadyAsync(): Promise<void>;
+        /**
+          * Decode Draco compressed mesh data to vertex data.
+          * @param data The ArrayBuffer or ArrayBufferView for the Draco compression data
+          * @param attributes A map of attributes from vertex buffer kinds to Draco unique ids
+          * @returns A promise that resolves with the decoded vertex data
+          */
         decodeMeshAsync(data: ArrayBuffer | ArrayBufferView, attributes: {
         decodeMeshAsync(data: ArrayBuffer | ArrayBufferView, attributes: {
             [kind: string]: number;
             [kind: string]: number;
         }): Promise<VertexData>;
         }): Promise<VertexData>;
-        private static _GetDecoderModule;
-        private static _LoadScriptAsync;
-        private static _LoadFileAsync;
+        /**
+         * The worker function that gets converted to a blob url to pass into a worker.
+         */
+        private static _Worker;
+        private _loadDecoderWasmBinaryAsync;
     }
     }
 }
 }
 declare module BABYLON {
 declare module BABYLON {
@@ -49651,7 +49673,7 @@ declare module BABYLON {
             sideOrientation?: number;
             sideOrientation?: number;
             frontUVs?: Vector4;
             frontUVs?: Vector4;
             backUVs?: Vector4;
             backUVs?: Vector4;
-        }, scene: Scene, earcutInjection?: any): Mesh;
+        }, scene?: Nullable<Scene>, earcutInjection?: any): Mesh;
         /**
         /**
          * Creates an extruded polygon mesh, with depth in the Y direction.
          * Creates an extruded polygon mesh, with depth in the Y direction.
          * * You can set different colors and different images to the top, bottom and extruded side by using the parameters `faceColors` (an array of 3 Color3 elements) and `faceUV` (an array of 3 Vector4 elements)
          * * You can set different colors and different images to the top, bottom and extruded side by using the parameters `faceColors` (an array of 3 Color3 elements) and `faceUV` (an array of 3 Vector4 elements)
@@ -49672,7 +49694,7 @@ declare module BABYLON {
             sideOrientation?: number;
             sideOrientation?: number;
             frontUVs?: Vector4;
             frontUVs?: Vector4;
             backUVs?: Vector4;
             backUVs?: Vector4;
-        }, scene: Scene, earcutInjection?: any): Mesh;
+        }, scene?: Nullable<Scene>, earcutInjection?: any): Mesh;
     }
     }
 }
 }
 declare module BABYLON {
 declare module BABYLON {
@@ -49713,7 +49735,7 @@ declare module BABYLON {
             backUVs?: Vector4;
             backUVs?: Vector4;
             cap?: number;
             cap?: number;
             invertUV?: boolean;
             invertUV?: boolean;
-        }, scene: Scene): Mesh;
+        }, scene?: Nullable<Scene>): Mesh;
     }
     }
 }
 }
 declare module BABYLON {
 declare module BABYLON {
@@ -49758,7 +49780,7 @@ declare module BABYLON {
             backUVs?: Vector4;
             backUVs?: Vector4;
             instance?: Mesh;
             instance?: Mesh;
             invertUV?: boolean;
             invertUV?: boolean;
-        }, scene: Scene): Mesh;
+        }, scene?: Nullable<Scene>): Mesh;
     }
     }
 }
 }
 declare module BABYLON {
 declare module BABYLON {
@@ -49792,7 +49814,7 @@ declare module BABYLON {
             frontUVs?: Vector4;
             frontUVs?: Vector4;
             backUVs?: Vector4;
             backUVs?: Vector4;
             updatable?: boolean;
             updatable?: boolean;
-        }, scene: Scene): Mesh;
+        }, scene?: Nullable<Scene>): Mesh;
     }
     }
 }
 }
 declare module BABYLON {
 declare module BABYLON {
@@ -49882,7 +49904,7 @@ declare module BABYLON {
             frontUVs?: Vector4;
             frontUVs?: Vector4;
             backUVs?: Vector4;
             backUVs?: Vector4;
             updatable?: boolean;
             updatable?: boolean;
-        }, scene: any): Mesh;
+        }, scene?: Nullable<Scene>): Mesh;
         /**
         /**
          * Creates a plane polygonal mesh.  By default, this is a disc
          * Creates a plane polygonal mesh.  By default, this is a disc
          * * The parameter `radius` sets the radius size (float) of the polygon (default 0.5)
          * * The parameter `radius` sets the radius size (float) of the polygon (default 0.5)
@@ -49932,7 +49954,7 @@ declare module BABYLON {
             frontUVs?: Vector4;
             frontUVs?: Vector4;
             backUVs?: Vector4;
             backUVs?: Vector4;
             updatable?: boolean;
             updatable?: boolean;
-        }, scene: Scene): Mesh;
+        }, scene?: Nullable<Scene>): Mesh;
         /**
         /**
          * Creates a ribbon mesh. The ribbon is a parametric shape.  It has no predefined shape. Its final shape will depend on the input parameters
          * Creates a ribbon mesh. The ribbon is a parametric shape.  It has no predefined shape. Its final shape will depend on the input parameters
          * * The parameter `pathArray` is a required array of paths, what are each an array of successive Vector3. The pathArray parameter depicts the ribbon geometry
          * * The parameter `pathArray` is a required array of paths, what are each an array of successive Vector3. The pathArray parameter depicts the ribbon geometry
@@ -50013,7 +50035,7 @@ declare module BABYLON {
             sideOrientation?: number;
             sideOrientation?: number;
             frontUVs?: Vector4;
             frontUVs?: Vector4;
             backUVs?: Vector4;
             backUVs?: Vector4;
-        }, scene: any): Mesh;
+        }, scene?: Nullable<Scene>): Mesh;
         /**
         /**
          * Creates a torus mesh
          * Creates a torus mesh
          * * The parameter `diameter` sets the diameter size (float) of the torus (default 1)
          * * The parameter `diameter` sets the diameter size (float) of the torus (default 1)
@@ -50036,7 +50058,7 @@ declare module BABYLON {
             sideOrientation?: number;
             sideOrientation?: number;
             frontUVs?: Vector4;
             frontUVs?: Vector4;
             backUVs?: Vector4;
             backUVs?: Vector4;
-        }, scene: any): Mesh;
+        }, scene?: Nullable<Scene>): Mesh;
         /**
         /**
          * Creates a torus knot mesh
          * Creates a torus knot mesh
          * * The parameter `radius` sets the global radius size (float) of the torus knot (default 2)
          * * The parameter `radius` sets the global radius size (float) of the torus knot (default 2)
@@ -50063,7 +50085,7 @@ declare module BABYLON {
             sideOrientation?: number;
             sideOrientation?: number;
             frontUVs?: Vector4;
             frontUVs?: Vector4;
             backUVs?: Vector4;
             backUVs?: Vector4;
-        }, scene: any): Mesh;
+        }, scene?: Nullable<Scene>): Mesh;
         /**
         /**
          * Creates a line system mesh. A line system is a pool of many lines gathered in a single mesh
          * Creates a line system mesh. A line system is a pool of many lines gathered in a single mesh
          * * A line system mesh is considered as a parametric shape since it has no predefined original shape. Its shape is determined by the passed array of lines as an input parameter
          * * A line system mesh is considered as a parametric shape since it has no predefined original shape. Its shape is determined by the passed array of lines as an input parameter
@@ -50209,7 +50231,7 @@ declare module BABYLON {
             backUVs?: Vector4;
             backUVs?: Vector4;
             instance?: Mesh;
             instance?: Mesh;
             invertUV?: boolean;
             invertUV?: boolean;
-        }, scene: Scene): Mesh;
+        }, scene?: Nullable<Scene>): Mesh;
         /**
         /**
          * Creates lathe mesh.
          * Creates lathe mesh.
          * The lathe is a shape with a symetry axis : a 2D model shape is rotated around this axis to design the lathe
          * The lathe is a shape with a symetry axis : a 2D model shape is rotated around this axis to design the lathe
@@ -50243,7 +50265,7 @@ declare module BABYLON {
             backUVs?: Vector4;
             backUVs?: Vector4;
             cap?: number;
             cap?: number;
             invertUV?: boolean;
             invertUV?: boolean;
-        }, scene: Scene): Mesh;
+        }, scene?: Nullable<Scene>): Mesh;
         /**
         /**
          * Creates a plane mesh
          * Creates a plane mesh
          * * The parameter `size` sets the size (float) of both sides of the plane at once (default 1)
          * * The parameter `size` sets the size (float) of both sides of the plane at once (default 1)
@@ -50267,7 +50289,7 @@ declare module BABYLON {
             backUVs?: Vector4;
             backUVs?: Vector4;
             updatable?: boolean;
             updatable?: boolean;
             sourcePlane?: Plane;
             sourcePlane?: Plane;
-        }, scene: Scene): Mesh;
+        }, scene?: Nullable<Scene>): Mesh;
         /**
         /**
          * Creates a ground mesh
          * Creates a ground mesh
          * * The parameters `width` and `height` (floats, default 1) set the width and height sizes of the ground
          * * The parameters `width` and `height` (floats, default 1) set the width and height sizes of the ground
@@ -50286,7 +50308,7 @@ declare module BABYLON {
             subdivisionsX?: number;
             subdivisionsX?: number;
             subdivisionsY?: number;
             subdivisionsY?: number;
             updatable?: boolean;
             updatable?: boolean;
-        }, scene: any): Mesh;
+        }, scene?: Nullable<Scene>): Mesh;
         /**
         /**
          * Creates a tiled ground mesh
          * Creates a tiled ground mesh
          * * The parameters `xmin` and `xmax` (floats, default -1 and 1) set the ground minimum and maximum X coordinates
          * * The parameters `xmin` and `xmax` (floats, default -1 and 1) set the ground minimum and maximum X coordinates
@@ -50314,7 +50336,7 @@ declare module BABYLON {
                 h: number;
                 h: number;
             };
             };
             updatable?: boolean;
             updatable?: boolean;
-        }, scene: Scene): Mesh;
+        }, scene?: Nullable<Scene>): Mesh;
         /**
         /**
          * Creates a ground mesh from a height map
          * Creates a ground mesh from a height map
          * * The parameter `url` sets the URL of the height map image resource.
          * * The parameter `url` sets the URL of the height map image resource.
@@ -50344,7 +50366,7 @@ declare module BABYLON {
             alphaFilter?: number;
             alphaFilter?: number;
             updatable?: boolean;
             updatable?: boolean;
             onReady?: (mesh: GroundMesh) => void;
             onReady?: (mesh: GroundMesh) => void;
-        }, scene: Scene): GroundMesh;
+        }, scene?: Nullable<Scene>): GroundMesh;
         /**
         /**
          * Creates a polygon mesh
          * Creates a polygon mesh
          * The polygon's shape will depend on the input parameters and is constructed parallel to a ground mesh
          * The polygon's shape will depend on the input parameters and is constructed parallel to a ground mesh
@@ -50369,7 +50391,7 @@ declare module BABYLON {
             sideOrientation?: number;
             sideOrientation?: number;
             frontUVs?: Vector4;
             frontUVs?: Vector4;
             backUVs?: Vector4;
             backUVs?: Vector4;
-        }, scene: Scene, earcutInjection?: any): Mesh;
+        }, scene?: Nullable<Scene>, earcutInjection?: any): Mesh;
         /**
         /**
          * Creates an extruded polygon mesh, with depth in the Y direction.
          * Creates an extruded polygon mesh, with depth in the Y direction.
          * * You can set different colors and different images to the top, bottom and extruded side by using the parameters `faceColors` (an array of 3 Color3 elements) and `faceUV` (an array of 3 Vector4 elements)
          * * You can set different colors and different images to the top, bottom and extruded side by using the parameters `faceColors` (an array of 3 Color3 elements) and `faceUV` (an array of 3 Vector4 elements)
@@ -50390,7 +50412,7 @@ declare module BABYLON {
             sideOrientation?: number;
             sideOrientation?: number;
             frontUVs?: Vector4;
             frontUVs?: Vector4;
             backUVs?: Vector4;
             backUVs?: Vector4;
-        }, scene: Scene, earcutInjection?: any): Mesh;
+        }, scene?: Nullable<Scene>, earcutInjection?: any): Mesh;
         /**
         /**
          * Creates a tube mesh.
          * Creates a tube mesh.
          * The tube is a parametric shape. It has no predefined shape. Its final shape will depend on the input parameters
          * The tube is a parametric shape. It has no predefined shape. Its final shape will depend on the input parameters
@@ -50428,7 +50450,7 @@ declare module BABYLON {
             backUVs?: Vector4;
             backUVs?: Vector4;
             instance?: Mesh;
             instance?: Mesh;
             invertUV?: boolean;
             invertUV?: boolean;
-        }, scene: Scene): Mesh;
+        }, scene?: Nullable<Scene>): Mesh;
         /**
         /**
          * Creates a polyhedron mesh
          * Creates a polyhedron mesh
          * * The parameter `type` (positive integer, max 14, default 0) sets the polyhedron type to build among the 15 embbeded types. Please refer to the type sheet in the tutorial to choose the wanted type
          * * The parameter `type` (positive integer, max 14, default 0) sets the polyhedron type to build among the 15 embbeded types. Please refer to the type sheet in the tutorial to choose the wanted type
@@ -50462,7 +50484,7 @@ declare module BABYLON {
             sideOrientation?: number;
             sideOrientation?: number;
             frontUVs?: Vector4;
             frontUVs?: Vector4;
             backUVs?: Vector4;
             backUVs?: Vector4;
-        }, scene: Scene): Mesh;
+        }, scene?: Nullable<Scene>): Mesh;
         /**
         /**
          * Creates a decal mesh.
          * Creates a decal mesh.
          * A decal is a mesh usually applied as a model onto the surface of another mesh. So don't forget the parameter `sourceMesh` depicting the decal
          * A decal is a mesh usually applied as a model onto the surface of another mesh. So don't forget the parameter `sourceMesh` depicting the decal
@@ -55959,31 +55981,6 @@ declare module BABYLON {
 }
 }
 declare module BABYLON {
 declare module BABYLON {
     /**
     /**
-     * Helper class to push actions to a pool of workers.
-     */
-    export class WorkerPool implements IDisposable {
-        private _workerInfos;
-        private _pendingActions;
-        /**
-         * Constructor
-         * @param workers Array of workers to use for actions
-         */
-        constructor(workers: Array<Worker>);
-        /**
-         * Terminates all workers and clears any pending actions.
-         */
-        dispose(): void;
-        /**
-         * Pushes an action to the worker pool. If all the workers are active, the action will be
-         * pended until a worker has completed its action.
-         * @param action The action to perform. Call onComplete when the action is complete.
-         */
-        push(action: (worker: Worker, onComplete: () => void) => void): void;
-        private _execute;
-    }
-}
-declare module BABYLON {
-    /**
      * Class containing a set of static utilities functions for screenshots
      * Class containing a set of static utilities functions for screenshots
      */
      */
     export class ScreenshotTools {
     export class ScreenshotTools {

文件差异内容过多而无法显示
+ 2 - 2
dist/preview release/babylon.js


文件差异内容过多而无法显示
+ 672 - 554
dist/preview release/babylon.max.js


文件差异内容过多而无法显示
+ 1 - 1
dist/preview release/babylon.max.js.map


文件差异内容过多而无法显示
+ 247 - 248
dist/preview release/babylon.module.d.ts


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

@@ -7,7 +7,7 @@
 		exports["babylonjs-gui"] = factory(require("babylonjs"));
 		exports["babylonjs-gui"] = factory(require("babylonjs"));
 	else
 	else
 		root["BABYLON"] = root["BABYLON"] || {}, root["BABYLON"]["GUI"] = factory(root["BABYLON"]);
 		root["BABYLON"] = root["BABYLON"] || {}, root["BABYLON"]["GUI"] = factory(root["BABYLON"]);
-})((typeof self !== "undefined" ? self : typeof global !== "undefined" ? global : this), function(__WEBPACK_EXTERNAL_MODULE_babylonjs_Misc_observable__) {
+})((typeof self !== "undefined" ? self : typeof global !== "undefined" ? global : this), function(__WEBPACK_EXTERNAL_MODULE_babylonjs_Misc_tools__) {
 return /******/ (function(modules) { // webpackBootstrap
 return /******/ (function(modules) { // webpackBootstrap
 /******/ 	// The module cache
 /******/ 	// The module cache
 /******/ 	var installedModules = {};
 /******/ 	var installedModules = {};
@@ -355,7 +355,7 @@ module.exports = g;
 "use strict";
 "use strict";
 __webpack_require__.r(__webpack_exports__);
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "AdvancedDynamicTextureInstrumentation", function() { return AdvancedDynamicTextureInstrumentation; });
 /* 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/Misc/observable");
+/* harmony import */ var babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! babylonjs/Misc/tools */ "babylonjs/Misc/tools");
 /* 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_tools__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_0__);
 
 
 /**
 /**
@@ -498,7 +498,7 @@ var AdvancedDynamicTextureInstrumentation = /** @class */ (function () {
 __webpack_require__.r(__webpack_exports__);
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "AdvancedDynamicTexture", function() { return AdvancedDynamicTexture; });
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "AdvancedDynamicTexture", function() { return AdvancedDynamicTexture; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
-/* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/observable */ "babylonjs/Misc/observable");
+/* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/observable */ "babylonjs/Misc/tools");
 /* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var _controls_container__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./controls/container */ "./2D/controls/container.ts");
 /* harmony import */ var _controls_container__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./controls/container */ "./2D/controls/container.ts");
 /* harmony import */ var _style__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./style */ "./2D/style.ts");
 /* harmony import */ var _style__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./style */ "./2D/style.ts");
@@ -1619,7 +1619,7 @@ var Button = /** @class */ (function (_super) {
 __webpack_require__.r(__webpack_exports__);
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Checkbox", function() { return Checkbox; });
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Checkbox", function() { return Checkbox; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
-/* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/observable */ "babylonjs/Misc/observable");
+/* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/observable */ "babylonjs/Misc/tools");
 /* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var _control__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./control */ "./2D/controls/control.ts");
 /* harmony import */ var _control__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./control */ "./2D/controls/control.ts");
 /* harmony import */ var _stackPanel__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./stackPanel */ "./2D/controls/stackPanel.ts");
 /* harmony import */ var _stackPanel__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./stackPanel */ "./2D/controls/stackPanel.ts");
@@ -1800,7 +1800,7 @@ var Checkbox = /** @class */ (function (_super) {
 __webpack_require__.r(__webpack_exports__);
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ColorPicker", function() { return ColorPicker; });
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ColorPicker", function() { return ColorPicker; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
-/* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/observable */ "babylonjs/Misc/observable");
+/* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/observable */ "babylonjs/Misc/tools");
 /* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var _control__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./control */ "./2D/controls/control.ts");
 /* harmony import */ var _control__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./control */ "./2D/controls/control.ts");
 /* harmony import */ var _inputText__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./inputText */ "./2D/controls/inputText.ts");
 /* harmony import */ var _inputText__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./inputText */ "./2D/controls/inputText.ts");
@@ -3247,7 +3247,7 @@ var ColorPicker = /** @class */ (function (_super) {
 __webpack_require__.r(__webpack_exports__);
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Container", function() { return Container; });
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Container", function() { return Container; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
-/* harmony import */ var babylonjs_Misc_logger__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/logger */ "babylonjs/Misc/observable");
+/* harmony import */ var babylonjs_Misc_logger__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/logger */ "babylonjs/Misc/tools");
 /* harmony import */ var babylonjs_Misc_logger__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_logger__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var babylonjs_Misc_logger__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_logger__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var _control__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./control */ "./2D/controls/control.ts");
 /* harmony import */ var _control__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./control */ "./2D/controls/control.ts");
 /* harmony import */ var _measure__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../measure */ "./2D/measure.ts");
 /* harmony import */ var _measure__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../measure */ "./2D/measure.ts");
@@ -3652,7 +3652,7 @@ var Container = /** @class */ (function (_super) {
 "use strict";
 "use strict";
 __webpack_require__.r(__webpack_exports__);
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Control", function() { return Control; });
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Control", function() { return Control; });
-/* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! babylonjs/Misc/observable */ "babylonjs/Misc/observable");
+/* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! babylonjs/Misc/observable */ "babylonjs/Misc/tools");
 /* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_0__);
 /* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_0__);
 /* harmony import */ var _valueAndUnit__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../valueAndUnit */ "./2D/valueAndUnit.ts");
 /* harmony import */ var _valueAndUnit__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../valueAndUnit */ "./2D/valueAndUnit.ts");
 /* harmony import */ var _measure__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../measure */ "./2D/measure.ts");
 /* harmony import */ var _measure__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../measure */ "./2D/measure.ts");
@@ -6212,7 +6212,7 @@ var Grid = /** @class */ (function (_super) {
 __webpack_require__.r(__webpack_exports__);
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Image", function() { return Image; });
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Image", function() { return Image; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
-/* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/observable */ "babylonjs/Misc/observable");
+/* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/observable */ "babylonjs/Misc/tools");
 /* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var _control__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./control */ "./2D/controls/control.ts");
 /* harmony import */ var _control__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./control */ "./2D/controls/control.ts");
 
 
@@ -6987,7 +6987,7 @@ var InputPassword = /** @class */ (function (_super) {
 __webpack_require__.r(__webpack_exports__);
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "InputText", function() { return InputText; });
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "InputText", function() { return InputText; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
-/* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/observable */ "babylonjs/Misc/observable");
+/* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/observable */ "babylonjs/Misc/tools");
 /* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var _control__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./control */ "./2D/controls/control.ts");
 /* harmony import */ var _control__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./control */ "./2D/controls/control.ts");
 /* harmony import */ var _valueAndUnit__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../valueAndUnit */ "./2D/valueAndUnit.ts");
 /* harmony import */ var _valueAndUnit__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../valueAndUnit */ "./2D/valueAndUnit.ts");
@@ -7996,7 +7996,7 @@ var InputText = /** @class */ (function (_super) {
 __webpack_require__.r(__webpack_exports__);
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Line", function() { return Line; });
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Line", function() { return Line; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
-/* harmony import */ var babylonjs_Maths_math__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Maths/math */ "babylonjs/Misc/observable");
+/* harmony import */ var babylonjs_Maths_math__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Maths/math */ "babylonjs/Misc/tools");
 /* harmony import */ var babylonjs_Maths_math__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Maths_math__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var babylonjs_Maths_math__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Maths_math__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var _control__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./control */ "./2D/controls/control.ts");
 /* harmony import */ var _control__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./control */ "./2D/controls/control.ts");
 /* harmony import */ var _valueAndUnit__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../valueAndUnit */ "./2D/valueAndUnit.ts");
 /* harmony import */ var _valueAndUnit__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../valueAndUnit */ "./2D/valueAndUnit.ts");
@@ -8264,7 +8264,7 @@ var Line = /** @class */ (function (_super) {
 __webpack_require__.r(__webpack_exports__);
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "MultiLine", function() { return MultiLine; });
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "MultiLine", function() { return MultiLine; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
-/* harmony import */ var babylonjs_Meshes_abstractMesh__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Meshes/abstractMesh */ "babylonjs/Misc/observable");
+/* harmony import */ var babylonjs_Meshes_abstractMesh__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Meshes/abstractMesh */ "babylonjs/Misc/tools");
 /* harmony import */ var babylonjs_Meshes_abstractMesh__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Meshes_abstractMesh__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var babylonjs_Meshes_abstractMesh__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Meshes_abstractMesh__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var _control__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./control */ "./2D/controls/control.ts");
 /* harmony import */ var _control__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./control */ "./2D/controls/control.ts");
 /* harmony import */ var _multiLinePoint__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../multiLinePoint */ "./2D/multiLinePoint.ts");
 /* harmony import */ var _multiLinePoint__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../multiLinePoint */ "./2D/multiLinePoint.ts");
@@ -8531,7 +8531,7 @@ var MultiLine = /** @class */ (function (_super) {
 __webpack_require__.r(__webpack_exports__);
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "RadioButton", function() { return RadioButton; });
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "RadioButton", function() { return RadioButton; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
-/* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/observable */ "babylonjs/Misc/observable");
+/* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/observable */ "babylonjs/Misc/tools");
 /* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var _control__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./control */ "./2D/controls/control.ts");
 /* harmony import */ var _control__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./control */ "./2D/controls/control.ts");
 /* harmony import */ var _stackPanel__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./stackPanel */ "./2D/controls/stackPanel.ts");
 /* harmony import */ var _stackPanel__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./stackPanel */ "./2D/controls/stackPanel.ts");
@@ -8876,7 +8876,7 @@ var Rectangle = /** @class */ (function (_super) {
 __webpack_require__.r(__webpack_exports__);
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ScrollViewer", function() { return ScrollViewer; });
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ScrollViewer", function() { return ScrollViewer; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
-/* harmony import */ var babylonjs_Events_pointerEvents__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Events/pointerEvents */ "babylonjs/Misc/observable");
+/* harmony import */ var babylonjs_Events_pointerEvents__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Events/pointerEvents */ "babylonjs/Misc/tools");
 /* harmony import */ var babylonjs_Events_pointerEvents__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Events_pointerEvents__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var babylonjs_Events_pointerEvents__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Events_pointerEvents__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var _rectangle__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../rectangle */ "./2D/controls/rectangle.ts");
 /* harmony import */ var _rectangle__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../rectangle */ "./2D/controls/rectangle.ts");
 /* harmony import */ var _grid__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../grid */ "./2D/controls/grid.ts");
 /* harmony import */ var _grid__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../grid */ "./2D/controls/grid.ts");
@@ -9967,7 +9967,7 @@ var SelectionPanel = /** @class */ (function (_super) {
 __webpack_require__.r(__webpack_exports__);
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "BaseSlider", function() { return BaseSlider; });
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "BaseSlider", function() { return BaseSlider; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
-/* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/observable */ "babylonjs/Misc/observable");
+/* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/observable */ "babylonjs/Misc/tools");
 /* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var _control__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../control */ "./2D/controls/control.ts");
 /* harmony import */ var _control__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../control */ "./2D/controls/control.ts");
 /* harmony import */ var _valueAndUnit__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../../valueAndUnit */ "./2D/valueAndUnit.ts");
 /* harmony import */ var _valueAndUnit__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../../valueAndUnit */ "./2D/valueAndUnit.ts");
@@ -10862,7 +10862,7 @@ var Slider = /** @class */ (function (_super) {
 __webpack_require__.r(__webpack_exports__);
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "StackPanel", function() { return StackPanel; });
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "StackPanel", function() { return StackPanel; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
-/* harmony import */ var babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/tools */ "babylonjs/Misc/observable");
+/* harmony import */ var babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/tools */ "babylonjs/Misc/tools");
 /* harmony import */ var babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var _container__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./container */ "./2D/controls/container.ts");
 /* harmony import */ var _container__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./container */ "./2D/controls/container.ts");
 /* harmony import */ var _control__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./control */ "./2D/controls/control.ts");
 /* harmony import */ var _control__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./control */ "./2D/controls/control.ts");
@@ -11120,7 +11120,7 @@ __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "TextWrapping", function() { return TextWrapping; });
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "TextWrapping", function() { return TextWrapping; });
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "TextBlock", function() { return TextBlock; });
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "TextBlock", function() { return TextBlock; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
-/* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/observable */ "babylonjs/Misc/observable");
+/* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/observable */ "babylonjs/Misc/tools");
 /* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var _valueAndUnit__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../valueAndUnit */ "./2D/valueAndUnit.ts");
 /* harmony import */ var _valueAndUnit__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../valueAndUnit */ "./2D/valueAndUnit.ts");
 /* harmony import */ var _control__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./control */ "./2D/controls/control.ts");
 /* harmony import */ var _control__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./control */ "./2D/controls/control.ts");
@@ -11560,7 +11560,7 @@ __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "KeyPropertySet", function() { return KeyPropertySet; });
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "KeyPropertySet", function() { return KeyPropertySet; });
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "VirtualKeyboard", function() { return VirtualKeyboard; });
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "VirtualKeyboard", function() { return VirtualKeyboard; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
-/* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/observable */ "babylonjs/Misc/observable");
+/* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/observable */ "babylonjs/Misc/tools");
 /* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var _stackPanel__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./stackPanel */ "./2D/controls/stackPanel.ts");
 /* harmony import */ var _stackPanel__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./stackPanel */ "./2D/controls/stackPanel.ts");
 /* harmony import */ var _button__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./button */ "./2D/controls/button.ts");
 /* harmony import */ var _button__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./button */ "./2D/controls/button.ts");
@@ -11935,7 +11935,7 @@ __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Vector2WithInfo", function() { return Vector2WithInfo; });
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Vector2WithInfo", function() { return Vector2WithInfo; });
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Matrix2D", function() { return Matrix2D; });
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Matrix2D", function() { return Matrix2D; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
-/* harmony import */ var babylonjs_Maths_math__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Maths/math */ "babylonjs/Misc/observable");
+/* harmony import */ var babylonjs_Maths_math__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Maths/math */ "babylonjs/Misc/tools");
 /* harmony import */ var babylonjs_Maths_math__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Maths_math__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var babylonjs_Maths_math__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Maths_math__WEBPACK_IMPORTED_MODULE_1__);
 
 
 
 
@@ -12159,7 +12159,7 @@ var Matrix2D = /** @class */ (function () {
 "use strict";
 "use strict";
 __webpack_require__.r(__webpack_exports__);
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Measure", function() { return Measure; });
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Measure", function() { return Measure; });
-/* harmony import */ var babylonjs_Maths_math__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! babylonjs/Maths/math */ "babylonjs/Misc/observable");
+/* harmony import */ var babylonjs_Maths_math__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! babylonjs/Maths/math */ "babylonjs/Misc/tools");
 /* harmony import */ var babylonjs_Maths_math__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Maths_math__WEBPACK_IMPORTED_MODULE_0__);
 /* harmony import */ var babylonjs_Maths_math__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Maths_math__WEBPACK_IMPORTED_MODULE_0__);
 
 
 
 
@@ -12292,7 +12292,7 @@ var Measure = /** @class */ (function () {
 "use strict";
 "use strict";
 __webpack_require__.r(__webpack_exports__);
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "MultiLinePoint", function() { return MultiLinePoint; });
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "MultiLinePoint", function() { return MultiLinePoint; });
-/* harmony import */ var babylonjs_Maths_math__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! babylonjs/Maths/math */ "babylonjs/Misc/observable");
+/* harmony import */ var babylonjs_Maths_math__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! babylonjs/Maths/math */ "babylonjs/Misc/tools");
 /* harmony import */ var babylonjs_Maths_math__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Maths_math__WEBPACK_IMPORTED_MODULE_0__);
 /* harmony import */ var babylonjs_Maths_math__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Maths_math__WEBPACK_IMPORTED_MODULE_0__);
 /* harmony import */ var _valueAndUnit__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./valueAndUnit */ "./2D/valueAndUnit.ts");
 /* harmony import */ var _valueAndUnit__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./valueAndUnit */ "./2D/valueAndUnit.ts");
 
 
@@ -12435,7 +12435,7 @@ var MultiLinePoint = /** @class */ (function () {
 "use strict";
 "use strict";
 __webpack_require__.r(__webpack_exports__);
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Style", function() { return Style; });
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Style", function() { return Style; });
-/* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! babylonjs/Misc/observable */ "babylonjs/Misc/observable");
+/* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! babylonjs/Misc/observable */ "babylonjs/Misc/tools");
 /* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_0__);
 /* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_0__);
 /* harmony import */ var _valueAndUnit__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./valueAndUnit */ "./2D/valueAndUnit.ts");
 /* harmony import */ var _valueAndUnit__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./valueAndUnit */ "./2D/valueAndUnit.ts");
 
 
@@ -12742,7 +12742,7 @@ var ValueAndUnit = /** @class */ (function () {
 __webpack_require__.r(__webpack_exports__);
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "AbstractButton3D", function() { return AbstractButton3D; });
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "AbstractButton3D", function() { return AbstractButton3D; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
-/* harmony import */ var babylonjs_Meshes_transformNode__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Meshes/transformNode */ "babylonjs/Misc/observable");
+/* harmony import */ var babylonjs_Meshes_transformNode__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Meshes/transformNode */ "babylonjs/Misc/tools");
 /* harmony import */ var babylonjs_Meshes_transformNode__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Meshes_transformNode__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var babylonjs_Meshes_transformNode__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Meshes_transformNode__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var _control3D__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./control3D */ "./3D/controls/control3D.ts");
 /* harmony import */ var _control3D__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./control3D */ "./3D/controls/control3D.ts");
 
 
@@ -12785,7 +12785,7 @@ var AbstractButton3D = /** @class */ (function (_super) {
 __webpack_require__.r(__webpack_exports__);
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Button3D", function() { return Button3D; });
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Button3D", function() { return Button3D; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
-/* harmony import */ var babylonjs_Maths_math__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Maths/math */ "babylonjs/Misc/observable");
+/* harmony import */ var babylonjs_Maths_math__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Maths/math */ "babylonjs/Misc/tools");
 /* harmony import */ var babylonjs_Maths_math__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Maths_math__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var babylonjs_Maths_math__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Maths_math__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var _abstractButton3D__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./abstractButton3D */ "./3D/controls/abstractButton3D.ts");
 /* harmony import */ var _abstractButton3D__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./abstractButton3D */ "./3D/controls/abstractButton3D.ts");
 /* harmony import */ var _2D_advancedDynamicTexture__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../../2D/advancedDynamicTexture */ "./2D/advancedDynamicTexture.ts");
 /* harmony import */ var _2D_advancedDynamicTexture__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../../2D/advancedDynamicTexture */ "./2D/advancedDynamicTexture.ts");
@@ -12962,7 +12962,7 @@ var Button3D = /** @class */ (function (_super) {
 __webpack_require__.r(__webpack_exports__);
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Container3D", function() { return Container3D; });
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Container3D", function() { return Container3D; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
-/* harmony import */ var babylonjs_Meshes_transformNode__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Meshes/transformNode */ "babylonjs/Misc/observable");
+/* harmony import */ var babylonjs_Meshes_transformNode__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Meshes/transformNode */ "babylonjs/Misc/tools");
 /* harmony import */ var babylonjs_Meshes_transformNode__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Meshes_transformNode__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var babylonjs_Meshes_transformNode__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Meshes_transformNode__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var _control3D__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./control3D */ "./3D/controls/control3D.ts");
 /* harmony import */ var _control3D__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./control3D */ "./3D/controls/control3D.ts");
 
 
@@ -13119,7 +13119,7 @@ var Container3D = /** @class */ (function (_super) {
 "use strict";
 "use strict";
 __webpack_require__.r(__webpack_exports__);
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Control3D", function() { return Control3D; });
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Control3D", function() { return Control3D; });
-/* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! babylonjs/Misc/observable */ "babylonjs/Misc/observable");
+/* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! babylonjs/Misc/observable */ "babylonjs/Misc/tools");
 /* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_0__);
 /* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_0__);
 /* harmony import */ var _vector3WithInfo__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../vector3WithInfo */ "./3D/vector3WithInfo.ts");
 /* harmony import */ var _vector3WithInfo__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../vector3WithInfo */ "./3D/vector3WithInfo.ts");
 
 
@@ -13513,7 +13513,7 @@ var Control3D = /** @class */ (function () {
 __webpack_require__.r(__webpack_exports__);
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "CylinderPanel", function() { return CylinderPanel; });
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "CylinderPanel", function() { return CylinderPanel; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
-/* harmony import */ var babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/tools */ "babylonjs/Misc/observable");
+/* harmony import */ var babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/tools */ "babylonjs/Misc/tools");
 /* harmony import */ var babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var _volumeBasedPanel__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./volumeBasedPanel */ "./3D/controls/volumeBasedPanel.ts");
 /* harmony import */ var _volumeBasedPanel__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./volumeBasedPanel */ "./3D/controls/volumeBasedPanel.ts");
 /* harmony import */ var _container3D__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./container3D */ "./3D/controls/container3D.ts");
 /* harmony import */ var _container3D__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./container3D */ "./3D/controls/container3D.ts");
@@ -13598,7 +13598,7 @@ __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "HolographicButton", function() { return HolographicButton; });
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "HolographicButton", function() { return HolographicButton; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
 /* harmony import */ var _button3D__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./button3D */ "./3D/controls/button3D.ts");
 /* harmony import */ var _button3D__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./button3D */ "./3D/controls/button3D.ts");
-/* harmony import */ var babylonjs_Maths_math__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! babylonjs/Maths/math */ "babylonjs/Misc/observable");
+/* harmony import */ var babylonjs_Maths_math__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! babylonjs/Maths/math */ "babylonjs/Misc/tools");
 /* harmony import */ var babylonjs_Maths_math__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Maths_math__WEBPACK_IMPORTED_MODULE_2__);
 /* harmony import */ var babylonjs_Maths_math__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Maths_math__WEBPACK_IMPORTED_MODULE_2__);
 /* harmony import */ var _materials_fluentMaterial__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../materials/fluentMaterial */ "./3D/materials/fluentMaterial.ts");
 /* harmony import */ var _materials_fluentMaterial__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../materials/fluentMaterial */ "./3D/materials/fluentMaterial.ts");
 /* harmony import */ var _2D_controls_stackPanel__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../../2D/controls/stackPanel */ "./2D/controls/stackPanel.ts");
 /* harmony import */ var _2D_controls_stackPanel__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../../2D/controls/stackPanel */ "./2D/controls/stackPanel.ts");
@@ -14074,7 +14074,7 @@ var MeshButton3D = /** @class */ (function (_super) {
 __webpack_require__.r(__webpack_exports__);
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "PlanePanel", function() { return PlanePanel; });
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "PlanePanel", function() { return PlanePanel; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
-/* harmony import */ var babylonjs_Maths_math__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Maths/math */ "babylonjs/Misc/observable");
+/* harmony import */ var babylonjs_Maths_math__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Maths/math */ "babylonjs/Misc/tools");
 /* harmony import */ var babylonjs_Maths_math__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Maths_math__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var babylonjs_Maths_math__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Maths_math__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var _container3D__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./container3D */ "./3D/controls/container3D.ts");
 /* harmony import */ var _container3D__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./container3D */ "./3D/controls/container3D.ts");
 /* harmony import */ var _volumeBasedPanel__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./volumeBasedPanel */ "./3D/controls/volumeBasedPanel.ts");
 /* harmony import */ var _volumeBasedPanel__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./volumeBasedPanel */ "./3D/controls/volumeBasedPanel.ts");
@@ -14129,7 +14129,7 @@ var PlanePanel = /** @class */ (function (_super) {
 __webpack_require__.r(__webpack_exports__);
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ScatterPanel", function() { return ScatterPanel; });
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ScatterPanel", function() { return ScatterPanel; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
-/* harmony import */ var babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/tools */ "babylonjs/Misc/observable");
+/* harmony import */ var babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/tools */ "babylonjs/Misc/tools");
 /* harmony import */ var babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var _volumeBasedPanel__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./volumeBasedPanel */ "./3D/controls/volumeBasedPanel.ts");
 /* harmony import */ var _volumeBasedPanel__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./volumeBasedPanel */ "./3D/controls/volumeBasedPanel.ts");
 /* harmony import */ var _container3D__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./container3D */ "./3D/controls/container3D.ts");
 /* harmony import */ var _container3D__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./container3D */ "./3D/controls/container3D.ts");
@@ -14256,7 +14256,7 @@ var ScatterPanel = /** @class */ (function (_super) {
 __webpack_require__.r(__webpack_exports__);
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "SpherePanel", function() { return SpherePanel; });
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "SpherePanel", function() { return SpherePanel; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
-/* harmony import */ var babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/tools */ "babylonjs/Misc/observable");
+/* harmony import */ var babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/tools */ "babylonjs/Misc/tools");
 /* harmony import */ var babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var _volumeBasedPanel__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./volumeBasedPanel */ "./3D/controls/volumeBasedPanel.ts");
 /* harmony import */ var _volumeBasedPanel__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./volumeBasedPanel */ "./3D/controls/volumeBasedPanel.ts");
 /* harmony import */ var _container3D__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./container3D */ "./3D/controls/container3D.ts");
 /* harmony import */ var _container3D__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./container3D */ "./3D/controls/container3D.ts");
@@ -14341,7 +14341,7 @@ var SpherePanel = /** @class */ (function (_super) {
 __webpack_require__.r(__webpack_exports__);
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "StackPanel3D", function() { return StackPanel3D; });
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "StackPanel3D", function() { return StackPanel3D; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
-/* harmony import */ var babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/tools */ "babylonjs/Misc/observable");
+/* harmony import */ var babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/tools */ "babylonjs/Misc/tools");
 /* harmony import */ var babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var _container3D__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./container3D */ "./3D/controls/container3D.ts");
 /* harmony import */ var _container3D__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./container3D */ "./3D/controls/container3D.ts");
 
 
@@ -14466,7 +14466,7 @@ var StackPanel3D = /** @class */ (function (_super) {
 __webpack_require__.r(__webpack_exports__);
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "VolumeBasedPanel", function() { return VolumeBasedPanel; });
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "VolumeBasedPanel", function() { return VolumeBasedPanel; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
-/* harmony import */ var babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/tools */ "babylonjs/Misc/observable");
+/* harmony import */ var babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/tools */ "babylonjs/Misc/tools");
 /* harmony import */ var babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var _container3D__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./container3D */ "./3D/controls/container3D.ts");
 /* harmony import */ var _container3D__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./container3D */ "./3D/controls/container3D.ts");
 
 
@@ -14657,7 +14657,7 @@ var VolumeBasedPanel = /** @class */ (function (_super) {
 "use strict";
 "use strict";
 __webpack_require__.r(__webpack_exports__);
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "GUI3DManager", function() { return GUI3DManager; });
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "GUI3DManager", function() { return GUI3DManager; });
-/* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! babylonjs/Misc/observable */ "babylonjs/Misc/observable");
+/* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! babylonjs/Misc/observable */ "babylonjs/Misc/tools");
 /* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_0__);
 /* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_0__);
 /* harmony import */ var _controls_container3D__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./controls/container3D */ "./3D/controls/container3D.ts");
 /* harmony import */ var _controls_container3D__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./controls/container3D */ "./3D/controls/container3D.ts");
 
 
@@ -14924,7 +14924,7 @@ __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "FluentMaterialDefines", function() { return FluentMaterialDefines; });
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "FluentMaterialDefines", function() { return FluentMaterialDefines; });
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "FluentMaterial", function() { return FluentMaterial; });
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "FluentMaterial", function() { return FluentMaterial; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
-/* harmony import */ var babylonjs_Misc_decorators__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/decorators */ "babylonjs/Misc/observable");
+/* harmony import */ var babylonjs_Misc_decorators__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/decorators */ "babylonjs/Misc/tools");
 /* harmony import */ var babylonjs_Misc_decorators__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_decorators__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var babylonjs_Misc_decorators__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_decorators__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var _shaders_fluent_vertex__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./shaders/fluent.vertex */ "./3D/materials/shaders/fluent.vertex.ts");
 /* harmony import */ var _shaders_fluent_vertex__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./shaders/fluent.vertex */ "./3D/materials/shaders/fluent.vertex.ts");
 /* harmony import */ var _shaders_fluent_fragment__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./shaders/fluent.fragment */ "./3D/materials/shaders/fluent.fragment.ts");
 /* harmony import */ var _shaders_fluent_fragment__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./shaders/fluent.fragment */ "./3D/materials/shaders/fluent.fragment.ts");
@@ -15246,7 +15246,7 @@ __webpack_require__.r(__webpack_exports__);
 "use strict";
 "use strict";
 __webpack_require__.r(__webpack_exports__);
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "fluentPixelShader", function() { return fluentPixelShader; });
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "fluentPixelShader", function() { return fluentPixelShader; });
-/* harmony import */ var babylonjs_Materials_effect__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! babylonjs/Materials/effect */ "babylonjs/Misc/observable");
+/* harmony import */ var babylonjs_Materials_effect__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! babylonjs/Materials/effect */ "babylonjs/Misc/tools");
 /* harmony import */ var babylonjs_Materials_effect__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Materials_effect__WEBPACK_IMPORTED_MODULE_0__);
 /* harmony import */ var babylonjs_Materials_effect__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Materials_effect__WEBPACK_IMPORTED_MODULE_0__);
 
 
 var name = 'fluentPixelShader';
 var name = 'fluentPixelShader';
@@ -15268,7 +15268,7 @@ var fluentPixelShader = { name: name, shader: shader };
 "use strict";
 "use strict";
 __webpack_require__.r(__webpack_exports__);
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "fluentVertexShader", function() { return fluentVertexShader; });
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "fluentVertexShader", function() { return fluentVertexShader; });
-/* harmony import */ var babylonjs_Materials_effect__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! babylonjs/Materials/effect */ "babylonjs/Misc/observable");
+/* harmony import */ var babylonjs_Materials_effect__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! babylonjs/Materials/effect */ "babylonjs/Misc/tools");
 /* harmony import */ var babylonjs_Materials_effect__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Materials_effect__WEBPACK_IMPORTED_MODULE_0__);
 /* harmony import */ var babylonjs_Materials_effect__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Materials_effect__WEBPACK_IMPORTED_MODULE_0__);
 
 
 var name = 'fluentVertexShader';
 var name = 'fluentVertexShader';
@@ -15291,7 +15291,7 @@ var fluentVertexShader = { name: name, shader: shader };
 __webpack_require__.r(__webpack_exports__);
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Vector3WithInfo", function() { return Vector3WithInfo; });
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Vector3WithInfo", function() { return Vector3WithInfo; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
-/* harmony import */ var babylonjs_Maths_math__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Maths/math */ "babylonjs/Misc/observable");
+/* harmony import */ var babylonjs_Maths_math__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Maths/math */ "babylonjs/Misc/tools");
 /* harmony import */ var babylonjs_Maths_math__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Maths_math__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var babylonjs_Maths_math__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Maths_math__WEBPACK_IMPORTED_MODULE_1__);
 
 
 
 
@@ -15585,14 +15585,14 @@ if (typeof globalObject !== "undefined") {
 
 
 /***/ }),
 /***/ }),
 
 
-/***/ "babylonjs/Misc/observable":
+/***/ "babylonjs/Misc/tools":
 /*!****************************************************************************************************!*\
 /*!****************************************************************************************************!*\
   !*** external {"root":"BABYLON","commonjs":"babylonjs","commonjs2":"babylonjs","amd":"babylonjs"} ***!
   !*** external {"root":"BABYLON","commonjs":"babylonjs","commonjs2":"babylonjs","amd":"babylonjs"} ***!
   \****************************************************************************************************/
   \****************************************************************************************************/
 /*! no static exports found */
 /*! no static exports found */
 /***/ (function(module, exports) {
 /***/ (function(module, exports) {
 
 
-module.exports = __WEBPACK_EXTERNAL_MODULE_babylonjs_Misc_observable__;
+module.exports = __WEBPACK_EXTERNAL_MODULE_babylonjs_Misc_tools__;
 
 
 /***/ })
 /***/ })
 
 

文件差异内容过多而无法显示
+ 1 - 1
dist/preview release/gui/babylon.gui.js.map


文件差异内容过多而无法显示
+ 1 - 1
dist/preview release/inspector/babylon.inspector.bundle.js


+ 7 - 8
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"));
 		exports["babylonjs-inspector"] = factory(require("babylonjs-gui"), require("babylonjs-loaders"), require("babylonjs-serializers"), require("babylonjs"));
 	else
 	else
 		root["INSPECTOR"] = factory(root["BABYLON"]["GUI"], root["BABYLON"], root["BABYLON"], root["BABYLON"]);
 		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
 return /******/ (function(modules) { // webpackBootstrap
 /******/ 	// The module cache
 /******/ 	// The module cache
 /******/ 	var installedModules = {};
 /******/ 	var installedModules = {};
@@ -36010,7 +36010,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 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 _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 _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 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_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");
 /* harmony import */ var _lines_floatLineComponent__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ../../../lines/floatLineComponent */ "./components/actionTabs/lines/floatLineComponent.tsx");
@@ -36311,7 +36311,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 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 _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 _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 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_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");
 /* harmony import */ var _lines_checkBoxLineComponent__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ../../../lines/checkBoxLineComponent */ "./components/actionTabs/lines/checkBoxLineComponent.tsx");
@@ -36725,7 +36725,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__ = __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 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 _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 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 _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");
 /* harmony import */ var _lines_textInputLineComponent__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ../../../lines/textInputLineComponent */ "./components/actionTabs/lines/textInputLineComponent.tsx");
@@ -37748,7 +37748,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_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_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 _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 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");
 /* harmony import */ var _customPropertyGridComponent__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(/*! ../customPropertyGridComponent */ "./components/actionTabs/tabs/propertyGrids/customPropertyGridComponent.tsx");
 
 
@@ -39188,7 +39188,6 @@ var StatisticsTabComponent = /** @class */ (function (_super) {
                 react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_textLineComponent__WEBPACK_IMPORTED_MODULE_3__["TextLineComponent"], { label: "Active bones", value: scene.getActiveBones().toString() }),
                 react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_textLineComponent__WEBPACK_IMPORTED_MODULE_3__["TextLineComponent"], { label: "Active bones", value: scene.getActiveBones().toString() }),
                 react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_textLineComponent__WEBPACK_IMPORTED_MODULE_3__["TextLineComponent"], { label: "Active particles", value: scene.getActiveParticles().toString() }),
                 react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_textLineComponent__WEBPACK_IMPORTED_MODULE_3__["TextLineComponent"], { label: "Active particles", value: scene.getActiveParticles().toString() }),
                 react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_textLineComponent__WEBPACK_IMPORTED_MODULE_3__["TextLineComponent"], { label: "Draw calls", value: sceneInstrumentation.drawCallsCounter.current.toString() }),
                 react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_textLineComponent__WEBPACK_IMPORTED_MODULE_3__["TextLineComponent"], { label: "Draw calls", value: sceneInstrumentation.drawCallsCounter.current.toString() }),
-                react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_textLineComponent__WEBPACK_IMPORTED_MODULE_3__["TextLineComponent"], { label: "Texture collisions", value: sceneInstrumentation.textureCollisionsCounter.current.toString() }),
                 react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_textLineComponent__WEBPACK_IMPORTED_MODULE_3__["TextLineComponent"], { label: "Total lights", value: scene.lights.length.toString() }),
                 react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_textLineComponent__WEBPACK_IMPORTED_MODULE_3__["TextLineComponent"], { label: "Total lights", value: scene.lights.length.toString() }),
                 react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_textLineComponent__WEBPACK_IMPORTED_MODULE_3__["TextLineComponent"], { label: "Total vertices", value: scene.getTotalVertices().toString() }),
                 react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_textLineComponent__WEBPACK_IMPORTED_MODULE_3__["TextLineComponent"], { label: "Total vertices", value: scene.getTotalVertices().toString() }),
                 react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_textLineComponent__WEBPACK_IMPORTED_MODULE_3__["TextLineComponent"], { label: "Total materials", value: scene.materials.length.toString() }),
                 react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_textLineComponent__WEBPACK_IMPORTED_MODULE_3__["TextLineComponent"], { label: "Total materials", value: scene.materials.length.toString() }),
@@ -42206,14 +42205,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"} ***!
   !*** external {"root":["BABYLON","GUI"],"commonjs":"babylonjs-gui","commonjs2":"babylonjs-gui","amd":"babylonjs-gui"} ***!
   \************************************************************************************************************************/
   \************************************************************************************************************************/
 /*! no static exports found */
 /*! no static exports found */
 /***/ (function(module, exports) {
 /***/ (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


+ 13 - 6
dist/preview release/loaders/babylon.glTF2FileLoader.js

@@ -277,13 +277,14 @@ var KHR_draco_mesh_compression = /** @class */ (function () {
         this.name = NAME;
         this.name = NAME;
         /** Defines whether this extension is enabled. */
         /** Defines whether this extension is enabled. */
         this.enabled = babylonjs_Meshes_Compression_dracoCompression__WEBPACK_IMPORTED_MODULE_0__["DracoCompression"].DecoderAvailable;
         this.enabled = babylonjs_Meshes_Compression_dracoCompression__WEBPACK_IMPORTED_MODULE_0__["DracoCompression"].DecoderAvailable;
+        this._dracoCompressionOwned = false;
         this._loader = loader;
         this._loader = loader;
     }
     }
     /** @hidden */
     /** @hidden */
     KHR_draco_mesh_compression.prototype.dispose = function () {
     KHR_draco_mesh_compression.prototype.dispose = function () {
-        if (this._dracoCompression) {
-            this._dracoCompression.dispose();
-            delete this._dracoCompression;
+        if (this.dracoCompression && this._dracoCompressionOwned) {
+            this.dracoCompression.dispose();
+            delete this.dracoCompression;
         }
         }
         delete this._loader;
         delete this._loader;
     };
     };
@@ -324,10 +325,11 @@ var KHR_draco_mesh_compression = /** @class */ (function () {
             var bufferView = _glTFLoader__WEBPACK_IMPORTED_MODULE_1__["ArrayItem"].Get(extensionContext, _this._loader.gltf.bufferViews, extension.bufferView);
             var bufferView = _glTFLoader__WEBPACK_IMPORTED_MODULE_1__["ArrayItem"].Get(extensionContext, _this._loader.gltf.bufferViews, extension.bufferView);
             if (!bufferView._dracoBabylonGeometry) {
             if (!bufferView._dracoBabylonGeometry) {
                 bufferView._dracoBabylonGeometry = _this._loader.loadBufferViewAsync("#/bufferViews/" + bufferView.index, bufferView).then(function (data) {
                 bufferView._dracoBabylonGeometry = _this._loader.loadBufferViewAsync("#/bufferViews/" + bufferView.index, bufferView).then(function (data) {
-                    if (!_this._dracoCompression) {
-                        _this._dracoCompression = new babylonjs_Meshes_Compression_dracoCompression__WEBPACK_IMPORTED_MODULE_0__["DracoCompression"]();
+                    if (!_this.dracoCompression) {
+                        _this.dracoCompression = new babylonjs_Meshes_Compression_dracoCompression__WEBPACK_IMPORTED_MODULE_0__["DracoCompression"]();
+                        _this._dracoCompressionOwned = true;
                     }
                     }
-                    return _this._dracoCompression.decodeMeshAsync(data, attributes).then(function (babylonVertexData) {
+                    return _this.dracoCompression.decodeMeshAsync(data, attributes).then(function (babylonVertexData) {
                         var babylonGeometry = new babylonjs_Meshes_Compression_dracoCompression__WEBPACK_IMPORTED_MODULE_0__["Geometry"](babylonMesh.name, _this._loader.babylonScene);
                         var babylonGeometry = new babylonjs_Meshes_Compression_dracoCompression__WEBPACK_IMPORTED_MODULE_0__["Geometry"](babylonMesh.name, _this._loader.babylonScene);
                         babylonVertexData.applyToGeometry(babylonGeometry);
                         babylonVertexData.applyToGeometry(babylonGeometry);
                         return babylonGeometry;
                         return babylonGeometry;
@@ -1570,6 +1572,9 @@ var GLTFLoader = /** @class */ (function () {
             _this._setState(_glTFFileLoader__WEBPACK_IMPORTED_MODULE_1__["GLTFLoaderState"].LOADING);
             _this._setState(_glTFFileLoader__WEBPACK_IMPORTED_MODULE_1__["GLTFLoaderState"].LOADING);
             _this._extensionsOnLoading();
             _this._extensionsOnLoading();
             var promises = new Array();
             var promises = new Array();
+            // Block the marking of materials dirty until the scene is loaded.
+            var oldBlockMaterialDirtyMechanism = _this._babylonScene.blockMaterialDirtyMechanism;
+            _this._babylonScene.blockMaterialDirtyMechanism = true;
             if (nodes) {
             if (nodes) {
                 promises.push(_this.loadSceneAsync("/nodes", { nodes: nodes, index: -1 }));
                 promises.push(_this.loadSceneAsync("/nodes", { nodes: nodes, index: -1 }));
             }
             }
@@ -1577,6 +1582,8 @@ var GLTFLoader = /** @class */ (function () {
                 var scene = ArrayItem.Get("/scene", _this._gltf.scenes, _this._gltf.scene || 0);
                 var scene = ArrayItem.Get("/scene", _this._gltf.scenes, _this._gltf.scene || 0);
                 promises.push(_this.loadSceneAsync("/scenes/" + scene.index, scene));
                 promises.push(_this.loadSceneAsync("/scenes/" + scene.index, scene));
             }
             }
+            // Restore the blocking of material dirty.
+            _this._babylonScene.blockMaterialDirtyMechanism = oldBlockMaterialDirtyMechanism;
             if (_this._parent.compileMaterials) {
             if (_this._parent.compileMaterials) {
                 promises.push(_this._compileMaterialsAsync());
                 promises.push(_this._compileMaterialsAsync());
             }
             }

文件差异内容过多而无法显示
+ 1 - 1
dist/preview release/loaders/babylon.glTF2FileLoader.js.map


文件差异内容过多而无法显示
+ 1 - 1
dist/preview release/loaders/babylon.glTF2FileLoader.min.js


+ 13 - 6
dist/preview release/loaders/babylon.glTFFileLoader.js

@@ -2826,13 +2826,14 @@ var KHR_draco_mesh_compression = /** @class */ (function () {
         this.name = NAME;
         this.name = NAME;
         /** Defines whether this extension is enabled. */
         /** Defines whether this extension is enabled. */
         this.enabled = babylonjs_Meshes_Compression_dracoCompression__WEBPACK_IMPORTED_MODULE_0__["DracoCompression"].DecoderAvailable;
         this.enabled = babylonjs_Meshes_Compression_dracoCompression__WEBPACK_IMPORTED_MODULE_0__["DracoCompression"].DecoderAvailable;
+        this._dracoCompressionOwned = false;
         this._loader = loader;
         this._loader = loader;
     }
     }
     /** @hidden */
     /** @hidden */
     KHR_draco_mesh_compression.prototype.dispose = function () {
     KHR_draco_mesh_compression.prototype.dispose = function () {
-        if (this._dracoCompression) {
-            this._dracoCompression.dispose();
-            delete this._dracoCompression;
+        if (this.dracoCompression && this._dracoCompressionOwned) {
+            this.dracoCompression.dispose();
+            delete this.dracoCompression;
         }
         }
         delete this._loader;
         delete this._loader;
     };
     };
@@ -2873,10 +2874,11 @@ var KHR_draco_mesh_compression = /** @class */ (function () {
             var bufferView = _glTFLoader__WEBPACK_IMPORTED_MODULE_1__["ArrayItem"].Get(extensionContext, _this._loader.gltf.bufferViews, extension.bufferView);
             var bufferView = _glTFLoader__WEBPACK_IMPORTED_MODULE_1__["ArrayItem"].Get(extensionContext, _this._loader.gltf.bufferViews, extension.bufferView);
             if (!bufferView._dracoBabylonGeometry) {
             if (!bufferView._dracoBabylonGeometry) {
                 bufferView._dracoBabylonGeometry = _this._loader.loadBufferViewAsync("#/bufferViews/" + bufferView.index, bufferView).then(function (data) {
                 bufferView._dracoBabylonGeometry = _this._loader.loadBufferViewAsync("#/bufferViews/" + bufferView.index, bufferView).then(function (data) {
-                    if (!_this._dracoCompression) {
-                        _this._dracoCompression = new babylonjs_Meshes_Compression_dracoCompression__WEBPACK_IMPORTED_MODULE_0__["DracoCompression"]();
+                    if (!_this.dracoCompression) {
+                        _this.dracoCompression = new babylonjs_Meshes_Compression_dracoCompression__WEBPACK_IMPORTED_MODULE_0__["DracoCompression"]();
+                        _this._dracoCompressionOwned = true;
                     }
                     }
-                    return _this._dracoCompression.decodeMeshAsync(data, attributes).then(function (babylonVertexData) {
+                    return _this.dracoCompression.decodeMeshAsync(data, attributes).then(function (babylonVertexData) {
                         var babylonGeometry = new babylonjs_Meshes_Compression_dracoCompression__WEBPACK_IMPORTED_MODULE_0__["Geometry"](babylonMesh.name, _this._loader.babylonScene);
                         var babylonGeometry = new babylonjs_Meshes_Compression_dracoCompression__WEBPACK_IMPORTED_MODULE_0__["Geometry"](babylonMesh.name, _this._loader.babylonScene);
                         babylonVertexData.applyToGeometry(babylonGeometry);
                         babylonVertexData.applyToGeometry(babylonGeometry);
                         return babylonGeometry;
                         return babylonGeometry;
@@ -4119,6 +4121,9 @@ var GLTFLoader = /** @class */ (function () {
             _this._setState(_glTFFileLoader__WEBPACK_IMPORTED_MODULE_1__["GLTFLoaderState"].LOADING);
             _this._setState(_glTFFileLoader__WEBPACK_IMPORTED_MODULE_1__["GLTFLoaderState"].LOADING);
             _this._extensionsOnLoading();
             _this._extensionsOnLoading();
             var promises = new Array();
             var promises = new Array();
+            // Block the marking of materials dirty until the scene is loaded.
+            var oldBlockMaterialDirtyMechanism = _this._babylonScene.blockMaterialDirtyMechanism;
+            _this._babylonScene.blockMaterialDirtyMechanism = true;
             if (nodes) {
             if (nodes) {
                 promises.push(_this.loadSceneAsync("/nodes", { nodes: nodes, index: -1 }));
                 promises.push(_this.loadSceneAsync("/nodes", { nodes: nodes, index: -1 }));
             }
             }
@@ -4126,6 +4131,8 @@ var GLTFLoader = /** @class */ (function () {
                 var scene = ArrayItem.Get("/scene", _this._gltf.scenes, _this._gltf.scene || 0);
                 var scene = ArrayItem.Get("/scene", _this._gltf.scenes, _this._gltf.scene || 0);
                 promises.push(_this.loadSceneAsync("/scenes/" + scene.index, scene));
                 promises.push(_this.loadSceneAsync("/scenes/" + scene.index, scene));
             }
             }
+            // Restore the blocking of material dirty.
+            _this._babylonScene.blockMaterialDirtyMechanism = oldBlockMaterialDirtyMechanism;
             if (_this._parent.compileMaterials) {
             if (_this._parent.compileMaterials) {
                 promises.push(_this._compileMaterialsAsync());
                 promises.push(_this._compileMaterialsAsync());
             }
             }

文件差异内容过多而无法显示
+ 1 - 1
dist/preview release/loaders/babylon.glTFFileLoader.js.map


文件差异内容过多而无法显示
+ 2 - 2
dist/preview release/loaders/babylon.glTFFileLoader.min.js


+ 3 - 1
dist/preview release/loaders/babylonjs.loaders.d.ts

@@ -1545,10 +1545,12 @@ declare module BABYLON.GLTF2.Loader.Extensions {
     export class KHR_draco_mesh_compression implements IGLTFLoaderExtension {
     export class KHR_draco_mesh_compression implements IGLTFLoaderExtension {
         /** The name of this extension. */
         /** The name of this extension. */
         readonly name: string;
         readonly name: string;
+        /** The draco compression used to decode vertex data. */
+        dracoCompression?: DracoCompression;
         /** Defines whether this extension is enabled. */
         /** Defines whether this extension is enabled. */
         enabled: boolean;
         enabled: boolean;
         private _loader;
         private _loader;
-        private _dracoCompression?;
+        private _dracoCompressionOwned;
         /** @hidden */
         /** @hidden */
         constructor(loader: GLTFLoader);
         constructor(loader: GLTFLoader);
         /** @hidden */
         /** @hidden */

+ 13 - 6
dist/preview release/loaders/babylonjs.loaders.js

@@ -4158,13 +4158,14 @@ var KHR_draco_mesh_compression = /** @class */ (function () {
         this.name = NAME;
         this.name = NAME;
         /** Defines whether this extension is enabled. */
         /** Defines whether this extension is enabled. */
         this.enabled = babylonjs_Meshes_Compression_dracoCompression__WEBPACK_IMPORTED_MODULE_0__["DracoCompression"].DecoderAvailable;
         this.enabled = babylonjs_Meshes_Compression_dracoCompression__WEBPACK_IMPORTED_MODULE_0__["DracoCompression"].DecoderAvailable;
+        this._dracoCompressionOwned = false;
         this._loader = loader;
         this._loader = loader;
     }
     }
     /** @hidden */
     /** @hidden */
     KHR_draco_mesh_compression.prototype.dispose = function () {
     KHR_draco_mesh_compression.prototype.dispose = function () {
-        if (this._dracoCompression) {
-            this._dracoCompression.dispose();
-            delete this._dracoCompression;
+        if (this.dracoCompression && this._dracoCompressionOwned) {
+            this.dracoCompression.dispose();
+            delete this.dracoCompression;
         }
         }
         delete this._loader;
         delete this._loader;
     };
     };
@@ -4205,10 +4206,11 @@ var KHR_draco_mesh_compression = /** @class */ (function () {
             var bufferView = _glTFLoader__WEBPACK_IMPORTED_MODULE_1__["ArrayItem"].Get(extensionContext, _this._loader.gltf.bufferViews, extension.bufferView);
             var bufferView = _glTFLoader__WEBPACK_IMPORTED_MODULE_1__["ArrayItem"].Get(extensionContext, _this._loader.gltf.bufferViews, extension.bufferView);
             if (!bufferView._dracoBabylonGeometry) {
             if (!bufferView._dracoBabylonGeometry) {
                 bufferView._dracoBabylonGeometry = _this._loader.loadBufferViewAsync("#/bufferViews/" + bufferView.index, bufferView).then(function (data) {
                 bufferView._dracoBabylonGeometry = _this._loader.loadBufferViewAsync("#/bufferViews/" + bufferView.index, bufferView).then(function (data) {
-                    if (!_this._dracoCompression) {
-                        _this._dracoCompression = new babylonjs_Meshes_Compression_dracoCompression__WEBPACK_IMPORTED_MODULE_0__["DracoCompression"]();
+                    if (!_this.dracoCompression) {
+                        _this.dracoCompression = new babylonjs_Meshes_Compression_dracoCompression__WEBPACK_IMPORTED_MODULE_0__["DracoCompression"]();
+                        _this._dracoCompressionOwned = true;
                     }
                     }
-                    return _this._dracoCompression.decodeMeshAsync(data, attributes).then(function (babylonVertexData) {
+                    return _this.dracoCompression.decodeMeshAsync(data, attributes).then(function (babylonVertexData) {
                         var babylonGeometry = new babylonjs_Meshes_Compression_dracoCompression__WEBPACK_IMPORTED_MODULE_0__["Geometry"](babylonMesh.name, _this._loader.babylonScene);
                         var babylonGeometry = new babylonjs_Meshes_Compression_dracoCompression__WEBPACK_IMPORTED_MODULE_0__["Geometry"](babylonMesh.name, _this._loader.babylonScene);
                         babylonVertexData.applyToGeometry(babylonGeometry);
                         babylonVertexData.applyToGeometry(babylonGeometry);
                         return babylonGeometry;
                         return babylonGeometry;
@@ -5451,6 +5453,9 @@ var GLTFLoader = /** @class */ (function () {
             _this._setState(_glTFFileLoader__WEBPACK_IMPORTED_MODULE_1__["GLTFLoaderState"].LOADING);
             _this._setState(_glTFFileLoader__WEBPACK_IMPORTED_MODULE_1__["GLTFLoaderState"].LOADING);
             _this._extensionsOnLoading();
             _this._extensionsOnLoading();
             var promises = new Array();
             var promises = new Array();
+            // Block the marking of materials dirty until the scene is loaded.
+            var oldBlockMaterialDirtyMechanism = _this._babylonScene.blockMaterialDirtyMechanism;
+            _this._babylonScene.blockMaterialDirtyMechanism = true;
             if (nodes) {
             if (nodes) {
                 promises.push(_this.loadSceneAsync("/nodes", { nodes: nodes, index: -1 }));
                 promises.push(_this.loadSceneAsync("/nodes", { nodes: nodes, index: -1 }));
             }
             }
@@ -5458,6 +5463,8 @@ var GLTFLoader = /** @class */ (function () {
                 var scene = ArrayItem.Get("/scene", _this._gltf.scenes, _this._gltf.scene || 0);
                 var scene = ArrayItem.Get("/scene", _this._gltf.scenes, _this._gltf.scene || 0);
                 promises.push(_this.loadSceneAsync("/scenes/" + scene.index, scene));
                 promises.push(_this.loadSceneAsync("/scenes/" + scene.index, scene));
             }
             }
+            // Restore the blocking of material dirty.
+            _this._babylonScene.blockMaterialDirtyMechanism = oldBlockMaterialDirtyMechanism;
             if (_this._parent.compileMaterials) {
             if (_this._parent.compileMaterials) {
                 promises.push(_this._compileMaterialsAsync());
                 promises.push(_this._compileMaterialsAsync());
             }
             }

文件差异内容过多而无法显示
+ 1 - 1
dist/preview release/loaders/babylonjs.loaders.js.map


文件差异内容过多而无法显示
+ 2 - 2
dist/preview release/loaders/babylonjs.loaders.min.js


+ 7 - 2
dist/preview release/loaders/babylonjs.loaders.module.d.ts

@@ -1628,6 +1628,7 @@ declare module "babylonjs-loaders/glTF/2.0/Extensions/EXT_lights_image_based" {
     }
     }
 }
 }
 declare module "babylonjs-loaders/glTF/2.0/Extensions/KHR_draco_mesh_compression" {
 declare module "babylonjs-loaders/glTF/2.0/Extensions/KHR_draco_mesh_compression" {
+    import { DracoCompression } from "babylonjs/Meshes/Compression/dracoCompression";
     import { Nullable } from "babylonjs/types";
     import { Nullable } from "babylonjs/types";
     import { Geometry } from "babylonjs/Meshes/geometry";
     import { Geometry } from "babylonjs/Meshes/geometry";
     import { Mesh } from "babylonjs/Meshes/mesh";
     import { Mesh } from "babylonjs/Meshes/mesh";
@@ -1640,10 +1641,12 @@ declare module "babylonjs-loaders/glTF/2.0/Extensions/KHR_draco_mesh_compression
     export class KHR_draco_mesh_compression implements IGLTFLoaderExtension {
     export class KHR_draco_mesh_compression implements IGLTFLoaderExtension {
         /** The name of this extension. */
         /** The name of this extension. */
         readonly name: string;
         readonly name: string;
+        /** The draco compression used to decode vertex data. */
+        dracoCompression?: DracoCompression;
         /** Defines whether this extension is enabled. */
         /** Defines whether this extension is enabled. */
         enabled: boolean;
         enabled: boolean;
         private _loader;
         private _loader;
-        private _dracoCompression?;
+        private _dracoCompressionOwned;
         /** @hidden */
         /** @hidden */
         constructor(loader: GLTFLoader);
         constructor(loader: GLTFLoader);
         /** @hidden */
         /** @hidden */
@@ -3784,10 +3787,12 @@ declare module BABYLON.GLTF2.Loader.Extensions {
     export class KHR_draco_mesh_compression implements IGLTFLoaderExtension {
     export class KHR_draco_mesh_compression implements IGLTFLoaderExtension {
         /** The name of this extension. */
         /** The name of this extension. */
         readonly name: string;
         readonly name: string;
+        /** The draco compression used to decode vertex data. */
+        dracoCompression?: DracoCompression;
         /** Defines whether this extension is enabled. */
         /** Defines whether this extension is enabled. */
         enabled: boolean;
         enabled: boolean;
         private _loader;
         private _loader;
-        private _dracoCompression?;
+        private _dracoCompressionOwned;
         /** @hidden */
         /** @hidden */
         constructor(loader: GLTFLoader);
         constructor(loader: GLTFLoader);
         /** @hidden */
         /** @hidden */

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

@@ -1 +1 @@
-{"engineOnly":308951,"sceneOnly":510918,"minGridMaterial":634687,"minStandardMaterial":758506}
+{"engineOnly":307125,"sceneOnly":509236,"minGridMaterial":633005,"minStandardMaterial":756824}

文件差异内容过多而无法显示
+ 247 - 248
dist/preview release/viewer/babylon.module.d.ts


+ 1 - 48
dist/preview release/viewer/babylon.viewer.d.ts

@@ -951,7 +951,7 @@ declare module BabylonViewer {
       * @param name the name of the custom optimizer configuration
       * @param name the name of the custom optimizer configuration
       * @param upgrade set to true if you want to upgrade optimizer and false if you want to degrade
       * @param upgrade set to true if you want to upgrade optimizer and false if you want to degrade
       */
       */
-    export function getCustomOptimizerByName(name: string, upgrade?: boolean): typeof extendedUpgrade;
+    export function getCustomOptimizerByName(name: string, upgrade?: boolean): (sceneManager: SceneManager) => boolean;
     export function registerCustomOptimizer(name: string, optimizer: (sceneManager: SceneManager) => boolean): void;
     export function registerCustomOptimizer(name: string, optimizer: (sceneManager: SceneManager) => boolean): void;
 }
 }
 declare module BabylonViewer {
 declare module BabylonViewer {
@@ -1594,20 +1594,6 @@ declare module BabylonViewer {
     export function addLoaderPlugin(name: string, plugin: ILoaderPlugin): void;
     export function addLoaderPlugin(name: string, plugin: ILoaderPlugin): void;
 }
 }
 declare module BabylonViewer {
 declare module BabylonViewer {
-    /**
-        * A custom upgrade-oriented function configuration for the scene optimizer.
-        *
-        * @param viewer the viewer to optimize
-        */
-    export function extendedUpgrade(sceneManager: SceneManager): boolean;
-    /**
-        * A custom degrade-oriented function configuration for the scene optimizer.
-        *
-        * @param viewer the viewer to optimize
-        */
-    export function extendedDegrade(sceneManager: SceneManager): boolean;
-}
-declare module BabylonViewer {
     export interface IEnvironmentMapConfiguration {
     export interface IEnvironmentMapConfiguration {
             /**
             /**
                 * Environment map texture path in relative to the asset folder.
                 * Environment map texture path in relative to the asset folder.
@@ -1781,39 +1767,6 @@ declare module BabylonViewer {
     }
     }
 }
 }
 declare module BabylonViewer {
 declare module BabylonViewer {
-    export interface ICameraConfiguration {
-        position?: {
-            x: number;
-            y: number;
-            z: number;
-        };
-        rotation?: {
-            x: number;
-            y: number;
-            z: number;
-            w: number;
-        };
-        fov?: number;
-        fovMode?: number;
-        minZ?: number;
-        maxZ?: number;
-        inertia?: number;
-        exposure?: number;
-        pinchPrecision?: number;
-        behaviors?: {
-            [name: string]: boolean | number | ICameraBehaviorConfiguration;
-        };
-        disableCameraControl?: boolean;
-        disableCtrlForPanning?: boolean;
-        disableAutoFocus?: boolean;
-        [propName: string]: any;
-    }
-    export interface ICameraBehaviorConfiguration {
-        type: number;
-        [propName: string]: any;
-    }
-}
-declare module BabylonViewer {
     /**
     /**
         * The Color Grading Configuration groups the different settings used to define the color grading used in the viewer.
         * The Color Grading Configuration groups the different settings used to define the color grading used in the viewer.
         */
         */

文件差异内容过多而无法显示
+ 32 - 36
dist/preview release/viewer/babylon.viewer.js


文件差异内容过多而无法显示
+ 2 - 2
dist/preview release/viewer/babylon.viewer.max.js


+ 2 - 49
dist/preview release/viewer/babylon.viewer.module.d.ts

@@ -1031,14 +1031,13 @@ declare module 'babylonjs-viewer/templating/viewerTemplatePlugin' {
 }
 }
 
 
 declare module 'babylonjs-viewer/optimizer/custom' {
 declare module 'babylonjs-viewer/optimizer/custom' {
-    import { extendedUpgrade } from "babylonjs-viewer/optimizer/custom/extended";
     import { SceneManager } from "babylonjs-viewer/managers/sceneManager";
     import { SceneManager } from "babylonjs-viewer/managers/sceneManager";
     /**
     /**
       *
       *
       * @param name the name of the custom optimizer configuration
       * @param name the name of the custom optimizer configuration
       * @param upgrade set to true if you want to upgrade optimizer and false if you want to degrade
       * @param upgrade set to true if you want to upgrade optimizer and false if you want to degrade
       */
       */
-    export function getCustomOptimizerByName(name: string, upgrade?: boolean): typeof extendedUpgrade;
+    export function getCustomOptimizerByName(name: string, upgrade?: boolean): (sceneManager: SceneManager) => boolean;
     export function registerCustomOptimizer(name: string, optimizer: (sceneManager: SceneManager) => boolean): void;
     export function registerCustomOptimizer(name: string, optimizer: (sceneManager: SceneManager) => boolean): void;
 }
 }
 
 
@@ -1738,22 +1737,6 @@ declare module 'babylonjs-viewer/loader/plugins' {
     export function addLoaderPlugin(name: string, plugin: ILoaderPlugin): void;
     export function addLoaderPlugin(name: string, plugin: ILoaderPlugin): void;
 }
 }
 
 
-declare module 'babylonjs-viewer/optimizer/custom/extended' {
-    import { SceneManager } from 'babylonjs-viewer/managers/sceneManager';
-    /**
-        * A custom upgrade-oriented function configuration for the scene optimizer.
-        *
-        * @param viewer the viewer to optimize
-        */
-    export function extendedUpgrade(sceneManager: SceneManager): boolean;
-    /**
-        * A custom degrade-oriented function configuration for the scene optimizer.
-        *
-        * @param viewer the viewer to optimize
-        */
-    export function extendedDegrade(sceneManager: SceneManager): boolean;
-}
-
 declare module 'babylonjs-viewer/configuration/interfaces' {
 declare module 'babylonjs-viewer/configuration/interfaces' {
     export * from 'babylonjs-viewer/configuration/interfaces/cameraConfiguration';
     export * from 'babylonjs-viewer/configuration/interfaces/cameraConfiguration';
     export * from 'babylonjs-viewer/configuration/interfaces/colorGradingConfiguration';
     export * from 'babylonjs-viewer/configuration/interfaces/colorGradingConfiguration';
@@ -1974,37 +1957,7 @@ declare module 'babylonjs-viewer/loader/plugins/extendedMaterialLoaderPlugin' {
 }
 }
 
 
 declare module 'babylonjs-viewer/configuration/interfaces/cameraConfiguration' {
 declare module 'babylonjs-viewer/configuration/interfaces/cameraConfiguration' {
-    export interface ICameraConfiguration {
-        position?: {
-            x: number;
-            y: number;
-            z: number;
-        };
-        rotation?: {
-            x: number;
-            y: number;
-            z: number;
-            w: number;
-        };
-        fov?: number;
-        fovMode?: number;
-        minZ?: number;
-        maxZ?: number;
-        inertia?: number;
-        exposure?: number;
-        pinchPrecision?: number;
-        behaviors?: {
-            [name: string]: boolean | number | ICameraBehaviorConfiguration;
-        };
-        disableCameraControl?: boolean;
-        disableCtrlForPanning?: boolean;
-        disableAutoFocus?: boolean;
-        [propName: string]: any;
-    }
-    export interface ICameraBehaviorConfiguration {
-        type: number;
-        [propName: string]: any;
-    }
+    
 }
 }
 
 
 declare module 'babylonjs-viewer/configuration/interfaces/colorGradingConfiguration' {
 declare module 'babylonjs-viewer/configuration/interfaces/colorGradingConfiguration' {

+ 7 - 2
dist/preview release/viewer/babylonjs.loaders.module.d.ts

@@ -1628,6 +1628,7 @@ declare module "babylonjs-loaders/glTF/2.0/Extensions/EXT_lights_image_based" {
     }
     }
 }
 }
 declare module "babylonjs-loaders/glTF/2.0/Extensions/KHR_draco_mesh_compression" {
 declare module "babylonjs-loaders/glTF/2.0/Extensions/KHR_draco_mesh_compression" {
+    import { DracoCompression } from "babylonjs/Meshes/Compression/dracoCompression";
     import { Nullable } from "babylonjs/types";
     import { Nullable } from "babylonjs/types";
     import { Geometry } from "babylonjs/Meshes/geometry";
     import { Geometry } from "babylonjs/Meshes/geometry";
     import { Mesh } from "babylonjs/Meshes/mesh";
     import { Mesh } from "babylonjs/Meshes/mesh";
@@ -1640,10 +1641,12 @@ declare module "babylonjs-loaders/glTF/2.0/Extensions/KHR_draco_mesh_compression
     export class KHR_draco_mesh_compression implements IGLTFLoaderExtension {
     export class KHR_draco_mesh_compression implements IGLTFLoaderExtension {
         /** The name of this extension. */
         /** The name of this extension. */
         readonly name: string;
         readonly name: string;
+        /** The draco compression used to decode vertex data. */
+        dracoCompression?: DracoCompression;
         /** Defines whether this extension is enabled. */
         /** Defines whether this extension is enabled. */
         enabled: boolean;
         enabled: boolean;
         private _loader;
         private _loader;
-        private _dracoCompression?;
+        private _dracoCompressionOwned;
         /** @hidden */
         /** @hidden */
         constructor(loader: GLTFLoader);
         constructor(loader: GLTFLoader);
         /** @hidden */
         /** @hidden */
@@ -3784,10 +3787,12 @@ declare module BABYLON.GLTF2.Loader.Extensions {
     export class KHR_draco_mesh_compression implements IGLTFLoaderExtension {
     export class KHR_draco_mesh_compression implements IGLTFLoaderExtension {
         /** The name of this extension. */
         /** The name of this extension. */
         readonly name: string;
         readonly name: string;
+        /** The draco compression used to decode vertex data. */
+        dracoCompression?: DracoCompression;
         /** Defines whether this extension is enabled. */
         /** Defines whether this extension is enabled. */
         enabled: boolean;
         enabled: boolean;
         private _loader;
         private _loader;
-        private _dracoCompression?;
+        private _dracoCompressionOwned;
         /** @hidden */
         /** @hidden */
         constructor(loader: GLTFLoader);
         constructor(loader: GLTFLoader);
         /** @hidden */
         /** @hidden */

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

@@ -57,7 +57,7 @@
   - Added an option `useClonedMeshhMap` in the `Scene` constructor options. When set to true, each `Mesh` will have and will keep up-to-date a map of cloned meshes. This is to avoid browsing all the meshes of the scene to retrieve the ones that have the current mesh as source mesh. Disabled by default
   - Added an option `useClonedMeshhMap` in the `Scene` constructor options. When set to true, each `Mesh` will have and will keep up-to-date a map of cloned meshes. This is to avoid browsing all the meshes of the scene to retrieve the ones that have the current mesh as source mesh. Disabled by default
   - Added `blockfreeActiveMeshesAndRenderingGroups` property in the `Scene`, following the same model as `blockMaterialDirtyMechanism`. This is to avoid calling `Scene.freeActiveMeshes` and `Scene.freeRenderingGroups` for each disposed mesh when we dispose several meshes in a row. One have to set `blockfreeActiveMeshesAndRenderingGroups` to `true` just before disposing the meshes, and set it back to `false` just after
   - Added `blockfreeActiveMeshesAndRenderingGroups` property in the `Scene`, following the same model as `blockMaterialDirtyMechanism`. This is to avoid calling `Scene.freeActiveMeshes` and `Scene.freeRenderingGroups` for each disposed mesh when we dispose several meshes in a row. One have to set `blockfreeActiveMeshesAndRenderingGroups` to `true` just before disposing the meshes, and set it back to `false` just after
   - Prevented code from doing useless and possible time consuming computation when disposing the `ShaderMaterial` of a `LinesMesh`
   - Prevented code from doing useless and possible time consuming computation when disposing the `ShaderMaterial` of a `LinesMesh`
-  - Make a better use of the `isIdentity` cached value wihtin a `Matrix`
+  - Make a better use of the `isIdentity` cached value within a `Matrix`
   - Make sure we browse all the submeshes only once in `Material.markAsDirty` function
   - Make sure we browse all the submeshes only once in `Material.markAsDirty` function
   - Added an `Vector3.UnprojectRayToRef` static function to avoid computing and inverting the projection matrix twice when updating a Ray.
   - Added an `Vector3.UnprojectRayToRef` static function to avoid computing and inverting the projection matrix twice when updating a Ray.
 - Added per mesh culling strategy ([jerome](https://github.com/jbousquie))
 - Added per mesh culling strategy ([jerome](https://github.com/jbousquie))
@@ -135,6 +135,11 @@
 - Added customShaderNameResolve to PBRMaterialBase to allow subclasses to specify custom shader information [MackeyK24](https://github.com/mackeyk24))
 - Added customShaderNameResolve to PBRMaterialBase to allow subclasses to specify custom shader information [MackeyK24](https://github.com/mackeyk24))
 - Added PBRCustomMaterial to material library to allow easy subclassing of PBR materials [MackeyK24](https://github.com/mackeyk24))
 - Added PBRCustomMaterial to material library to allow easy subclassing of PBR materials [MackeyK24](https://github.com/mackeyk24))
 - Added `auto-exposure` support in `StandardRenderingPipeline` when `HDR` is enabled ([julien-moreau](https://github.com/julien-moreau))
 - Added `auto-exposure` support in `StandardRenderingPipeline` when `HDR` is enabled ([julien-moreau](https://github.com/julien-moreau))
+- Add `EquiRectangularCubeTexture` class to enable the usage of browser-canvas supported images as `CubeTexture`'s ([Dennis Dervisis](https://github.com/ddervisis))
+- Add `EquiRectangularCubeTextureAssetTask` to be able to load `EquiRectangularCubeTextures`s via Asset Manager ([Dennis Dervisis](https://github.com/ddervisis))
+- Added `Matrix.RotationAlignToRef` method to obtain rotation matrix from one vector to another ([sable](https://github.com/thscott))
+- ArcRotateCamera will now cache the necessary matrices when modifying its upVector, instead of calculating them each time they're needed ([sable](https://github.com/thscott))
+- Update `DracoCompression` to use web workers ([bghgary](https://github.com/bghgary))
 
 
 ### OBJ Loader
 ### OBJ Loader
 - Add color vertex support (not part of standard) ([brianzinn](https://github.com/brianzinn))
 - Add color vertex support (not part of standard) ([brianzinn](https://github.com/brianzinn))
@@ -150,8 +155,7 @@
 - Skinned meshes now behave as intended by glTF ([bghgary](https://github.com/bghgary))
 - Skinned meshes now behave as intended by glTF ([bghgary](https://github.com/bghgary))
   - Skinned meshes now set an override mesh instead of reparenting to the `__root__` transform node
   - Skinned meshes now set an override mesh instead of reparenting to the `__root__` transform node
   - Loaded bones are linked with the transform node created for the corresponding glTF node
   - Loaded bones are linked with the transform node created for the corresponding glTF node
-- Add `EquiRectangularCubeTexture` class to enable the usage of browser-canvas supported images as `CubeTexture`'s ([Dennis Dervisis](https://github.com/ddervisis))
-- Add `EquiRectangularCubeTextureAssetTask` to be able to load `EquiRectangularCubeTextures`s via Asset Manager ([Dennis Dervisis](https://github.com/ddervisis))
+- Improve load performance by blocking material dirtying during load ([bghgary](https://github.com/bghgary))
 
 
 ### glTF Serializer
 ### glTF Serializer
 
 
@@ -170,6 +174,7 @@
 ### Infrastructure
 ### Infrastructure
 
 
 - Migrating CI to Azure DevOps pipelines ([Sebavan](https://github.com/Sebavan))
 - Migrating CI to Azure DevOps pipelines ([Sebavan](https://github.com/Sebavan))
+- Test both WebGL1 and WebGL2 ([Sebavan](https://github.com/Sebavan))
 
 
 ### Viewer
 ### Viewer
 
 
@@ -218,6 +223,8 @@
 - Fix `mesh.visibility` not working properly when certain material properties are set that changes the interpretation of alpha (e.g. refraction, specular over alpha, etc.) ([bghgary](https://github.com/bghgary))
 - Fix `mesh.visibility` not working properly when certain material properties are set that changes the interpretation of alpha (e.g. refraction, specular over alpha, etc.) ([bghgary](https://github.com/bghgary))
 - Fix material and texture leak when loading/removing GLTF/obj/babylon files with AssetContainer ([TrevorDev](https://github.com/TrevorDev))
 - Fix material and texture leak when loading/removing GLTF/obj/babylon files with AssetContainer ([TrevorDev](https://github.com/TrevorDev))
 - Avoid exception when removing impostor during cannon world step ([TrevorDev](https://github.com/TrevorDev))
 - Avoid exception when removing impostor during cannon world step ([TrevorDev](https://github.com/TrevorDev))
+- Fix ArcRotateCamera divide by zero error (when looking along up axis) in rebuildAnglesAndRadius ([sable](https://github.com/thscott))
+- Fix ArcRotateCamera rebuildAnglesAndRadius when upVector modified ([sable](https://github.com/thscott))
 
 
 ### Core Engine
 ### Core Engine
 - Fixed a bug with `mesh.alwaysSelectAsActiveMesh` preventing layerMask to be taken in account ([Deltakosh](https://github.com/deltakosh))
 - Fixed a bug with `mesh.alwaysSelectAsActiveMesh` preventing layerMask to be taken in account ([Deltakosh](https://github.com/deltakosh))

+ 0 - 1
inspector/src/components/actionTabs/tabs/statisticsTabComponent.tsx

@@ -82,7 +82,6 @@ export class StatisticsTabComponent extends PaneComponent {
                     <TextLineComponent label="Active bones" value={scene.getActiveBones().toString()} />
                     <TextLineComponent label="Active bones" value={scene.getActiveBones().toString()} />
                     <TextLineComponent label="Active particles" value={scene.getActiveParticles().toString()} />
                     <TextLineComponent label="Active particles" value={scene.getActiveParticles().toString()} />
                     <TextLineComponent label="Draw calls" value={sceneInstrumentation.drawCallsCounter.current.toString()} />
                     <TextLineComponent label="Draw calls" value={sceneInstrumentation.drawCallsCounter.current.toString()} />
-                    <TextLineComponent label="Texture collisions" value={sceneInstrumentation.textureCollisionsCounter.current.toString()} />
                     <TextLineComponent label="Total lights" value={scene.lights.length.toString()} />
                     <TextLineComponent label="Total lights" value={scene.lights.length.toString()} />
                     <TextLineComponent label="Total vertices" value={scene.getTotalVertices().toString()} />
                     <TextLineComponent label="Total vertices" value={scene.getTotalVertices().toString()} />
                     <TextLineComponent label="Total materials" value={scene.materials.length.toString()} />
                     <TextLineComponent label="Total materials" value={scene.materials.length.toString()} />

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

@@ -27,11 +27,14 @@ export class KHR_draco_mesh_compression implements IGLTFLoaderExtension {
     /** The name of this extension. */
     /** The name of this extension. */
     public readonly name = NAME;
     public readonly name = NAME;
 
 
+    /** The draco compression used to decode vertex data. */
+    public dracoCompression?: DracoCompression;
+
     /** Defines whether this extension is enabled. */
     /** Defines whether this extension is enabled. */
     public enabled = DracoCompression.DecoderAvailable;
     public enabled = DracoCompression.DecoderAvailable;
 
 
     private _loader: GLTFLoader;
     private _loader: GLTFLoader;
-    private _dracoCompression?: DracoCompression;
+    private _dracoCompressionOwned = false;
 
 
     /** @hidden */
     /** @hidden */
     constructor(loader: GLTFLoader) {
     constructor(loader: GLTFLoader) {
@@ -40,9 +43,9 @@ export class KHR_draco_mesh_compression implements IGLTFLoaderExtension {
 
 
     /** @hidden */
     /** @hidden */
     public dispose(): void {
     public dispose(): void {
-        if (this._dracoCompression) {
-            this._dracoCompression.dispose();
-            delete this._dracoCompression;
+        if (this.dracoCompression && this._dracoCompressionOwned) {
+            this.dracoCompression.dispose();
+            delete this.dracoCompression;
         }
         }
 
 
         delete this._loader;
         delete this._loader;
@@ -90,11 +93,12 @@ export class KHR_draco_mesh_compression implements IGLTFLoaderExtension {
             var bufferView = ArrayItem.Get(extensionContext, this._loader.gltf.bufferViews, extension.bufferView) as IBufferViewDraco;
             var bufferView = ArrayItem.Get(extensionContext, this._loader.gltf.bufferViews, extension.bufferView) as IBufferViewDraco;
             if (!bufferView._dracoBabylonGeometry) {
             if (!bufferView._dracoBabylonGeometry) {
                 bufferView._dracoBabylonGeometry = this._loader.loadBufferViewAsync(`#/bufferViews/${bufferView.index}`, bufferView).then((data) => {
                 bufferView._dracoBabylonGeometry = this._loader.loadBufferViewAsync(`#/bufferViews/${bufferView.index}`, bufferView).then((data) => {
-                    if (!this._dracoCompression) {
-                        this._dracoCompression = new DracoCompression();
+                    if (!this.dracoCompression) {
+                        this.dracoCompression = new DracoCompression();
+                        this._dracoCompressionOwned = true;
                     }
                     }
 
 
-                    return this._dracoCompression.decodeMeshAsync(data, attributes).then((babylonVertexData) => {
+                    return this.dracoCompression.decodeMeshAsync(data, attributes).then((babylonVertexData) => {
                         const babylonGeometry = new Geometry(babylonMesh.name, this._loader.babylonScene);
                         const babylonGeometry = new Geometry(babylonMesh.name, this._loader.babylonScene);
                         babylonVertexData.applyToGeometry(babylonGeometry);
                         babylonVertexData.applyToGeometry(babylonGeometry);
                         return babylonGeometry;
                         return babylonGeometry;

+ 7 - 0
loaders/src/glTF/2.0/glTFLoader.ts

@@ -273,6 +273,10 @@ export class GLTFLoader implements IGLTFLoader {
 
 
             const promises = new Array<Promise<any>>();
             const promises = new Array<Promise<any>>();
 
 
+            // Block the marking of materials dirty until the scene is loaded.
+            const oldBlockMaterialDirtyMechanism = this._babylonScene.blockMaterialDirtyMechanism;
+            this._babylonScene.blockMaterialDirtyMechanism = true;
+
             if (nodes) {
             if (nodes) {
                 promises.push(this.loadSceneAsync("/nodes", { nodes: nodes, index: -1 }));
                 promises.push(this.loadSceneAsync("/nodes", { nodes: nodes, index: -1 }));
             }
             }
@@ -281,6 +285,9 @@ export class GLTFLoader implements IGLTFLoader {
                 promises.push(this.loadSceneAsync(`/scenes/${scene.index}`, scene));
                 promises.push(this.loadSceneAsync(`/scenes/${scene.index}`, scene));
             }
             }
 
 
+            // Restore the blocking of material dirty.
+            this._babylonScene.blockMaterialDirtyMechanism = oldBlockMaterialDirtyMechanism;
+
             if (this._parent.compileMaterials) {
             if (this._parent.compileMaterials) {
                 promises.push(this._compileMaterialsAsync());
                 promises.push(this._compileMaterialsAsync());
             }
             }

+ 3 - 3
package.json

@@ -75,7 +75,6 @@
         "karma-chai": "^0.1.0",
         "karma-chai": "^0.1.0",
         "karma-chrome-launcher": "^2.2.0",
         "karma-chrome-launcher": "^2.2.0",
         "karma-firefox-launcher": "^1.1.0",
         "karma-firefox-launcher": "^1.1.0",
-        "karma-junit-reporter": "^1.2.0",
         "karma-mocha": "^1.3.0",
         "karma-mocha": "^1.3.0",
         "karma-sinon": "^1.0.5",
         "karma-sinon": "^1.0.5",
         "merge2": "~1.2.2",
         "merge2": "~1.2.2",
@@ -104,6 +103,7 @@
         "webpack-cli": "^3.1.2",
         "webpack-cli": "^3.1.2",
         "webpack-dev-server": "^3.1.14",
         "webpack-dev-server": "^3.1.14",
         "webpack-stream": "5.0.0",
         "webpack-stream": "5.0.0",
-        "xhr2": "^0.1.4"
+        "xhr2": "^0.1.4",
+        "xmlbuilder": "8.2.2"
     }
     }
-}
+}

+ 1 - 1
readme.md

@@ -3,7 +3,7 @@
 Getting started? Play directly with the Babylon.js API using our [playground](https://playground.babylonjs.com/). It also contains a lot of samples to learn how to use it.
 Getting started? Play directly with the Babylon.js API using our [playground](https://playground.babylonjs.com/). It also contains a lot of samples to learn how to use it.
 
 
 [![npm version](https://badge.fury.io/js/babylonjs.svg)](https://badge.fury.io/js/babylonjs)
 [![npm version](https://badge.fury.io/js/babylonjs.svg)](https://badge.fury.io/js/babylonjs)
-[![Build Status](https://travis-ci.com/BabylonJS/Babylon.js.svg?branch=master)](https://travis-ci.com/BabylonJS/Babylon.js)
+[![Build Status](https://dev.azure.com/babylonjs/ContinousIntegration/_apis/build/status/CI?branchName=master)](https://dev.azure.com/babylonjs/ContinousIntegration/_build/latest?definitionId=1&branchName=master)
 [![Average time to resolve an issue](http://isitmaintained.com/badge/resolution/BabylonJS/Babylon.js.svg)](http://isitmaintained.com/project/BabylonJS/Babylon.js "Average time to resolve an issue")
 [![Average time to resolve an issue](http://isitmaintained.com/badge/resolution/BabylonJS/Babylon.js.svg)](http://isitmaintained.com/project/BabylonJS/Babylon.js "Average time to resolve an issue")
 [![Percentage of issues still open](https://isitmaintained.com/badge/open/babylonJS/babylon.js.svg)](https://isitmaintained.com/project/babylonJS/babylon.js "Percentage of issues still open")
 [![Percentage of issues still open](https://isitmaintained.com/badge/open/babylonJS/babylon.js.svg)](https://isitmaintained.com/project/babylonJS/babylon.js "Percentage of issues still open")
 [![Build Size](https://img.badgesize.io/BabylonJS/Babylon.js/master/dist/preview%20release/babylon.js.svg?compression=gzip)](https://img.badgesize.io/BabylonJS/Babylon.js/master/dist/preview%20release/babylon.js.svg?compression=gzip)
 [![Build Size](https://img.badgesize.io/BabylonJS/Babylon.js/master/dist/preview%20release/babylon.js.svg?compression=gzip)](https://img.badgesize.io/BabylonJS/Babylon.js/master/dist/preview%20release/babylon.js.svg?compression=gzip)

+ 91 - 0
sandbox/debug.html

@@ -0,0 +1,91 @@
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml">
+
+<head>
+    <title>BabylonJS Sandbox - View glTF, glb, obj and babylon files</title>
+    <meta name="description" content="Viewer for glTF, glb, obj and babylon files powered by BabylonJS" />
+    <meta name="keywords"
+        content="Babylon.js, Babylon, BabylonJS, glTF, glb, obj, viewer, online viewer, 3D model viewer, 3D, webgl" />
+    <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1">
+
+    <link rel="shortcut icon" href="https://www.babylonjs.com/img/favicon/favicon.ico">
+    <link rel="apple-touch-icon" sizes="57x57" href="https://www.babylonjs.com/img/favicon/apple-icon-57x57.png">
+    <link rel="apple-touch-icon" sizes="60x60" href="https://www.babylonjs.com/img/favicon/apple-icon-60x60.png">
+    <link rel="apple-touch-icon" sizes="72x72" href="https://www.babylonjs.com/img/favicon/apple-icon-72x72.png">
+    <link rel="apple-touch-icon" sizes="76x76" href="https://www.babylonjs.com/img/favicon/apple-icon-76x76.png">
+    <link rel="apple-touch-icon" sizes="114x114" href="https://www.babylonjs.com/img/favicon/apple-icon-114x114.png">
+    <link rel="apple-touch-icon" sizes="120x120" href="https://www.babylonjs.com/img/favicon/apple-icon-120x120.png">
+    <link rel="apple-touch-icon" sizes="144x144" href="https://www.babylonjs.com/img/favicon/apple-icon-144x144.png">
+    <link rel="apple-touch-icon" sizes="152x152" href="https://www.babylonjs.com/img/favicon/apple-icon-152x152.png">
+    <link rel="apple-touch-icon" sizes="180x180" href="https://www.babylonjs.com/img/favicon/apple-icon-180x180.png">
+    <link rel="icon" type="image/png" sizes="192x192"
+        href="https://www.babylonjs.com/img/favicon/android-icon-192x192.png">
+    <link rel="icon" type="image/png" sizes="32x32" href="https://www.babylonjs.com/img/favicon/favicon-32x32.png">
+    <link rel="icon" type="image/png" sizes="96x96" href="https://www.babylonjs.com/img/favicon/favicon-96x96.png">
+    <link rel="icon" type="image/png" sizes="16x16" href="https://www.babylonjs.com/img/favicon/favicon-16x16.png">
+    <link rel="manifest" href="https://www.babylonjs.com/img/favicon/manifest.json">
+    <meta name="msapplication-TileColor" content="#ffffff">
+    <meta name="msapplication-TileImage" content="https://www.babylonjs.com/img/favicon/ms-icon-144x144.png">
+    <meta name="msapplication-config" content="https://www.babylonjs.com/img/favicon/browserconfig.xml">
+    <meta name="theme-color" content="#ffffff">
+
+    <link href="index.css" rel="stylesheet" />
+    <script src="https://code.jquery.com/pep/0.4.2/pep.min.js"></script>
+    <script src="https://playground.babylonjs.com/js/libs/split.js"></script>
+
+    <script src="https://preview.babylonjs.com/ammo.js"></script>
+    <script src="https://preview.babylonjs.com/cannon.js"></script>
+    <script src="https://preview.babylonjs.com/Oimo.js"></script>
+    <script src="https://preview.babylonjs.com/gltf_validator.js"></script>
+    <script src="https://preview.babylonjs.com/babylon.max.js"></script>
+    <script src="https://preview.babylonjs.com/inspector/babylon.inspector.bundle.js"></script>
+
+    <script src="https://preview.babylonjs.com/loaders/babylonjs.loaders.js"></script>
+    <script src="https://preview.babylonjs.com/serializers/babylonjs.serializers.js"></script>
+    <script src="https://preview.babylonjs.com/materialsLibrary/babylonjs.materials.js"></script>
+</head>
+
+<body>
+    <div id="root">
+        <p id="droptext">Drag and drop gltf, glb, obj or babylon files to view them</p>
+        <div id="canvasZone">
+            <canvas id="renderCanvas" touch-action="none"></canvas>
+        </div>
+        <div id="footer" class="footer">
+            <div id="animationBar">
+                <div class="dropdown">
+                    <div id="dropdownBtn">
+                        <img src="Assets/Icon_Up.svg" id="chevronUp">
+                        <img src="Assets/Icon_Down.svg" id="chevronDown">
+                        <span id="dropdownLabel"></span>
+                    </div>
+                    <div id="dropdownContent">
+                    </div>
+                </div>
+                <div class="row">
+                    <button id="playBtn" class="pause">
+                        <img id="playImg" src="Assets/Icon_Play.svg">
+                        <img id="pauseImg" src="Assets/Icon_Pause.svg">
+                    </button>
+                    <input id="slider" type="range" min="0" max="100" value="0" step="any">
+                </div>
+            </div>
+            <div class="footerRight">
+                <a href="javascript:void(null);" id="btnInspector" class="hidden"><img src="./Assets/Icon_EditModel.svg"
+                        alt="Display inspector" title="Display inspector" /></a>
+                <a href="javascript:void(null);">
+                    <div class="custom-upload"
+                        title="Open your scene from your hard drive (.babylon, .gltf, .glb, .obj)">
+                        <input type="file" id="files" multiple />
+                    </div>
+                </a>
+            </div>
+        </div>
+        <div id="logo">
+        </div>
+        <div id="errorZone"></div>
+    </div>
+    <script src="index.js"></script>
+</body>
+
+</html>

+ 10 - 1
sandbox/index.js

@@ -112,7 +112,7 @@ if (BABYLON.Engine.isSupported()) {
             }
             }
             currentGroup = babylonScene.animationGroups[0];
             currentGroup = babylonScene.animationGroups[0];
             currentGroupIndex = 0;
             currentGroupIndex = 0;
-            document.getElementById(formatId(currentGroup.name + "-" + currentGroupIndex)).click();
+            currentGroup.play(true);
         }
         }
 
 
         // Sync the slider with the current frame
         // Sync the slider with the current frame
@@ -213,6 +213,15 @@ if (BABYLON.Engine.isSupported()) {
         if (debugLayerEnabled) {
         if (debugLayerEnabled) {
             currentScene.debugLayer.show();
             currentScene.debugLayer.show();
         }
         }
+
+        currentScene.dispatchAllSubMeshesOfActiveMeshes = true;
+        currentScene.meshes.forEach((mesh) => mesh.alwaysSelectAsActiveMesh = true);
+        currentScene.getEngine().disableTextureBindingOptimization = true;
+        currentScene.meshes.forEach((mesh) => mesh.doNotSyncBoundingInfo = true);
+        currentScene.materials.forEach((mat) => mat.freeze());
+
+        currentScene.meshes.forEach((mesh) => mesh.ignoreNonUniformScaling = true);
+        currentScene.transformNodes.forEach((node) => node.ignoreNonUniformScaling = true);
     };
     };
 
 
     var sceneError = function(sceneFile, babylonScene, message) {
     var sceneError = function(sceneFile, babylonScene, message) {

+ 1 - 1
src/Actions/actionEvent.ts

@@ -59,7 +59,7 @@ export class ActionEvent implements IActionEvent {
      */
      */
     public static CreateNew(source: AbstractMesh, evt?: Event, additionalData?: any): ActionEvent {
     public static CreateNew(source: AbstractMesh, evt?: Event, additionalData?: any): ActionEvent {
         var scene = source.getScene();
         var scene = source.getScene();
-        return new ActionEvent(source, scene.pointerX, scene.pointerY, scene.meshUnderPointer, evt, additionalData);
+        return new ActionEvent(source, scene.pointerX, scene.pointerY, scene.meshUnderPointer || source, evt, additionalData);
     }
     }
 
 
     /**
     /**

+ 1 - 1
src/Animations/animatable.ts

@@ -259,7 +259,7 @@ export class Animatable {
             var fps = runtimeAnimations[0].animation.framePerSecond;
             var fps = runtimeAnimations[0].animation.framePerSecond;
             var currentFrame = runtimeAnimations[0].currentFrame;
             var currentFrame = runtimeAnimations[0].currentFrame;
             var adjustTime = frame - currentFrame;
             var adjustTime = frame - currentFrame;
-            var delay = adjustTime * 1000 / (fps * this.speedRatio);
+            var delay = this.speedRatio !== 0 ? adjustTime * 1000 / (fps * this.speedRatio) : 0;
             if (this._localDelayOffset === null) {
             if (this._localDelayOffset === null) {
                 this._localDelayOffset = 0;
                 this._localDelayOffset = 0;
             }
             }

+ 81 - 43
src/Animations/runtimeAnimation.ts

@@ -96,7 +96,8 @@ export class RuntimeAnimation {
     /**
     /**
      * The active target of the runtime animation
      * The active target of the runtime animation
      */
      */
-    private _activeTarget: any;
+    private _activeTargets: any[];
+    private _currentActiveTarget: any;
 
 
     /**
     /**
      * The target path of the runtime animation
      * The target path of the runtime animation
@@ -123,6 +124,9 @@ export class RuntimeAnimation {
      */
      */
     private _previousRatio: number = 0;
     private _previousRatio: number = 0;
 
 
+    private _enableBlending: boolean;
+    private _correctLoopMode: number | undefined;
+
     /**
     /**
      * Gets the current frame of the runtime animation
      * Gets the current frame of the runtime animation
      */
      */
@@ -155,7 +159,7 @@ export class RuntimeAnimation {
      * Gets the actual target of the runtime animation
      * Gets the actual target of the runtime animation
      */
      */
     public get target(): any {
     public get target(): any {
-        return this._activeTarget;
+        return this._currentActiveTarget;
     }
     }
 
 
     /**
     /**
@@ -170,9 +174,24 @@ export class RuntimeAnimation {
         this._target = target;
         this._target = target;
         this._scene = scene;
         this._scene = scene;
         this._host = host;
         this._host = host;
+        this._activeTargets = [];
 
 
         animation._runtimeAnimations.push(this);
         animation._runtimeAnimations.push(this);
 
 
+        // Check data
+        if (this._target instanceof Array) {
+            var index = 0;
+            for (const target of this._target) {
+                this._preparePath(target, index);
+                this._getOriginalValues(index);
+                index++;
+            }
+        }
+        else {
+            this._preparePath(this._target);
+            this._getOriginalValues();
+        }
+
         // Cloning events locally
         // Cloning events locally
         var events = animation.getEvents();
         var events = animation.getEvents();
         if (events && events.length > 0) {
         if (events && events.length > 0) {
@@ -180,6 +199,33 @@ export class RuntimeAnimation {
                 this._events.push(e._clone());
                 this._events.push(e._clone());
             });
             });
         }
         }
+
+        this._correctLoopMode = this._getCorrectLoopMode();
+        this._enableBlending = target && target.animationPropertiesOverride ? target.animationPropertiesOverride.enableBlending : this._animation.enableBlending;
+
+        if (this._enableBlending) {
+            this._activeBlendingProcessor = this._blendingProcessor;
+        } else {
+            this._activeBlendingProcessor = this._noBlendingProcessor;
+        }
+    }
+
+    private _preparePath(target: any, targetIndex = 0) {
+        let targetPropertyPath = this._animation.targetPropertyPath;
+
+        if (targetPropertyPath.length > 1) {
+            var property = target[targetPropertyPath[0]];
+
+            for (var index = 1; index < targetPropertyPath.length - 1; index++) {
+                property = property[targetPropertyPath[index]];
+            }
+
+            this._targetPath = targetPropertyPath[targetPropertyPath.length - 1];
+            this._activeTargets[targetIndex] = property;
+        } else {
+            this._targetPath = targetPropertyPath[0];
+            this._activeTargets[targetIndex] = target;
+        }
     }
     }
 
 
     /**
     /**
@@ -279,52 +325,33 @@ export class RuntimeAnimation {
         }
         }
     }
     }
 
 
-    private _setValue(target: any, currentValue: any, weight: number, targetIndex = 0): void {
-        // Set value
-        var path: any;
-        var destination: any;
-
-        let targetPropertyPath = this._animation.targetPropertyPath;
-
-        if (targetPropertyPath.length > 1) {
-            var property = target[targetPropertyPath[0]];
-
-            for (var index = 1; index < targetPropertyPath.length - 1; index++) {
-                property = property[targetPropertyPath[index]];
-            }
+    private _getOriginalValues(targetIndex = 0) {
+        let originalValue: any;
+        let target = this._activeTargets[targetIndex];
 
 
-            path = targetPropertyPath[targetPropertyPath.length - 1];
-            destination = property;
+        if (target.getRestPose && this._targetPath === "_matrix") { // For bones
+            originalValue = target.getRestPose();
         } else {
         } else {
-            path = targetPropertyPath[0];
-            destination = target;
+            originalValue = target[this._targetPath];
         }
         }
 
 
-        this._targetPath = path;
-        this._activeTarget = destination;
-        this._weight = weight;
-
-        if (this._originalValue[targetIndex] === undefined) {
-            let originalValue: any;
+        if (originalValue && originalValue.clone) {
+            this._originalValue[targetIndex] = originalValue.clone();
+        } else {
+            this._originalValue[targetIndex] = originalValue;
+        }
+    }
 
 
-            if (destination.getRestPose && path === "_matrix") { // For bones
-                originalValue = destination.getRestPose();
-            } else {
-                originalValue = destination[path];
-            }
+    private _activeBlendingProcessor: (currentValue: any, target: any) => void;
 
 
-            if (originalValue && originalValue.clone) {
-                this._originalValue[targetIndex] = originalValue.clone();
-            } else {
-                this._originalValue[targetIndex] = originalValue;
-            }
-        }
+    private _noBlendingProcessor = (currentValue: any) => {
+        this._currentValue = currentValue;
+    }
 
 
-        // Blending
-        const enableBlending = target && target.animationPropertiesOverride ? target.animationPropertiesOverride.enableBlending : this._animation.enableBlending;
-        if (enableBlending && this._blendingFactor <= 1.0) {
+    private _blendingProcessor = (currentValue: any, target: any) => {
+        if (this._blendingFactor <= 1.0) {
             if (!this._originalBlendValue) {
             if (!this._originalBlendValue) {
-                let originalValue = destination[path];
+                let originalValue = this._currentActiveTarget[this._targetPath];
 
 
                 if (originalValue.clone) {
                 if (originalValue.clone) {
                     this._originalBlendValue = originalValue.clone();
                     this._originalBlendValue = originalValue.clone();
@@ -356,6 +383,17 @@ export class RuntimeAnimation {
         } else {
         } else {
             this._currentValue = currentValue;
             this._currentValue = currentValue;
         }
         }
+    }
+
+    private _setValue(target: any, currentValue: any, weight: number, targetIndex = 0): void {
+        // Set value
+        var path = this._targetPath;
+        var destination = this._activeTargets[targetIndex];
+        this._currentActiveTarget = destination;
+
+        this._weight = weight;
+
+        this._activeBlendingProcessor(currentValue, target);
 
 
         if (weight !== -1.0) {
         if (weight !== -1.0) {
             this._scene._registerTargetForLateAnimationBinding(this, this._originalValue[targetIndex]);
             this._scene._registerTargetForLateAnimationBinding(this, this._originalValue[targetIndex]);
@@ -393,7 +431,7 @@ export class RuntimeAnimation {
             frame = keys[keys.length - 1].frame;
             frame = keys[keys.length - 1].frame;
         }
         }
 
 
-        var currentValue = this._interpolate(frame, 0, this._getCorrectLoopMode());
+        var currentValue = this._interpolate(frame, 0, this._correctLoopMode);
 
 
         this.setValue(currentValue, -1);
         this.setValue(currentValue, -1);
     }
     }
@@ -464,7 +502,7 @@ export class RuntimeAnimation {
         } else {
         } else {
             // Get max value if required
             // Get max value if required
 
 
-            if (this._getCorrectLoopMode() !== Animation.ANIMATIONLOOPMODE_CYCLE) {
+            if (this._correctLoopMode !== Animation.ANIMATIONLOOPMODE_CYCLE) {
 
 
                 var keyOffset = to.toString() + from.toString();
                 var keyOffset = to.toString() + from.toString();
                 if (!this._offsetsCache[keyOffset]) {
                 if (!this._offsetsCache[keyOffset]) {
@@ -559,7 +597,7 @@ export class RuntimeAnimation {
         }
         }
 
 
         const repeatCount = range === 0 ? 0 : (ratio / range) >> 0;
         const repeatCount = range === 0 ? 0 : (ratio / range) >> 0;
-        const currentValue = this._interpolate(currentFrame, repeatCount, this._getCorrectLoopMode(), offsetValue, highLimitValue);
+        const currentValue = this._interpolate(currentFrame, repeatCount, this._correctLoopMode, offsetValue, highLimitValue);
 
 
         // Set value
         // Set value
         this.setValue(currentValue, weight);
         this.setValue(currentValue, weight);

+ 52 - 19
src/Cameras/arcRotateCamera.ts

@@ -74,6 +74,45 @@ export class ArcRotateCamera extends TargetCamera {
         this.setPosition(newPosition);
         this.setPosition(newPosition);
     }
     }
 
 
+    @serializeAsVector3("upVector")
+    protected _upVector = Vector3.Up();
+
+    protected _upToYMatrix: Matrix;
+    protected _YToUpMatrix: Matrix;
+
+    /**
+     * The vector the camera should consider as up. (default is Vector3(0, 1, 0) as returned by Vector3.Up())
+     * Setting this will copy the given vector to the camera's upVector, and set rotation matrices to and from Y up.
+     * DO NOT set the up vector using copyFrom or copyFromFloats, as this bypasses setting the above matrices.
+     */
+    set upVector(vec: Vector3) {
+        if (!this._upToYMatrix) {
+            this._YToUpMatrix = new Matrix();
+            this._upToYMatrix = new Matrix();
+
+            this._upVector = Vector3.Zero();
+        }
+
+        vec.normalize();
+        this._upVector.copyFrom(vec);
+        this.setMatUp();
+    }
+
+    get upVector() {
+        return this._upVector;
+    }
+
+    /**
+     * Sets the Y-up to camera up-vector rotation matrix, and the up-vector to Y-up rotation matrix.
+     */
+    public setMatUp() {
+        // from y-up to custom-up (used in _getViewMatrix)
+        Matrix.RotationAlignToRef(Vector3.UpReadOnly, this._upVector, this._YToUpMatrix);
+
+        // from custom-up to y-up (used in rebuildAnglesAndRadius)
+        Matrix.RotationAlignToRef(this._upVector, Vector3.UpReadOnly, this._upToYMatrix);
+    }
+
     /**
     /**
      * Current inertia value on the longitudinal axis.
      * Current inertia value on the longitudinal axis.
      * The bigger this number the longer it will take for the camera to stop.
      * The bigger this number the longer it will take for the camera to stop.
@@ -574,8 +613,6 @@ export class ArcRotateCamera extends TargetCamera {
     protected _targetBoundingCenter: Nullable<Vector3>;
     protected _targetBoundingCenter: Nullable<Vector3>;
 
 
     private _computationVector: Vector3 = Vector3.Zero();
     private _computationVector: Vector3 = Vector3.Zero();
-    private _tempAxisVector: Vector3;
-    private _tempAxisRotationMatrix: Matrix;
 
 
     /**
     /**
      * Instantiates a new ArcRotateCamera in a given scene
      * Instantiates a new ArcRotateCamera in a given scene
@@ -859,6 +896,12 @@ export class ArcRotateCamera extends TargetCamera {
      */
      */
     public rebuildAnglesAndRadius(): void {
     public rebuildAnglesAndRadius(): void {
         this._position.subtractToRef(this._getTargetPosition(), this._computationVector);
         this._position.subtractToRef(this._getTargetPosition(), this._computationVector);
+
+        // need to rotate to Y up equivalent if up vector not Axis.Y
+        if (this._upVector.x !== 0 || this._upVector.y !== 1.0 || this._upVector.z !== 0) {
+            Vector3.TransformCoordinatesToRef(this._computationVector, this._upToYMatrix, this._computationVector);
+        }
+
         this.radius = this._computationVector.length();
         this.radius = this._computationVector.length();
 
 
         if (this.radius === 0) {
         if (this.radius === 0) {
@@ -866,7 +909,11 @@ export class ArcRotateCamera extends TargetCamera {
         }
         }
 
 
         // Alpha
         // Alpha
-        this.alpha = Math.acos(this._computationVector.x / Math.sqrt(Math.pow(this._computationVector.x, 2) + Math.pow(this._computationVector.z, 2)));
+        if (this._computationVector.x === 0 && this._computationVector.z === 0) {
+            this.alpha = Math.PI / 2; // avoid division by zero when looking along up axis, and set to acos(0)
+        } else {
+            this.alpha = Math.acos(this._computationVector.x / Math.sqrt(Math.pow(this._computationVector.x, 2) + Math.pow(this._computationVector.z, 2)));
+        }
 
 
         if (this._computationVector.z < 0) {
         if (this._computationVector.z < 0) {
             this.alpha = 2 * Math.PI - this.alpha;
             this.alpha = 2 * Math.PI - this.alpha;
@@ -942,22 +989,8 @@ export class ArcRotateCamera extends TargetCamera {
         this._computationVector.copyFromFloats(this.radius * cosa * sinb, this.radius * cosb, this.radius * sina * sinb);
         this._computationVector.copyFromFloats(this.radius * cosa * sinb, this.radius * cosb, this.radius * sina * sinb);
 
 
         // Rotate according to up vector
         // Rotate according to up vector
-        if (this.upVector.x !== 0 || this.upVector.y !== 1.0 || this.upVector.z !== 0) {
-
-            if (!this._tempAxisVector) {
-                this._tempAxisVector = new Vector3();
-                this._tempAxisRotationMatrix = new Matrix();
-            }
-
-            Vector3.CrossToRef(Vector3.Up(), this.upVector, this._tempAxisVector);
-            this._tempAxisVector.normalize();
-
-            let angle = Math.acos(Vector3.Dot(Vector3.UpReadOnly, this.upVector));
-
-            Matrix.RotationAxisToRef(this._tempAxisVector, angle, this._tempAxisRotationMatrix);
-
-            this._tempAxisVector.copyFrom(this._computationVector);
-            Vector3.TransformCoordinatesToRef(this._tempAxisVector, this._tempAxisRotationMatrix, this._computationVector);
+        if (this._upVector.x !== 0 || this._upVector.y !== 1.0 || this._upVector.z !== 0) {
+            Vector3.TransformCoordinatesToRef(this._computationVector, this._YToUpMatrix, this._computationVector);
         }
         }
 
 
         target.addToRef(this._computationVector, this._newPosition);
         target.addToRef(this._computationVector, this._newPosition);

+ 38 - 0
src/Debug/physicsViewer.ts

@@ -11,6 +11,7 @@ import { StandardMaterial } from "../Materials/standardMaterial";
 import { IPhysicsEnginePlugin } from "../Physics/IPhysicsEngine";
 import { IPhysicsEnginePlugin } from "../Physics/IPhysicsEngine";
 import { PhysicsImpostor } from "../Physics/physicsImpostor";
 import { PhysicsImpostor } from "../Physics/physicsImpostor";
 import { UtilityLayerRenderer } from "../Rendering/utilityLayerRenderer";
 import { UtilityLayerRenderer } from "../Rendering/utilityLayerRenderer";
+import { CylinderBuilder } from '../Meshes/Builders/cylinderBuilder';
 
 
 /**
 /**
      * Used to show the physics impostor around the specific mesh
      * Used to show the physics impostor around the specific mesh
@@ -32,6 +33,7 @@ export class PhysicsViewer {
 
 
     private _debugBoxMesh: Mesh;
     private _debugBoxMesh: Mesh;
     private _debugSphereMesh: Mesh;
     private _debugSphereMesh: Mesh;
+    private _debugCylinderMesh: Mesh;
     private _debugMaterial: StandardMaterial;
     private _debugMaterial: StandardMaterial;
     private _debugMeshMeshes = new Array<Mesh>();
     private _debugMeshMeshes = new Array<Mesh>();
 
 
@@ -196,6 +198,17 @@ export class PhysicsViewer {
         return this._debugSphereMesh.createInstance('physicsBodyBoxViewInstance');
         return this._debugSphereMesh.createInstance('physicsBodyBoxViewInstance');
     }
     }
 
 
+    private _getDebugCylinderMesh(scene: Scene): AbstractMesh {
+        if (!this._debugCylinderMesh) {
+            this._debugCylinderMesh = CylinderBuilder.CreateCylinder('physicsBodyCylinderViewMesh', { diameterTop: 1, diameterBottom: 1, height: 1 }, scene);
+            this._debugCylinderMesh.rotationQuaternion = Quaternion.Identity();
+            this._debugCylinderMesh.material = this._getDebugMaterial(scene);
+            this._debugCylinderMesh.setEnabled(false);
+        }
+
+        return this._debugCylinderMesh.createInstance('physicsBodyBoxViewInstance');
+    }
+
     private _getDebugMeshMesh(mesh: Mesh, scene: Scene): AbstractMesh {
     private _getDebugMeshMesh(mesh: Mesh, scene: Scene): AbstractMesh {
         var wireframeOver = new Mesh(mesh.name, scene, null, mesh);
         var wireframeOver = new Mesh(mesh.name, scene, null, mesh);
         wireframeOver.position = Vector3.Zero();
         wireframeOver.position = Vector3.Zero();
@@ -212,6 +225,11 @@ export class PhysicsViewer {
             return null;
             return null;
         }
         }
 
 
+        // Only create child impostor debug meshes when evaluating the parent
+        if (targetMesh && targetMesh.parent && (targetMesh.parent as Mesh).physicsImpostor) {
+            return null;
+        }
+
         var mesh: Nullable<AbstractMesh> = null;
         var mesh: Nullable<AbstractMesh> = null;
         const utilityLayerScene = this._utilityLayer.utilityLayerScene;
         const utilityLayerScene = this._utilityLayer.utilityLayerScene;
 
 
@@ -232,6 +250,23 @@ export class PhysicsViewer {
                     mesh = this._getDebugMeshMesh(targetMesh, utilityLayerScene);
                     mesh = this._getDebugMeshMesh(targetMesh, utilityLayerScene);
                 }
                 }
                 break;
                 break;
+            case PhysicsImpostor.NoImpostor:
+                if (targetMesh) {
+                    // Handle compound impostors
+                    var childMeshes = targetMesh.getChildMeshes().filter((c) => {return c.physicsImpostor ? 1 : 0; });
+                    childMeshes.forEach((m) => {
+                        var a = this._getDebugBoxMesh(utilityLayerScene);
+                        a.parent = m;
+                    });
+                }
+                break;
+            case PhysicsImpostor.CylinderImpostor:
+                mesh = this._getDebugCylinderMesh(utilityLayerScene);
+                var bi = impostor.object.getBoundingInfo();
+                mesh.scaling.x = bi.boundingBox.maximum.x - bi.boundingBox.minimum.x;
+                mesh.scaling.y = bi.boundingBox.maximum.y - bi.boundingBox.minimum.y;
+                mesh.scaling.z = bi.boundingBox.maximum.z - bi.boundingBox.minimum.z;
+                break;
         }
         }
         return mesh;
         return mesh;
     }
     }
@@ -249,6 +284,9 @@ export class PhysicsViewer {
         if (this._debugSphereMesh) {
         if (this._debugSphereMesh) {
             this._debugSphereMesh.dispose();
             this._debugSphereMesh.dispose();
         }
         }
+        if (this._debugCylinderMesh) {
+            this._debugCylinderMesh.dispose();
+        }
         if (this._debugMaterial) {
         if (this._debugMaterial) {
             this._debugMaterial.dispose();
             this._debugMaterial.dispose();
         }
         }

+ 22 - 130
src/Engines/engine.ts

@@ -13,7 +13,6 @@ import { VertexBuffer } from "../Meshes/buffer";
 import { UniformBuffer } from "../Materials/uniformBuffer";
 import { UniformBuffer } from "../Materials/uniformBuffer";
 import { Effect, EffectCreationOptions, EffectFallbacks } from "../Materials/effect";
 import { Effect, EffectCreationOptions, EffectFallbacks } from "../Materials/effect";
 import { Material } from "../Materials/material";
 import { Material } from "../Materials/material";
-import { IInternalTextureTracker, DummyInternalTextureTracker } from "../Materials/Textures/internalTextureTracker";
 import { IInternalTextureLoader } from "../Materials/Textures/internalTextureLoader";
 import { IInternalTextureLoader } from "../Materials/Textures/internalTextureLoader";
 import { InternalTexture } from "../Materials/Textures/internalTexture";
 import { InternalTexture } from "../Materials/Textures/internalTexture";
 import { BaseTexture } from "../Materials/Textures/baseTexture";
 import { BaseTexture } from "../Materials/Textures/baseTexture";
@@ -246,9 +245,6 @@ export class Engine {
         { key: "Chrome\/63\.0", capture: "63\\.0\\.3239\\.(\\d+)", captureConstraint: 108, targets: ["uniformBuffer"] },
         { key: "Chrome\/63\.0", capture: "63\\.0\\.3239\\.(\\d+)", captureConstraint: 108, targets: ["uniformBuffer"] },
         { key: "Firefox\/58", capture: null, captureConstraint: null, targets: ["uniformBuffer"] },
         { key: "Firefox\/58", capture: null, captureConstraint: null, targets: ["uniformBuffer"] },
         { key: "Firefox\/59", capture: null, captureConstraint: null, targets: ["uniformBuffer"] },
         { key: "Firefox\/59", capture: null, captureConstraint: null, targets: ["uniformBuffer"] },
-        { key: "Macintosh", capture: null, captureConstraint: null, targets: ["textureBindingOptimization"] },
-        { key: "iPhone", capture: null, captureConstraint: null, targets: ["textureBindingOptimization"] },
-        { key: "iPad", capture: null, captureConstraint: null, targets: ["textureBindingOptimization"] },
         { key: "Chrome\/72.+?Mobile", capture: null, captureConstraint: null, targets: ["vao"] },
         { key: "Chrome\/72.+?Mobile", capture: null, captureConstraint: null, targets: ["vao"] },
         { key: "Chrome\/73.+?Mobile", capture: null, captureConstraint: null, targets: ["vao"] },
         { key: "Chrome\/73.+?Mobile", capture: null, captureConstraint: null, targets: ["vao"] },
         { key: "Chrome\/74.+?Mobile", capture: null, captureConstraint: null, targets: ["vao"] },
         { key: "Chrome\/74.+?Mobile", capture: null, captureConstraint: null, targets: ["vao"] },
@@ -735,13 +731,6 @@ export class Engine {
     public _badDesktopOS = false;
     public _badDesktopOS = false;
 
 
     /**
     /**
-     * Gets or sets a value indicating if we want to disable texture binding optimization.
-     * This could be required on some buggy drivers which wants to have textures bound in a progressive order.
-     * By default Babylon.js will try to let textures bound where they are and only update the samplers to point where the texture is
-     */
-    public disableTextureBindingOptimization = false;
-
-    /**
      * Gets the audio engine
      * Gets the audio engine
      * @see http://doc.babylonjs.com/how_to/playing_sounds_and_music
      * @see http://doc.babylonjs.com/how_to/playing_sounds_and_music
      * @ignorenaming
      * @ignorenaming
@@ -802,8 +791,6 @@ export class Engine {
 
 
     /** @hidden */
     /** @hidden */
     public _drawCalls = new PerfCounter();
     public _drawCalls = new PerfCounter();
-    /** @hidden */
-    public _textureCollisions = new PerfCounter();
 
 
     private _glVersion: string;
     private _glVersion: string;
     private _glRenderer: string;
     private _glRenderer: string;
@@ -908,8 +895,6 @@ export class Engine {
     private _currentInstanceLocations = new Array<number>();
     private _currentInstanceLocations = new Array<number>();
     private _currentInstanceBuffers = new Array<WebGLBuffer>();
     private _currentInstanceBuffers = new Array<WebGLBuffer>();
     private _textureUnits: Int32Array;
     private _textureUnits: Int32Array;
-    private _firstBoundInternalTextureTracker = new DummyInternalTextureTracker();
-    private _lastBoundInternalTextureTracker = new DummyInternalTextureTracker();
 
 
     private _workingCanvas: Nullable<HTMLCanvasElement>;
     private _workingCanvas: Nullable<HTMLCanvasElement>;
     private _workingContext: Nullable<CanvasRenderingContext2D>;
     private _workingContext: Nullable<CanvasRenderingContext2D>;
@@ -1090,9 +1075,6 @@ export class Engine {
                                 case "vao":
                                 case "vao":
                                     this.disableVertexArrayObjects = true;
                                     this.disableVertexArrayObjects = true;
                                     break;
                                     break;
-                                case "textureBindingOptimization":
-                                    this.disableTextureBindingOptimization = true;
-                                    break;
                             }
                             }
                         }
                         }
                     }
                     }
@@ -1311,8 +1293,6 @@ export class Engine {
             this._currentBufferPointers[i] = new BufferPointer();
             this._currentBufferPointers[i] = new BufferPointer();
         }
         }
 
 
-        this._linkTrackers(this._firstBoundInternalTextureTracker, this._lastBoundInternalTextureTracker);
-
         // Load WebVR Devices
         // Load WebVR Devices
         if (options.autoEnableWebVR) {
         if (options.autoEnableWebVR) {
             this.initWebVR();
             this.initWebVR();
@@ -1605,20 +1585,9 @@ export class Engine {
             if (!this._boundTexturesCache.hasOwnProperty(key)) {
             if (!this._boundTexturesCache.hasOwnProperty(key)) {
                 continue;
                 continue;
             }
             }
-            let boundTexture = this._boundTexturesCache[key];
-            if (boundTexture) {
-                this._removeDesignatedSlot(boundTexture);
-            }
             this._boundTexturesCache[key] = null;
             this._boundTexturesCache[key] = null;
         }
         }
 
 
-        if (!this.disableTextureBindingOptimization) {
-            this._nextFreeTextureSlots = [];
-            for (let slot = 0; slot < this._maxSimultaneousTextures; slot++) {
-                this._nextFreeTextureSlots.push(slot);
-            }
-        }
-
         this._currentTextureChannel = -1;
         this._currentTextureChannel = -1;
     }
     }
 
 
@@ -2810,7 +2779,11 @@ export class Engine {
                 if (data instanceof ArrayBuffer) {
                 if (data instanceof ArrayBuffer) {
                     data = new Uint8Array(data, byteOffset, byteLength);
                     data = new Uint8Array(data, byteOffset, byteLength);
                 } else {
                 } else {
-                    data = new Uint8Array(data.buffer, data.byteOffset + byteOffset, byteLength);
+                    let offset = data.byteOffset + byteOffset;
+
+                    if (offset || byteLength !== data.byteLength) {
+                        data = new Uint8Array(data.buffer, offset, byteLength);
+                    }
                 }
                 }
 
 
                 this._gl.bufferSubData(this._gl.ARRAY_BUFFER, 0, <ArrayBuffer>data);
                 this._gl.bufferSubData(this._gl.ARRAY_BUFFER, 0, <ArrayBuffer>data);
@@ -6396,79 +6369,6 @@ export class Engine {
         this._currentEffect = null;
         this._currentEffect = null;
     }
     }
 
 
-    private _moveBoundTextureOnTop(internalTexture: InternalTexture): void {
-        if (this.disableTextureBindingOptimization || this._lastBoundInternalTextureTracker.previous === internalTexture) {
-            return;
-        }
-
-        // Remove
-        this._linkTrackers(internalTexture.previous, internalTexture.next);
-
-        // Bind last to it
-        this._linkTrackers(this._lastBoundInternalTextureTracker.previous, internalTexture);
-
-        // Bind to dummy
-        this._linkTrackers(internalTexture, this._lastBoundInternalTextureTracker);
-    }
-
-    private _getCorrectTextureChannel(channel: number, internalTexture: Nullable<InternalTexture>): number {
-        if (!internalTexture) {
-            return -1;
-        }
-
-        internalTexture._initialSlot = channel;
-
-        if (this.disableTextureBindingOptimization) { // We want texture sampler ID === texture channel
-            if (channel !== internalTexture._designatedSlot) {
-                this._textureCollisions.addCount(1, false);
-            }
-        } else {
-            if (channel !== internalTexture._designatedSlot) {
-                if (internalTexture._designatedSlot > -1) { // Texture is already assigned to a slot
-                    return internalTexture._designatedSlot;
-                } else {
-                    // No slot for this texture, let's pick a new one (if we find a free slot)
-                    if (this._nextFreeTextureSlots.length) {
-                        return this._nextFreeTextureSlots[0];
-                    }
-
-                    // We need to recycle the oldest bound texture, sorry.
-                    this._textureCollisions.addCount(1, false);
-                    return this._removeDesignatedSlot(<InternalTexture>this._firstBoundInternalTextureTracker.next);
-                }
-            }
-        }
-
-        return channel;
-    }
-
-    private _linkTrackers(previous: Nullable<IInternalTextureTracker>, next: Nullable<IInternalTextureTracker>) {
-        previous!.next = next;
-        next!.previous = previous;
-    }
-
-    private _removeDesignatedSlot(internalTexture: InternalTexture): number {
-        let currentSlot = internalTexture._designatedSlot;
-        if (currentSlot === -1) {
-            return -1;
-        }
-
-        internalTexture._designatedSlot = -1;
-
-        if (this.disableTextureBindingOptimization) {
-            return -1;
-        }
-
-        // Remove from bound list
-        this._linkTrackers(internalTexture.previous, internalTexture.next);
-
-        // Free the slot
-        this._boundTexturesCache[currentSlot] = null;
-        this._nextFreeTextureSlots.push(currentSlot);
-
-        return currentSlot;
-    }
-
     private _activateCurrentTexture() {
     private _activateCurrentTexture() {
         if (this._currentTextureChannel !== this._activeChannel) {
         if (this._currentTextureChannel !== this._activeChannel) {
             this._gl.activeTexture(this._gl.TEXTURE0 + this._activeChannel);
             this._gl.activeTexture(this._gl.TEXTURE0 + this._activeChannel);
@@ -6479,18 +6379,14 @@ export class Engine {
     /** @hidden */
     /** @hidden */
     public _bindTextureDirectly(target: number, texture: Nullable<InternalTexture>, forTextureDataUpdate = false, force = false): boolean {
     public _bindTextureDirectly(target: number, texture: Nullable<InternalTexture>, forTextureDataUpdate = false, force = false): boolean {
         var wasPreviouslyBound = false;
         var wasPreviouslyBound = false;
-        if (forTextureDataUpdate && texture && texture._designatedSlot > -1) {
-            this._activeChannel = texture._designatedSlot;
+        let isTextureForRendering = texture && texture._associatedChannel > -1;
+        if (forTextureDataUpdate && isTextureForRendering) {
+            this._activeChannel = texture!._associatedChannel;
         }
         }
 
 
         let currentTextureBound = this._boundTexturesCache[this._activeChannel];
         let currentTextureBound = this._boundTexturesCache[this._activeChannel];
-        let isTextureForRendering = texture && texture._initialSlot > -1;
 
 
         if (currentTextureBound !== texture || force) {
         if (currentTextureBound !== texture || force) {
-            if (currentTextureBound) {
-                this._removeDesignatedSlot(currentTextureBound);
-            }
-
             this._activateCurrentTexture();
             this._activateCurrentTexture();
 
 
             if (texture && texture.isMultiview) {
             if (texture && texture.isMultiview) {
@@ -6502,17 +6398,7 @@ export class Engine {
             this._boundTexturesCache[this._activeChannel] = texture;
             this._boundTexturesCache[this._activeChannel] = texture;
 
 
             if (texture) {
             if (texture) {
-                if (!this.disableTextureBindingOptimization) {
-                    let slotIndex = this._nextFreeTextureSlots.indexOf(this._activeChannel);
-                    if (slotIndex > -1) {
-                        this._nextFreeTextureSlots.splice(slotIndex, 1);
-                    }
-
-                    this._linkTrackers(this._lastBoundInternalTextureTracker.previous, texture);
-                    this._linkTrackers(texture, this._lastBoundInternalTextureTracker);
-                }
-
-                texture._designatedSlot = this._activeChannel;
+                texture._associatedChannel = this._activeChannel;
             }
             }
         } else if (forTextureDataUpdate) {
         } else if (forTextureDataUpdate) {
             wasPreviouslyBound = true;
             wasPreviouslyBound = true;
@@ -6520,7 +6406,7 @@ export class Engine {
         }
         }
 
 
         if (isTextureForRendering && !forTextureDataUpdate) {
         if (isTextureForRendering && !forTextureDataUpdate) {
-            this._bindSamplerUniformToChannel(texture!._initialSlot, this._activeChannel);
+            this._bindSamplerUniformToChannel(texture!._associatedChannel, this._activeChannel);
         }
         }
 
 
         return wasPreviouslyBound;
         return wasPreviouslyBound;
@@ -6533,7 +6419,7 @@ export class Engine {
         }
         }
 
 
         if (texture) {
         if (texture) {
-            channel = this._getCorrectTextureChannel(channel, texture);
+            texture._associatedChannel = channel;
         }
         }
 
 
         this._activeChannel = channel;
         this._activeChannel = channel;
@@ -6674,15 +6560,14 @@ export class Engine {
             internalTexture = this.emptyTexture;
             internalTexture = this.emptyTexture;
         }
         }
 
 
-        if (!isPartOfTextureArray) {
-            channel = this._getCorrectTextureChannel(channel, internalTexture);
+        if (!isPartOfTextureArray && internalTexture) {
+            internalTexture._associatedChannel = channel;
         }
         }
 
 
         let needToBind = true;
         let needToBind = true;
         if (this._boundTexturesCache[channel] === internalTexture) {
         if (this._boundTexturesCache[channel] === internalTexture) {
-            this._moveBoundTextureOnTop(internalTexture);
             if (!isPartOfTextureArray) {
             if (!isPartOfTextureArray) {
-                this._bindSamplerUniformToChannel(internalTexture._initialSlot, channel);
+                this._bindSamplerUniformToChannel(internalTexture._associatedChannel, channel);
             }
             }
 
 
             needToBind = false;
             needToBind = false;
@@ -6765,7 +6650,14 @@ export class Engine {
             this._textureUnits = new Int32Array(textures.length);
             this._textureUnits = new Int32Array(textures.length);
         }
         }
         for (let i = 0; i < textures.length; i++) {
         for (let i = 0; i < textures.length; i++) {
-            this._textureUnits[i] = this._getCorrectTextureChannel(channel + i, textures[i].getInternalTexture());
+            let texture = textures[i].getInternalTexture();
+
+            if (texture) {
+                this._textureUnits[channel + i] = channel + i;
+                texture._associatedChannel = channel + i;
+            } else {
+                this._textureUnits[channel + i] = -1;
+            }
         }
         }
         this._gl.uniform1iv(uniform, this._textureUnits);
         this._gl.uniform1iv(uniform, this._textureUnits);
 
 

+ 0 - 8
src/Instrumentation/sceneInstrumentation.ts

@@ -459,13 +459,6 @@ export class SceneInstrumentation implements IDisposable {
     }
     }
 
 
     /**
     /**
-     * Gets the perf counter used for texture collisions
-     */
-    public get textureCollisionsCounter(): PerfCounter {
-        return this.scene.getEngine()._textureCollisions;
-    }
-
-    /**
      * Instantiates a new scene instrumentation.
      * Instantiates a new scene instrumentation.
      * This class can be used to get instrumentation data from a Babylon engine
      * This class can be used to get instrumentation data from a Babylon engine
      * @see http://doc.babylonjs.com/how_to/optimizing_your_scene#sceneinstrumentation
      * @see http://doc.babylonjs.com/how_to/optimizing_your_scene#sceneinstrumentation
@@ -508,7 +501,6 @@ export class SceneInstrumentation implements IDisposable {
             }
             }
 
 
             this.scene.getEngine()._drawCalls.fetchNewFrame();
             this.scene.getEngine()._drawCalls.fetchNewFrame();
-            this.scene.getEngine()._textureCollisions.fetchNewFrame();
         });
         });
 
 
         // After render
         // After render

+ 1 - 1
src/Lights/shadowLight.ts

@@ -350,7 +350,7 @@ export abstract class ShadowLight extends Light implements IShadowLight {
         }
         }
 
 
         // Cache the determinant
         // Cache the determinant
-        this._worldMatrixDeterminant = this._worldMatrix.determinant();
+        this._worldMatrixDeterminantIsDirty = true;
 
 
         return this._worldMatrix;
         return this._worldMatrix;
     }
     }

+ 0 - 1
src/Materials/Textures/index.ts

@@ -6,7 +6,6 @@ export * from "./equiRectangularCubeTexture";
 export * from "./hdrCubeTexture";
 export * from "./hdrCubeTexture";
 export * from "./internalTexture";
 export * from "./internalTexture";
 export * from "./internalTextureLoader";
 export * from "./internalTextureLoader";
-export * from "./internalTextureTracker";
 export * from "./Loaders/index";
 export * from "./Loaders/index";
 export * from "./mirrorTexture";
 export * from "./mirrorTexture";
 export * from "./multiRenderTarget";
 export * from "./multiRenderTarget";

+ 3 - 17
src/Materials/Textures/internalTexture.ts

@@ -2,7 +2,6 @@ import { Observable } from "../../Misc/observable";
 import { Nullable, int } from "../../types";
 import { Nullable, int } from "../../types";
 import { SphericalPolynomial } from "../../Maths/sphericalPolynomial";
 import { SphericalPolynomial } from "../../Maths/sphericalPolynomial";
 import { RenderTargetCreationOptions } from "../../Materials/Textures/renderTargetCreationOptions";
 import { RenderTargetCreationOptions } from "../../Materials/Textures/renderTargetCreationOptions";
-import { IInternalTextureTracker } from "../../Materials/Textures/internalTextureTracker";
 import { _TimeToken } from "../../Instrumentation/timeToken";
 import { _TimeToken } from "../../Instrumentation/timeToken";
 import { _DepthCullingState, _StencilState, _AlphaState } from "../../States/index";
 import { _DepthCullingState, _StencilState, _AlphaState } from "../../States/index";
 import { Constants } from "../../Engines/constants";
 import { Constants } from "../../Engines/constants";
@@ -15,7 +14,7 @@ declare type BaseTexture = import("../../Materials/Textures/baseTexture").BaseTe
  * Class used to store data associated with WebGL texture data for the engine
  * Class used to store data associated with WebGL texture data for the engine
  * This class should not be used directly
  * This class should not be used directly
  */
  */
-export class InternalTexture implements IInternalTextureTracker {
+export class InternalTexture {
 
 
     /** hidden */
     /** hidden */
     public static _UpdateRGBDAsync = (internalTexture: InternalTexture, data: ArrayBufferView[][], sphericalPolynomial: Nullable<SphericalPolynomial>, lodScale: number, lodOffset: number): Promise<void> => {
     public static _UpdateRGBDAsync = (internalTexture: InternalTexture, data: ArrayBufferView[][], sphericalPolynomial: Nullable<SphericalPolynomial>, lodScale: number, lodOffset: number): Promise<void> => {
@@ -148,22 +147,11 @@ export class InternalTexture implements IInternalTextureTracker {
      */
      */
     public invertY: boolean;
     public invertY: boolean;
 
 
-    /**
-     * Gets or set the previous tracker in the list
-     */
-    public previous: Nullable<IInternalTextureTracker> = null;
-    /**
-     * Gets or set the next tracker in the list
-     */
-    public next: Nullable<IInternalTextureTracker> = null;
-
     // Private
     // Private
     /** @hidden */
     /** @hidden */
     public _invertVScale = false;
     public _invertVScale = false;
     /** @hidden */
     /** @hidden */
-    public _initialSlot = -1;
-    /** @hidden */
-    public _designatedSlot = -1;
+    public _associatedChannel = -1;
     /** @hidden */
     /** @hidden */
     public _dataSource = InternalTexture.DATASOURCE_UNKNOWN;
     public _dataSource = InternalTexture.DATASOURCE_UNKNOWN;
     /** @hidden */
     /** @hidden */
@@ -225,7 +213,7 @@ export class InternalTexture implements IInternalTextureTracker {
     /** @hidden */
     /** @hidden */
     public _colorTextureArray: Nullable<WebGLTexture>;
     public _colorTextureArray: Nullable<WebGLTexture>;
     /** @hidden */
     /** @hidden */
-    public _depthStencilTextureArray:  Nullable<WebGLTexture>;
+    public _depthStencilTextureArray: Nullable<WebGLTexture>;
 
 
     // The following three fields helps sharing generated fixed LODs for texture filtering
     // The following three fields helps sharing generated fixed LODs for texture filtering
     // In environment not supporting the textureLOD extension like EDGE. They are for internal use only.
     // In environment not supporting the textureLOD extension like EDGE. They are for internal use only.
@@ -468,8 +456,6 @@ export class InternalTexture implements IInternalTextureTracker {
         if (this._references === 0) {
         if (this._references === 0) {
             this._engine._releaseTexture(this);
             this._engine._releaseTexture(this);
             this._webGLTexture = null;
             this._webGLTexture = null;
-            this.previous = null;
-            this.next = null;
         }
         }
     }
     }
 }
 }

+ 0 - 30
src/Materials/Textures/internalTextureTracker.ts

@@ -1,30 +0,0 @@
-import { Nullable } from "../../types";
-import { _TimeToken } from "../../Instrumentation/timeToken";
-import { _DepthCullingState, _StencilState, _AlphaState } from "../../States/index";
-/**
- * Internal interface used to track InternalTexture already bound to the GL context
- */
-export interface IInternalTextureTracker {
-    /**
-     * Gets or set the previous tracker in the list
-     */
-    previous: Nullable<IInternalTextureTracker>;
-    /**
-     * Gets or set the next tracker in the list
-     */
-    next: Nullable<IInternalTextureTracker>;
-}
-
-/**
- * Internal class used by the engine to get list of InternalTexture already bound to the GL context
- */
-export class DummyInternalTextureTracker {
-    /**
-     * Gets or set the previous tracker in the list
-     */
-    public previous: Nullable<IInternalTextureTracker> = null;
-    /**
-     * Gets or set the next tracker in the list
-     */
-    public next: Nullable<IInternalTextureTracker> = null;
-}

+ 65 - 5
src/Maths/math.ts

@@ -15,7 +15,8 @@ export const ToLinearSpace = 2.2;
  * Constant used to define the minimal number value in Babylon.js
  * Constant used to define the minimal number value in Babylon.js
  * @ignorenaming
  * @ignorenaming
  */
  */
-export const Epsilon = 0.001;
+let Epsilon = 0.001;
+export { Epsilon };
 
 
 /**
 /**
  * Class used to hold a RBG color
  * Class used to hold a RBG color
@@ -4701,6 +4702,21 @@ export class Matrix {
     }
     }
 
 
     /**
     /**
+     * Adds the translation vector (using 3 floats) in the current matrix
+     * @param x defines the 1st component of the translation
+     * @param y defines the 2nd component of the translation
+     * @param z defines the 3rd component of the translation
+     * @returns the current updated matrix
+     */
+    public addTranslationFromFloats(x: number, y: number, z: number): Matrix {
+        this._m[12] += x;
+        this._m[13] += y;
+        this._m[14] += z;
+        this._markAsUpdated();
+        return this;
+    }
+
+    /**
      * Inserts the translation vector in the current matrix
      * Inserts the translation vector in the current matrix
      * @param vector3 defines the translation to insert
      * @param vector3 defines the translation to insert
      * @returns the current updated matrix
      * @returns the current updated matrix
@@ -5277,11 +5293,34 @@ export class Matrix {
      * @param result defines the target matrix
      * @param result defines the target matrix
      */
      */
     public static ComposeToRef(scale: DeepImmutable<Vector3>, rotation: DeepImmutable<Quaternion>, translation: DeepImmutable<Vector3>, result: Matrix): void {
     public static ComposeToRef(scale: DeepImmutable<Vector3>, rotation: DeepImmutable<Quaternion>, translation: DeepImmutable<Vector3>, result: Matrix): void {
-        Matrix.ScalingToRef(scale.x, scale.y, scale.z, MathTmp.Matrix[1]);
-        rotation.toRotationMatrix(MathTmp.Matrix[0]);
-        MathTmp.Matrix[1].multiplyToRef(MathTmp.Matrix[0], result);
+        let m = result._m;
+        var x = rotation.x, y = rotation.y, z = rotation.z, w = rotation.w;
+        var x2 = x + x, y2 = y + y, z2 = z + z;
+        var xx = x * x2, xy = x * y2, xz = x * z2;
+        var yy = y * y2, yz = y * z2, zz = z * z2;
+        var wx = w * x2, wy = w * y2, wz = w * z2;
+
+        var sx = scale.x, sy = scale.y, sz = scale.z;
+
+        m[0] = (1 - (yy + zz)) * sx;
+        m[1] = (xy + wz) * sx;
+        m[2] = (xz - wy) * sx;
+        m[3] = 0;
 
 
-        result.setTranslation(translation);
+        m[4] = (xy - wz) * sy;
+        m[5] = (1 - (xx + zz)) * sy;
+        m[6] = (yz + wx) * sy;
+        m[7] = 0;
+
+        m[8] = (xz + wy) * sz;
+        m[9] = (yz - wx) * sz;
+        m[10] = (1 - (xx + yy)) * sz;
+        m[11] = 0;
+
+        m[12] = translation.x;
+        m[13] = translation.y;
+        m[14] = translation.z;
+        m[15] = 1;
     }
     }
 
 
     /**
     /**
@@ -5477,6 +5516,27 @@ export class Matrix {
     }
     }
 
 
     /**
     /**
+     * Takes normalised vectors and returns a rotation matrix to align "from" with "to".
+     * Taken from http://www.iquilezles.org/www/articles/noacos/noacos.htm
+     * @param from defines the vector to align
+     * @param to defines the vector to align to
+     * @param result defines the target matrix
+     */
+    public static RotationAlignToRef(from: DeepImmutable<Vector3>, to: DeepImmutable<Vector3>, result: Matrix): void {
+        const v = Vector3.Cross(to, from);
+        const c = Vector3.Dot(to, from);
+        const k = 1 / (1 + c);
+
+        const m = result._m;
+        m[0] = v.x * v.x * k + c; m[1] = v.y * v.x * k - v.z; m[2] = v.z * v.x * k + v.y; m[3] = 0;
+        m[4] = v.x * v.y * k + v.z; m[5] = v.y * v.y * k + c; m[6] = v.z * v.y * k - v.x; m[7] = 0;
+        m[8] = v.x * v.z * k - v.y; m[9] = v.y * v.z * k + v.x; m[10] = v.z * v.z * k + c; m[11] = 0;
+        m[12] = 0; m[13] = 0; m[14] = 0; m[15] = 1;
+
+        result._markAsUpdated();
+    }
+
+    /**
      * Creates a rotation matrix
      * Creates a rotation matrix
      * @param yaw defines the yaw angle in radians (Y axis)
      * @param yaw defines the yaw angle in radians (Y axis)
      * @param pitch defines the pitch angle in radians (X axis)
      * @param pitch defines the pitch angle in radians (X axis)

+ 7 - 3
src/Meshes/Builders/groundBuilder.ts

@@ -4,6 +4,8 @@ import { Mesh, _CreationDataStorage } from "../mesh";
 import { VertexData } from "../mesh.vertexData";
 import { VertexData } from "../mesh.vertexData";
 import { GroundMesh } from "../groundMesh";
 import { GroundMesh } from "../groundMesh";
 import { Tools } from "../../Misc/tools";
 import { Tools } from "../../Misc/tools";
+import { Nullable } from '../../types';
+import { EngineStore } from '../../Engines/engineStore';
 
 
 VertexData.CreateGround = function(options: { width?: number, height?: number, subdivisions?: number, subdivisionsX?: number, subdivisionsY?: number }): VertexData {
 VertexData.CreateGround = function(options: { width?: number, height?: number, subdivisions?: number, subdivisionsX?: number, subdivisionsY?: number }): VertexData {
     var indices = [];
     var indices = [];
@@ -324,7 +326,7 @@ export class GroundBuilder {
      * @returns the tiled ground mesh
      * @returns the tiled ground mesh
      * @see https://doc.babylonjs.com/how_to/set_shapes#tiled-ground
      * @see https://doc.babylonjs.com/how_to/set_shapes#tiled-ground
      */
      */
-    public static CreateTiledGround(name: string, options: { xmin: number, zmin: number, xmax: number, zmax: number, subdivisions?: { w: number; h: number; }, precision?: { w: number; h: number; }, updatable?: boolean }, scene: Scene): Mesh {
+    public static CreateTiledGround(name: string, options: { xmin: number, zmin: number, xmax: number, zmax: number, subdivisions?: { w: number; h: number; }, precision?: { w: number; h: number; }, updatable?: boolean }, scene: Nullable<Scene> = null): Mesh {
         var tiledGround = new Mesh(name, scene);
         var tiledGround = new Mesh(name, scene);
 
 
         var vertexData = VertexData.CreateTiledGround(options);
         var vertexData = VertexData.CreateTiledGround(options);
@@ -353,7 +355,7 @@ export class GroundBuilder {
      * @see https://doc.babylonjs.com/babylon101/height_map
      * @see https://doc.babylonjs.com/babylon101/height_map
      * @see https://doc.babylonjs.com/how_to/set_shapes#ground-from-a-height-map
      * @see https://doc.babylonjs.com/how_to/set_shapes#ground-from-a-height-map
      */
      */
-    public static CreateGroundFromHeightMap(name: string, url: string, options: { width?: number, height?: number, subdivisions?: number, minHeight?: number, maxHeight?: number, colorFilter?: Color3, alphaFilter?: number, updatable?: boolean, onReady?: (mesh: GroundMesh) => void }, scene: Scene): GroundMesh {
+    public static CreateGroundFromHeightMap(name: string, url: string, options: { width?: number, height?: number, subdivisions?: number, minHeight?: number, maxHeight?: number, colorFilter?: Color3, alphaFilter?: number, updatable?: boolean, onReady?: (mesh: GroundMesh) => void }, scene: Nullable<Scene> = null): GroundMesh {
         var width = options.width || 10.0;
         var width = options.width || 10.0;
         var height = options.height || 10.0;
         var height = options.height || 10.0;
         var subdivisions = options.subdivisions || 1 | 0;
         var subdivisions = options.subdivisions || 1 | 0;
@@ -364,6 +366,8 @@ export class GroundBuilder {
         var updatable = options.updatable;
         var updatable = options.updatable;
         var onReady = options.onReady;
         var onReady = options.onReady;
 
 
+        scene = scene || EngineStore.LastCreatedScene!;
+
         var ground = new GroundMesh(name, scene);
         var ground = new GroundMesh(name, scene);
         ground._subdivisionsX = subdivisions;
         ground._subdivisionsX = subdivisions;
         ground._subdivisionsY = subdivisions;
         ground._subdivisionsY = subdivisions;
@@ -385,7 +389,7 @@ export class GroundBuilder {
                 throw new Error("Unable to get 2d context for CreateGroundFromHeightMap");
                 throw new Error("Unable to get 2d context for CreateGroundFromHeightMap");
             }
             }
 
 
-            if (scene.isDisposed) {
+            if (scene!.isDisposed) {
                 return;
                 return;
             }
             }
 
 

+ 2 - 1
src/Meshes/Builders/icoSphereBuilder.ts

@@ -2,6 +2,7 @@ import { Scene } from "../../scene";
 import { Vector4, Vector3, Vector2 } from "../../Maths/math";
 import { Vector4, Vector3, Vector2 } from "../../Maths/math";
 import { Mesh, _CreationDataStorage } from "../mesh";
 import { Mesh, _CreationDataStorage } from "../mesh";
 import { VertexData } from "../mesh.vertexData";
 import { VertexData } from "../mesh.vertexData";
+import { Nullable } from '../../types';
 
 
 VertexData.CreateIcoSphere = function(options: { radius?: number, radiusX?: number, radiusY?: number, radiusZ?: number, flat?: boolean, subdivisions?: number, sideOrientation?: number, frontUVs?: Vector4, backUVs?: Vector4 }): VertexData {
 VertexData.CreateIcoSphere = function(options: { radius?: number, radiusX?: number, radiusY?: number, radiusZ?: number, flat?: boolean, subdivisions?: number, sideOrientation?: number, frontUVs?: Vector4, backUVs?: Vector4 }): VertexData {
     var sideOrientation = options.sideOrientation || VertexData.DEFAULTSIDE;
     var sideOrientation = options.sideOrientation || VertexData.DEFAULTSIDE;
@@ -283,7 +284,7 @@ export class IcoSphereBuilder {
      * @returns the icosahedron mesh
      * @returns the icosahedron mesh
      * @see https://doc.babylonjs.com/how_to/polyhedra_shapes#icosphere
      * @see https://doc.babylonjs.com/how_to/polyhedra_shapes#icosphere
      */
      */
-    public static CreateIcoSphere(name: string, options: { radius?: number, radiusX?: number, radiusY?: number, radiusZ?: number, flat?: boolean, subdivisions?: number, sideOrientation?: number, frontUVs?: Vector4, backUVs?: Vector4, updatable?: boolean }, scene: Scene): Mesh {
+    public static CreateIcoSphere(name: string, options: { radius?: number, radiusX?: number, radiusY?: number, radiusZ?: number, flat?: boolean, subdivisions?: number, sideOrientation?: number, frontUVs?: Vector4, backUVs?: Vector4, updatable?: boolean }, scene: Nullable<Scene> = null): Mesh {
         var sphere = new Mesh(name, scene);
         var sphere = new Mesh(name, scene);
 
 
         options.sideOrientation = Mesh._GetDefaultSideOrientation(options.sideOrientation);
         options.sideOrientation = Mesh._GetDefaultSideOrientation(options.sideOrientation);

+ 2 - 1
src/Meshes/Builders/latheBuilder.ts

@@ -2,6 +2,7 @@ import { Scene } from "../../scene";
 import { Vector3, Vector4 } from "../../Maths/math";
 import { Vector3, Vector4 } from "../../Maths/math";
 import { Mesh, _CreationDataStorage } from "../mesh";
 import { Mesh, _CreationDataStorage } from "../mesh";
 import { RibbonBuilder } from "./ribbonBuilder";
 import { RibbonBuilder } from "./ribbonBuilder";
+import { Nullable } from '../../types';
 
 
 Mesh.CreateLathe = (name: string, shape: Vector3[], radius: number, tessellation: number, scene: Scene, updatable?: boolean, sideOrientation?: number): Mesh => {
 Mesh.CreateLathe = (name: string, shape: Vector3[], radius: number, tessellation: number, scene: Scene, updatable?: boolean, sideOrientation?: number): Mesh => {
     var options = {
     var options = {
@@ -39,7 +40,7 @@ export class LatheBuilder {
      * @returns the lathe mesh
      * @returns the lathe mesh
      * @see https://doc.babylonjs.com/how_to/parametric_shapes#lathe
      * @see https://doc.babylonjs.com/how_to/parametric_shapes#lathe
      */
      */
-    public static CreateLathe(name: string, options: { shape: Vector3[], radius?: number, tessellation?: number, clip?: number, arc?: number, closed?: boolean, updatable?: boolean, sideOrientation?: number, frontUVs?: Vector4, backUVs?: Vector4, cap?: number, invertUV?: boolean }, scene: Scene): Mesh {
+    public static CreateLathe(name: string, options: { shape: Vector3[], radius?: number, tessellation?: number, clip?: number, arc?: number, closed?: boolean, updatable?: boolean, sideOrientation?: number, frontUVs?: Vector4, backUVs?: Vector4, cap?: number, invertUV?: boolean }, scene: Nullable<Scene> = null): Mesh {
         var arc: number = options.arc ? ((options.arc <= 0 || options.arc > 1) ? 1.0 : options.arc) : 1.0;
         var arc: number = options.arc ? ((options.arc <= 0 || options.arc > 1) ? 1.0 : options.arc) : 1.0;
         var closed: boolean = (options.closed === undefined) ? true : options.closed;
         var closed: boolean = (options.closed === undefined) ? true : options.closed;
         var shape = options.shape;
         var shape = options.shape;

+ 2 - 1
src/Meshes/Builders/planeBuilder.ts

@@ -2,6 +2,7 @@ import { Scene } from "../../scene";
 import { Vector4, Plane } from "../../Maths/math";
 import { Vector4, Plane } from "../../Maths/math";
 import { Mesh, _CreationDataStorage } from "../mesh";
 import { Mesh, _CreationDataStorage } from "../mesh";
 import { VertexData } from "../mesh.vertexData";
 import { VertexData } from "../mesh.vertexData";
+import { Nullable } from '../../types';
 
 
 VertexData.CreatePlane = function(options: { size?: number, width?: number, height?: number, sideOrientation?: number, frontUVs?: Vector4, backUVs?: Vector4 }): VertexData {
 VertexData.CreatePlane = function(options: { size?: number, width?: number, height?: number, sideOrientation?: number, frontUVs?: Vector4, backUVs?: Vector4 }): VertexData {
     var indices = [];
     var indices = [];
@@ -86,7 +87,7 @@ export class PlaneBuilder {
      * @returns the plane mesh
      * @returns the plane mesh
      * @see https://doc.babylonjs.com/how_to/set_shapes#plane
      * @see https://doc.babylonjs.com/how_to/set_shapes#plane
      */
      */
-    public static CreatePlane(name: string, options: { size?: number, width?: number, height?: number, sideOrientation?: number, frontUVs?: Vector4, backUVs?: Vector4, updatable?: boolean, sourcePlane?: Plane }, scene: Scene): Mesh {
+    public static CreatePlane(name: string, options: { size?: number, width?: number, height?: number, sideOrientation?: number, frontUVs?: Vector4, backUVs?: Vector4, updatable?: boolean, sourcePlane?: Plane }, scene: Nullable<Scene> = null): Mesh {
         var plane = new Mesh(name, scene);
         var plane = new Mesh(name, scene);
 
 
         options.sideOrientation = Mesh._GetDefaultSideOrientation(options.sideOrientation);
         options.sideOrientation = Mesh._GetDefaultSideOrientation(options.sideOrientation);

+ 5 - 4
src/Meshes/Builders/polygonBuilder.ts

@@ -3,8 +3,9 @@ import { Vector3, Vector2, Color4, Vector4 } from "../../Maths/math";
 import { Mesh, _CreationDataStorage } from "../mesh";
 import { Mesh, _CreationDataStorage } from "../mesh";
 import { VertexData } from "../mesh.vertexData";
 import { VertexData } from "../mesh.vertexData";
 import { PolygonMeshBuilder } from "../polygonMesh";
 import { PolygonMeshBuilder } from "../polygonMesh";
-import { FloatArray, IndicesArray } from "../../types";
+import { FloatArray, IndicesArray, Nullable } from "../../types";
 import { VertexBuffer } from "../../Meshes/buffer";
 import { VertexBuffer } from "../../Meshes/buffer";
+import { EngineStore } from '../../Engines/engineStore';
 
 
 declare var earcut: any;
 declare var earcut: any;
 
 
@@ -109,7 +110,7 @@ export class PolygonBuilder {
      * @param earcutInjection can be used to inject your own earcut reference
      * @param earcutInjection can be used to inject your own earcut reference
      * @returns the polygon mesh
      * @returns the polygon mesh
      */
      */
-    public static CreatePolygon(name: string, options: { shape: Vector3[], holes?: Vector3[][], depth?: number, faceUV?: Vector4[], faceColors?: Color4[], updatable?: boolean, sideOrientation?: number, frontUVs?: Vector4, backUVs?: Vector4, }, scene: Scene, earcutInjection = earcut): Mesh {
+    public static CreatePolygon(name: string, options: { shape: Vector3[], holes?: Vector3[][], depth?: number, faceUV?: Vector4[], faceColors?: Color4[], updatable?: boolean, sideOrientation?: number, frontUVs?: Vector4, backUVs?: Vector4, }, scene: Nullable<Scene> = null, earcutInjection = earcut): Mesh {
         options.sideOrientation = Mesh._GetDefaultSideOrientation(options.sideOrientation);
         options.sideOrientation = Mesh._GetDefaultSideOrientation(options.sideOrientation);
         var shape = options.shape;
         var shape = options.shape;
         var holes = options.holes || [];
         var holes = options.holes || [];
@@ -125,7 +126,7 @@ export class PolygonBuilder {
             contours.pop();
             contours.pop();
         }
         }
 
 
-        var polygonTriangulation = new PolygonMeshBuilder(name, contours, scene, earcutInjection);
+        var polygonTriangulation = new PolygonMeshBuilder(name, contours, scene || EngineStore.LastCreatedScene!, earcutInjection);
         for (var hNb = 0; hNb < holes.length; hNb++) {
         for (var hNb = 0; hNb < holes.length; hNb++) {
             hole = [];
             hole = [];
             for (var hPoint = 0; hPoint < holes[hNb].length; hPoint++) {
             for (var hPoint = 0; hPoint < holes[hNb].length; hPoint++) {
@@ -151,7 +152,7 @@ export class PolygonBuilder {
      * @param earcutInjection can be used to inject your own earcut reference
      * @param earcutInjection can be used to inject your own earcut reference
      * @returns the polygon mesh
      * @returns the polygon mesh
      */
      */
-    public static ExtrudePolygon(name: string, options: { shape: Vector3[], holes?: Vector3[][], depth?: number, faceUV?: Vector4[], faceColors?: Color4[], updatable?: boolean, sideOrientation?: number, frontUVs?: Vector4, backUVs?: Vector4 }, scene: Scene, earcutInjection = earcut): Mesh {
+    public static ExtrudePolygon(name: string, options: { shape: Vector3[], holes?: Vector3[][], depth?: number, faceUV?: Vector4[], faceColors?: Color4[], updatable?: boolean, sideOrientation?: number, frontUVs?: Vector4, backUVs?: Vector4 }, scene: Nullable<Scene> = null, earcutInjection = earcut): Mesh {
         return PolygonBuilder.CreatePolygon(name, options, scene, earcutInjection);
         return PolygonBuilder.CreatePolygon(name, options, scene, earcutInjection);
     }
     }
 }
 }

+ 2 - 1
src/Meshes/Builders/polyhedronBuilder.ts

@@ -2,6 +2,7 @@ import { Scene } from "../../scene";
 import { Color4, Vector4 } from "../../Maths/math";
 import { Color4, Vector4 } from "../../Maths/math";
 import { Mesh, _CreationDataStorage } from "../mesh";
 import { Mesh, _CreationDataStorage } from "../mesh";
 import { VertexData } from "../mesh.vertexData";
 import { VertexData } from "../mesh.vertexData";
+import { Nullable } from '../../types';
 
 
 VertexData.CreatePolyhedron = function(options: { type?: number, size?: number, sizeX?: number, sizeY?: number, sizeZ?: number, custom?: any, faceUV?: Vector4[], faceColors?: Color4[], flat?: boolean, sideOrientation?: number, frontUVs?: Vector4, backUVs?: Vector4 }): VertexData {
 VertexData.CreatePolyhedron = function(options: { type?: number, size?: number, sizeX?: number, sizeY?: number, sizeZ?: number, custom?: any, faceUV?: Vector4[], faceColors?: Color4[], flat?: boolean, sideOrientation?: number, frontUVs?: Vector4, backUVs?: Vector4 }): VertexData {
     // provided polyhedron types :
     // provided polyhedron types :
@@ -160,7 +161,7 @@ export class PolyhedronBuilder {
      * @returns the polyhedron mesh
      * @returns the polyhedron mesh
      * @see https://doc.babylonjs.com/how_to/polyhedra_shapes
      * @see https://doc.babylonjs.com/how_to/polyhedra_shapes
      */
      */
-    public static CreatePolyhedron(name: string, options: { type?: number, size?: number, sizeX?: number, sizeY?: number, sizeZ?: number, custom?: any, faceUV?: Vector4[], faceColors?: Color4[], flat?: boolean, updatable?: boolean, sideOrientation?: number, frontUVs?: Vector4, backUVs?: Vector4 }, scene: Scene): Mesh {
+    public static CreatePolyhedron(name: string, options: { type?: number, size?: number, sizeX?: number, sizeY?: number, sizeZ?: number, custom?: any, faceUV?: Vector4[], faceColors?: Color4[], flat?: boolean, updatable?: boolean, sideOrientation?: number, frontUVs?: Vector4, backUVs?: Vector4 }, scene: Nullable<Scene> = null): Mesh {
         var polyhedron = new Mesh(name, scene);
         var polyhedron = new Mesh(name, scene);
 
 
         options.sideOrientation = Mesh._GetDefaultSideOrientation(options.sideOrientation);
         options.sideOrientation = Mesh._GetDefaultSideOrientation(options.sideOrientation);

+ 1 - 1
src/Meshes/Builders/shapeBuilder.ts

@@ -100,7 +100,7 @@ export class ShapeBuilder {
      * @see https://doc.babylonjs.com/how_to/parametric_shapes
      * @see https://doc.babylonjs.com/how_to/parametric_shapes
      * @see https://doc.babylonjs.com/how_to/parametric_shapes#extruded-shapes
      * @see https://doc.babylonjs.com/how_to/parametric_shapes#extruded-shapes
      */
      */
-    public static ExtrudeShapeCustom(name: string, options: { shape: Vector3[], path: Vector3[], scaleFunction?: any, rotationFunction?: any, ribbonCloseArray?: boolean, ribbonClosePath?: boolean, cap?: number, updatable?: boolean, sideOrientation?: number, frontUVs?: Vector4, backUVs?: Vector4, instance?: Mesh, invertUV?: boolean }, scene: Scene): Mesh {
+    public static ExtrudeShapeCustom(name: string, options: { shape: Vector3[], path: Vector3[], scaleFunction?: any, rotationFunction?: any, ribbonCloseArray?: boolean, ribbonClosePath?: boolean, cap?: number, updatable?: boolean, sideOrientation?: number, frontUVs?: Vector4, backUVs?: Vector4, instance?: Mesh, invertUV?: boolean }, scene: Nullable<Scene> = null): Mesh {
         var path = options.path;
         var path = options.path;
         var shape = options.shape;
         var shape = options.shape;
         var scaleFunction = options.scaleFunction || (() => { return 1; });
         var scaleFunction = options.scaleFunction || (() => { return 1; });

+ 1 - 1
src/Meshes/Builders/tubeBuilder.ts

@@ -45,7 +45,7 @@ export class TubeBuilder {
      * @see https://doc.babylonjs.com/how_to/parametric_shapes
      * @see https://doc.babylonjs.com/how_to/parametric_shapes
      * @see https://doc.babylonjs.com/how_to/set_shapes#tube
      * @see https://doc.babylonjs.com/how_to/set_shapes#tube
      */
      */
-    public static CreateTube(name: string, options: { path: Vector3[], radius?: number, tessellation?: number, radiusFunction?: { (i: number, distance: number): number; }, cap?: number, arc?: number, updatable?: boolean, sideOrientation?: number, frontUVs?: Vector4, backUVs?: Vector4, instance?: Mesh, invertUV?: boolean }, scene: Scene): Mesh {
+    public static CreateTube(name: string, options: { path: Vector3[], radius?: number, tessellation?: number, radiusFunction?: { (i: number, distance: number): number; }, cap?: number, arc?: number, updatable?: boolean, sideOrientation?: number, frontUVs?: Vector4, backUVs?: Vector4, instance?: Mesh, invertUV?: boolean }, scene: Nullable<Scene> = null): Mesh {
         var path = options.path;
         var path = options.path;
         var instance = options.instance;
         var instance = options.instance;
         var radius = 1.0;
         var radius = 1.0;

+ 237 - 122
src/Meshes/Compression/dracoCompression.ts

@@ -1,4 +1,5 @@
 import { Tools } from "../../Misc/tools";
 import { Tools } from "../../Misc/tools";
+import { WorkerPool } from '../../Misc/workerPool';
 import { Nullable } from "../../types";
 import { Nullable } from "../../types";
 import { IDisposable } from "../../scene";
 import { IDisposable } from "../../scene";
 import { VertexData } from "../../Meshes/mesh.vertexData";
 import { VertexData } from "../../Meshes/mesh.vertexData";
@@ -6,6 +7,8 @@ import { VertexData } from "../../Meshes/mesh.vertexData";
 declare var DracoDecoderModule: any;
 declare var DracoDecoderModule: any;
 declare var WebAssembly: any;
 declare var WebAssembly: any;
 
 
+declare function importScripts(...urls: string[]): void;
+
 /**
 /**
  * Configuration for Draco compression
  * Configuration for Draco compression
  */
  */
@@ -70,7 +73,7 @@ export interface IDracoCompressionConfiguration {
  * @see https://www.babylonjs-playground.com/#N3EK4B#0
  * @see https://www.babylonjs-playground.com/#N3EK4B#0
  */
  */
 export class DracoCompression implements IDisposable {
 export class DracoCompression implements IDisposable {
-    private static _DecoderModulePromise: Promise<any>;
+    private _workerPoolPromise: Promise<WorkerPool>;
 
 
     /**
     /**
      * The configuration. Defaults to the following urls:
      * The configuration. Defaults to the following urls:
@@ -109,18 +112,94 @@ export class DracoCompression implements IDisposable {
     }
     }
 
 
     /**
     /**
+     * Default number of workers to create when creating the draco compression object.
+     */
+    public static DefaultNumWorkers = DracoCompression.GetDefaultNumWorkers();
+
+    private static GetDefaultNumWorkers(): number {
+        const hardwareConcurrency = navigator && navigator.hardwareConcurrency;
+        if (!hardwareConcurrency) {
+            return 1;
+        }
+
+        // Use 50% of the available logical processors but capped at 4.
+        return Math.min(Math.floor(hardwareConcurrency * 0.5), 4);
+    }
+
+    /**
      * Constructor
      * Constructor
+     * @param numWorkers The number of workers for async operations
      */
      */
-    constructor() {
+    constructor(numWorkers = DracoCompression.DefaultNumWorkers) {
+        if (!URL || !URL.createObjectURL) {
+            throw new Error("Object URLs are not available");
+        }
+
+        if (!Worker) {
+            throw new Error("Workers are not available");
+        }
+
+        this._workerPoolPromise = this._loadDecoderWasmBinaryAsync().then((decoderWasmBinary) => {
+            const workerBlobUrl = URL.createObjectURL(new Blob([`(${DracoCompression._Worker.toString()})()`], { type: "application/javascript" }));
+            const workerPromises = new Array<Promise<Worker>>(numWorkers);
+            for (let i = 0; i < workerPromises.length; i++) {
+                workerPromises[i] = new Promise((resolve, reject) => {
+                    const decoder = DracoCompression.Configuration.decoder;
+                    if (decoder) {
+                        const worker = new Worker(workerBlobUrl);
+                        const onError = (error: ErrorEvent) => {
+                            worker.removeEventListener("error", onError);
+                            worker.removeEventListener("message", onMessage);
+                            reject(error);
+                        };
+
+                        const onMessage = (message: MessageEvent) => {
+                            if (message.data === "done") {
+                                worker.removeEventListener("error", onError);
+                                worker.removeEventListener("message", onMessage);
+                                resolve(worker);
+                            }
+                        };
+
+                        worker.addEventListener("error", onError);
+                        worker.addEventListener("message", onMessage);
+
+                        worker.postMessage({
+                            id: "initDecoder",
+                            decoderWasmUrl: decoder.wasmUrl ? Tools.GetAbsoluteUrl(decoder.wasmUrl) : null,
+                            decoderWasmBinary: decoderWasmBinary,
+                            fallbackUrl: decoder.fallbackUrl ? Tools.GetAbsoluteUrl(decoder.fallbackUrl) : null
+                        });
+                    }
+                });
+            }
+
+            return Promise.all(workerPromises).then((workers) => {
+                return new WorkerPool(workers);
+            });
+        });
     }
     }
 
 
     /**
     /**
      * Stop all async operations and release resources.
      * Stop all async operations and release resources.
      */
      */
     public dispose(): void {
     public dispose(): void {
+        this._workerPoolPromise.then((workerPool) => {
+            workerPool.dispose();
+        });
+
+        delete this._workerPoolPromise;
     }
     }
 
 
     /**
     /**
+     * Returns a promise that resolves when ready. Call this manually to ensure draco compression is ready before use.
+     * @returns a promise that resolves when ready
+     */
+    public whenReadyAsync(): Promise<void> {
+        return this._workerPoolPromise.then(() => { });
+    }
+
+   /**
      * Decode Draco compressed mesh data to vertex data.
      * Decode Draco compressed mesh data to vertex data.
      * @param data The ArrayBuffer or ArrayBufferView for the Draco compression data
      * @param data The ArrayBuffer or ArrayBufferView for the Draco compression data
      * @param attributes A map of attributes from vertex buffer kinds to Draco unique ids
      * @param attributes A map of attributes from vertex buffer kinds to Draco unique ids
@@ -129,148 +208,184 @@ export class DracoCompression implements IDisposable {
     public decodeMeshAsync(data: ArrayBuffer | ArrayBufferView, attributes: { [kind: string]: number }): Promise<VertexData> {
     public decodeMeshAsync(data: ArrayBuffer | ArrayBufferView, attributes: { [kind: string]: number }): Promise<VertexData> {
         const dataView = data instanceof ArrayBuffer ? new Uint8Array(data) : data;
         const dataView = data instanceof ArrayBuffer ? new Uint8Array(data) : data;
 
 
-        return DracoCompression._GetDecoderModule().then((wrappedModule) => {
-            const module = wrappedModule.module;
-            const vertexData = new VertexData();
-
-            const buffer = new module.DecoderBuffer();
-            buffer.Init(dataView, dataView.byteLength);
-
-            const decoder = new module.Decoder();
-            let geometry: any;
-            let status: any;
-
-            try {
-                const type = decoder.GetEncodedGeometryType(buffer);
-                switch (type) {
-                    case module.TRIANGULAR_MESH:
-                        geometry = new module.Mesh();
-                        status = decoder.DecodeBufferToMesh(buffer, geometry);
-                        break;
-                    case module.POINT_CLOUD:
-                        geometry = new module.PointCloud();
-                        status = decoder.DecodeBufferToPointCloud(buffer, geometry);
-                        break;
-                    default:
-                        throw new Error(`Invalid geometry type ${type}`);
-                }
+        return this._workerPoolPromise.then((workerPool) => {
+            return new Promise<VertexData>((resolve, reject) => {
+                workerPool.push((worker, onComplete) => {
+                    const vertexData = new VertexData();
 
 
-                if (!status.ok() || !geometry.ptr) {
-                    throw new Error(status.error_msg());
-                }
+                    const onError = (error: ErrorEvent) => {
+                        worker.removeEventListener("error", onError);
+                        worker.removeEventListener("message", onMessage);
+                        reject(error);
+                        onComplete();
+                    };
 
 
-                const numPoints = geometry.num_points();
-
-                if (type === module.TRIANGULAR_MESH) {
-                    const numFaces = geometry.num_faces();
-                    const faceIndices = new module.DracoInt32Array();
-                    try {
-                        const indices = new Uint32Array(numFaces * 3);
-                        for (let i = 0; i < numFaces; i++) {
-                            decoder.GetFaceFromMesh(geometry, i, faceIndices);
-                            const offset = i * 3;
-                            indices[offset + 0] = faceIndices.GetValue(0);
-                            indices[offset + 1] = faceIndices.GetValue(1);
-                            indices[offset + 2] = faceIndices.GetValue(2);
+                    const onMessage = (message: MessageEvent) => {
+                        if (message.data === "done") {
+                            worker.removeEventListener("error", onError);
+                            worker.removeEventListener("message", onMessage);
+                            resolve(vertexData);
+                            onComplete();
                         }
                         }
-                        vertexData.indices = indices;
-                    }
-                    finally {
-                        module.destroy(faceIndices);
-                    }
-                }
-
-                for (const kind in attributes) {
-                    const uniqueId = attributes[kind];
-                    const attribute = decoder.GetAttributeByUniqueId(geometry, uniqueId);
-                    const dracoData = new module.DracoFloat32Array();
-                    try {
-                        decoder.GetAttributeFloatForAllPoints(geometry, attribute, dracoData);
-                        const babylonData = new Float32Array(numPoints * attribute.num_components());
-                        for (let i = 0; i < babylonData.length; i++) {
-                            babylonData[i] = dracoData.GetValue(i);
+                        else if (message.data.id === "indices") {
+                            vertexData.indices = message.data.value;
                         }
                         }
-                        vertexData.set(babylonData, kind);
-                    }
-                    finally {
-                        module.destroy(dracoData);
-                    }
-                }
-            }
-            finally {
-                if (geometry) {
-                    module.destroy(geometry);
-                }
+                        else {
+                            vertexData.set(message.data.value, message.data.id);
+                        }
+                    };
 
 
-                module.destroy(decoder);
-                module.destroy(buffer);
-            }
+                    worker.addEventListener("error", onError);
+                    worker.addEventListener("message", onMessage);
+
+                    const dataViewCopy = new Uint8Array(dataView.byteLength);
+                    dataViewCopy.set(new Uint8Array(dataView.buffer, dataView.byteOffset, dataView.byteLength));
 
 
-            return vertexData;
+                    worker.postMessage({ id: "decodeMesh", dataView: dataViewCopy, attributes: attributes }, [dataViewCopy.buffer]);
+                });
+            });
         });
         });
     }
     }
 
 
-    private static _GetDecoderModule(): Promise<any> {
-        if (!DracoCompression._DecoderModulePromise) {
-            let promise: Nullable<Promise<any>> = null;
-            let config: any = {};
+    /**
+     * The worker function that gets converted to a blob url to pass into a worker.
+     */
+    private static _Worker(): void {
+        // self is actually a DedicatedWorkerGlobalScope
+        const _self = self as any as {
+            onmessage: (event: MessageEvent) => void;
+            postMessage: (message: any, transfer?: any[]) => void;
+            close: () => void;
+        };
+
+        let decoderModulePromise: Promise<any>;
 
 
-            if (typeof DracoDecoderModule !== "undefined") {
-                promise = Promise.resolve();
+        function initDecoder(decoderWasmUrl: string | undefined, decoderWasmBinary: ArrayBuffer | undefined, fallbackUrl: string | undefined): void {
+            if (decoderWasmUrl && decoderWasmBinary && typeof WebAssembly === "object") {
+                importScripts(decoderWasmUrl);
+                decoderModulePromise = DracoDecoderModule({
+                    wasmBinary: decoderWasmBinary
+                });
+            }
+            else if (fallbackUrl) {
+                importScripts(fallbackUrl);
+                decoderModulePromise = DracoDecoderModule();
             }
             }
             else {
             else {
-                const decoder = DracoCompression.Configuration.decoder;
-                if (decoder) {
-                    if (decoder.wasmUrl && decoder.wasmBinaryUrl && typeof WebAssembly === "object") {
-                        promise = Promise.all([
-                            DracoCompression._LoadScriptAsync(decoder.wasmUrl),
-                            DracoCompression._LoadFileAsync(decoder.wasmBinaryUrl).then((data) => {
-                                config.wasmBinary = data;
-                            })
-                        ]);
+                throw Error("Failed to initialize Draco decoder");
+            }
+
+            _self.postMessage("done");
+        }
+
+        function decodeMesh(dataView: ArrayBufferView, attributes: { [kind: string]: number }): void {
+            decoderModulePromise.then((decoderModule) => {
+                const buffer = new decoderModule.DecoderBuffer();
+                buffer.Init(dataView, dataView.byteLength);
+
+                const decoder = new decoderModule.Decoder();
+                let geometry: any;
+                let status: any;
+
+                try {
+                    const type = decoder.GetEncodedGeometryType(buffer);
+                    switch (type) {
+                        case decoderModule.TRIANGULAR_MESH:
+                            geometry = new decoderModule.Mesh();
+                            status = decoder.DecodeBufferToMesh(buffer, geometry);
+                            break;
+                        case decoderModule.POINT_CLOUD:
+                            geometry = new decoderModule.PointCloud();
+                            status = decoder.DecodeBufferToPointCloud(buffer, geometry);
+                            break;
+                        default:
+                            throw new Error(`Invalid geometry type ${type}`);
                     }
                     }
-                    else if (decoder.fallbackUrl) {
-                        promise = DracoCompression._LoadScriptAsync(decoder.fallbackUrl);
+
+                    if (!status.ok() || !geometry.ptr) {
+                        throw new Error(status.error_msg());
                     }
                     }
-                }
-            }
 
 
-            if (!promise) {
-                throw new Error("Draco decoder module is not available");
-            }
+                    const numPoints = geometry.num_points();
 
 
-            DracoCompression._DecoderModulePromise = promise.then(() => {
-                return new Promise((resolve) => {
-                    config.onModuleLoaded = (decoderModule: any) => {
-                        // decoderModule is Promise-like. Wrap before resolving to avoid loop.
-                        resolve({ module: decoderModule });
-                    };
+                    if (type === decoderModule.TRIANGULAR_MESH) {
+                        const numFaces = geometry.num_faces();
+                        const faceIndices = new decoderModule.DracoInt32Array();
+                        try {
+                            const indices = new Uint32Array(numFaces * 3);
+                            for (let i = 0; i < numFaces; i++) {
+                                decoder.GetFaceFromMesh(geometry, i, faceIndices);
+                                const offset = i * 3;
+                                indices[offset + 0] = faceIndices.GetValue(0);
+                                indices[offset + 1] = faceIndices.GetValue(1);
+                                indices[offset + 2] = faceIndices.GetValue(2);
+                            }
+                            _self.postMessage({ id: "indices", value: indices }, [indices.buffer]);
+                        }
+                        finally {
+                            decoderModule.destroy(faceIndices);
+                        }
+                    }
 
 
-                    DracoDecoderModule(config);
-                });
-            });
-        }
+                    for (const kind in attributes) {
+                        const uniqueId = attributes[kind];
+                        const attribute = decoder.GetAttributeByUniqueId(geometry, uniqueId);
+                        const dracoData = new decoderModule.DracoFloat32Array();
+                        try {
+                            decoder.GetAttributeFloatForAllPoints(geometry, attribute, dracoData);
+                            const babylonData = new Float32Array(numPoints * attribute.num_components());
+                            for (let i = 0; i < babylonData.length; i++) {
+                                babylonData[i] = dracoData.GetValue(i);
+                            }
+                            _self.postMessage({ id: kind, value: babylonData }, [babylonData.buffer]);
+                        }
+                        finally {
+                            decoderModule.destroy(dracoData);
+                        }
+                    }
+                }
+                finally {
+                    if (geometry) {
+                        decoderModule.destroy(geometry);
+                    }
 
 
-        return DracoCompression._DecoderModulePromise;
-    }
+                    decoderModule.destroy(decoder);
+                    decoderModule.destroy(buffer);
+                }
 
 
-    private static _LoadScriptAsync(url: string): Promise<void> {
-        return new Promise((resolve, reject) => {
-            Tools.LoadScript(url, () => {
-                resolve();
-            }, (message) => {
-                reject(new Error(message));
+                _self.postMessage("done");
             });
             });
-        });
+        }
+
+        _self.onmessage = (event) => {
+            const data = event.data;
+            switch (data.id) {
+                case "initDecoder": {
+                    initDecoder(data.decoderWasmUrl, data.decoderWasmBinary, data.fallbackUrl);
+                    break;
+                }
+                case "decodeMesh": {
+                    decodeMesh(data.dataView, data.attributes);
+                    break;
+                }
+            }
+        };
     }
     }
 
 
-    private static _LoadFileAsync(url: string): Promise<ArrayBuffer> {
-        return new Promise((resolve, reject) => {
-            Tools.LoadFile(url, (data) => {
-                resolve(data as ArrayBuffer);
-            }, undefined, undefined, true, (request, exception) => {
-                reject(exception);
+    private _loadDecoderWasmBinaryAsync(): Promise<Nullable<ArrayBuffer>> {
+        const decoder = DracoCompression.Configuration.decoder;
+        if (decoder && decoder.wasmUrl && decoder.wasmBinaryUrl && typeof WebAssembly === "object") {
+            const wasmBinaryUrl = Tools.GetAbsoluteUrl(decoder.wasmBinaryUrl);
+            return new Promise((resolve, reject) => {
+                Tools.LoadFile(wasmBinaryUrl, (data) => {
+                    resolve(data as ArrayBuffer);
+                }, undefined, undefined, true, (request, exception) => {
+                    reject(exception);
+                });
             });
             });
-        });
+        }
+        else {
+            return Promise.resolve(null);
+        }
     }
     }
 }
 }

+ 8 - 0
src/Meshes/abstractMesh.ts

@@ -487,6 +487,11 @@ export class AbstractMesh extends TransformNode implements IDisposable, ICullabl
     public alwaysSelectAsActiveMesh = false;
     public alwaysSelectAsActiveMesh = false;
 
 
     /**
     /**
+     * Gets or sets a boolean indicating that the bounding info does not need to be kept in sync (for performance reason)
+     */
+    public doNotSyncBoundingInfo = false;
+
+    /**
      * Gets or sets the current action manager
      * Gets or sets the current action manager
      * @see http://doc.babylonjs.com/how_to/how_to_use_actions
      * @see http://doc.babylonjs.com/how_to/how_to_use_actions
      */
      */
@@ -1284,6 +1289,9 @@ export class AbstractMesh extends TransformNode implements IDisposable, ICullabl
 
 
     /** @hidden */
     /** @hidden */
     protected _afterComputeWorldMatrix(): void {
     protected _afterComputeWorldMatrix(): void {
+        if (this.doNotSyncBoundingInfo) {
+            return;
+        }
         // Bounding info
         // Bounding info
         this._updateBoundingInfo();
         this._updateBoundingInfo();
     }
     }

+ 15 - 15
src/Meshes/meshBuilder.ts

@@ -65,7 +65,7 @@ export class MeshBuilder {
      * @returns the sphere mesh
      * @returns the sphere mesh
      * @see https://doc.babylonjs.com/how_to/set_shapes#sphere
      * @see https://doc.babylonjs.com/how_to/set_shapes#sphere
      */
      */
-    public static CreateSphere(name: string, options: { segments?: number, diameter?: number, diameterX?: number, diameterY?: number, diameterZ?: number, arc?: number, slice?: number, sideOrientation?: number, frontUVs?: Vector4, backUVs?: Vector4, updatable?: boolean }, scene: any): Mesh {
+    public static CreateSphere(name: string, options: { segments?: number, diameter?: number, diameterX?: number, diameterY?: number, diameterZ?: number, arc?: number, slice?: number, sideOrientation?: number, frontUVs?: Vector4, backUVs?: Vector4, updatable?: boolean }, scene: Nullable<Scene> = null): Mesh {
         return SphereBuilder.CreateSphere(name, options, scene);
         return SphereBuilder.CreateSphere(name, options, scene);
     }
     }
 
 
@@ -102,7 +102,7 @@ export class MeshBuilder {
      * @returns the icosahedron mesh
      * @returns the icosahedron mesh
      * @see https://doc.babylonjs.com/how_to/polyhedra_shapes#icosphere
      * @see https://doc.babylonjs.com/how_to/polyhedra_shapes#icosphere
      */
      */
-    public static CreateIcoSphere(name: string, options: { radius?: number, radiusX?: number, radiusY?: number, radiusZ?: number, flat?: boolean, subdivisions?: number, sideOrientation?: number, frontUVs?: Vector4, backUVs?: Vector4, updatable?: boolean }, scene: Scene): Mesh {
+    public static CreateIcoSphere(name: string, options: { radius?: number, radiusX?: number, radiusY?: number, radiusZ?: number, flat?: boolean, subdivisions?: number, sideOrientation?: number, frontUVs?: Vector4, backUVs?: Vector4, updatable?: boolean }, scene: Nullable<Scene> = null): Mesh {
         return IcoSphereBuilder.CreateIcoSphere(name, options, scene);
         return IcoSphereBuilder.CreateIcoSphere(name, options, scene);
     }
     }
 
 
@@ -160,7 +160,7 @@ export class MeshBuilder {
      * @returns the cylinder mesh
      * @returns the cylinder mesh
      * @see https://doc.babylonjs.com/how_to/set_shapes#cylinder-or-cone
      * @see https://doc.babylonjs.com/how_to/set_shapes#cylinder-or-cone
      */
      */
-    public static CreateCylinder(name: string, options: { height?: number, diameterTop?: number, diameterBottom?: number, diameter?: number, tessellation?: number, subdivisions?: number, arc?: number, faceColors?: Color4[], faceUV?: Vector4[], updatable?: boolean, hasRings?: boolean, enclose?: boolean, sideOrientation?: number, frontUVs?: Vector4, backUVs?: Vector4 }, scene: any): Mesh {
+    public static CreateCylinder(name: string, options: { height?: number, diameterTop?: number, diameterBottom?: number, diameter?: number, tessellation?: number, subdivisions?: number, arc?: number, faceColors?: Color4[], faceUV?: Vector4[], updatable?: boolean, hasRings?: boolean, enclose?: boolean, sideOrientation?: number, frontUVs?: Vector4, backUVs?: Vector4 }, scene: Nullable<Scene> = null): Mesh {
         return CylinderBuilder.CreateCylinder(name, options, scene);
         return CylinderBuilder.CreateCylinder(name, options, scene);
     }
     }
 
 
@@ -178,7 +178,7 @@ export class MeshBuilder {
      * @returns the torus mesh
      * @returns the torus mesh
      * @see https://doc.babylonjs.com/how_to/set_shapes#torus
      * @see https://doc.babylonjs.com/how_to/set_shapes#torus
      */
      */
-    public static CreateTorus(name: string, options: { diameter?: number, thickness?: number, tessellation?: number, updatable?: boolean, sideOrientation?: number, frontUVs?: Vector4, backUVs?: Vector4 }, scene: any): Mesh {
+    public static CreateTorus(name: string, options: { diameter?: number, thickness?: number, tessellation?: number, updatable?: boolean, sideOrientation?: number, frontUVs?: Vector4, backUVs?: Vector4 }, scene: Nullable<Scene> = null): Mesh {
         return TorusBuilder.CreateTorus(name, options, scene);
         return TorusBuilder.CreateTorus(name, options, scene);
     }
     }
 
 
@@ -197,7 +197,7 @@ export class MeshBuilder {
      * @returns the torus knot mesh
      * @returns the torus knot mesh
      * @see  https://doc.babylonjs.com/how_to/set_shapes#torus-knot
      * @see  https://doc.babylonjs.com/how_to/set_shapes#torus-knot
      */
      */
-    public static CreateTorusKnot(name: string, options: { radius?: number, tube?: number, radialSegments?: number, tubularSegments?: number, p?: number, q?: number, updatable?: boolean, sideOrientation?: number, frontUVs?: Vector4, backUVs?: Vector4 }, scene: any): Mesh {
+    public static CreateTorusKnot(name: string, options: { radius?: number, tube?: number, radialSegments?: number, tubularSegments?: number, p?: number, q?: number, updatable?: boolean, sideOrientation?: number, frontUVs?: Vector4, backUVs?: Vector4 }, scene: Nullable<Scene> = null): Mesh {
         return TorusKnotBuilder.CreateTorusKnot(name, options, scene);
         return TorusKnotBuilder.CreateTorusKnot(name, options, scene);
     }
     }
 
 
@@ -313,7 +313,7 @@ export class MeshBuilder {
      * @see https://doc.babylonjs.com/how_to/parametric_shapes
      * @see https://doc.babylonjs.com/how_to/parametric_shapes
      * @see https://doc.babylonjs.com/how_to/parametric_shapes#extruded-shapes
      * @see https://doc.babylonjs.com/how_to/parametric_shapes#extruded-shapes
      */
      */
-    public static ExtrudeShapeCustom(name: string, options: { shape: Vector3[], path: Vector3[], scaleFunction?: any, rotationFunction?: any, ribbonCloseArray?: boolean, ribbonClosePath?: boolean, cap?: number, updatable?: boolean, sideOrientation?: number, frontUVs?: Vector4, backUVs?: Vector4, instance?: Mesh, invertUV?: boolean }, scene: Scene): Mesh {
+    public static ExtrudeShapeCustom(name: string, options: { shape: Vector3[], path: Vector3[], scaleFunction?: any, rotationFunction?: any, ribbonCloseArray?: boolean, ribbonClosePath?: boolean, cap?: number, updatable?: boolean, sideOrientation?: number, frontUVs?: Vector4, backUVs?: Vector4, instance?: Mesh, invertUV?: boolean }, scene: Nullable<Scene> = null): Mesh {
         return ShapeBuilder.ExtrudeShapeCustom(name, options, scene);
         return ShapeBuilder.ExtrudeShapeCustom(name, options, scene);
     }
     }
 
 
@@ -337,7 +337,7 @@ export class MeshBuilder {
      * @returns the lathe mesh
      * @returns the lathe mesh
      * @see https://doc.babylonjs.com/how_to/parametric_shapes#lathe
      * @see https://doc.babylonjs.com/how_to/parametric_shapes#lathe
      */
      */
-    public static CreateLathe(name: string, options: { shape: Vector3[], radius?: number, tessellation?: number, clip?: number, arc?: number, closed?: boolean, updatable?: boolean, sideOrientation?: number, frontUVs?: Vector4, backUVs?: Vector4, cap?: number, invertUV?: boolean }, scene: Scene): Mesh {
+    public static CreateLathe(name: string, options: { shape: Vector3[], radius?: number, tessellation?: number, clip?: number, arc?: number, closed?: boolean, updatable?: boolean, sideOrientation?: number, frontUVs?: Vector4, backUVs?: Vector4, cap?: number, invertUV?: boolean }, scene: Nullable<Scene> = null): Mesh {
         return LatheBuilder.CreateLathe(name, options, scene);
         return LatheBuilder.CreateLathe(name, options, scene);
     }
     }
 
 
@@ -355,7 +355,7 @@ export class MeshBuilder {
      * @returns the plane mesh
      * @returns the plane mesh
      * @see https://doc.babylonjs.com/how_to/set_shapes#plane
      * @see https://doc.babylonjs.com/how_to/set_shapes#plane
      */
      */
-    public static CreatePlane(name: string, options: { size?: number, width?: number, height?: number, sideOrientation?: number, frontUVs?: Vector4, backUVs?: Vector4, updatable?: boolean, sourcePlane?: Plane }, scene: Scene): Mesh {
+    public static CreatePlane(name: string, options: { size?: number, width?: number, height?: number, sideOrientation?: number, frontUVs?: Vector4, backUVs?: Vector4, updatable?: boolean, sourcePlane?: Plane }, scene: Nullable<Scene> = null): Mesh {
         return PlaneBuilder.CreatePlane(name, options, scene);
         return PlaneBuilder.CreatePlane(name, options, scene);
     }
     }
 
 
@@ -370,7 +370,7 @@ export class MeshBuilder {
      * @returns the ground mesh
      * @returns the ground mesh
      * @see https://doc.babylonjs.com/how_to/set_shapes#ground
      * @see https://doc.babylonjs.com/how_to/set_shapes#ground
      */
      */
-    public static CreateGround(name: string, options: { width?: number, height?: number, subdivisions?: number, subdivisionsX?: number, subdivisionsY?: number, updatable?: boolean }, scene: any): Mesh {
+    public static CreateGround(name: string, options: { width?: number, height?: number, subdivisions?: number, subdivisionsX?: number, subdivisionsY?: number, updatable?: boolean }, scene: Nullable<Scene> = null): Mesh {
         return GroundBuilder.CreateGround(name, options, scene);
         return GroundBuilder.CreateGround(name, options, scene);
     }
     }
 
 
@@ -387,7 +387,7 @@ export class MeshBuilder {
      * @returns the tiled ground mesh
      * @returns the tiled ground mesh
      * @see https://doc.babylonjs.com/how_to/set_shapes#tiled-ground
      * @see https://doc.babylonjs.com/how_to/set_shapes#tiled-ground
      */
      */
-    public static CreateTiledGround(name: string, options: { xmin: number, zmin: number, xmax: number, zmax: number, subdivisions?: { w: number; h: number; }, precision?: { w: number; h: number; }, updatable?: boolean }, scene: Scene): Mesh {
+    public static CreateTiledGround(name: string, options: { xmin: number, zmin: number, xmax: number, zmax: number, subdivisions?: { w: number; h: number; }, precision?: { w: number; h: number; }, updatable?: boolean }, scene: Nullable<Scene> = null): Mesh {
         return GroundBuilder.CreateTiledGround(name, options, scene);
         return GroundBuilder.CreateTiledGround(name, options, scene);
     }
     }
 
 
@@ -410,7 +410,7 @@ export class MeshBuilder {
      * @see https://doc.babylonjs.com/babylon101/height_map
      * @see https://doc.babylonjs.com/babylon101/height_map
      * @see https://doc.babylonjs.com/how_to/set_shapes#ground-from-a-height-map
      * @see https://doc.babylonjs.com/how_to/set_shapes#ground-from-a-height-map
      */
      */
-    public static CreateGroundFromHeightMap(name: string, url: string, options: { width?: number, height?: number, subdivisions?: number, minHeight?: number, maxHeight?: number, colorFilter?: Color3, alphaFilter?: number, updatable?: boolean, onReady?: (mesh: GroundMesh) => void }, scene: Scene): GroundMesh {
+    public static CreateGroundFromHeightMap(name: string, url: string, options: { width?: number, height?: number, subdivisions?: number, minHeight?: number, maxHeight?: number, colorFilter?: Color3, alphaFilter?: number, updatable?: boolean, onReady?: (mesh: GroundMesh) => void }, scene: Nullable<Scene> = null): GroundMesh {
         return GroundBuilder.CreateGroundFromHeightMap(name, url, options, scene);
         return GroundBuilder.CreateGroundFromHeightMap(name, url, options, scene);
     }
     }
 
 
@@ -428,7 +428,7 @@ export class MeshBuilder {
      * @param earcutInjection can be used to inject your own earcut reference
      * @param earcutInjection can be used to inject your own earcut reference
      * @returns the polygon mesh
      * @returns the polygon mesh
      */
      */
-    public static CreatePolygon(name: string, options: { shape: Vector3[], holes?: Vector3[][], depth?: number, faceUV?: Vector4[], faceColors?: Color4[], updatable?: boolean, sideOrientation?: number, frontUVs?: Vector4, backUVs?: Vector4, }, scene: Scene, earcutInjection = earcut): Mesh {
+    public static CreatePolygon(name: string, options: { shape: Vector3[], holes?: Vector3[][], depth?: number, faceUV?: Vector4[], faceColors?: Color4[], updatable?: boolean, sideOrientation?: number, frontUVs?: Vector4, backUVs?: Vector4, }, scene: Nullable<Scene> = null, earcutInjection = earcut): Mesh {
         return PolygonBuilder.CreatePolygon(name, options, scene, earcutInjection);
         return PolygonBuilder.CreatePolygon(name, options, scene, earcutInjection);
     }
     }
 
 
@@ -442,7 +442,7 @@ export class MeshBuilder {
      * @param earcutInjection can be used to inject your own earcut reference
      * @param earcutInjection can be used to inject your own earcut reference
      * @returns the polygon mesh
      * @returns the polygon mesh
      */
      */
-    public static ExtrudePolygon(name: string, options: { shape: Vector3[], holes?: Vector3[][], depth?: number, faceUV?: Vector4[], faceColors?: Color4[], updatable?: boolean, sideOrientation?: number, frontUVs?: Vector4, backUVs?: Vector4 }, scene: Scene, earcutInjection = earcut): Mesh {
+    public static ExtrudePolygon(name: string, options: { shape: Vector3[], holes?: Vector3[][], depth?: number, faceUV?: Vector4[], faceColors?: Color4[], updatable?: boolean, sideOrientation?: number, frontUVs?: Vector4, backUVs?: Vector4 }, scene: Nullable<Scene> = null, earcutInjection = earcut): Mesh {
         return PolygonBuilder.ExtrudePolygon(name, options, scene, earcutInjection);
         return PolygonBuilder.ExtrudePolygon(name, options, scene, earcutInjection);
     }
     }
 
 
@@ -468,7 +468,7 @@ export class MeshBuilder {
      * @see https://doc.babylonjs.com/how_to/parametric_shapes
      * @see https://doc.babylonjs.com/how_to/parametric_shapes
      * @see https://doc.babylonjs.com/how_to/set_shapes#tube
      * @see https://doc.babylonjs.com/how_to/set_shapes#tube
      */
      */
-    public static CreateTube(name: string, options: { path: Vector3[], radius?: number, tessellation?: number, radiusFunction?: { (i: number, distance: number): number; }, cap?: number, arc?: number, updatable?: boolean, sideOrientation?: number, frontUVs?: Vector4, backUVs?: Vector4, instance?: Mesh, invertUV?: boolean }, scene: Scene): Mesh {
+    public static CreateTube(name: string, options: { path: Vector3[], radius?: number, tessellation?: number, radiusFunction?: { (i: number, distance: number): number; }, cap?: number, arc?: number, updatable?: boolean, sideOrientation?: number, frontUVs?: Vector4, backUVs?: Vector4, instance?: Mesh, invertUV?: boolean }, scene: Nullable<Scene> = null): Mesh {
         return TubeBuilder.CreateTube(name, options, scene);
         return TubeBuilder.CreateTube(name, options, scene);
     }
     }
 
 
@@ -491,7 +491,7 @@ export class MeshBuilder {
      * @returns the polyhedron mesh
      * @returns the polyhedron mesh
      * @see https://doc.babylonjs.com/how_to/polyhedra_shapes
      * @see https://doc.babylonjs.com/how_to/polyhedra_shapes
      */
      */
-    public static CreatePolyhedron(name: string, options: { type?: number, size?: number, sizeX?: number, sizeY?: number, sizeZ?: number, custom?: any, faceUV?: Vector4[], faceColors?: Color4[], flat?: boolean, updatable?: boolean, sideOrientation?: number, frontUVs?: Vector4, backUVs?: Vector4 }, scene: Scene): Mesh {
+    public static CreatePolyhedron(name: string, options: { type?: number, size?: number, sizeX?: number, sizeY?: number, sizeZ?: number, custom?: any, faceUV?: Vector4[], faceColors?: Color4[], flat?: boolean, updatable?: boolean, sideOrientation?: number, frontUVs?: Vector4, backUVs?: Vector4 }, scene: Nullable<Scene> = null): Mesh {
         return PolyhedronBuilder.CreatePolyhedron(name, options, scene);
         return PolyhedronBuilder.CreatePolyhedron(name, options, scene);
     }
     }
 
 

+ 3 - 1
src/Meshes/meshSimplification.ts

@@ -575,7 +575,9 @@ class QuadraticErrorSimplification implements ISimplifier {
                     if (uvs && uvs.length) {
                     if (uvs && uvs.length) {
                         newUVsData.push(uvs[(originalOffset * 2)]);
                         newUVsData.push(uvs[(originalOffset * 2)]);
                         newUVsData.push(uvs[(originalOffset * 2) + 1]);
                         newUVsData.push(uvs[(originalOffset * 2) + 1]);
-                    } else if (colorsData && colorsData.length) {
+                    }
+
+                    if (colorsData && colorsData.length) {
                         newColorsData.push(colorsData[(originalOffset * 4)]);
                         newColorsData.push(colorsData[(originalOffset * 4)]);
                         newColorsData.push(colorsData[(originalOffset * 4) + 1]);
                         newColorsData.push(colorsData[(originalOffset * 4) + 1]);
                         newColorsData.push(colorsData[(originalOffset * 4) + 2]);
                         newColorsData.push(colorsData[(originalOffset * 4) + 2]);

+ 183 - 115
src/Meshes/transformNode.ts

@@ -56,8 +56,11 @@ export class TransformNode extends Node {
     protected _isDirty = false;
     protected _isDirty = false;
     private _transformToBoneReferal: Nullable<TransformNode>;
     private _transformToBoneReferal: Nullable<TransformNode>;
 
 
+    @serialize("billboardMode")
+    private _billboardMode = TransformNode.BILLBOARDMODE_NONE;
+
     /**
     /**
-    * Set the billboard mode. Default is 0.
+    * Gets or sets the billboard mode. Default is 0.
     *
     *
     * | Value | Type | Description |
     * | Value | Type | Description |
     * | --- | --- | --- |
     * | --- | --- | --- |
@@ -68,14 +71,36 @@ export class TransformNode extends Node {
     * | 7 | BILLBOARDMODE_ALL |  |
     * | 7 | BILLBOARDMODE_ALL |  |
     *
     *
     */
     */
-    @serialize()
-    public billboardMode = TransformNode.BILLBOARDMODE_NONE;
+    public get billboardMode() {
+        return this._billboardMode;
+    }
+
+    public set billboardMode(value: number) {
+        if (this._billboardMode === value) {
+            return;
+        }
+        this._billboardMode = value;
+
+        this._connectBillboardProcessors();
+    }
 
 
+    private _preserveParentRotationForBillboard = false;
     /**
     /**
      * Gets or sets a boolean indicating that parent rotation should be preserved when using billboards.
      * Gets or sets a boolean indicating that parent rotation should be preserved when using billboards.
      * This could be useful for glTF objects where parent rotation helps converting from right handed to left handed
      * This could be useful for glTF objects where parent rotation helps converting from right handed to left handed
      */
      */
-    public preserveParentRotationForBillboard = false;
+    public get preserveParentRotationForBillboard() {
+        return this._preserveParentRotationForBillboard;
+    };
+
+    public set preserveParentRotationForBillboard(value: boolean) {
+        if (value === this._preserveParentRotationForBillboard) {
+            return;
+        }
+        this._preserveParentRotationForBillboard = value;
+
+        this._connectBillboardProcessors();
+    };
 
 
     /**
     /**
      * Multiplication factor on scale x/y/z when computing the world matrix. Eg. for a 1x1x1 cube setting this to 2 will make it a 2x2x2 cube
      * Multiplication factor on scale x/y/z when computing the world matrix. Eg. for a 1x1x1 cube setting this to 2 will make it a 2x2x2 cube
@@ -96,6 +121,12 @@ export class TransformNode extends Node {
     @serialize()
     @serialize()
     public ignoreNonUniformScaling = false;
     public ignoreNonUniformScaling = false;
 
 
+    /**
+     * Gets or sets a boolean indicating that even if rotationQuaternion is defined, you can keep updating rotation property and Babylon.js will just mix both
+     */
+    @serialize()
+    public reIntegrateRotationIntoRotationQuaternion = false;
+
     // Cache
     // Cache
     /** @hidden */
     /** @hidden */
     public _poseMatrix: Matrix;
     public _poseMatrix: Matrix;
@@ -106,14 +137,22 @@ export class TransformNode extends Node {
     private _pivotMatrix = Matrix.Identity();
     private _pivotMatrix = Matrix.Identity();
     private _pivotMatrixInverse: Matrix;
     private _pivotMatrixInverse: Matrix;
     protected _postMultiplyPivotMatrix = false;
     protected _postMultiplyPivotMatrix = false;
-    private _tempMatrix = Matrix.Identity();
-    private _tempMatrix2 = Matrix.Identity();
 
 
     protected _isWorldMatrixFrozen = false;
     protected _isWorldMatrixFrozen = false;
 
 
     /** @hidden */
     /** @hidden */
     public _indexInSceneTransformNodesArray = -1;
     public _indexInSceneTransformNodesArray = -1;
 
 
+    private _connectBillboardProcessors() {
+        if (this._billboardMode !== TransformNode.BILLBOARDMODE_NONE && !this.preserveParentRotationForBillboard) {
+            this._activeParentProcessor = this._billboardParentProcessor;
+            this._activeBillboardPostProcessor = this._billboardPostProcessor;
+        } else {
+            this._activeParentProcessor = this._defaultParentProcessor;
+            this._activeBillboardPostProcessor = () => { };
+        }
+    }
+
     /**
     /**
     * An event triggered after the world matrix is updated
     * An event triggered after the world matrix is updated
     */
     */
@@ -125,6 +164,9 @@ export class TransformNode extends Node {
         if (isPure) {
         if (isPure) {
             this.getScene().addTransformNode(this);
             this.getScene().addTransformNode(this);
         }
         }
+
+        this._activeParentProcessor = this._defaultParentProcessor;
+        this._activeCompositionProcess = this._defaultCompositionProcessor;
     }
     }
 
 
     /**
     /**
@@ -157,6 +199,7 @@ export class TransformNode extends Node {
 
 
     public set rotation(newRotation: Vector3) {
     public set rotation(newRotation: Vector3) {
         this._rotation = newRotation;
         this._rotation = newRotation;
+        this._rotationQuaternion = null;
         this._isDirty = true;
         this._isDirty = true;
     }
     }
 
 
@@ -186,6 +229,7 @@ export class TransformNode extends Node {
         if (quaternion) {
         if (quaternion) {
             this.rotation.setAll(0.0);
             this.rotation.setAll(0.0);
         }
         }
+        this._isDirty = true;
     }
     }
 
 
     /**
     /**
@@ -238,10 +282,6 @@ export class TransformNode extends Node {
 
 
     /** @hidden */
     /** @hidden */
     public _isSynchronized(): boolean {
     public _isSynchronized(): boolean {
-        if (this._isDirty) {
-            return false;
-        }
-
         if (this.billboardMode !== this._cache.billboardMode || this.billboardMode !== TransformNode.BILLBOARDMODE_NONE) {
         if (this.billboardMode !== this._cache.billboardMode || this.billboardMode !== TransformNode.BILLBOARDMODE_NONE) {
             return false;
             return false;
         }
         }
@@ -262,9 +302,7 @@ export class TransformNode extends Node {
             if (!this._cache.rotationQuaternion.equals(this._rotationQuaternion)) {
             if (!this._cache.rotationQuaternion.equals(this._rotationQuaternion)) {
                 return false;
                 return false;
             }
             }
-        }
-
-        if (!this._cache.rotation.equals(this._rotation)) {
+        } else if (!this._cache.rotation.equals(this._rotation)) {
             return false;
             return false;
         }
         }
 
 
@@ -294,9 +332,6 @@ export class TransformNode extends Node {
     * @returns this transform node
     * @returns this transform node
     */
     */
     public markAsDirty(property: string): TransformNode {
     public markAsDirty(property: string): TransformNode {
-        if (property === "rotation") {
-            this.rotationQuaternion = null;
-        }
         this._currentRenderId = Number.MAX_VALUE;
         this._currentRenderId = Number.MAX_VALUE;
         this._isDirty = true;
         this._isDirty = true;
         return this;
         return this;
@@ -327,6 +362,11 @@ export class TransformNode extends Node {
     */
     */
     public setPivotMatrix(matrix: DeepImmutable<Matrix>, postMultiplyPivotMatrix = true): TransformNode {
     public setPivotMatrix(matrix: DeepImmutable<Matrix>, postMultiplyPivotMatrix = true): TransformNode {
         this._pivotMatrix.copyFrom(matrix);
         this._pivotMatrix.copyFrom(matrix);
+        if (this._pivotMatrix.isIdentity()) {
+            this._activeCompositionProcess = this._defaultCompositionProcessor;
+        } else {
+            this._activeCompositionProcess = this._pivotCompositionProcessor;
+        }
         this._cache.pivotMatrixUpdated = true;
         this._cache.pivotMatrixUpdated = true;
         this._postMultiplyPivotMatrix = postMultiplyPivotMatrix;
         this._postMultiplyPivotMatrix = postMultiplyPivotMatrix;
 
 
@@ -863,152 +903,180 @@ export class TransformNode extends Node {
         return this.parent;
         return this.parent;
     }
     }
 
 
+    private _activeCompositionProcess: (scaling: Vector3, rotation: Quaternion, translation: Vector3) => void;
+
+    private _defaultCompositionProcessor = (scaling: Vector3, rotation: Quaternion, translation: Vector3) => {
+        Matrix.ComposeToRef(scaling, rotation, translation, this._localMatrix);
+    }
+
+    private _pivotCompositionProcessor = (scaling: Vector3, rotation: Quaternion, translation: Vector3) => {
+        let scaleMatrix = Tmp.Matrix[1];
+        Matrix.ScalingToRef(scaling.x, scaling.y, scaling.z, scaleMatrix);
+
+        // Rotation
+        let rotationMatrix = Tmp.Matrix[0];
+        rotation.toRotationMatrix(rotationMatrix);
+
+        // Composing transformations
+        this._pivotMatrix.multiplyToRef(scaleMatrix, Tmp.Matrix[4]);
+        Tmp.Matrix[4].multiplyToRef(rotationMatrix, this._localMatrix);
+
+        // Post multiply inverse of pivotMatrix
+        if (this._postMultiplyPivotMatrix) {
+            this._localMatrix.multiplyToRef(this._pivotMatrixInverse, this._localMatrix);
+        }
+
+        this._localMatrix.addTranslationFromFloats(translation.x, translation.y, translation.z);
+    }
+
+    // Billboards
+    private _activeParentProcessor: (parent: Node) => void;
+    private _activeBillboardPostProcessor = () => { };
+
+    private _defaultParentProcessor = (parent: Node) => {
+        if (this._transformToBoneReferal) {
+            this._localMatrix.multiplyToRef(parent.getWorldMatrix(), Tmp.Matrix[6]);
+            Tmp.Matrix[6].multiplyToRef(this._transformToBoneReferal.getWorldMatrix(), this._worldMatrix);
+        } else {
+            this._localMatrix.multiplyToRef(parent.getWorldMatrix(), this._worldMatrix);
+        }
+    };
+
+    private _billboardParentProcessor = (parent: Node) => {
+        if (this._transformToBoneReferal) {
+            parent.getWorldMatrix().multiplyToRef(this._transformToBoneReferal.getWorldMatrix(), Tmp.Matrix[7]);
+        } else {
+            Tmp.Matrix[7].copyFrom(parent.getWorldMatrix());
+        }
+
+        // Extract scaling and translation from parent
+        let translation = Tmp.Vector3[5];
+        let scale = Tmp.Vector3[6];
+        Tmp.Matrix[7].decompose(scale, undefined, translation);
+        Matrix.ScalingToRef(scale.x, scale.y, scale.z, Tmp.Matrix[7]);
+        Tmp.Matrix[7].setTranslation(translation);
+
+        this._localMatrix.multiplyToRef(Tmp.Matrix[7], this._worldMatrix);
+    }
+
+    private _billboardPostProcessor = () => {
+        let camera = (<Camera>this.getScene().activeCamera);
+        if (!camera) {
+            return;
+        }
+        let storedTranslation = Tmp.Vector3[0];
+        this._worldMatrix.getTranslationToRef(storedTranslation); // Save translation
+
+        // Cancel camera rotation
+        Tmp.Matrix[1].copyFrom(camera.getViewMatrix());
+        Tmp.Matrix[1].setTranslationFromFloats(0, 0, 0);
+        Tmp.Matrix[1].invertToRef(Tmp.Matrix[0]);
+
+        if ((this.billboardMode & TransformNode.BILLBOARDMODE_ALL) !== TransformNode.BILLBOARDMODE_ALL) {
+            Tmp.Matrix[0].decompose(undefined, Tmp.Quaternion[0], undefined);
+            let eulerAngles = Tmp.Vector3[1];
+            Tmp.Quaternion[0].toEulerAnglesToRef(eulerAngles);
+
+            if ((this.billboardMode & TransformNode.BILLBOARDMODE_X) !== TransformNode.BILLBOARDMODE_X) {
+                eulerAngles.x = 0;
+            }
+
+            if ((this.billboardMode & TransformNode.BILLBOARDMODE_Y) !== TransformNode.BILLBOARDMODE_Y) {
+                eulerAngles.y = 0;
+            }
+
+            if ((this.billboardMode & TransformNode.BILLBOARDMODE_Z) !== TransformNode.BILLBOARDMODE_Z) {
+                eulerAngles.z = 0;
+            }
+
+            Matrix.RotationYawPitchRollToRef(eulerAngles.y, eulerAngles.x, eulerAngles.z, Tmp.Matrix[0]);
+        }
+        this._worldMatrix.setTranslationFromFloats(0, 0, 0);
+        this._worldMatrix.multiplyToRef(Tmp.Matrix[0], this._worldMatrix);
+
+        // Restore translation
+        this._worldMatrix.setTranslation(Tmp.Vector3[0]);
+    }
+
     /**
     /**
      * Computes the world matrix of the node
      * Computes the world matrix of the node
      * @param force defines if the cache version should be invalidated forcing the world matrix to be created from scratch
      * @param force defines if the cache version should be invalidated forcing the world matrix to be created from scratch
      * @returns the world matrix
      * @returns the world matrix
      */
      */
     public computeWorldMatrix(force?: boolean): Matrix {
     public computeWorldMatrix(force?: boolean): Matrix {
+        let currentRenderId = this.getScene().getRenderId();
+
         if (this._isWorldMatrixFrozen) {
         if (this._isWorldMatrixFrozen) {
             return this._worldMatrix;
             return this._worldMatrix;
         }
         }
 
 
-        if (!force && this.isSynchronized()) {
-            this._currentRenderId = this.getScene().getRenderId();
+        if (!this._isDirty && !force && this.isSynchronized()) {
+            this._currentRenderId = currentRenderId;
             return this._worldMatrix;
             return this._worldMatrix;
         }
         }
 
 
         this._updateCache();
         this._updateCache();
-        this._cache.position.copyFrom(this.position);
-        this._cache.scaling.copyFrom(this.scaling);
         this._cache.pivotMatrixUpdated = false;
         this._cache.pivotMatrixUpdated = false;
         this._cache.billboardMode = this.billboardMode;
         this._cache.billboardMode = this.billboardMode;
         this._cache.infiniteDistance = this.infiniteDistance;
         this._cache.infiniteDistance = this.infiniteDistance;
-        this._currentRenderId = this.getScene().getRenderId();
+
+        this._currentRenderId = currentRenderId;
         this._childUpdateId++;
         this._childUpdateId++;
         this._isDirty = false;
         this._isDirty = false;
         let parent = this._getEffectiveParent();
         let parent = this._getEffectiveParent();
 
 
         // Scaling
         // Scaling
-        Matrix.ScalingToRef(this.scaling.x * this.scalingDeterminant, this.scaling.y * this.scalingDeterminant, this.scaling.z * this.scalingDeterminant, Tmp.Matrix[1]);
-
-        // Rotation
-
-        //rotate, if quaternion is set and rotation was used
-        if (this.rotationQuaternion) {
-            var len = this.rotation.length();
-            if (len) {
-                this.rotationQuaternion.multiplyInPlace(Quaternion.RotationYawPitchRoll(this.rotation.y, this.rotation.x, this.rotation.z));
-                this.rotation.copyFromFloats(0, 0, 0);
-            }
-        }
-
-        if (this.rotationQuaternion) {
-            this.rotationQuaternion.toRotationMatrix(Tmp.Matrix[0]);
-            this._cache.rotationQuaternion.copyFrom(this.rotationQuaternion);
-        } else {
-            Matrix.RotationYawPitchRollToRef(this.rotation.y, this.rotation.x, this.rotation.z, Tmp.Matrix[0]);
-            this._cache.rotation.copyFrom(this.rotation);
-        }
+        let scaling: Vector3 = this._cache.scaling;
+        let translation: Vector3 = this._cache.position;
 
 
         // Translation
         // Translation
         let camera = (<Camera>this.getScene().activeCamera);
         let camera = (<Camera>this.getScene().activeCamera);
 
 
         if (this.infiniteDistance && !this.parent && camera) {
         if (this.infiniteDistance && !this.parent && camera) {
-
             var cameraWorldMatrix = camera.getWorldMatrix();
             var cameraWorldMatrix = camera.getWorldMatrix();
-
             var cameraGlobalPosition = new Vector3(cameraWorldMatrix.m[12], cameraWorldMatrix.m[13], cameraWorldMatrix.m[14]);
             var cameraGlobalPosition = new Vector3(cameraWorldMatrix.m[12], cameraWorldMatrix.m[13], cameraWorldMatrix.m[14]);
 
 
-            Matrix.TranslationToRef(this.position.x + cameraGlobalPosition.x, this.position.y + cameraGlobalPosition.y,
-                this.position.z + cameraGlobalPosition.z, this._tempMatrix2);
+            translation.copyFromFloats(this._position.x + cameraGlobalPosition.x, this._position.y + cameraGlobalPosition.y, this._position.z + cameraGlobalPosition.z);
         } else {
         } else {
-            Matrix.TranslationToRef(this.position.x, this.position.y, this.position.z, this._tempMatrix2);
+            translation.copyFrom(this._position);
         }
         }
 
 
-        // Composing transformations
-        this._pivotMatrix.multiplyToRef(Tmp.Matrix[1], Tmp.Matrix[4]);
-        Tmp.Matrix[4].multiplyToRef(Tmp.Matrix[0], this._tempMatrix);
+        // Scaling
+        scaling.copyFromFloats(this._scaling.x * this.scalingDeterminant, this._scaling.y * this.scalingDeterminant, this._scaling.z * this.scalingDeterminant);
 
 
-        // Post multiply inverse of pivotMatrix
-        if (this._postMultiplyPivotMatrix) {
-            this._tempMatrix.multiplyToRef(this._pivotMatrixInverse, this._tempMatrix);
+        // Rotation
+        let rotation: Quaternion = this._cache.rotationQuaternion;
+        if (this._rotationQuaternion) {
+            if (this.reIntegrateRotationIntoRotationQuaternion) {
+                var len = this.rotation.lengthSquared();
+                if (len) {
+                    this._rotationQuaternion.multiplyInPlace(Quaternion.RotationYawPitchRoll(this._rotation.y, this._rotation.x, this._rotation.z));
+                    this._rotation.copyFromFloats(0, 0, 0);
+                }
+            }
+            rotation.copyFrom(this._rotationQuaternion);
+        } else {
+            Quaternion.RotationYawPitchRollToRef(this._rotation.y, this._rotation.x, this._rotation.z, rotation);
+            this._cache.rotation.copyFrom(this._rotation);
         }
         }
 
 
-        // Local world
-        this._tempMatrix.multiplyToRef(this._tempMatrix2, this._localMatrix);
+        // Compose
+        this._activeCompositionProcess(scaling, rotation, translation);
 
 
         // Parent
         // Parent
         if (parent && parent.getWorldMatrix) {
         if (parent && parent.getWorldMatrix) {
-            // We do not want parent rotation
-            if (this.billboardMode !== TransformNode.BILLBOARDMODE_NONE && !this.preserveParentRotationForBillboard) {
-                if (this._transformToBoneReferal) {
-                    parent.getWorldMatrix().multiplyToRef(this._transformToBoneReferal.getWorldMatrix(), Tmp.Matrix[7]);
-                } else {
-                    Tmp.Matrix[7].copyFrom(parent.getWorldMatrix());
-                }
-
-                // Extract scaling and translation from parent
-                let translation = Tmp.Vector3[5];
-                let scale = Tmp.Vector3[6];
-                Tmp.Matrix[7].decompose(scale, undefined, translation);
-                Matrix.ScalingToRef(scale.x, scale.y, scale.z, Tmp.Matrix[7]);
-                Tmp.Matrix[7].setTranslation(translation);
-
-                this._localMatrix.multiplyToRef(Tmp.Matrix[7], this._worldMatrix);
-            } else {
-                if (this._transformToBoneReferal) {
-                    this._localMatrix.multiplyToRef(parent.getWorldMatrix(), Tmp.Matrix[6]);
-                    Tmp.Matrix[6].multiplyToRef(this._transformToBoneReferal.getWorldMatrix(), this._worldMatrix);
-                } else {
-                    this._localMatrix.multiplyToRef(parent.getWorldMatrix(), this._worldMatrix);
-                }
-            }
-
+            this._activeParentProcessor(parent);
             this._markSyncedWithParent();
             this._markSyncedWithParent();
         } else {
         } else {
             this._worldMatrix.copyFrom(this._localMatrix);
             this._worldMatrix.copyFrom(this._localMatrix);
         }
         }
 
 
         // Billboarding (testing PG:http://www.babylonjs-playground.com/#UJEIL#13)
         // Billboarding (testing PG:http://www.babylonjs-playground.com/#UJEIL#13)
-        if (this.billboardMode !== TransformNode.BILLBOARDMODE_NONE && camera) {
-            let storedTranslation = Tmp.Vector3[0];
-            this._worldMatrix.getTranslationToRef(storedTranslation); // Save translation
-
-            // Cancel camera rotation
-            Tmp.Matrix[1].copyFrom(camera.getViewMatrix());
-            Tmp.Matrix[1].setTranslationFromFloats(0, 0, 0);
-            Tmp.Matrix[1].invertToRef(Tmp.Matrix[0]);
-
-            if ((this.billboardMode & TransformNode.BILLBOARDMODE_ALL) !== TransformNode.BILLBOARDMODE_ALL) {
-                Tmp.Matrix[0].decompose(undefined, Tmp.Quaternion[0], undefined);
-                let eulerAngles = Tmp.Vector3[1];
-                Tmp.Quaternion[0].toEulerAnglesToRef(eulerAngles);
-
-                if ((this.billboardMode & TransformNode.BILLBOARDMODE_X) !== TransformNode.BILLBOARDMODE_X) {
-                    eulerAngles.x = 0;
-                }
-
-                if ((this.billboardMode & TransformNode.BILLBOARDMODE_Y) !== TransformNode.BILLBOARDMODE_Y) {
-                    eulerAngles.y = 0;
-                }
-
-                if ((this.billboardMode & TransformNode.BILLBOARDMODE_Z) !== TransformNode.BILLBOARDMODE_Z) {
-                    eulerAngles.z = 0;
-                }
-
-                Matrix.RotationYawPitchRollToRef(eulerAngles.y, eulerAngles.x, eulerAngles.z, Tmp.Matrix[0]);
-            }
-            this._worldMatrix.setTranslationFromFloats(0, 0, 0);
-            this._worldMatrix.multiplyToRef(Tmp.Matrix[0], this._worldMatrix);
-
-            // Restore translation
-            this._worldMatrix.setTranslation(Tmp.Vector3[0]);
-        }
+        this._activeBillboardPostProcessor();
 
 
         // Normal matrix
         // Normal matrix
         if (!this.ignoreNonUniformScaling) {
         if (!this.ignoreNonUniformScaling) {
-            if (this.scaling.isNonUniform) {
+            if (this._scaling.isNonUniform) {
                 this._updateNonUniformScalingState(true);
                 this._updateNonUniformScalingState(true);
             } else if (parent && (<TransformNode>parent)._nonUniformScaling) {
             } else if (parent && (<TransformNode>parent)._nonUniformScaling) {
                 this._updateNonUniformScalingState((<TransformNode>parent)._nonUniformScaling);
                 this._updateNonUniformScalingState((<TransformNode>parent)._nonUniformScaling);
@@ -1032,7 +1100,7 @@ export class TransformNode extends Node {
         }
         }
 
 
         // Cache the determinant
         // Cache the determinant
-        this._worldMatrixDeterminant = this._worldMatrix.determinant();
+        this._worldMatrixDeterminantIsDirty = true;
 
 
         return this._worldMatrix;
         return this._worldMatrix;
     }
     }

+ 2 - 1
src/Misc/dds.ts

@@ -533,7 +533,8 @@ export class DDSTools {
             mipmapCount = Math.max(1, header[off_mipmapCount]);
             mipmapCount = Math.max(1, header[off_mipmapCount]);
         }
         }
 
 
-        for (var face = 0; face < faces; face++) {
+        const startFace = currentFace || 0;
+        for (var face = startFace; face < faces; face++) {
             width = header[off_width];
             width = header[off_width];
             height = header[off_height];
             height = header[off_height];
 
 

+ 11 - 0
src/Misc/tools.ts

@@ -1462,6 +1462,17 @@ export class Tools {
         return bufferView.buffer;
         return bufferView.buffer;
     }
     }
 
 
+    /**
+     * Gets the absolute url.
+     * @param url the input url
+     * @return the absolute url
+     */
+    public static GetAbsoluteUrl(url: string): string {
+        const a = document.createElement("a");
+        a.href = url;
+        return a.href;
+    }
+
     // Logs
     // Logs
     /**
     /**
      * No log
      * No log

+ 3 - 0
src/Physics/Plugins/ammoJSPlugin.ts

@@ -856,6 +856,9 @@ export class AmmoJSPlugin implements IPhysicsEnginePlugin {
             meshChildren.forEach((childMesh) => {
             meshChildren.forEach((childMesh) => {
                 var childImpostor = childMesh.getPhysicsImpostor();
                 var childImpostor = childMesh.getPhysicsImpostor();
                 if (childImpostor) {
                 if (childImpostor) {
+                    if (childImpostor.type == PhysicsImpostor.MeshImpostor) {
+                        throw "A child MeshImpostor is not supported. Only primitive impostors are supported as children (eg. box or sphere)";
+                    }
                     var shape = this._createShape(childImpostor);
                     var shape = this._createShape(childImpostor);
 
 
                     // Position needs to be scaled based on parent's scaling
                     // Position needs to be scaled based on parent's scaling

+ 6 - 0
src/node.ts

@@ -141,6 +141,8 @@ export class Node implements IBehaviorAware<Node> {
     public _worldMatrix = Matrix.Identity();
     public _worldMatrix = Matrix.Identity();
     /** @hidden */
     /** @hidden */
     public _worldMatrixDeterminant = 0;
     public _worldMatrixDeterminant = 0;
+    /** @hidden */
+    public _worldMatrixDeterminantIsDirty = true;
 
 
     /** @hidden */
     /** @hidden */
     private _sceneRootNodesIndex = -1;
     private _sceneRootNodesIndex = -1;
@@ -381,6 +383,10 @@ export class Node implements IBehaviorAware<Node> {
 
 
     /** @hidden */
     /** @hidden */
     public _getWorldMatrixDeterminant(): number {
     public _getWorldMatrixDeterminant(): number {
+        if (this._worldMatrixDeterminantIsDirty) {
+            this._worldMatrixDeterminantIsDirty = false;
+            this._worldMatrixDeterminant = this._worldMatrix.determinant();
+        }
         return this._worldMatrixDeterminant;
         return this._worldMatrixDeterminant;
     }
     }
 
 

+ 3 - 0
src/scene.ts

@@ -2282,6 +2282,9 @@ export class Scene extends AbstractScene implements IAnimatable {
         this.onPreKeyboardObservable.clear();
         this.onPreKeyboardObservable.clear();
         this.onPointerObservable.clear();
         this.onPointerObservable.clear();
         this.onPrePointerObservable.clear();
         this.onPrePointerObservable.clear();
+
+        // Cursor
+        canvas.style.cursor = this.defaultCursor;
     }
     }
 
 
     /**
     /**

+ 10 - 0
tests/modules/karma.conf.js

@@ -36,6 +36,16 @@ module.exports = function (config) {
 
 
         reporters: ['progress', 'junit'],
         reporters: ['progress', 'junit'],
 
 
+        plugins: [
+            'karma-mocha',
+            'karma-chai',
+            'karma-sinon',
+            'karma-chrome-launcher',
+            'karma-firefox-launcher',
+
+            require('../../Tools/Gulp/helpers/gulp-karmaJunitPlugin')
+        ],
+
         junitReporter: {
         junitReporter: {
             outputDir: '.temp/testResults', // results will be saved as $outputDir/$browserName.xml
             outputDir: '.temp/testResults', // results will be saved as $outputDir/$browserName.xml
             outputFile: 'ModuleTests.xml', // if included, results will be saved as $outputDir/$browserName/$outputFile
             outputFile: 'ModuleTests.xml', // if included, results will be saved as $outputDir/$browserName/$outputFile

+ 4 - 0
tests/modules/tests.json

@@ -2,11 +2,15 @@
     "tests": [
     "tests": [
         {
         {
             "name": "typescript-webpack",
             "name": "typescript-webpack",
+            "reportName": "ModuleTestsWebpack",
+            "displayName": "Webpack Module Tests",
             "typescript": true,
             "typescript": true,
             "bundler": "webpack"
             "bundler": "webpack"
         },
         },
         {
         {
             "name": "typescript-vanilla",
             "name": "typescript-vanilla",
+            "reportName": "ModuleTestsVanilla",
+            "displayName": "Vanilla Module Tests",
             "typescript": true,
             "typescript": true,
             "tsconfig": "tsconfig.json",
             "tsconfig": "tsconfig.json",
             "dependencies": [
             "dependencies": [

+ 10 - 0
tests/unit/karma.conf.js

@@ -50,6 +50,16 @@ module.exports = function (config) {
 
 
         reporters: ['progress', 'junit'],
         reporters: ['progress', 'junit'],
 
 
+        plugins: [
+            'karma-mocha',
+            'karma-chai',
+            'karma-sinon',
+            'karma-chrome-launcher',
+            'karma-firefox-launcher',
+
+            require('../../Tools/Gulp/helpers/gulp-karmaJunitPlugin')
+        ],
+
         junitReporter: {
         junitReporter: {
             outputDir: '.temp/testResults', // results will be saved as $outputDir/$browserName.xml
             outputDir: '.temp/testResults', // results will be saved as $outputDir/$browserName.xml
             outputFile: 'UnitTests.xml', // if included, results will be saved as $outputDir/$browserName/$outputFile
             outputFile: 'UnitTests.xml', // if included, results will be saved as $outputDir/$browserName/$outputFile

+ 4 - 0
tests/validation/integration.js

@@ -12,6 +12,10 @@ xhr.addEventListener("load", function () {
 
 
         describe("Validation Tests", function () {
         describe("Validation Tests", function () {
             before(function (done) {
             before(function (done) {
+                window.disableWebGL2Support = (window.__karma__.config.args && window.__karma__.config.args.indexOf('--disableWebGL2Support') > -1) ? 
+                    true :
+                    false;
+
                 this.timeout(180000);
                 this.timeout(180000);
                 require = null;
                 require = null;
                 BABYLONDEVTOOLS.Loader
                 BABYLONDEVTOOLS.Loader

+ 12 - 2
tests/validation/karma.conf.js

@@ -44,10 +44,20 @@ module.exports = function (config) {
 
 
         reporters: ['progress', 'junit'],
         reporters: ['progress', 'junit'],
 
 
+        plugins: [
+            'karma-mocha',
+            'karma-chai',
+            'karma-sinon',
+            'karma-chrome-launcher',
+            'karma-firefox-launcher',
+
+            require('../../Tools/Gulp/helpers/gulp-karmaJunitPlugin')
+        ],
+
         junitReporter: {
         junitReporter: {
             outputDir: '.temp/testResults', // results will be saved as $outputDir/$browserName.xml
             outputDir: '.temp/testResults', // results will be saved as $outputDir/$browserName.xml
-            outputFile: 'ValidationTests.xml', // if included, results will be saved as $outputDir/$browserName/$outputFile
-            suite: 'Validation Tests', // suite will become the package name attribute in xml testsuite element
+            outputFile: 'ValidationTests2.xml', // if included, results will be saved as $outputDir/$browserName/$outputFile
+            suite: 'Validation Tests WebGL2', // suite will become the package name attribute in xml testsuite element
             useBrowserName: false, // add browser name to report and classes names
             useBrowserName: false, // add browser name to report and classes names
             nameFormatter: undefined, // function (browser, result) to customize the name attribute in xml testcase element
             nameFormatter: undefined, // function (browser, result) to customize the name attribute in xml testcase element
             classNameFormatter: undefined, // function (browser, result) to customize the classname attribute in xml testcase element
             classNameFormatter: undefined, // function (browser, result) to customize the classname attribute in xml testcase element

+ 1 - 1
tests/validation/validation.js

@@ -371,7 +371,7 @@ function init() {
     canvas = document.createElement("canvas");
     canvas = document.createElement("canvas");
     canvas.className = "renderCanvas";
     canvas.className = "renderCanvas";
     document.body.appendChild(canvas);
     document.body.appendChild(canvas);
-    engine = new BABYLON.Engine(canvas, false, { useHighPrecisionFloats: true });
+    engine = new BABYLON.Engine(canvas, false, { useHighPrecisionFloats: true, disableWebGL2Support: window.disableWebGL2Support ? true : false });
     engine.enableOfflineSupport = false;
     engine.enableOfflineSupport = false;
     engine.setDitheringState(false);
     engine.setDitheringState(false);
 }
 }