nockawa преди 8 години
родител
ревизия
423fd4547c
променени са 74 файла, в които са добавени 6953 реда и са изтрити 3766 реда
  1. 1 0
      Playground/debug.html
  2. 1 0
      Playground/frame.html
  3. 1 0
      Playground/index.html
  4. 82 0
      Playground/scripts/pointer events handling.js
  5. 2 1
      Playground/scripts/scripts.txt
  6. 15 0
      Tools/Gulp/config.json
  7. 7 5
      canvas2D/src/Engine/babylon.group2d.ts
  8. 180 59
      canvas2D/src/Engine/babylon.prim2dBase.ts
  9. 4 0
      canvas2D/src/Engine/babylon.text2d.ts
  10. 28 27
      dist/preview release/babylon.core.js
  11. 1361 1274
      dist/preview release/babylon.d.ts
  12. 36 36
      dist/preview release/babylon.js
  13. 707 191
      dist/preview release/babylon.max.js
  14. 1361 1274
      dist/preview release/babylon.module.d.ts
  15. 36 36
      dist/preview release/babylon.noworker.js
  16. 24 2
      dist/preview release/canvas2D/babylon.canvas2d.d.ts
  17. 209 85
      dist/preview release/canvas2D/babylon.canvas2d.js
  18. 12 12
      dist/preview release/canvas2D/babylon.canvas2d.min.js
  19. 4 4
      dist/preview release/inspector/babylon.inspector.bundle.js
  20. 3 0
      dist/preview release/inspector/babylon.inspector.css
  21. 107 3
      dist/preview release/inspector/babylon.inspector.d.ts
  22. 414 48
      dist/preview release/inspector/babylon.inspector.js
  23. 3 3
      dist/preview release/inspector/babylon.inspector.min.js
  24. 1 1
      dist/preview release/loaders/babylon.glTFFileLoader.js
  25. 2 2
      dist/preview release/loaders/babylon.glTFFileLoader.min.js
  26. 21 0
      dist/preview release/materialsLibrary/babylon.shadowOnlyMaterial.d.ts
  27. 209 0
      dist/preview release/materialsLibrary/babylon.shadowOnlyMaterial.js
  28. 1 0
      dist/preview release/materialsLibrary/babylon.shadowOnlyMaterial.min.js
  29. 0 1
      dist/preview release/materialsLibrary/babylon.waterMaterial.d.ts
  30. 0 1
      dist/preview release/materialsLibrary/babylon.waterMaterial.js
  31. 31 3
      dist/preview release/what's new.md
  32. 4 0
      inspector/sass/_tabPanel.scss
  33. 1 0
      inspector/sass/_tree.scss
  34. 140 107
      inspector/src/Inspector.ts
  35. 25 18
      inspector/src/adapters/Adapter.ts
  36. 55 0
      inspector/src/adapters/CameraAdapter.ts
  37. 37 0
      inspector/src/adapters/TextureAdapter.ts
  38. 179 131
      inspector/src/properties.ts
  39. 22 0
      inspector/src/tabs/CameraTab.ts
  40. 49 85
      inspector/src/tabs/ShaderTab.ts
  41. 42 31
      inspector/src/tabs/Tab.ts
  42. 44 35
      inspector/src/tabs/TabBar.ts
  43. 143 0
      inspector/src/tabs/TextureTab.ts
  44. 49 42
      inspector/src/tree/TreeItem.ts
  45. 39 0
      inspector/src/treetools/CameraPOV.ts
  46. 228 91
      inspector/test/index.js
  47. 1 1
      loaders/src/glTF/babylon.glTFFileLoader.ts
  48. 1 1
      localDev/index.html
  49. 6 2
      materialsLibrary/index.html
  50. 240 0
      materialsLibrary/src/shadowOnly/babylon.shadowOnlyMaterial.ts
  51. 50 0
      materialsLibrary/src/shadowOnly/shadowOnly.fragment.fx
  52. 62 0
      materialsLibrary/src/shadowOnly/shadowOnly.vertex.fx
  53. 0 1
      materialsLibrary/src/water/babylon.waterMaterial.ts
  54. 78 13
      src/Actions/babylon.actionManager.ts
  55. 28 8
      src/Cameras/VR/babylon.webVRCamera.ts
  56. 16 10
      src/Cameras/babylon.camera.ts
  57. 8 0
      src/Cameras/babylon.targetCamera.ts
  58. 12 9
      src/Debug/babylon.debugLayer.ts
  59. 5 1
      src/Loading/babylon.sceneLoader.ts
  60. 2 0
      src/Materials/babylon.pbrMaterial.ts
  61. 2 0
      src/Materials/babylon.standardMaterial.ts
  62. 7 10
      src/Mesh/babylon.abstractMesh.ts
  63. 2 2
      src/PostProcess/babylon.postProcess.ts
  64. 2 0
      src/Rendering/babylon.boundingBoxRenderer.ts
  65. 8 0
      src/Rendering/babylon.renderingGroup.ts
  66. 11 0
      src/Rendering/babylon.renderingManager.ts
  67. 91 19
      src/Tools/babylon.extendedGamepad.ts
  68. 14 0
      src/Tools/babylon.observable.ts
  69. 5 0
      src/Tools/babylon.smartArray.ts
  70. 12 0
      src/Tools/babylon.tools.ts
  71. 16 4
      src/babylon.engine.ts
  72. 7 0
      src/babylon.node.ts
  73. 346 77
      src/babylon.scene.ts
  74. 1 0
      what's new.md

+ 1 - 0
Playground/debug.html

@@ -32,6 +32,7 @@
     <script src="https://babylonjs.azurewebsites.net/lib/babylon.gradientMaterial.js"></script>
     <script src="https://babylonjs.azurewebsites.net/lib/babylon.gradientMaterial.js"></script>
     <script src="https://babylonjs.azurewebsites.net/lib/babylon.furMaterial.js"></script>
     <script src="https://babylonjs.azurewebsites.net/lib/babylon.furMaterial.js"></script>
     <script src="https://babylonjs.azurewebsites.net/lib/babylon.gridMaterial.js"></script>
     <script src="https://babylonjs.azurewebsites.net/lib/babylon.gridMaterial.js"></script>
+    <script src="https://babylonjs.azurewebsites.net/lib/babylon.shadowOnlyMaterial.js"></script>    
 
 
     <script src="https://babylonjs.azurewebsites.net/lib/babylon.brickProceduralTexture.js"></script>
     <script src="https://babylonjs.azurewebsites.net/lib/babylon.brickProceduralTexture.js"></script>
     <script src="https://babylonjs.azurewebsites.net/lib/babylon.cloudProceduralTexture.js"></script>
     <script src="https://babylonjs.azurewebsites.net/lib/babylon.cloudProceduralTexture.js"></script>

+ 1 - 0
Playground/frame.html

@@ -21,6 +21,7 @@
     <script src="https://babylonjs.azurewebsites.net/lib/babylon.gradientMaterial.min.js"></script>
     <script src="https://babylonjs.azurewebsites.net/lib/babylon.gradientMaterial.min.js"></script>
     <script src="https://babylonjs.azurewebsites.net/lib/babylon.furMaterial.min.js"></script>
     <script src="https://babylonjs.azurewebsites.net/lib/babylon.furMaterial.min.js"></script>
     <script src="https://babylonjs.azurewebsites.net/lib/babylon.gridMaterial.min.js"></script>
     <script src="https://babylonjs.azurewebsites.net/lib/babylon.gridMaterial.min.js"></script>
+    <script src="https://babylonjs.azurewebsites.net/lib/babylon.shadowOnlyMaterial.min.js"></script>
 
 
     <script src="https://babylonjs.azurewebsites.net/lib/babylon.brickProceduralTexture.min.js"></script>
     <script src="https://babylonjs.azurewebsites.net/lib/babylon.brickProceduralTexture.min.js"></script>
     <script src="https://babylonjs.azurewebsites.net/lib/babylon.cloudProceduralTexture.min.js"></script>
     <script src="https://babylonjs.azurewebsites.net/lib/babylon.cloudProceduralTexture.min.js"></script>

+ 1 - 0
Playground/index.html

@@ -33,6 +33,7 @@
     <script src="https://babylonjs.azurewebsites.net/lib/babylon.gradientMaterial.min.js"></script>
     <script src="https://babylonjs.azurewebsites.net/lib/babylon.gradientMaterial.min.js"></script>
     <script src="https://babylonjs.azurewebsites.net/lib/babylon.furMaterial.min.js"></script>
     <script src="https://babylonjs.azurewebsites.net/lib/babylon.furMaterial.min.js"></script>
     <script src="https://babylonjs.azurewebsites.net/lib/babylon.gridMaterial.min.js"></script>
     <script src="https://babylonjs.azurewebsites.net/lib/babylon.gridMaterial.min.js"></script>
+    <script src="https://babylonjs.azurewebsites.net/lib/babylon.shadowOnlyMaterial.min.js"></script>
 
 
     <script src="https://babylonjs.azurewebsites.net/lib/babylon.brickProceduralTexture.min.js"></script>
     <script src="https://babylonjs.azurewebsites.net/lib/babylon.brickProceduralTexture.min.js"></script>
     <script src="https://babylonjs.azurewebsites.net/lib/babylon.cloudProceduralTexture.min.js"></script>
     <script src="https://babylonjs.azurewebsites.net/lib/babylon.cloudProceduralTexture.min.js"></script>

+ 82 - 0
Playground/scripts/pointer events handling.js

@@ -0,0 +1,82 @@
+var createScene = function () {
+
+    var scene = new BABYLON.Scene(engine);
+    var camera = new BABYLON.FreeCamera("camera1", new BABYLON.Vector3(0, 5, -10), scene);
+    camera.setTarget(BABYLON.Vector3.Zero());
+    camera.attachControl(canvas, true);
+    var light = new BABYLON.HemisphericLight("light1", new BABYLON.Vector3(0, 1, 0), scene);
+    light.intensity = 0.7;
+    var sphere = BABYLON.Mesh.CreateSphere("sphere1", 16, 2, scene);
+    sphere.position.y = 1;
+    var ground = BABYLON.Mesh.CreateGround("ground1", 6, 6, 2, scene);
+
+    scene.exclusiveDoubleMode = false;
+
+    scene.onPrePointerObservable.add( function(pointerInfo, eventState) {
+        console.log('%c PrePointerObservable: pointer down', 'background: red; color: white');
+        //pointerInfo.skipOnPointerObservable = true;
+    }, BABYLON.PointerEventTypes.POINTERDOWN, false);
+    scene.onPrePointerObservable.add( function(pointerInfo, eventState) {
+        console.log('%c PrePointerObservable: pointer up', 'background: red; color: white');
+        // pointerInfo.skipOnPointerObservable = true;
+    }, BABYLON.PointerEventTypes.POINTERUP, false);
+    scene.onPrePointerObservable.add( function(pointerInfo, eventState) {
+        console.log('%c PrePointerObservable: pointer pick: ' + pointerInfo.pickInfo.pickedMesh.name, 'background: red; color: white');
+    }, BABYLON.PointerEventTypes.POINTERPICK, false);
+    scene.onPrePointerObservable.add( function(pointerInfo, eventState) {
+        console.log('%c PrePointerObservable: pointer tap', 'background: red; color: white');
+    }, BABYLON.PointerEventTypes.POINTERTAP, false);
+    scene.onPrePointerObservable.add( function(pointerInfo, eventState) {
+        console.log('%c PrePointerObservable: pointer double tap', 'background: red; color: white');
+    }, BABYLON.PointerEventTypes.POINTERDOUBLETAP, false);
+    scene.onPointerObservable.add( function(pointerInfo, eventState) {
+        console.log('%c PointerObservable: pointer down', 'background: blue; color: white');
+    }, BABYLON.PointerEventTypes.POINTERDOWN, false);
+    scene.onPointerObservable.add( function(pointerInfo, eventState) {
+        console.log('%c PointerObservable: pointer up', 'background: blue; color: white');
+    }, BABYLON.PointerEventTypes.POINTERUP, false);
+    scene.onPointerObservable.add( function(pointerInfo, eventState) {
+        console.log('%c PointerObservable: pointer pick: ' + pointerInfo.pickInfo.pickedMesh.name, 'background: blue; color: white');
+    }, BABYLON.PointerEventTypes.POINTERPICK, false);
+    scene.onPointerObservable.add( function(pointerInfo, eventState) {
+        console.log('%c PointerObservable: pointer tap', 'background: blue; color: white');
+    }, BABYLON.PointerEventTypes.POINTERTAP, false);
+    scene.onPointerObservable.add( function(pointerInfo, eventState) {
+        console.log('%c PointerObservable: pointer double tap', 'background: blue; color: white');
+    }, BABYLON.PointerEventTypes.POINTERDOUBLETAP, false);
+
+    var meshes = [sphere, ground];
+    for (var i=0; i< meshes.length; i++) {
+        let mesh = meshes[i];
+        mesh.actionManager = new BABYLON.ActionManager(scene);
+        mesh.actionManager.registerAction(new BABYLON.ExecuteCodeAction(BABYLON.ActionManager.OnLongPressTrigger, (function(mesh) {
+            console.log("%c ActionManager: long press : " + mesh.name, 'background: green; color: white');
+        }).bind(this, mesh)));
+        mesh.actionManager.registerAction(new BABYLON.ExecuteCodeAction(BABYLON.ActionManager.OnLeftPickTrigger, (function(mesh) {
+            console.log("%c ActionManager: left pick: " + mesh.name, 'background: green; color: white');
+        }).bind(this, mesh)));
+        mesh.actionManager.registerAction(new BABYLON.ExecuteCodeAction(BABYLON.ActionManager.OnRightPickTrigger, (function(mesh) {
+            console.log("%c ActionManager: right pick: " + mesh.name, 'background: green; color: white');
+        }).bind(this, mesh)));
+        mesh.actionManager.registerAction(new BABYLON.ExecuteCodeAction(BABYLON.ActionManager.OnCenterPickTrigger, (function(mesh) {
+            console.log("%c ActionManager: center pick: " + mesh.name, 'background: green; color: white');
+        }).bind(this, mesh)));
+        mesh.actionManager.registerAction(new BABYLON.ExecuteCodeAction(BABYLON.ActionManager.OnPickTrigger, (function(mesh) {
+            console.log("%c ActionManager: pick : " + mesh.name, 'background: green; color: white');
+        }).bind(this, mesh)));
+        mesh.actionManager.registerAction(new BABYLON.ExecuteCodeAction(BABYLON.ActionManager.OnPickDownTrigger, (function(mesh) {
+            console.log("%c ActionManager: pick down : " + mesh.name, 'background: green; color: white');
+        }).bind(this, mesh)));
+        mesh.actionManager.registerAction(new BABYLON.ExecuteCodeAction(BABYLON.ActionManager.OnPickUpTrigger, (function(mesh) {
+            console.log("%c ActionManager: pick up : " + mesh.name, 'background: green; color: white');
+        }).bind(this, mesh)));
+        mesh.actionManager.registerAction(new BABYLON.ExecuteCodeAction(BABYLON.ActionManager.OnDoublePickTrigger, (function(mesh) {
+            console.log("%c ActionManager: double pick : " + mesh.name, 'background: green; color: white');
+        }).bind(this, mesh)));
+        mesh.actionManager.registerAction(new BABYLON.ExecuteCodeAction(BABYLON.ActionManager.OnPickOutTrigger, (function(mesh) {
+            console.log("%c ActionManager: pick out : " + mesh.name, 'background: green; color: white');
+        }).bind(this, mesh)));
+    }
+
+    return scene;
+};

+ 2 - 1
Playground/scripts/scripts.txt

@@ -26,4 +26,5 @@ Volumetric Light Scattering
 HDR Rendering Pipeline
 HDR Rendering Pipeline
 Refraction and Reflection
 Refraction and Reflection
 PBR
 PBR
-Instanced bones
+Instanced bones
+Pointer events handling

+ 15 - 0
Tools/Gulp/config.json

@@ -243,6 +243,16 @@
         "libraries": [
         "libraries": [
             {
             {
                 "files": [
                 "files": [
+                    "../../materialsLibrary/src/shadowOnly/babylon.shadowOnlyMaterial.ts"
+                ],
+                "shaderFiles": [
+                    "../../materialsLibrary/src/shadowOnly/shadowOnly.vertex.fx",
+                    "../../materialsLibrary/src/shadowOnly/shadowOnly.fragment.fx"
+                ],
+                "output": "babylon.shadowOnlyMaterial.js"
+            },            
+            {
+                "files": [
                     "../../materialsLibrary/src/gradient/babylon.gradientMaterial.ts"
                     "../../materialsLibrary/src/gradient/babylon.gradientMaterial.ts"
                 ],
                 ],
                 "shaderFiles": [
                 "shaderFiles": [
@@ -577,6 +587,8 @@
                     "../../inspector/src/properties.ts",
                     "../../inspector/src/properties.ts",
                     "../../inspector/src/gui/BasicElement.ts",
                     "../../inspector/src/gui/BasicElement.ts",
                     "../../inspector/src/adapters/Adapter.ts",
                     "../../inspector/src/adapters/Adapter.ts",
+                    "../../inspector/src/adapters/CameraAdapter.ts",
+                    "../../inspector/src/adapters/TextureAdapter.ts",
                     "../../inspector/src/adapters/Canvas2DAdapter.ts",
                     "../../inspector/src/adapters/Canvas2DAdapter.ts",
                     "../../inspector/src/adapters/LightAdapter.ts",
                     "../../inspector/src/adapters/LightAdapter.ts",
                     "../../inspector/src/adapters/MaterialAdapter.ts",
                     "../../inspector/src/adapters/MaterialAdapter.ts",
@@ -594,6 +606,8 @@
                     "../../inspector/src/scheduler/Scheduler.ts",
                     "../../inspector/src/scheduler/Scheduler.ts",
                     "../../inspector/src/tabs/Tab.ts",
                     "../../inspector/src/tabs/Tab.ts",
                     "../../inspector/src/tabs/PropertyTab.ts",
                     "../../inspector/src/tabs/PropertyTab.ts",
+                    "../../inspector/src/tabs/CameraTab.ts",
+                    "../../inspector/src/tabs/TextureTab.ts",
                     "../../inspector/src/tabs/Canvas2DTab.ts",
                     "../../inspector/src/tabs/Canvas2DTab.ts",
                     "../../inspector/src/tabs/LightTab.ts",
                     "../../inspector/src/tabs/LightTab.ts",
                     "../../inspector/src/tabs/MaterialTab.ts",
                     "../../inspector/src/tabs/MaterialTab.ts",
@@ -614,6 +628,7 @@
                     "../../inspector/src/tree/TreeItem.ts",
                     "../../inspector/src/tree/TreeItem.ts",
                     "../../inspector/src/treetools/AbstractTreeTool.ts",
                     "../../inspector/src/treetools/AbstractTreeTool.ts",
                     "../../inspector/src/treetools/BoundingBox.ts",
                     "../../inspector/src/treetools/BoundingBox.ts",
+                    "../../inspector/src/treetools/CameraPOV.ts",
                     "../../inspector/src/treetools/Checkbox.ts",
                     "../../inspector/src/treetools/Checkbox.ts",
                     "../../inspector/src/treetools/DebugArea.ts",
                     "../../inspector/src/treetools/DebugArea.ts",
                     "../../inspector/src/treetools/Info.ts",
                     "../../inspector/src/treetools/Info.ts",

+ 7 - 5
canvas2D/src/Engine/babylon.group2d.ts

@@ -53,7 +53,7 @@
          * - layoutEngine: either an instance of a layout engine based class (StackPanel.Vertical, StackPanel.Horizontal) or a string ('canvas' for Canvas layout, 'StackPanel' or 'HorizontalStackPanel' for horizontal Stack Panel layout, 'VerticalStackPanel' for vertical Stack Panel layout).
          * - layoutEngine: either an instance of a layout engine based class (StackPanel.Vertical, StackPanel.Horizontal) or a string ('canvas' for Canvas layout, 'StackPanel' or 'HorizontalStackPanel' for horizontal Stack Panel layout, 'VerticalStackPanel' for vertical Stack Panel layout).
          * - isVisible: true if the group must be visible, false for hidden. Default is true.
          * - isVisible: true if the group must be visible, false for hidden. Default is true.
          * - isPickable: if true the Primitive can be used with interaction mode and will issue Pointer Event. If false it will be ignored for interaction/intersection test. Default value is true.
          * - isPickable: if true the Primitive can be used with interaction mode and will issue Pointer Event. If false it will be ignored for interaction/intersection test. Default value is true.
-         * - isContainer: if true the Primitive acts as a container for interaction, if the primitive is not pickable or doesn't intersection, no further test will be perform on its children. If set to false, children will always be considered for intersection/interaction. Default value is true.
+         * - isContainer: if true the Primitive acts as a container for interaction, if the primitive is not pickable or doesn't intersect, no further test will be perform on its children. If set to false, children will always be considered for intersection/interaction. Default value is true.
          * - childrenFlatZOrder: if true all the children (direct and indirect) will share the same Z-Order. Use this when there's a lot of children which don't overlap. The drawing order IS NOT GUARANTED!
          * - childrenFlatZOrder: if true all the children (direct and indirect) will share the same Z-Order. Use this when there's a lot of children which don't overlap. The drawing order IS NOT GUARANTED!
          * - levelCollision: this primitive is an actor of the Collision Manager and only this level will be used for collision (i.e. not the children). Use deepCollision if you want collision detection on the primitives and its children.
          * - levelCollision: this primitive is an actor of the Collision Manager and only this level will be used for collision (i.e. not the children). Use deepCollision if you want collision detection on the primitives and its children.
          * - deepCollision: this primitive is an actor of the Collision Manager, this level AND ALSO its children will be used for collision (note: you don't need to set the children as level/deepCollision).
          * - deepCollision: this primitive is an actor of the Collision Manager, this level AND ALSO its children will be used for collision (note: you don't need to set the children as level/deepCollision).
@@ -126,10 +126,12 @@
 
 
             let size = (!settings.size && !settings.width && !settings.height) ? null : (settings.size || (new Size(settings.width || 0, settings.height || 0)));
             let size = (!settings.size && !settings.width && !settings.height) ? null : (settings.size || (new Size(settings.width || 0, settings.height || 0)));
 
 
-            this._trackedNode = (settings.trackNode == null) ? null : settings.trackNode;
-            this._trackedNodeOffset = (settings.trackNodeOffset == null) ? null : settings.trackNodeOffset;
-            if (this._trackedNode && this.owner) {
-                this.owner._registerTrackedNode(this);
+            if (!(this instanceof WorldSpaceCanvas2D)) {
+                this._trackedNode = (settings.trackNode == null) ? null : settings.trackNode;
+                this._trackedNodeOffset = (settings.trackNodeOffset == null) ? null : settings.trackNodeOffset;
+                if (this._trackedNode && this.owner) {
+                    this.owner._registerTrackedNode(this);
+                }
             }
             }
 
 
             this._cacheBehavior = (settings.cacheBehavior == null) ? Group2D.GROUPCACHEBEHAVIOR_FOLLOWCACHESTRATEGY : settings.cacheBehavior;
             this._cacheBehavior = (settings.cacheBehavior == null) ? Group2D.GROUPCACHEBEHAVIOR_FOLLOWCACHESTRATEGY : settings.cacheBehavior;

+ 180 - 59
canvas2D/src/Engine/babylon.prim2dBase.ts

@@ -1178,7 +1178,7 @@
                         } else {
                         } else {
                             dstArea.width = (sourceArea.width * isx) - (dstOffset.x + rightPixels) * isx;
                             dstArea.width = (sourceArea.width * isx) - (dstOffset.x + rightPixels) * isx;
                         }
                         }
-                        
+
                         dstOffset.z = this.rightPixels;
                         dstOffset.z = this.rightPixels;
                         break;
                         break;
                     }
                     }
@@ -1208,7 +1208,7 @@
                         break;
                         break;
                     }
                     }
                 }
                 }
-                
+
             }
             }
 
 
             if (computeAxis & PrimitiveThickness.ComputeV) {
             if (computeAxis & PrimitiveThickness.ComputeV) {
@@ -1308,7 +1308,7 @@
 
 
                         break;
                         break;
                     }
                     }
-                }                
+                }
             }
             }
         }
         }
 
 
@@ -1466,7 +1466,7 @@
             dontInheritParentScale  ?: boolean,
             dontInheritParentScale  ?: boolean,
             alignToPixel            ?: boolean,
             alignToPixel            ?: boolean,
             opacity                 ?: number,
             opacity                 ?: number,
-            zOrder                  ?: number, 
+            zOrder                  ?: number,
             origin                  ?: Vector2,
             origin                  ?: Vector2,
             layoutEngine            ?: LayoutEngineBase | string,
             layoutEngine            ?: LayoutEngineBase | string,
             isVisible               ?: boolean,
             isVisible               ?: boolean,
@@ -1757,7 +1757,7 @@
         /**
         /**
          * Return the ObservableStringDictionary containing all the primitives intersecting with this one.
          * Return the ObservableStringDictionary containing all the primitives intersecting with this one.
          * The key is the primitive uid, the value is the ActorInfo object
          * The key is the primitive uid, the value is the ActorInfo object
-         * @returns {} 
+         * @returns {}
          */
          */
         public get intersectWith(): ObservableStringDictionary<ActorInfoBase> {
         public get intersectWith(): ObservableStringDictionary<ActorInfoBase> {
             if (!this._actorInfo) {
             if (!this._actorInfo) {
@@ -1994,6 +1994,9 @@
             return this.actualPosition.x;
             return this.actualPosition.x;
         }
         }
 
 
+        /**
+         * DO NOT INVOKE for internal purpose only
+         */
         public set actualX(val: number) {
         public set actualX(val: number) {
             this._actualPosition.x = val;
             this._actualPosition.x = val;
             this._triggerPropertyChanged(Prim2DBase.actualPositionProperty, this._actualPosition);
             this._triggerPropertyChanged(Prim2DBase.actualPositionProperty, this._actualPosition);
@@ -2007,6 +2010,9 @@
             return this.actualPosition.y;
             return this.actualPosition.y;
         }
         }
 
 
+        /**
+        * DO NOT INVOKE for internal purpose only
+        */
         public set actualY(val: number) {
         public set actualY(val: number) {
             this._actualPosition.y = val;
             this._actualPosition.y = val;
             this._triggerPropertyChanged(Prim2DBase.actualPositionProperty, this._actualPosition);
             this._triggerPropertyChanged(Prim2DBase.actualPositionProperty, this._actualPosition);
@@ -2027,20 +2033,44 @@
         }
         }
 
 
         public set position(value: Vector2) {
         public set position(value: Vector2) {
-            if (!this._checkPositionChange()) {
+            //if (!this._checkPositionChange()) {
+            //    return;
+            //}
+            if (this._checkUseMargin()) {
+                switch (this._marginAlignment.horizontal) {
+                    case PrimitiveAlignment.AlignLeft:
+                    case PrimitiveAlignment.AlignStretch:
+                    case PrimitiveAlignment.AlignCenter:
+                        this.margin.leftPixels = value.x;
+                        break;
+                    case PrimitiveAlignment.AlignRight:
+                        this.margin.rightPixels = value.x;
+                        break;
+                    }
+                switch (this._marginAlignment.vertical) {
+                    case PrimitiveAlignment.AlignBottom:
+                    case PrimitiveAlignment.AlignStretch:
+                    case PrimitiveAlignment.AlignCenter:
+                        this.margin.bottomPixels = value.y;
+                        break;
+                    case PrimitiveAlignment.AlignTop:
+                        this.margin.topPixels = value.y;
+                        break;
+                }
                 return;
                 return;
-            }
-            if (!value) {
-                this._position = null;
             } else {
             } else {
-                if (!this._position) {
-                    this._position = value.clone();
+                if (!value) {
+                    this._position = null;
                 } else {
                 } else {
-                    this._position.copyFrom(value);
+                    if (!this._position) {
+                        this._position = value.clone();
+                    } else {
+                        this._position.copyFrom(value);
+                    }
                 }
                 }
+                this._actualPosition = null;
+                this._triggerPropertyChanged(Prim2DBase.actualPositionProperty, value);
             }
             }
-            this._actualPosition = null;
-            this._triggerPropertyChanged(Prim2DBase.actualPositionProperty, value);
         }
         }
 
 
         /**
         /**
@@ -2056,24 +2086,38 @@
         }
         }
 
 
         public set x(value: number) {
         public set x(value: number) {
-            if (!this._checkPositionChange()) {
-                return;
-            }
+            //if (!this._checkPositionChange()) {
+            //    return;
+            //}
             if (value == null) {
             if (value == null) {
                 throw new Error(`Can't set a null x in primitive ${this.id}, only the position can be turned to null`);
                 throw new Error(`Can't set a null x in primitive ${this.id}, only the position can be turned to null`);
             }
             }
-            if (!this._position) {
-                this._position = Vector2.Zero();
-            }
-
-            if (this._position.x === value) {
+            if (this._checkUseMargin()) {
+                switch (this._marginAlignment.horizontal) {
+                    case PrimitiveAlignment.AlignLeft:
+                    case PrimitiveAlignment.AlignStretch:
+                    case PrimitiveAlignment.AlignCenter:
+                        this.margin.leftPixels = value;
+                        break;
+                    case PrimitiveAlignment.AlignRight:
+                        this.margin.rightPixels = value;
+                        break;
+                    }
                 return;
                 return;
-            }
+            } else {
+                if (!this._position) {
+                    this._position = Vector2.Zero();
+                }
 
 
-            this._position.x = value;
-            this._actualPosition = null;
-            this._triggerPropertyChanged(Prim2DBase.positionProperty, value);
-            this._triggerPropertyChanged(Prim2DBase.actualPositionProperty, value);
+                if (this._position.x === value) {
+                    return;
+                }
+
+                this._position.x = value;
+                this._actualPosition = null;
+                this._triggerPropertyChanged(Prim2DBase.positionProperty, value);
+                this._triggerPropertyChanged(Prim2DBase.actualPositionProperty, value);
+            }
         }
         }
 
 
         /**
         /**
@@ -2089,24 +2133,38 @@
         }
         }
 
 
         public set y(value: number) {
         public set y(value: number) {
-            if (!this._checkPositionChange()) {
-                return;
-            }
+            //if (!this._checkPositionChange()) {
+            //    return;
+            //}
             if (value == null) {
             if (value == null) {
                 throw new Error(`Can't set a null y in primitive ${this.id}, only the position can be turned to null`);
                 throw new Error(`Can't set a null y in primitive ${this.id}, only the position can be turned to null`);
             }
             }
-            if (!this._position) {
-                this._position = Vector2.Zero();
-            }
-
-            if (this._position.y === value) {
+            if (this._checkUseMargin()) {
+                switch (this._marginAlignment.vertical) {
+                    case PrimitiveAlignment.AlignBottom:
+                    case PrimitiveAlignment.AlignStretch:
+                    case PrimitiveAlignment.AlignCenter:
+                        this.margin.bottomPixels = value;
+                        break;
+                    case PrimitiveAlignment.AlignTop:
+                        this.margin.topPixels = value;
+                        break;
+                }
                 return;
                 return;
-            }
+            } else {
+                if (!this._position) {
+                    this._position = Vector2.Zero();
+                }
 
 
-            this._position.y = value;
-            this._actualPosition = null;
-            this._triggerPropertyChanged(Prim2DBase.positionProperty, value);
-            this._triggerPropertyChanged(Prim2DBase.actualPositionProperty, value);
+                if (this._position.y === value) {
+                    return;
+                }
+
+                this._position.y = value;
+                this._actualPosition = null;
+                this._triggerPropertyChanged(Prim2DBase.positionProperty, value);
+                this._triggerPropertyChanged(Prim2DBase.actualPositionProperty, value);
+            }
         }
         }
 
 
         private static boundinbBoxReentrency: number = -1;
         private static boundinbBoxReentrency: number = -1;
@@ -2153,7 +2211,7 @@
 
 
                 return this._internalSize || Prim2DBase._nullSize;
                 return this._internalSize || Prim2DBase._nullSize;
             } else {
             } else {
-                C2DLogging.setPostMessage(() => "user set size");                
+                C2DLogging.setPostMessage(() => "user set size");
             }
             }
             return this._size || Prim2DBase._nullSize;
             return this._size || Prim2DBase._nullSize;
         }
         }
@@ -2258,6 +2316,9 @@
          * Uniform scale applied on the primitive. If a non-uniform scale is applied through scaleX/scaleY property the getter of this property will return scaleX.
          * Uniform scale applied on the primitive. If a non-uniform scale is applied through scaleX/scaleY property the getter of this property will return scaleX.
          */
          */
         public set scale(value: number) {
         public set scale(value: number) {
+            if (value <= 0) {
+                throw new Error("You can't set the scale to less or equal to 0");
+            }
             this._scale.x = this._scale.y = value;
             this._scale.x = this._scale.y = value;
             this._setFlags(SmartPropertyPrim.flagActualScaleDirty);
             this._setFlags(SmartPropertyPrim.flagActualScaleDirty);
             this._spreadActualScaleDirty();
             this._spreadActualScaleDirty();
@@ -2484,6 +2545,16 @@
         }
         }
 
 
         /**
         /**
+         * Set the margin from a string value
+         * @param value is "top: <value>, left:<value>, right:<value>, bottom:<value>" or "<value>" (same for all edges) each are optional, auto will be set if it's omitted.
+         * Values are: 'auto', 'inherit', 'XX%' for percentage, 'XXpx' or 'XX' for pixels.
+         */
+        public setMargin(value: string) {
+            this.margin.fromString(value);
+            this._updatePositioningState();
+        }
+
+        /**
          * Check for both margin and marginAlignment, return true if at least one of them is specified with a non default value
          * Check for both margin and marginAlignment, return true if at least one of them is specified with a non default value
          */
          */
         public get _hasMargin(): boolean {
         public get _hasMargin(): boolean {
@@ -2517,6 +2588,15 @@
             this._updatePositioningState();
             this._updatePositioningState();
         }
         }
 
 
+        /**
+         * Set the padding from a string value
+         * @param value is "top: <value>, left:<value>, right:<value>, bottom:<value>" or "<value>" (same for all edges) each are optional, auto will be set if it's omitted.
+         * Values are: 'auto', 'inherit', 'XX%' for percentage, 'XXpx' or 'XX' for pixels.         */
+        public setPadding(value: string) {
+            this.padding.fromString(value);
+            this._updatePositioningState();
+        }
+
         private get _hasPadding(): boolean {
         private get _hasPadding(): boolean {
             return this._padding !== null && !this._padding.isDefault;
             return this._padding !== null && !this._padding.isDefault;
         }
         }
@@ -2543,6 +2623,15 @@
         }
         }
 
 
         /**
         /**
+         * Set the margin's horizontal and or vertical alignments from a string value.
+         * @param value can be: [<h:|horizontal:><left|right|center|stretch>], [<v:|vertical:><top|bottom|center|stretch>]
+         */
+        public setMarginalignment(value: string) {
+            this.marginAlignment.fromString(value);
+            this._updatePositioningState();
+        }
+
+        /**
          * Check if there a marginAlignment specified (non null and not default)
          * Check if there a marginAlignment specified (non null and not default)
          */
          */
         public get _hasMarginAlignment(): boolean {
         public get _hasMarginAlignment(): boolean {
@@ -2585,6 +2674,9 @@
          * Scale applied on the X axis of the primitive
          * Scale applied on the X axis of the primitive
          */
          */
         public set scaleX(value: number) {
         public set scaleX(value: number) {
+            if (value <= 0) {
+                throw new Error("You can't set the scaleX to less or equal to 0");
+            }
             this._scale.x = value;
             this._scale.x = value;
             this._setFlags(SmartPropertyPrim.flagActualScaleDirty);
             this._setFlags(SmartPropertyPrim.flagActualScaleDirty);
             this._spreadActualScaleDirty();
             this._spreadActualScaleDirty();
@@ -2600,6 +2692,9 @@
          * Scale applied on the Y axis of the primitive
          * Scale applied on the Y axis of the primitive
          */
          */
         public set scaleY(value: number) {
         public set scaleY(value: number) {
+            if (value <= 0) {
+                throw new Error("You can't set the scaleY to less or equal to 0");
+            }
             this._scale.y = value;
             this._scale.y = value;
             this._setFlags(SmartPropertyPrim.flagActualScaleDirty);
             this._setFlags(SmartPropertyPrim.flagActualScaleDirty);
             this._spreadActualScaleDirty();
             this._spreadActualScaleDirty();
@@ -2908,9 +3003,11 @@
                     this._boundingInfo.unionToRef(contentBI, this._boundingInfo);
                     this._boundingInfo.unionToRef(contentBI, this._boundingInfo);
                 }
                 }
 
 
-                this._clearFlags(SmartPropertyPrim.flagBoundingInfoDirty);
+                if (sizedByContent || !this._isFlagSet(SmartPropertyPrim.flagLevelBoundingInfoDirty)) {
+                    this._clearFlags(SmartPropertyPrim.flagBoundingInfoDirty);
+                }
             } else {
             } else {
-                C2DLogging.setPostMessage(() => "cache hit");                
+                C2DLogging.setPostMessage(() => "cache hit");
             }
             }
             return this._boundingInfo;
             return this._boundingInfo;
         }
         }
@@ -2948,11 +3045,23 @@
                         C2DLogging.setPostMessage(() => "re entrance detected, boundingInfo returned");
                         C2DLogging.setPostMessage(() => "re entrance detected, boundingInfo returned");
                         return this.boundingInfo;
                         return this.boundingInfo;
                     }
                     }
+
+                    if (this._isFlagSet(SmartPropertyPrim.flagPositioningDirty)) {
+                        C2DLogging.setPostMessage(() => "couldn't compute positioning, boundingInfo returned");
+                        return this.boundingInfo;
+                    }
                 }
                 }
 
 
+                if (!usePositioning) {
+                    let bi = this.boundingInfo;
+                    if (!this._isFlagSet(SmartPropertyPrim.flagBoundingInfoDirty)) {
+                        this._clearFlags(SmartPropertyPrim.flagLayoutBoundingInfoDirty);
+                    }
+                    return bi;
+                }
                 this._clearFlags(SmartPropertyPrim.flagLayoutBoundingInfoDirty);
                 this._clearFlags(SmartPropertyPrim.flagLayoutBoundingInfoDirty);
             } else {
             } else {
-                C2DLogging.setPostMessage(() => "cache hit");                
+                C2DLogging.setPostMessage(() => "cache hit");
             }
             }
             return usePositioning ? this._layoutBoundingInfo : this.boundingInfo;
             return usePositioning ? this._layoutBoundingInfo : this.boundingInfo;
         }
         }
@@ -3130,7 +3239,7 @@
             prims[3][0].levelVisible = true;
             prims[3][0].levelVisible = true;
 
 
             // Current offset
             // Current offset
-            let curOffset = Vector2.Zero(); 
+            let curOffset = Vector2.Zero();
 
 
             // Store the area info of the layout area
             // Store the area info of the layout area
             let curAreaIndex = 0;
             let curAreaIndex = 0;
@@ -3358,7 +3467,7 @@
                     return ownerGroup.intersect(intersectInfo);
                     return ownerGroup.intersect(intersectInfo);
                 } finally  {
                 } finally  {
                     Prim2DBase._bypassGroup2DExclusion = false;
                     Prim2DBase._bypassGroup2DExclusion = false;
-                } 
+                }
             }
             }
 
 
             // If we're testing a cachedGroup, we must reject pointer outside its levelBoundingInfo because children primitives could be partially clipped outside so we must not accept them as intersected when it's the case (because they're not visually visible).
             // If we're testing a cachedGroup, we must reject pointer outside its levelBoundingInfo because children primitives could be partially clipped outside so we must not accept them as intersected when it's the case (because they're not visually visible).
@@ -3672,18 +3781,27 @@
 
 
         }
         }
 
 
-        private _checkPositionChange(): boolean {
-            if (this.parent && this.parent.layoutEngine.isChildPositionAllowed === false) {
-                console.log(`Can't manually set the position of ${this.id}, the Layout Engine of its parent doesn't allow it`);
+        //private _checkPositionChange(): boolean {
+        //    if (this.parent && this.parent.layoutEngine.isChildPositionAllowed === false) {
+        //        console.log(`Can't manually set the position of ${this.id}, the Layout Engine of its parent doesn't allow it`);
+        //        return false;
+        //    }
+        //    if (this._isFlagSet(SmartPropertyPrim.flagUsePositioning)) {
+        //        if (<any>this instanceof Group2D && (<Group2D><any>this).trackedNode == null) {
+        //            console.log(`You can't set the position/x/y of ${this.id} properties while positioning engine is used (margin, margin alignment and/or padding are set`);
+        //            return false;
+        //        }
+        //    }
+        //    return true;
+        //}
+
+        private _checkUseMargin(): boolean {
+            // Special cae: tracked node
+            if (<any>this instanceof Group2D && (<Group2D><any>this).trackedNode != null) {
                 return false;
                 return false;
             }
             }
-            if (this._isFlagSet(SmartPropertyPrim.flagUsePositioning)) {
-                if (<any>this instanceof Group2D && (<Group2D><any>this).trackedNode == null) {
-                    console.log(`You can't set the position/x/y of ${this.id} properties while positioning engine is used (margin, margin alignment and/or padding are set`);
-                    return false;
-                }
-            }
-            return true;
+
+            return this._isFlagSet(SmartPropertyPrim.flagUsePositioning);
         }
         }
 
 
         @logMethod("", true)
         @logMethod("", true)
@@ -3804,7 +3922,7 @@
             this._updateCachesProcessStep = ownerProcessStep;
             this._updateCachesProcessStep = ownerProcessStep;
 
 
             this.owner.addUpdateCachedStateCounter(1);
             this.owner.addUpdateCachedStateCounter(1);
-            
+
             // Check if the parent is synced
             // Check if the parent is synced
             if (this._parent && ((this._parent._globalTransformProcessStep !== this.owner._globalTransformProcessStep) || this._parent._areSomeFlagsSet(SmartPropertyPrim.flagLayoutDirty | SmartPropertyPrim.flagPositioningDirty | SmartPropertyPrim.flagZOrderDirty))) {
             if (this._parent && ((this._parent._globalTransformProcessStep !== this.owner._globalTransformProcessStep) || this._parent._areSomeFlagsSet(SmartPropertyPrim.flagLayoutDirty | SmartPropertyPrim.flagPositioningDirty | SmartPropertyPrim.flagZOrderDirty))) {
                 this._parent.updateCachedStates(false);
                 this._parent.updateCachedStates(false);
@@ -3979,6 +4097,9 @@
                 let transformedBSize = Prim2DBase._size3;
                 let transformedBSize = Prim2DBase._size3;
                 let bSize = Prim2DBase._size4;
                 let bSize = Prim2DBase._size4;
                 let bi = this.boundingInfo;
                 let bi = this.boundingInfo;
+                if (this._isFlagSet(SmartPropertyPrim.flagBoundingInfoDirty)) {
+                    success = false;
+                }
                 let tbi = Prim2DBase._tbi;
                 let tbi = Prim2DBase._tbi;
                 bi.transformToRef(Matrix2D.Rotation(this.rotation), tbi);
                 bi.transformToRef(Matrix2D.Rotation(this.rotation), tbi);
                 tbi.sizeToRef(transformedBSize);
                 tbi.sizeToRef(transformedBSize);
@@ -4202,7 +4323,7 @@
         }
         }
 
 
         protected onSetOwner() {
         protected onSetOwner() {
-            
+
         }
         }
 
 
         private static _zOrderChangedNotifList = new Array<Prim2DBase>();
         private static _zOrderChangedNotifList = new Array<Prim2DBase>();
@@ -4459,7 +4580,7 @@
         // If a child prim has an older _parentTransformStep it means the child's transform should be updated
         // If a child prim has an older _parentTransformStep it means the child's transform should be updated
         protected _globalTransformStep: number;
         protected _globalTransformStep: number;
 
 
-        // Stores the previous 
+        // Stores the previous
         protected _globalTransformProcessStep: number;
         protected _globalTransformProcessStep: number;
         protected _prepareProcessStep: number;
         protected _prepareProcessStep: number;
         protected _updateCachesProcessStep: number;
         protected _updateCachesProcessStep: number;

+ 4 - 0
canvas2D/src/Engine/babylon.text2d.ts

@@ -368,6 +368,10 @@
             if (!this.owner || !this._text) {
             if (!this.owner || !this._text) {
                 return false;
                 return false;
             }
             }
+            let asize = this.actualSize;
+            if (asize.width===0 && asize.height===0) {
+                return false;
+            }
             BoundingInfo2D.CreateFromSizeToRef(this.actualSize, this._levelBoundingInfo);
             BoundingInfo2D.CreateFromSizeToRef(this.actualSize, this._levelBoundingInfo);
             return true;
             return true;
         }
         }

Файловите разлики са ограничени, защото са твърде много
+ 28 - 27
dist/preview release/babylon.core.js


Файловите разлики са ограничени, защото са твърде много
+ 1361 - 1274
dist/preview release/babylon.d.ts


Файловите разлики са ограничени, защото са твърде много
+ 36 - 36
dist/preview release/babylon.js


Файловите разлики са ограничени, защото са твърде много
+ 707 - 191
dist/preview release/babylon.max.js


Файловите разлики са ограничени, защото са твърде много
+ 1361 - 1274
dist/preview release/babylon.module.d.ts


Файловите разлики са ограничени, защото са твърде много
+ 36 - 36
dist/preview release/babylon.noworker.js


+ 24 - 2
dist/preview release/canvas2D/babylon.canvas2d.d.ts

@@ -2191,10 +2191,16 @@ declare module BABYLON {
         /**
         /**
          * Shortcut to actualPosition.x
          * Shortcut to actualPosition.x
          */
          */
+        /**
+         * DO NOT INVOKE for internal purpose only
+         */
         actualX: number;
         actualX: number;
         /**
         /**
          * Shortcut to actualPosition.y
          * Shortcut to actualPosition.y
          */
          */
+        /**
+        * DO NOT INVOKE for internal purpose only
+        */
         actualY: number;
         actualY: number;
         /**
         /**
          * Position of the primitive, relative to its parent.
          * Position of the primitive, relative to its parent.
@@ -2254,13 +2260,29 @@ declare module BABYLON {
         readonly isManualZOrder: boolean;
         readonly isManualZOrder: boolean;
         margin: PrimitiveThickness;
         margin: PrimitiveThickness;
         /**
         /**
+         * Set the margin from a string value
+         * @param value is "top: <value>, left:<value>, right:<value>, bottom:<value>" or "<value>" (same for all edges) each are optional, auto will be set if it's omitted.
+         * Values are: 'auto', 'inherit', 'XX%' for percentage, 'XXpx' or 'XX' for pixels.
+         */
+        setMargin(value: string): void;
+        /**
          * Check for both margin and marginAlignment, return true if at least one of them is specified with a non default value
          * Check for both margin and marginAlignment, return true if at least one of them is specified with a non default value
          */
          */
         readonly _hasMargin: boolean;
         readonly _hasMargin: boolean;
         padding: PrimitiveThickness;
         padding: PrimitiveThickness;
+        /**
+         * Set the padding from a string value
+         * @param value is "top: <value>, left:<value>, right:<value>, bottom:<value>" or "<value>" (same for all edges) each are optional, auto will be set if it's omitted.
+         * Values are: 'auto', 'inherit', 'XX%' for percentage, 'XXpx' or 'XX' for pixels.         */
+        setPadding(value: string): void;
         private readonly _hasPadding;
         private readonly _hasPadding;
         marginAlignment: PrimitiveAlignment;
         marginAlignment: PrimitiveAlignment;
         /**
         /**
+         * Set the margin's horizontal and or vertical alignments from a string value.
+         * @param value can be: [<h:|horizontal:><left|right|center|stretch>], [<v:|vertical:><top|bottom|center|stretch>]
+         */
+        setMarginalignment(value: string): void;
+        /**
          * Check if there a marginAlignment specified (non null and not default)
          * Check if there a marginAlignment specified (non null and not default)
          */
          */
         readonly _hasMarginAlignment: boolean;
         readonly _hasMarginAlignment: boolean;
@@ -2465,7 +2487,7 @@ declare module BABYLON {
         protected updateCachedStatesOf(list: Prim2DBase[], recurse: boolean): void;
         protected updateCachedStatesOf(list: Prim2DBase[], recurse: boolean): void;
         private _parentLayoutDirty();
         private _parentLayoutDirty();
         protected _setLayoutDirty(): void;
         protected _setLayoutDirty(): void;
-        private _checkPositionChange();
+        private _checkUseMargin();
         protected _positioningDirty(): void;
         protected _positioningDirty(): void;
         protected _spreadActualOpacityChanged(): void;
         protected _spreadActualOpacityChanged(): void;
         private _changeLayoutEngine(engine);
         private _changeLayoutEngine(engine);
@@ -2895,7 +2917,7 @@ declare module BABYLON {
          * - layoutEngine: either an instance of a layout engine based class (StackPanel.Vertical, StackPanel.Horizontal) or a string ('canvas' for Canvas layout, 'StackPanel' or 'HorizontalStackPanel' for horizontal Stack Panel layout, 'VerticalStackPanel' for vertical Stack Panel layout).
          * - layoutEngine: either an instance of a layout engine based class (StackPanel.Vertical, StackPanel.Horizontal) or a string ('canvas' for Canvas layout, 'StackPanel' or 'HorizontalStackPanel' for horizontal Stack Panel layout, 'VerticalStackPanel' for vertical Stack Panel layout).
          * - isVisible: true if the group must be visible, false for hidden. Default is true.
          * - isVisible: true if the group must be visible, false for hidden. Default is true.
          * - isPickable: if true the Primitive can be used with interaction mode and will issue Pointer Event. If false it will be ignored for interaction/intersection test. Default value is true.
          * - isPickable: if true the Primitive can be used with interaction mode and will issue Pointer Event. If false it will be ignored for interaction/intersection test. Default value is true.
-         * - isContainer: if true the Primitive acts as a container for interaction, if the primitive is not pickable or doesn't intersection, no further test will be perform on its children. If set to false, children will always be considered for intersection/interaction. Default value is true.
+         * - isContainer: if true the Primitive acts as a container for interaction, if the primitive is not pickable or doesn't intersect, no further test will be perform on its children. If set to false, children will always be considered for intersection/interaction. Default value is true.
          * - childrenFlatZOrder: if true all the children (direct and indirect) will share the same Z-Order. Use this when there's a lot of children which don't overlap. The drawing order IS NOT GUARANTED!
          * - childrenFlatZOrder: if true all the children (direct and indirect) will share the same Z-Order. Use this when there's a lot of children which don't overlap. The drawing order IS NOT GUARANTED!
          * - levelCollision: this primitive is an actor of the Collision Manager and only this level will be used for collision (i.e. not the children). Use deepCollision if you want collision detection on the primitives and its children.
          * - levelCollision: this primitive is an actor of the Collision Manager and only this level will be used for collision (i.e. not the children). Use deepCollision if you want collision detection on the primitives and its children.
          * - deepCollision: this primitive is an actor of the Collision Manager, this level AND ALSO its children will be used for collision (note: you don't need to set the children as level/deepCollision).
          * - deepCollision: this primitive is an actor of the Collision Manager, this level AND ALSO its children will be used for collision (note: you don't need to set the children as level/deepCollision).

Файловите разлики са ограничени, защото са твърде много
+ 209 - 85
dist/preview release/canvas2D/babylon.canvas2d.js


Файловите разлики са ограничени, защото са твърде много
+ 12 - 12
dist/preview release/canvas2D/babylon.canvas2d.min.js


Файловите разлики са ограничени, защото са твърде много
+ 4 - 4
dist/preview release/inspector/babylon.inspector.bundle.js


+ 3 - 0
dist/preview release/inspector/babylon.inspector.css

@@ -86,6 +86,8 @@
     height: 100%; }
     height: 100%; }
     .insp-wrapper .tab-panel.searchable {
     .insp-wrapper .tab-panel.searchable {
       height: calc(100% - 30px - 10px); }
       height: calc(100% - 30px - 10px); }
+    .insp-wrapper .tab-panel .texture-image {
+      max-height: 400px; }
     .insp-wrapper .tab-panel .scene-actions {
     .insp-wrapper .tab-panel .scene-actions {
       overflow-y: auto; }
       overflow-y: auto; }
       .insp-wrapper .tab-panel .scene-actions .actions-title {
       .insp-wrapper .tab-panel .scene-actions .actions-title {
@@ -243,6 +245,7 @@
     overflow-x: hidden;
     overflow-x: hidden;
     height: calc(50% - 32px - 30px); }
     height: calc(50% - 32px - 30px); }
     .insp-wrapper .insp-tree .line {
     .insp-wrapper .insp-tree .line {
+      padding: 3px;
       cursor: pointer; }
       cursor: pointer; }
       .insp-wrapper .insp-tree .line:hover {
       .insp-wrapper .insp-tree .line:hover {
         background-color: #2c2c2c; }
         background-color: #2c2c2c; }

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

@@ -18,11 +18,13 @@ declare module INSPECTOR {
         private _popupMode;
         private _popupMode;
         /** The original canvas style, before applying the inspector*/
         /** The original canvas style, before applying the inspector*/
         private _canvasStyle;
         private _canvasStyle;
+        private _initialTab;
+        private _parentElement;
         /** The inspector is created with the given engine.
         /** The inspector is created with the given engine.
          * If the parameter 'popup' is false, the inspector is created as a right panel on the main window.
          * If the parameter 'popup' is false, the inspector is created as a right panel on the main window.
          * If the parameter 'popup' is true, the inspector is created in another popup.
          * If the parameter 'popup' is true, the inspector is created in another popup.
          */
          */
-        constructor(scene: BABYLON.Scene, popup?: boolean);
+        constructor(scene: BABYLON.Scene, popup?: boolean, initialTab?: number, parentElement?: HTMLElement);
         /**
         /**
          * If the given element has a position 'asbolute' or 'relative',
          * If the given element has a position 'asbolute' or 'relative',
          * returns the first parent of the given element that has a position 'relative' or 'absolute'.
          * returns the first parent of the given element that has a position 'relative' or 'absolute'.
@@ -90,10 +92,29 @@ declare module INSPECTOR {
             properties: string[];
             properties: string[];
             format: (tex: BABYLON.Texture) => string;
             format: (tex: BABYLON.Texture) => string;
         };
         };
+        'MapTexture': {
+            type: typeof BABYLON.MapTexture;
+        };
+        'RenderTargetTexture': {
+            type: typeof BABYLON.RenderTargetTexture;
+        };
+        'DynamicTexture': {
+            type: typeof BABYLON.DynamicTexture;
+        };
+        'BaseTexture': {
+            type: typeof BABYLON.BaseTexture;
+        };
+        'FontTexture': {
+            type: typeof BABYLON.FontTexture;
+        };
         'ArcRotateCamera': {
         'ArcRotateCamera': {
             type: typeof BABYLON.ArcRotateCamera;
             type: typeof BABYLON.ArcRotateCamera;
             properties: string[];
             properties: string[];
         };
         };
+        'FreeCamera': {
+            type: typeof BABYLON.FreeCamera;
+            properties: string[];
+        };
         'Scene': {
         'Scene': {
             type: typeof BABYLON.Scene;
             type: typeof BABYLON.Scene;
             properties: string[];
             properties: string[];
@@ -177,6 +198,10 @@ declare module INSPECTOR {
         correspondsTo(obj: any): boolean;
         correspondsTo(obj: any): boolean;
         /** Returns the adapter unique name */
         /** Returns the adapter unique name */
         readonly name: string;
         readonly name: string;
+        /**
+         * Returns the actual object used for this adapter
+         */
+        readonly object: any;
         /** Returns the list of tools available for this adapter */
         /** Returns the list of tools available for this adapter */
         abstract getTools(): Array<AbstractTreeTool>;
         abstract getTools(): Array<AbstractTreeTool>;
         /** Should be overriden in subclasses */
         /** Should be overriden in subclasses */
@@ -185,6 +210,33 @@ declare module INSPECTOR {
 }
 }
 
 
 declare module INSPECTOR {
 declare module INSPECTOR {
+    class CameraAdapter extends Adapter implements ICameraPOV {
+        constructor(obj: BABYLON.Camera);
+        /** Returns the name displayed in the tree */
+        id(): string;
+        /** Returns the type of this object - displayed in the tree */
+        type(): string;
+        /** Returns the list of properties to be displayed for this adapter */
+        getProperties(): Array<PropertyLine>;
+        getTools(): Array<AbstractTreeTool>;
+        setPOV(): void;
+    }
+}
+
+declare module INSPECTOR {
+    class TextureAdapter extends Adapter {
+        constructor(obj: BABYLON.BaseTexture);
+        /** Returns the name displayed in the tree */
+        id(): string;
+        /** Returns the type of this object - displayed in the tree */
+        type(): string;
+        /** Returns the list of properties to be displayed for this adapter */
+        getProperties(): Array<PropertyLine>;
+        getTools(): Array<AbstractTreeTool>;
+    }
+}
+
+declare module INSPECTOR {
     class Canvas2DAdapter extends Adapter implements IToolVisible, IToolDebug {
     class Canvas2DAdapter extends Adapter implements IToolVisible, IToolDebug {
         constructor(obj: any);
         constructor(obj: any);
         /** Returns the name displayed in the tree */
         /** Returns the name displayed in the tree */
@@ -596,6 +648,10 @@ declare module INSPECTOR {
         filter(str: string): void;
         filter(str: string): void;
         /** Dispose properly this tab */
         /** Dispose properly this tab */
         abstract dispose(): any;
         abstract dispose(): any;
+        /** Select an item in the tree */
+        select(item: TreeItem): void;
+        /** Highlight the given node, and downplay all others */
+        highlightNode(item?: TreeItem): void;
         /**
         /**
          * Returns the total width in pixel of this tab, 0 by default
          * Returns the total width in pixel of this tab, 0 by default
         */
         */
@@ -639,6 +695,35 @@ declare module INSPECTOR {
 }
 }
 
 
 declare module INSPECTOR {
 declare module INSPECTOR {
+    class CameraTab extends PropertyTab {
+        constructor(tabbar: TabBar, inspector: Inspector);
+        protected _getTree(): Array<TreeItem>;
+    }
+}
+
+declare module INSPECTOR {
+    class TextureTab extends Tab {
+        private _inspector;
+        /** The panel containing a list of items */
+        protected _treePanel: HTMLElement;
+        protected _treeItems: Array<TreeItem>;
+        private _imagePanel;
+        constructor(tabbar: TabBar, inspector: Inspector);
+        dispose(): void;
+        update(_items?: Array<TreeItem>): void;
+        private _getTree();
+        /** Display the details of the given item */
+        displayDetails(item: TreeItem): void;
+        /** Select an item in the tree */
+        select(item: TreeItem): void;
+        /** Set the given item as active in the tree */
+        activateNode(item: TreeItem): void;
+        /** Highlight the given node, and downplay all others */
+        highlightNode(item?: TreeItem): void;
+    }
+}
+
+declare module INSPECTOR {
     class Canvas2DTab extends PropertyTab {
     class Canvas2DTab extends PropertyTab {
         constructor(tabbar: TabBar, inspector: Inspector);
         constructor(tabbar: TabBar, inspector: Inspector);
         protected _getTree(): Array<TreeItem>;
         protected _getTree(): Array<TreeItem>;
@@ -769,7 +854,7 @@ declare module INSPECTOR {
         private _invisibleTabs;
         private _invisibleTabs;
         /** The list of tabs visible, displayed in the tab bar */
         /** The list of tabs visible, displayed in the tab bar */
         private _visibleTabs;
         private _visibleTabs;
-        constructor(inspector: Inspector);
+        constructor(inspector: Inspector, initialTab?: number);
         update(): void;
         update(): void;
         protected _build(): void;
         protected _build(): void;
         /**
         /**
@@ -909,12 +994,16 @@ declare module INSPECTOR {
         private _tools;
         private _tools;
         children: Array<TreeItem>;
         children: Array<TreeItem>;
         private _lineContent;
         private _lineContent;
-        constructor(tab: PropertyTab, obj: Adapter);
+        constructor(tab: Tab, obj: Adapter);
         /** Returns the item ID == its adapter ID */
         /** Returns the item ID == its adapter ID */
         readonly id: string;
         readonly id: string;
         /** Add the given item as a child of this one */
         /** Add the given item as a child of this one */
         add(child: TreeItem): void;
         add(child: TreeItem): void;
         /**
         /**
+         * Returns the original adapter
+         */
+        readonly adapter: Adapter;
+        /**
          * Function used to compare this item to another tree item.
          * Function used to compare this item to another tree item.
          * Returns the alphabetical sort of the adapter ID
          * Returns the alphabetical sort of the adapter ID
          */
          */
@@ -983,6 +1072,21 @@ declare module INSPECTOR {
 }
 }
 
 
 declare module INSPECTOR {
 declare module INSPECTOR {
+    interface ICameraPOV {
+        setPOV: () => void;
+    }
+    /**
+     *
+     */
+    class CameraPOV extends AbstractTreeTool {
+        private cameraPOV;
+        constructor(camera: ICameraPOV);
+        protected action(): void;
+        private _gotoPOV();
+    }
+}
+
+declare module INSPECTOR {
     /** Any object implementing this interface should
     /** Any object implementing this interface should
      * provide methods to toggle its visibility
      * provide methods to toggle its visibility
      */
      */

+ 414 - 48
dist/preview release/inspector/babylon.inspector.js

@@ -5,10 +5,16 @@ var INSPECTOR;
          * If the parameter 'popup' is false, the inspector is created as a right panel on the main window.
          * If the parameter 'popup' is false, the inspector is created as a right panel on the main window.
          * If the parameter 'popup' is true, the inspector is created in another popup.
          * If the parameter 'popup' is true, the inspector is created in another popup.
          */
          */
-        function Inspector(scene, popup) {
+        function Inspector(scene, popup, initialTab, parentElement) {
             var _this = this;
             var _this = this;
             /** True if the inspector is built as a popup tab */
             /** True if the inspector is built as a popup tab */
             this._popupMode = false;
             this._popupMode = false;
+            //get Tabbar initialTab
+            this._initialTab = initialTab;
+            console.log(initialTab);
+            //get parentElement of our Inspector
+            this._parentElement = parentElement;
+            console.log(this._parentElement);
             // get canvas parent only if needed.
             // get canvas parent only if needed.
             this._scene = scene;
             this._scene = scene;
             // Save HTML document and window
             // Save HTML document and window
@@ -88,22 +94,40 @@ var INSPECTOR;
                 canvas.style.marginTop = "0";
                 canvas.style.marginTop = "0";
                 canvas.style.marginRight = "0";
                 canvas.style.marginRight = "0";
                 // Replace canvas with the wrapper...
                 // Replace canvas with the wrapper...
+                // if (this._parentElement) {
+                //     canvasParent.replaceChild(this._parentElement, canvas);
+                //     this._parentElement.appendChild(canvas);
+                // }
+                // else {
                 canvasParent.replaceChild(this._c2diwrapper, canvas);
                 canvasParent.replaceChild(this._c2diwrapper, canvas);
                 // ... and add canvas to the wrapper
                 // ... and add canvas to the wrapper
                 this._c2diwrapper.appendChild(canvas);
                 this._c2diwrapper.appendChild(canvas);
-                // add inspector     
-                var inspector = INSPECTOR.Helpers.CreateDiv('insp-right-panel', this._c2diwrapper);
+                // }
+                // add inspector
+                var inspector = void 0;
+                if (this._parentElement) {
+                    this._c2diwrapper.appendChild(this._parentElement);
+                    inspector = INSPECTOR.Helpers.CreateDiv('insp-right-panel', this._parentElement);
+                    inspector.style.width = '100%';
+                    inspector.style.height = '100%';
+                }
+                else {
+                    inspector = INSPECTOR.Helpers.CreateDiv('insp-right-panel', this._c2diwrapper);
+                }
+                console.log(inspector);
                 // Add split bar
                 // Add split bar
-                Split([canvas, inspector], {
-                    direction: 'horizontal',
-                    sizes: [75, 25],
-                    onDrag: function () {
-                        INSPECTOR.Helpers.SEND_EVENT('resize');
-                        if (_this._tabbar) {
-                            _this._tabbar.updateWidth();
+                if (!this._parentElement) {
+                    Split([canvas, inspector], {
+                        direction: 'horizontal',
+                        sizes: [75, 25],
+                        onDrag: function () {
+                            INSPECTOR.Helpers.SEND_EVENT('resize');
+                            if (_this._tabbar) {
+                                _this._tabbar.updateWidth();
+                            }
                         }
                         }
-                    }
-                });
+                    });
+                }
                 // Build the inspector
                 // Build the inspector
                 this._buildInspector(inspector);
                 this._buildInspector(inspector);
                 // Send resize event to the window
                 // Send resize event to the window
@@ -151,7 +175,7 @@ var INSPECTOR;
         /** Build the inspector panel in the given HTML element */
         /** Build the inspector panel in the given HTML element */
         Inspector.prototype._buildInspector = function (parent) {
         Inspector.prototype._buildInspector = function (parent) {
             // tabbar
             // tabbar
-            this._tabbar = new INSPECTOR.TabBar(this);
+            this._tabbar = new INSPECTOR.TabBar(this, this._initialTab);
             // Top panel
             // Top panel
             this._topPanel = INSPECTOR.Helpers.CreateDiv('top-panel', parent);
             this._topPanel = INSPECTOR.Helpers.CreateDiv('top-panel', parent);
             // Add tabbar
             // Add tabbar
@@ -333,9 +357,25 @@ var INSPECTOR;
             ],
             ],
             format: function (tex) { return tex.name; }
             format: function (tex) { return tex.name; }
         },
         },
+        'MapTexture': {
+            type: BABYLON.MapTexture
+        },
+        'RenderTargetTexture': {
+            type: BABYLON.RenderTargetTexture
+        },
+        'DynamicTexture': {
+            type: BABYLON.DynamicTexture
+        },
+        'BaseTexture': {
+            type: BABYLON.BaseTexture
+        },
+        'FontTexture': {
+            type: BABYLON.FontTexture
+        },
         'ArcRotateCamera': {
         'ArcRotateCamera': {
             type: BABYLON.ArcRotateCamera,
             type: BABYLON.ArcRotateCamera,
             properties: [
             properties: [
+                'position',
                 'alpha',
                 'alpha',
                 'beta',
                 'beta',
                 'radius',
                 'radius',
@@ -354,6 +394,36 @@ var INSPECTOR;
                 'checkCollisions'
                 'checkCollisions'
             ]
             ]
         },
         },
+        'FreeCamera': {
+            type: BABYLON.FreeCamera,
+            properties: [
+                'position',
+                'rotation',
+                'rotationQuaternion',
+                'cameraDirection',
+                'cameraRotation',
+                'ellipsoid',
+                'applyGravity',
+                'angularSensibility',
+                'keysUp',
+                'keysDown',
+                'keysLeft',
+                'keysRight',
+                'checkCollisions',
+                'speed',
+                'lockedTarget',
+                'noRotationConstraint',
+                'fov',
+                'inertia',
+                'minZ', 'maxZ',
+                'layerMask',
+                'mode',
+                'orthoBottom',
+                'orthoTop',
+                'orthoLeft',
+                'orthoRight'
+            ]
+        },
         'Scene': {
         'Scene': {
             type: BABYLON.Scene,
             type: BABYLON.Scene,
             properties: [
             properties: [
@@ -570,6 +640,16 @@ var INSPECTOR;
             enumerable: true,
             enumerable: true,
             configurable: true
             configurable: true
         });
         });
+        Object.defineProperty(Adapter.prototype, "object", {
+            /**
+             * Returns the actual object used for this adapter
+             */
+            get: function () {
+                return this._obj;
+            },
+            enumerable: true,
+            configurable: true
+        });
         /** Should be overriden in subclasses */
         /** Should be overriden in subclasses */
         Adapter.prototype.highlight = function (b) { };
         Adapter.prototype.highlight = function (b) { };
         ;
         ;
@@ -589,6 +669,105 @@ var __extends = (this && this.__extends) || function (d, b) {
 };
 };
 var INSPECTOR;
 var INSPECTOR;
 (function (INSPECTOR) {
 (function (INSPECTOR) {
+    var CameraAdapter = (function (_super) {
+        __extends(CameraAdapter, _super);
+        function CameraAdapter(obj) {
+            return _super.call(this, obj) || this;
+        }
+        /** Returns the name displayed in the tree */
+        CameraAdapter.prototype.id = function () {
+            var str = '';
+            if (this._obj.name) {
+                str = this._obj.name;
+            } // otherwise nothing displayed        
+            return str;
+        };
+        /** Returns the type of this object - displayed in the tree */
+        CameraAdapter.prototype.type = function () {
+            return INSPECTOR.Helpers.GET_TYPE(this._obj);
+        };
+        /** Returns the list of properties to be displayed for this adapter */
+        CameraAdapter.prototype.getProperties = function () {
+            var propertiesLines = [];
+            var camToDisplay = [];
+            // The if is there to work with the min version of babylon
+            if (this._obj instanceof BABYLON.ArcRotateCamera) {
+                camToDisplay = INSPECTOR.PROPERTIES['ArcRotateCamera'].properties;
+            }
+            else if (this._obj instanceof BABYLON.FreeCamera) {
+                camToDisplay = INSPECTOR.PROPERTIES['FreeCamera'].properties;
+            }
+            for (var _i = 0, camToDisplay_1 = camToDisplay; _i < camToDisplay_1.length; _i++) {
+                var dirty = camToDisplay_1[_i];
+                var infos = new INSPECTOR.Property(dirty, this._obj);
+                propertiesLines.push(new INSPECTOR.PropertyLine(infos));
+            }
+            return propertiesLines;
+        };
+        CameraAdapter.prototype.getTools = function () {
+            var tools = [];
+            // tools.push(new Checkbox(this));
+            tools.push(new INSPECTOR.CameraPOV(this));
+            return tools;
+        };
+        CameraAdapter.prototype.setPOV = function () {
+            this._obj.getScene().activeCamera = this._obj;
+        };
+        return CameraAdapter;
+    }(INSPECTOR.Adapter));
+    INSPECTOR.CameraAdapter = CameraAdapter;
+})(INSPECTOR || (INSPECTOR = {}));
+
+//# sourceMappingURL=CameraAdapter.js.map
+
+var __extends = (this && this.__extends) || function (d, b) {
+    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
+    function __() { this.constructor = d; }
+    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
+};
+var INSPECTOR;
+(function (INSPECTOR) {
+    var TextureAdapter = (function (_super) {
+        __extends(TextureAdapter, _super);
+        function TextureAdapter(obj) {
+            return _super.call(this, obj) || this;
+        }
+        /** Returns the name displayed in the tree */
+        TextureAdapter.prototype.id = function () {
+            var str = '';
+            if (this._obj.name) {
+                str = this._obj.name;
+            } // otherwise nothing displayed        
+            return str;
+        };
+        /** Returns the type of this object - displayed in the tree */
+        TextureAdapter.prototype.type = function () {
+            return INSPECTOR.Helpers.GET_TYPE(this._obj);
+        };
+        /** Returns the list of properties to be displayed for this adapter */
+        TextureAdapter.prototype.getProperties = function () {
+            // Not used in this tab
+            return [];
+        };
+        TextureAdapter.prototype.getTools = function () {
+            var tools = [];
+            // tools.push(new CameraPOV(this));
+            return tools;
+        };
+        return TextureAdapter;
+    }(INSPECTOR.Adapter));
+    INSPECTOR.TextureAdapter = TextureAdapter;
+})(INSPECTOR || (INSPECTOR = {}));
+
+//# sourceMappingURL=TextureAdapter.js.map
+
+var __extends = (this && this.__extends) || function (d, b) {
+    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
+    function __() { this.constructor = d; }
+    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
+};
+var INSPECTOR;
+(function (INSPECTOR) {
     var Canvas2DAdapter = (function (_super) {
     var Canvas2DAdapter = (function (_super) {
         __extends(Canvas2DAdapter, _super);
         __extends(Canvas2DAdapter, _super);
         function Canvas2DAdapter(obj) {
         function Canvas2DAdapter(obj) {
@@ -1694,8 +1873,6 @@ var INSPECTOR;
     INSPECTOR.SearchBar = SearchBar;
     INSPECTOR.SearchBar = SearchBar;
 })(INSPECTOR || (INSPECTOR = {}));
 })(INSPECTOR || (INSPECTOR = {}));
 
 
-//# sourceMappingURL=SearchBar.js.map
-
 var __extends = (this && this.__extends) || function (d, b) {
 var __extends = (this && this.__extends) || function (d, b) {
     for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
     for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
     function __() { this.constructor = d; }
     function __() { this.constructor = d; }
@@ -1737,8 +1914,6 @@ var INSPECTOR;
     INSPECTOR.TextureElement = TextureElement;
     INSPECTOR.TextureElement = TextureElement;
 })(INSPECTOR || (INSPECTOR = {}));
 })(INSPECTOR || (INSPECTOR = {}));
 
 
-//# sourceMappingURL=TextureElement.js.map
-
 var INSPECTOR;
 var INSPECTOR;
 (function (INSPECTOR) {
 (function (INSPECTOR) {
     /**
     /**
@@ -2014,6 +2189,14 @@ var INSPECTOR;
         /** Add this in the propertytab with the searchbar */
         /** Add this in the propertytab with the searchbar */
         Tab.prototype.filter = function (str) { };
         Tab.prototype.filter = function (str) { };
         ;
         ;
+        /** Select an item in the tree */
+        Tab.prototype.select = function (item) {
+            // To define in subclasses if needed 
+        };
+        /** Highlight the given node, and downplay all others */
+        Tab.prototype.highlightNode = function (item) {
+            // To define in subclasses if needed
+        };
         /**
         /**
          * Returns the total width in pixel of this tab, 0 by default
          * Returns the total width in pixel of this tab, 0 by default
         */
         */
@@ -2171,6 +2354,160 @@ var __extends = (this && this.__extends) || function (d, b) {
 };
 };
 var INSPECTOR;
 var INSPECTOR;
 (function (INSPECTOR) {
 (function (INSPECTOR) {
+    var CameraTab = (function (_super) {
+        __extends(CameraTab, _super);
+        function CameraTab(tabbar, inspector) {
+            return _super.call(this, tabbar, 'Camera', inspector) || this;
+        }
+        /* Overrides super */
+        CameraTab.prototype._getTree = function () {
+            var arr = [];
+            // get all cameras from the first scene
+            var instances = this._inspector.scene;
+            for (var _i = 0, _a = instances.cameras; _i < _a.length; _i++) {
+                var camera = _a[_i];
+                arr.push(new INSPECTOR.TreeItem(this, new INSPECTOR.CameraAdapter(camera)));
+            }
+            return arr;
+        };
+        return CameraTab;
+    }(INSPECTOR.PropertyTab));
+    INSPECTOR.CameraTab = CameraTab;
+})(INSPECTOR || (INSPECTOR = {}));
+
+var __extends = (this && this.__extends) || function (d, b) {
+    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
+    function __() { this.constructor = d; }
+    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
+};
+var INSPECTOR;
+(function (INSPECTOR) {
+    var TextureTab = (function (_super) {
+        __extends(TextureTab, _super);
+        function TextureTab(tabbar, inspector) {
+            var _this = _super.call(this, tabbar, 'Textures') || this;
+            _this._treeItems = [];
+            _this._inspector = inspector;
+            // Build the properties panel : a div that will contains the tree and the detail panel
+            _this._panel = INSPECTOR.Helpers.CreateDiv('tab-panel');
+            // Build the treepanel
+            _this._treePanel = INSPECTOR.Helpers.CreateDiv('insp-tree', _this._panel);
+            _this._imagePanel = INSPECTOR.Helpers.CreateDiv('image-panel', _this._panel);
+            Split([_this._treePanel, _this._imagePanel], {
+                blockDrag: _this._inspector.popupMode,
+                direction: 'vertical'
+            });
+            _this.update();
+            return _this;
+        }
+        TextureTab.prototype.dispose = function () {
+            // Nothing to dispose
+        };
+        TextureTab.prototype.update = function (_items) {
+            var items;
+            if (_items) {
+                items = _items;
+            }
+            else {
+                // Rebuild the tree
+                this._treeItems = this._getTree();
+                items = this._treeItems;
+            }
+            // Clean the tree
+            INSPECTOR.Helpers.CleanDiv(this._treePanel);
+            INSPECTOR.Helpers.CleanDiv(this._imagePanel);
+            // Sort items alphabetically
+            items.sort(function (item1, item2) {
+                return item1.compareTo(item2);
+            });
+            // Display items
+            for (var _i = 0, items_1 = items; _i < items_1.length; _i++) {
+                var item = items_1[_i];
+                this._treePanel.appendChild(item.toHtml());
+            }
+        };
+        /* Overrides super */
+        TextureTab.prototype._getTree = function () {
+            var arr = [];
+            // get all cameras from the first scene
+            var instances = this._inspector.scene;
+            for (var _i = 0, _a = instances.textures; _i < _a.length; _i++) {
+                var tex = _a[_i];
+                arr.push(new INSPECTOR.TreeItem(this, new INSPECTOR.TextureAdapter(tex)));
+            }
+            return arr;
+        };
+        /** Display the details of the given item */
+        TextureTab.prototype.displayDetails = function (item) {
+            // Remove active state on all items
+            this.activateNode(item);
+            INSPECTOR.Helpers.CleanDiv(this._imagePanel);
+            // Get the texture object
+            var texture = item.adapter.object;
+            var img = INSPECTOR.Helpers.CreateElement('img', 'texture-image', this._imagePanel);
+            if (texture instanceof BABYLON.MapTexture) {
+                // instance of Map texture
+                texture.bindTextureForPosSize(new BABYLON.Vector2(0, 0), new BABYLON.Size(texture.getSize().width, texture.getSize().height), false);
+                BABYLON.Tools.DumpFramebuffer(texture.getSize().width, texture.getSize().height, this._inspector.scene.getEngine(), function (data) { return img.src = data; });
+                texture.unbindTexture();
+            }
+            else if (texture instanceof BABYLON.RenderTargetTexture) {
+                // RenderTarget textures
+                BABYLON.Tools.CreateScreenshotUsingRenderTarget(this._inspector.scene.getEngine(), texture.activeCamera, { precision: 1 }, function (data) { return img.src = data; });
+            }
+            else if (texture.url) {
+                // If an url is present, the texture is an image
+                img.src = texture.url;
+            }
+            else if (texture['_canvas']) {
+                // Dynamic texture
+                var base64Image = texture['_canvas'].toDataURL("image/png");
+                img.src = base64Image;
+            }
+        };
+        /** Select an item in the tree */
+        TextureTab.prototype.select = function (item) {
+            // Remove the node highlight
+            this.highlightNode();
+            // Active the node
+            this.activateNode(item);
+            // Display its details
+            this.displayDetails(item);
+        };
+        /** Set the given item as active in the tree */
+        TextureTab.prototype.activateNode = function (item) {
+            if (this._treeItems) {
+                for (var _i = 0, _a = this._treeItems; _i < _a.length; _i++) {
+                    var node = _a[_i];
+                    node.active(false);
+                }
+            }
+            item.active(true);
+        };
+        /** Highlight the given node, and downplay all others */
+        TextureTab.prototype.highlightNode = function (item) {
+            if (this._treeItems) {
+                for (var _i = 0, _a = this._treeItems; _i < _a.length; _i++) {
+                    var node = _a[_i];
+                    node.highlight(false);
+                }
+            }
+            if (item) {
+                item.highlight(true);
+            }
+        };
+        return TextureTab;
+    }(INSPECTOR.Tab));
+    INSPECTOR.TextureTab = TextureTab;
+})(INSPECTOR || (INSPECTOR = {}));
+
+var __extends = (this && this.__extends) || function (d, b) {
+    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
+    function __() { this.constructor = d; }
+    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
+};
+var INSPECTOR;
+(function (INSPECTOR) {
     var Canvas2DTab = (function (_super) {
     var Canvas2DTab = (function (_super) {
         __extends(Canvas2DTab, _super);
         __extends(Canvas2DTab, _super);
         function Canvas2DTab(tabbar, inspector) {
         function Canvas2DTab(tabbar, inspector) {
@@ -2633,34 +2970,6 @@ var INSPECTOR;
                 inside = this._beautify(inside, level + 1);
                 inside = this._beautify(inside, level + 1);
                 return this._beautify(left, level) + '{\n' + inside + '\n' + spaces + '}\n' + this._beautify(right, level);
                 return this._beautify(left, level) + '{\n' + inside + '\n' + spaces + '}\n' + this._beautify(right, level);
             }
             }
-            // // Replace bracket with @1 and @2 with correct indentation
-            // let newInside          = "@1\n\t" + inside + "\n@2";
-            // newInside              = newInside.replace(/;\n/g, ";\n\t");
-            // glsl                   = glsl.replace(insideWithBrackets, newInside);
-            // firstBracket       = glsl.indexOf('{');
-            // lastBracket        = glsl.lastIndexOf('}');
-            // }
-            // console.log(glsl);
-            // let regex = /(\{(?:\{??[^\{]*?}))+/gmi;
-            // let tmp = glsl;
-            // let m;
-            // while ((m = regex.exec(tmp)) !== null) {
-            //     // This is necessary to avoid infinite loops with zero-width matches
-            //     if (m.index === regex.lastIndex) {
-            //         regex.lastIndex++;
-            //     }                
-            //     // The result can be accessed through the `m`-variable.
-            //     m.forEach((match, groupIndex) => {
-            //         // Remove the first and the last bracket only
-            //         let matchWithoutBrackets = match.replace(/{/, "").replace(/}/, "");
-            //         // Indent the content inside brackets with tabs
-            //         glsl = glsl.replace(match, `{\n\t${matchWithoutBrackets}\n}\n`);
-            //         // removes the match from tmp
-            //         tmp = tmp.replace(match, "");
-            //         // and continue
-            //     });
-            // }
-            // return 
         };
         };
         return ShaderTab;
         return ShaderTab;
     }(INSPECTOR.Tab));
     }(INSPECTOR.Tab));
@@ -3085,7 +3394,7 @@ var INSPECTOR;
      */
      */
     var TabBar = (function (_super) {
     var TabBar = (function (_super) {
         __extends(TabBar, _super);
         __extends(TabBar, _super);
-        function TabBar(inspector) {
+        function TabBar(inspector, initialTab) {
             var _this = _super.call(this) || this;
             var _this = _super.call(this) || this;
             // The list of available tabs
             // The list of available tabs
             _this._tabs = [];
             _this._tabs = [];
@@ -3106,10 +3415,15 @@ var INSPECTOR;
                 _this._tabs.push(new INSPECTOR.Canvas2DTab(_this, _this._inspector));
                 _this._tabs.push(new INSPECTOR.Canvas2DTab(_this, _this._inspector));
             }
             }
             _this._tabs.push(new INSPECTOR.MaterialTab(_this, _this._inspector));
             _this._tabs.push(new INSPECTOR.MaterialTab(_this, _this._inspector));
+            _this._tabs.push(new INSPECTOR.CameraTab(_this, _this._inspector));
             _this._toolBar = new INSPECTOR.Toolbar(_this._inspector);
             _this._toolBar = new INSPECTOR.Toolbar(_this._inspector);
             _this._build();
             _this._build();
-            // Active the first tab
-            _this._tabs[0].active(true);
+            //Check initialTab is defined and between tabs bounds
+            if (!initialTab || initialTab < 0 || initialTab >= _this._tabs.length) {
+                initialTab = 0;
+                console.warn('');
+            }
+            _this._tabs[initialTab].active(true);
             // set all tab as visible
             // set all tab as visible
             for (var _i = 0, _a = _this._tabs; _i < _a.length; _i++) {
             for (var _i = 0, _a = _this._tabs; _i < _a.length; _i++) {
                 var tab = _a[_i];
                 var tab = _a[_i];
@@ -3123,9 +3437,12 @@ var INSPECTOR;
             var _this = this;
             var _this = this;
             this._div.className = 'tabbar';
             this._div.className = 'tabbar';
             this._div.appendChild(this._toolBar.toHtml());
             this._div.appendChild(this._toolBar.toHtml());
+            var i = 1;
             for (var _i = 0, _a = this._tabs; _i < _a.length; _i++) {
             for (var _i = 0, _a = this._tabs; _i < _a.length; _i++) {
                 var tab = _a[_i];
                 var tab = _a[_i];
                 this._div.appendChild(tab.toHtml());
                 this._div.appendChild(tab.toHtml());
+                tab.toHtml().id = 'tab' + i;
+                i++;
             }
             }
             this._moreTabsIcon = INSPECTOR.Helpers.CreateElement('i', 'fa fa-angle-double-right more-tabs');
             this._moreTabsIcon = INSPECTOR.Helpers.CreateElement('i', 'fa fa-angle-double-right more-tabs');
             this._moreTabsPanel = INSPECTOR.Helpers.CreateDiv('more-tabs-panel');
             this._moreTabsPanel = INSPECTOR.Helpers.CreateDiv('more-tabs-panel');
@@ -3689,6 +4006,16 @@ var INSPECTOR;
             this.children.push(child);
             this.children.push(child);
             this.update();
             this.update();
         };
         };
+        Object.defineProperty(TreeItem.prototype, "adapter", {
+            /**
+             * Returns the original adapter
+             */
+            get: function () {
+                return this._adapter;
+            },
+            enumerable: true,
+            configurable: true
+        });
         /**
         /**
          * Function used to compare this item to another tree item.
          * Function used to compare this item to another tree item.
          * Returns the alphabetical sort of the adapter ID
          * Returns the alphabetical sort of the adapter ID
@@ -3911,6 +4238,45 @@ var __extends = (this && this.__extends) || function (d, b) {
 var INSPECTOR;
 var INSPECTOR;
 (function (INSPECTOR) {
 (function (INSPECTOR) {
     /**
     /**
+     *
+     */
+    var CameraPOV = (function (_super) {
+        __extends(CameraPOV, _super);
+        function CameraPOV(camera) {
+            var _this = _super.call(this) || this;
+            _this.cameraPOV = camera;
+            _this._elem.classList.add('fa-video-camera');
+            return _this;
+        }
+        CameraPOV.prototype.action = function () {
+            _super.prototype.action.call(this);
+            this._gotoPOV();
+        };
+        CameraPOV.prototype._gotoPOV = function () {
+            var actives = INSPECTOR.Inspector.DOCUMENT.querySelectorAll(".fa-video-camera.active");
+            console.log(actives);
+            for (var i = 0; i < actives.length; i++) {
+                actives[i].classList.remove('active');
+            }
+            //if (this._on) {
+            // set icon camera
+            this._elem.classList.add('active');
+            //}
+            this.cameraPOV.setPOV();
+        };
+        return CameraPOV;
+    }(INSPECTOR.AbstractTreeTool));
+    INSPECTOR.CameraPOV = CameraPOV;
+})(INSPECTOR || (INSPECTOR = {}));
+
+var __extends = (this && this.__extends) || function (d, b) {
+    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
+    function __() { this.constructor = d; }
+    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
+};
+var INSPECTOR;
+(function (INSPECTOR) {
+    /**
      * Checkbox to display/hide the primitive
      * Checkbox to display/hide the primitive
      */
      */
     var Checkbox = (function (_super) {
     var Checkbox = (function (_super) {

Файловите разлики са ограничени, защото са твърде много
+ 3 - 3
dist/preview release/inspector/babylon.inspector.min.js


+ 1 - 1
dist/preview release/loaders/babylon.glTFFileLoader.js

@@ -856,7 +856,7 @@ var BABYLON;
                 var translation = node.translation || [0, 0, 0];
                 var translation = node.translation || [0, 0, 0];
                 var rotation = node.rotation || [0, 0, 0, 1];
                 var rotation = node.rotation || [0, 0, 0, 1];
                 var scale = node.scale || [1, 1, 1];
                 var scale = node.scale || [1, 1, 1];
-                configureNode(lastNode, BABYLON.Vector3.FromArray(translation), BABYLON.Quaternion.RotationAxis(BABYLON.Vector3.FromArray(rotation).normalize(), rotation[3]), BABYLON.Vector3.FromArray(scale));
+                configureNode(lastNode, BABYLON.Vector3.FromArray(translation), BABYLON.Quaternion.FromArray(rotation), BABYLON.Vector3.FromArray(scale));
             }
             }
             lastNode.updateCache(true);
             lastNode.updateCache(true);
             node.babylonNode = lastNode;
             node.babylonNode = lastNode;

Файловите разлики са ограничени, защото са твърде много
+ 2 - 2
dist/preview release/loaders/babylon.glTFFileLoader.min.js


+ 21 - 0
dist/preview release/materialsLibrary/babylon.shadowOnlyMaterial.d.ts

@@ -0,0 +1,21 @@
+/// <reference path="../../../dist/preview release/babylon.d.ts" />
+declare module BABYLON {
+    class ShadowOnlyMaterial extends Material {
+        private _worldViewProjectionMatrix;
+        private _scaledDiffuse;
+        private _renderId;
+        private _defines;
+        private _cachedDefines;
+        constructor(name: string, scene: Scene);
+        needAlphaBlending(): boolean;
+        needAlphaTesting(): boolean;
+        getAlphaTestTexture(): BaseTexture;
+        private _checkCache(scene, mesh?, useInstances?);
+        isReady(mesh?: AbstractMesh, useInstances?: boolean): boolean;
+        bindOnlyWorldMatrix(world: Matrix): void;
+        bind(world: Matrix, mesh?: Mesh): void;
+        clone(name: string): ShadowOnlyMaterial;
+        serialize(): any;
+        static Parse(source: any, scene: Scene, rootUrl: string): ShadowOnlyMaterial;
+    }
+}

Файловите разлики са ограничени, защото са твърде много
+ 209 - 0
dist/preview release/materialsLibrary/babylon.shadowOnlyMaterial.js


Файловите разлики са ограничени, защото са твърде много
+ 1 - 0
dist/preview release/materialsLibrary/babylon.shadowOnlyMaterial.min.js


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

@@ -1,5 +1,4 @@
 /// <reference path="../../../dist/preview release/babylon.d.ts" />
 /// <reference path="../../../dist/preview release/babylon.d.ts" />
-/// <reference path="../simple/babylon.simpleMaterial.d.ts" />
 declare module BABYLON {
 declare module BABYLON {
     class WaterMaterial extends Material {
     class WaterMaterial extends Material {
         renderTargetSize: Vector2;
         renderTargetSize: Vector2;

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

@@ -1,5 +1,4 @@
 /// <reference path="../../../dist/preview release/babylon.d.ts"/>
 /// <reference path="../../../dist/preview release/babylon.d.ts"/>
-/// <reference path="../simple/babylon.simpleMaterial.ts"/>
 var __extends = (this && this.__extends) || function (d, b) {
 var __extends = (this && this.__extends) || function (d, b) {
     for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
     for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
     function __() { this.constructor = d; }
     function __() { this.constructor = d; }

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

@@ -4,12 +4,12 @@
 
 
 ### Major updates
 ### Major updates
  - WebGL2 context support. WebGL2 is now used instead of WebGL 1 when available. [More info here](http://doc.babylonjs.com/overviews/webgl2) ([deltakosh](https://github.com/deltakosh))
  - WebGL2 context support. WebGL2 is now used instead of WebGL 1 when available. [More info here](http://doc.babylonjs.com/overviews/webgl2) ([deltakosh](https://github.com/deltakosh))
+ - Complete WebVR 1.1 support including controllers for HTC Vive and Occulus. [More info here](http://doc.babylonjs.com/overviews/webvr_camera) ([raanan](https://github.com/raananw))
  - Support for [Vertex Array Objects](https://www.opengl.org/registry/specs/ARB/vertex_array_object.txt) ([deltakosh](https://github.com/deltakosh))
  - Support for [Vertex Array Objects](https://www.opengl.org/registry/specs/ARB/vertex_array_object.txt) ([deltakosh](https://github.com/deltakosh))
  - Support for multisample render targets. [Demo](http://www.babylonjs-playground.com/#12MKMN) ([deltakosh](https://github.com/deltakosh))
  - Support for multisample render targets. [Demo](http://www.babylonjs-playground.com/#12MKMN) ([deltakosh](https://github.com/deltakosh))
  - New Unity 5 Editor Toolkit. Complete pipeline integration [Doc](TODO) - ([MackeyK24](https://github.com/MackeyK24))
  - New Unity 5 Editor Toolkit. Complete pipeline integration [Doc](TODO) - ([MackeyK24](https://github.com/MackeyK24))
  - New DebugLayer. [Doc](TODO) - ([temechon](https://github.com/temechon))
  - New DebugLayer. [Doc](TODO) - ([temechon](https://github.com/temechon))
  - New `VideoTexture.CreateFromWebCam` to generate video texture using WebRTC. [Demo](https://www.babylonjs-playground.com#1R77YT#2) - (Sebastien Vandenberghe)(https://github.com/sebavanmicrosoft) / ([deltakosh](https://github.com/deltakosh))
  - New `VideoTexture.CreateFromWebCam` to generate video texture using WebRTC. [Demo](https://www.babylonjs-playground.com#1R77YT#2) - (Sebastien Vandenberghe)(https://github.com/sebavanmicrosoft) / ([deltakosh](https://github.com/deltakosh))
- - New `HolographicCamera` to support rendering on Windows Holographic. - ([sebavan](https://github.com/sebavan))
  - New Facet Data feature ([jerome](https://github.com/jbousquie))
  - New Facet Data feature ([jerome](https://github.com/jbousquie))
  - babylon.fontTexture.ts was moved from babylon.js to canvas2D ([nockawa](https://github.com/nockawa))
  - babylon.fontTexture.ts was moved from babylon.js to canvas2D ([nockawa](https://github.com/nockawa))
  - Multi-platform Compressed Textures for Desktops & Mobile Devices with fall back.  Batch (dos) scripts to convert entire directories of .jpg's & .png's ([jcpalmer](https://github.com/Palmer-JC))
  - Multi-platform Compressed Textures for Desktops & Mobile Devices with fall back.  Batch (dos) scripts to convert entire directories of .jpg's & .png's ([jcpalmer](https://github.com/Palmer-JC))
@@ -35,7 +35,10 @@
 - Improved the internal code of `Vector3.RotationFromAxisToRef()` ([jerome](https://github.com/jbousquie), thanks to [abow](https://github.com/abow))  
 - Improved the internal code of `Vector3.RotationFromAxisToRef()` ([jerome](https://github.com/jbousquie), thanks to [abow](https://github.com/abow))  
 - GroundMeshes are now serialized correctly ([deltakosh](https://github.com/deltakosh))
 - GroundMeshes are now serialized correctly ([deltakosh](https://github.com/deltakosh))
 - Added `mesh.markVerticesDataAsUpdatable()` to allow a specific vertexbuffer to become updatable ([deltakosh](https://github.com/deltakosh)) 
 - Added `mesh.markVerticesDataAsUpdatable()` to allow a specific vertexbuffer to become updatable ([deltakosh](https://github.com/deltakosh)) 
-
+- Added `POINTERTAP` and `POINTERDOUBLETAP` PointerEventTypes to register new Observer mask. (Demo here)[http://www.babylonjs-playground.com/?30] ([yuccai](https://github.com/yuccai))
+- Added OnDoublePickTrigger for ActionManager ([yuccai](https://github.com/yuccai))
+- Added Scene.DoubleClickDelay to set the timing within a double click event like PointerEventTypes.POINTERDOUBLETAP or ActionManager.OnDoublePickTrigger has to be processed ([yuccai](https://github.com/yuccai))
+- New material: ShadowOnlyMaterial to display shadows on transparent surfaces ([deltakosh](https://github.com/deltakosh)) 
  
  
 ### Bug fixes
 ### Bug fixes
 - Fixed a bug with spotlight direction ([deltakosh](https://github.com/deltakosh)) 
 - Fixed a bug with spotlight direction ([deltakosh](https://github.com/deltakosh)) 
@@ -45,7 +48,7 @@
 - Fixed SPS particle access start index when used with `setParticles(start, end)` ([jerome](https://github.com/jbousquie))  
 - Fixed SPS particle access start index when used with `setParticles(start, end)` ([jerome](https://github.com/jbousquie))  
 
 
 ### API Documentation
 ### API Documentation
-- File `abstractMesh.ts` documented  ([jerome](https://github.com/jbousquie))  
+`- File `abstractMesh.ts` documented  ([jerome](https://github.com/jbousquie))  
 - File `mesh.ts` documented ([jerome](https://github.com/jbousquie))  
 - File `mesh.ts` documented ([jerome](https://github.com/jbousquie))  
 - File `groundMesh.ts` documented ([jerome](https://github.com/jbousquie))  
 - File `groundMesh.ts` documented ([jerome](https://github.com/jbousquie))  
 - File `instancedMesh.ts` documented ([jerome](https://github.com/jbousquie))  
 - File `instancedMesh.ts` documented ([jerome](https://github.com/jbousquie))  
@@ -61,6 +64,31 @@
 - File `spotLight.ts` documented ([jerome](https://github.com/jbousquie))  
 - File `spotLight.ts` documented ([jerome](https://github.com/jbousquie))  
 - File `shadowGenerator.ts` documented ([jerome](https://github.com/jbousquie))  
 - File `shadowGenerator.ts` documented ([jerome](https://github.com/jbousquie))  
 
 
+### Breaking changes
+- WebVRCamera:
+  - `requestVRFullscreen` has been removed. Call `attachControl()` inside a user-interaction callback to start sending frames to the VR display
+  - `setPositionOffset` has been used to change the position offset. it is now done using `camera.position`
+- Ray :
+  - `show` has been removed. Use new `RayHelper.show()` instead
+  - `hide` has been removed. Use new `RayHelper.hide()` instead
+- AbstractMesh:
+  - `onPhysicsCollide` has been removed. Use `mesh.physicsImpostor.registerOnPhysicsCollide()` instead
+  - `setPhysicsState` has been removed. Use `new PhysicsImpostor()` instead
+  - `getPhysicsMass` has been removed. Use `mesh.physicsImpostor.getParam("mass")` instead
+  - `getPhysicsFriction` has been removed. Use `mesh.physicsImpostor.getParam("friction")` instead
+  - `getPhysicsRestitution` has been removed. Use `mesh.physicsImpostor.getParam("restitution")` instead
+  - `updatePhysicsBodyPosition` has been removed. Changes are synchronized automatically now
+- Mesh:
+  - `updateVerticesDataDirectly` has been removed. Use `mesh.updateVerticesData()` instead
+- SsaoRenderingPipeline:
+  - `getBlurHPostProcess` has been removed. Blur post-process is no more required
+  - `getBlurVPostProcess` has been removed. Blur post-process is no more required
+- Scene:
+  - `setGravity` has been removed. Use `scene.getPhysicsEngine().setGravity()` instead
+  - `createCompoundImpostor` has been removed. Use PhysicsImpostor parent/child instead
+- ActionManager:
+  - `LongPressDelay` and `DragMovementThreshold` are now respectively Scene.LongPressDelay and Scene.DragMovementThreshold
+ 
 ## Canvas2D
 ## Canvas2D
 
 
 ### Major Updates
 ### Major Updates

+ 4 - 0
inspector/sass/_tabPanel.scss

@@ -3,6 +3,10 @@
     &.searchable {
     &.searchable {
         height:calc(100% - #{$searchbar-height} - 10px);   
         height:calc(100% - #{$searchbar-height} - 10px);   
     }  
     }  
+
+    .texture-image {
+        max-height:400px;
+    }
     
     
     .scene-actions {
     .scene-actions {
         overflow-y: auto;
         overflow-y: auto;

+ 1 - 0
inspector/sass/_tree.scss

@@ -15,6 +15,7 @@
   
   
     
     
     .line {
     .line {
+        padding:3px;
         cursor:pointer;
         cursor:pointer;
         // Hover
         // Hover
         &:hover {
         &:hover {

+ 140 - 107
inspector/src/Inspector.ts

@@ -1,119 +1,129 @@
 module INSPECTOR {
 module INSPECTOR {
     export class Inspector {
     export class Inspector {
 
 
-        private _c2diwrapper    : HTMLElement;
+        private _c2diwrapper: HTMLElement;
         // private _detailsPanel: DetailPanel;
         // private _detailsPanel: DetailPanel;
         /** The panel displayed at the top of the inspector */
         /** The panel displayed at the top of the inspector */
-        private _topPanel       : HTMLElement;
+        private _topPanel: HTMLElement;
         /** The div containing the content of the active tab */
         /** The div containing the content of the active tab */
-        private _tabPanel       : HTMLElement;
+        private _tabPanel: HTMLElement;
         /** The panel containing the list if items */
         /** The panel containing the list if items */
         // private _treePanel   : HTMLElement;
         // private _treePanel   : HTMLElement;
         /** The list if tree items displayed in the tree panel. */
         /** The list if tree items displayed in the tree panel. */
-        private _items          : Array<TreeItem>;
-        private _tabbar         : TabBar;
-        private _scene          : BABYLON.Scene;
+        private _items: Array<TreeItem>;
+        private _tabbar: TabBar;
+        private _scene: BABYLON.Scene;
         /** The HTML document relative to this inspector (the window or the popup depending on its mode) */
         /** The HTML document relative to this inspector (the window or the popup depending on its mode) */
-        public static DOCUMENT  : HTMLDocument;
+        public static DOCUMENT: HTMLDocument;
         /** The HTML window. In popup mode, it's the popup itself. Otherwise, it's the current tab */
         /** The HTML window. In popup mode, it's the popup itself. Otherwise, it's the current tab */
-        public static WINDOW : Window;
+        public static WINDOW: Window;
         /** True if the inspector is built as a popup tab */
         /** True if the inspector is built as a popup tab */
-        private _popupMode      : boolean = false;
+        private _popupMode: boolean = false;
         /** The original canvas style, before applying the inspector*/
         /** The original canvas style, before applying the inspector*/
-        private _canvasStyle :any ;
+        private _canvasStyle: any;
+
+        private _initialTab: number;
+
+        private _parentElement: HTMLElement;
 
 
         /** The inspector is created with the given engine.
         /** The inspector is created with the given engine.
          * If the parameter 'popup' is false, the inspector is created as a right panel on the main window.
          * If the parameter 'popup' is false, the inspector is created as a right panel on the main window.
          * If the parameter 'popup' is true, the inspector is created in another popup.
          * If the parameter 'popup' is true, the inspector is created in another popup.
          */
          */
-        constructor(scene: BABYLON.Scene, popup?:boolean) {
+        constructor(scene: BABYLON.Scene, popup?: boolean, initialTab?: number, parentElement?: HTMLElement) {
+
+            //get Tabbar initialTab
+            this._initialTab = initialTab;
+
+            //get parentElement of our Inspector
+            this._parentElement = parentElement;
 
 
             // get canvas parent only if needed.
             // get canvas parent only if needed.
-            this._scene     = scene;
-            
+            this._scene = scene;
+
             // Save HTML document and window
             // Save HTML document and window
-            Inspector.DOCUMENT = window.document;   
-            Inspector.WINDOW = window;                       
-            
+            Inspector.DOCUMENT = window.document;
+            Inspector.WINDOW = window;
+
             // Load the Canvas2D library if it's not already done
             // Load the Canvas2D library if it's not already done
             if (!BABYLON.Canvas2D) {
             if (!BABYLON.Canvas2D) {
-                BABYLON.Tools.LoadScript("http://www.babylonjs.com/babylon.canvas2d.js", () => {});
+                BABYLON.Tools.LoadScript("http://www.babylonjs.com/babylon.canvas2d.js", () => { });
             }
             }
 
 
             // POPUP MODE
             // POPUP MODE
-            if (popup) { 
+            if (popup) {
                 // Build the inspector in the given parent
                 // Build the inspector in the given parent
                 this.openPopup(true);// set to true in order to NOT dispose the inspector (done in openPopup), as it's not existing yet
                 this.openPopup(true);// set to true in order to NOT dispose the inspector (done in openPopup), as it's not existing yet
-            } else {        
+            } else {
                 // Get canvas and its DOM parent
                 // Get canvas and its DOM parent
-                let canvas                    = this._scene.getEngine().getRenderingCanvas();            
-                let canvasParent              = canvas.parentElement;            
+                let canvas = this._scene.getEngine().getRenderingCanvas();
+                let canvasParent = canvas.parentElement;
                 let canvasParentComputedStyle = Inspector.WINDOW.getComputedStyle(canvasParent);
                 let canvasParentComputedStyle = Inspector.WINDOW.getComputedStyle(canvasParent);
 
 
                 // get canvas style                
                 // get canvas style                
-                let canvasComputedStyle  = Inspector.WINDOW.getComputedStyle(canvas);
+                let canvasComputedStyle = Inspector.WINDOW.getComputedStyle(canvas);
 
 
-                this._canvasStyle = { 
-                    width        : Helpers.Css(canvas, 'width'),
-                    height       : Helpers.Css(canvas, 'height'),
+                this._canvasStyle = {
+                    width: Helpers.Css(canvas, 'width'),
+                    height: Helpers.Css(canvas, 'height'),
 
 
-                    position     : canvasComputedStyle.position,
-                    top          : canvasComputedStyle.top,
-                    bottom       : canvasComputedStyle.bottom,
-                    left         : canvasComputedStyle.left,
-                    right        : canvasComputedStyle.right,
+                    position: canvasComputedStyle.position,
+                    top: canvasComputedStyle.top,
+                    bottom: canvasComputedStyle.bottom,
+                    left: canvasComputedStyle.left,
+                    right: canvasComputedStyle.right,
 
 
-                    padding      : canvasComputedStyle.padding,
+                    padding: canvasComputedStyle.padding,
                     paddingBottom: canvasComputedStyle.paddingBottom,
                     paddingBottom: canvasComputedStyle.paddingBottom,
-                    paddingLeft  : canvasComputedStyle.paddingLeft,
-                    paddingTop   : canvasComputedStyle.paddingTop,
-                    paddingRight : canvasComputedStyle.paddingRight,
+                    paddingLeft: canvasComputedStyle.paddingLeft,
+                    paddingTop: canvasComputedStyle.paddingTop,
+                    paddingRight: canvasComputedStyle.paddingRight,
 
 
-                    margin       : canvasComputedStyle.margin,
-                    marginBottom : canvasComputedStyle.marginBottom,
-                    marginLeft   : canvasComputedStyle.marginLeft,
-                    marginTop    : canvasComputedStyle.marginTop,
-                    marginRight  : canvasComputedStyle.marginRight
+                    margin: canvasComputedStyle.margin,
+                    marginBottom: canvasComputedStyle.marginBottom,
+                    marginLeft: canvasComputedStyle.marginLeft,
+                    marginTop: canvasComputedStyle.marginTop,
+                    marginRight: canvasComputedStyle.marginRight
 
 
                 };
                 };
-                
+
                 // Create c2di wrapper
                 // Create c2di wrapper
-                this._c2diwrapper  = Helpers.CreateDiv('insp-wrapper');
-                
+                this._c2diwrapper = Helpers.CreateDiv('insp-wrapper');
+
                 // copy style from canvas to wrapper
                 // copy style from canvas to wrapper
                 for (let prop in this._canvasStyle) {
                 for (let prop in this._canvasStyle) {
                     this._c2diwrapper.style[prop] = this._canvasStyle[prop];
                     this._c2diwrapper.style[prop] = this._canvasStyle[prop];
                 }
                 }
-                
+
                 // Convert wrapper size in % (because getComputedStyle returns px only)
                 // Convert wrapper size in % (because getComputedStyle returns px only)
-                let widthPx        = parseFloat(canvasComputedStyle.width.substr(0,canvasComputedStyle.width.length-2)) || 0;
-                let heightPx       = parseFloat(canvasComputedStyle.height.substr(0,canvasComputedStyle.height.length-2)) || 0;
+                let widthPx = parseFloat(canvasComputedStyle.width.substr(0, canvasComputedStyle.width.length - 2)) || 0;
+                let heightPx = parseFloat(canvasComputedStyle.height.substr(0, canvasComputedStyle.height.length - 2)) || 0;
 
 
                 // If the canvas position is absolute, restrain the wrapper width to the window width + left positionning
                 // If the canvas position is absolute, restrain the wrapper width to the window width + left positionning
                 if (canvasComputedStyle.position === "absolute" || canvasComputedStyle.position === "relative") {
                 if (canvasComputedStyle.position === "absolute" || canvasComputedStyle.position === "relative") {
                     // compute only left as it takes predominance if right is also specified (and it will be for the wrapper)
                     // compute only left as it takes predominance if right is also specified (and it will be for the wrapper)
-                    let leftPx = parseFloat(canvasComputedStyle.left.substr(0,canvasComputedStyle.left.length-2)) || 0;
+                    let leftPx = parseFloat(canvasComputedStyle.left.substr(0, canvasComputedStyle.left.length - 2)) || 0;
                     if (widthPx + leftPx >= Inspector.WINDOW.innerWidth) {
                     if (widthPx + leftPx >= Inspector.WINDOW.innerWidth) {
-                        this._c2diwrapper.style.maxWidth = `${widthPx-leftPx}px`;
+                        this._c2diwrapper.style.maxWidth = `${widthPx - leftPx}px`;
                     }
                     }
                 }
                 }
-                
+
                 // Check if the parent of the canvas is the body page. If yes, the size ratio is computed
                 // Check if the parent of the canvas is the body page. If yes, the size ratio is computed
                 let parent = this._getRelativeParent(canvas);
                 let parent = this._getRelativeParent(canvas);
 
 
-                let parentWidthPx  = parent.clientWidth;
+                let parentWidthPx = parent.clientWidth;
                 let parentHeightPx = parent.clientHeight;
                 let parentHeightPx = parent.clientHeight;
-                
+
                 let pWidth = widthPx / parentWidthPx * 100;
                 let pWidth = widthPx / parentWidthPx * 100;
                 let pheight = heightPx / parentHeightPx * 100;
                 let pheight = heightPx / parentHeightPx * 100;
 
 
-                this._c2diwrapper.style.width = pWidth+"%";
-                this._c2diwrapper.style.height = pheight+"%";            
+                this._c2diwrapper.style.width = pWidth + "%";
+                this._c2diwrapper.style.height = pheight + "%";
 
 
                 // reset canvas style
                 // reset canvas style
                 canvas.style.position = "static";
                 canvas.style.position = "static";
-                canvas.style.width    = "100%";
-                canvas.style.height   = "100%";
+                canvas.style.width = "100%";
+                canvas.style.height = "100%";
                 canvas.style.paddingBottom = "0";
                 canvas.style.paddingBottom = "0";
                 canvas.style.paddingLeft = "0";
                 canvas.style.paddingLeft = "0";
                 canvas.style.paddingTop = "0";
                 canvas.style.paddingTop = "0";
@@ -127,25 +137,47 @@ module INSPECTOR {
 
 
 
 
                 // Replace canvas with the wrapper...
                 // Replace canvas with the wrapper...
+                // if (this._parentElement) {
+                //     canvasParent.replaceChild(this._parentElement, canvas);
+                //     this._parentElement.appendChild(canvas);
+                // }
+                // else {
                 canvasParent.replaceChild(this._c2diwrapper, canvas);
                 canvasParent.replaceChild(this._c2diwrapper, canvas);
                 // ... and add canvas to the wrapper
                 // ... and add canvas to the wrapper
                 this._c2diwrapper.appendChild(canvas);
                 this._c2diwrapper.appendChild(canvas);
-                // add inspector     
-                let inspector      = Helpers.CreateDiv('insp-right-panel', this._c2diwrapper);
+                // }
+
+
+
+                // add inspector
+                let inspector;
+                if (this._parentElement) {
+                    this._c2diwrapper.appendChild(this._parentElement);
+                    inspector = Helpers.CreateDiv('insp-right-panel', this._parentElement);
+                    inspector.style.width = '100%';
+                    inspector.style.height = '100%';
+                }
+                else {
+                    inspector = Helpers.CreateDiv('insp-right-panel', this._c2diwrapper);
+                }
+                console.log(inspector);
+
                 // Add split bar
                 // Add split bar
-                Split([canvas, inspector], {
-                    direction:'horizontal',
-                    sizes : [75, 25],
-                    onDrag : () => { 
-                        Helpers.SEND_EVENT('resize');
-                        if (this._tabbar) {
-                            this._tabbar.updateWidth()
+                if (!this._parentElement) {
+                    Split([canvas, inspector], {
+                        direction: 'horizontal',
+                        sizes: [75, 25],
+                        onDrag: () => {
+                            Helpers.SEND_EVENT('resize');
+                            if (this._tabbar) {
+                                this._tabbar.updateWidth()
+                            }
                         }
                         }
-                    }
-                });
+                    });
+                }
 
 
                 // Build the inspector
                 // Build the inspector
-                this._buildInspector(inspector);   
+                this._buildInspector(inspector);
                 // Send resize event to the window
                 // Send resize event to the window
                 Helpers.SEND_EVENT('resize');
                 Helpers.SEND_EVENT('resize');
                 this._tabbar.updateWidth();
                 this._tabbar.updateWidth();
@@ -156,25 +188,25 @@ module INSPECTOR {
                 this.refresh();
                 this.refresh();
             }
             }
         }
         }
-        
+
         /**
         /**
          * If the given element has a position 'asbolute' or 'relative', 
          * If the given element has a position 'asbolute' or 'relative', 
          * returns the first parent of the given element that has a position 'relative' or 'absolute'.
          * returns the first parent of the given element that has a position 'relative' or 'absolute'.
          * If the given element has no position, returns the first parent
          * If the given element has no position, returns the first parent
          * 
          * 
          */
          */
-        private _getRelativeParent(elem:HTMLElement, lookForAbsoluteOrRelative?:boolean) : HTMLElement{
+        private _getRelativeParent(elem: HTMLElement, lookForAbsoluteOrRelative?: boolean): HTMLElement {
             // If the elem has no parent, returns himself
             // If the elem has no parent, returns himself
             if (!elem.parentElement) {
             if (!elem.parentElement) {
                 return elem;
                 return elem;
-            } 
+            }
             let computedStyle = Inspector.WINDOW.getComputedStyle(elem);
             let computedStyle = Inspector.WINDOW.getComputedStyle(elem);
             // looking for the first element absolute or relative
             // looking for the first element absolute or relative
             if (lookForAbsoluteOrRelative) {
             if (lookForAbsoluteOrRelative) {
                 // if found, return this one
                 // if found, return this one
                 if (computedStyle.position === "relative" || computedStyle.position === "absolute") {
                 if (computedStyle.position === "relative" || computedStyle.position === "absolute") {
                     return elem;
                     return elem;
-                }else {
+                } else {
                     // otherwise keep looking
                     // otherwise keep looking
                     return this._getRelativeParent(elem.parentElement, true);
                     return this._getRelativeParent(elem.parentElement, true);
                 }
                 }
@@ -186,30 +218,30 @@ module INSPECTOR {
                 } else {
                 } else {
                     // the elem has a position relative or absolute, look for the closest relative/absolute parent
                     // the elem has a position relative or absolute, look for the closest relative/absolute parent
                     return this._getRelativeParent(elem.parentElement, true);
                     return this._getRelativeParent(elem.parentElement, true);
-                }         
-            }   
+                }
+            }
         }
         }
-        
+
         /** Build the inspector panel in the given HTML element */
         /** Build the inspector panel in the given HTML element */
-        private _buildInspector(parent:HTMLElement) {            
+        private _buildInspector(parent: HTMLElement) {
             // tabbar
             // tabbar
-            this._tabbar = new TabBar(this);
+            this._tabbar = new TabBar(this, this._initialTab);
 
 
             // Top panel
             // Top panel
             this._topPanel = Helpers.CreateDiv('top-panel', parent);
             this._topPanel = Helpers.CreateDiv('top-panel', parent);
             // Add tabbar
             // Add tabbar
             this._topPanel.appendChild(this._tabbar.toHtml());
             this._topPanel.appendChild(this._tabbar.toHtml());
             this._tabbar.updateWidth();
             this._tabbar.updateWidth();
-            
+
             // Tab panel
             // Tab panel
             this._tabPanel = Helpers.CreateDiv('tab-panel-content', this._topPanel);
             this._tabPanel = Helpers.CreateDiv('tab-panel-content', this._topPanel);
-            
+
         }
         }
 
 
-        public get scene() : BABYLON.Scene {
+        public get scene(): BABYLON.Scene {
             return this._scene;
             return this._scene;
         }
         }
-        public get popupMode() : boolean {
+        public get popupMode(): boolean {
             return this._popupMode;
             return this._popupMode;
         }
         }
 
 
@@ -217,12 +249,12 @@ module INSPECTOR {
          * Filter the list of item present in the tree.
          * Filter the list of item present in the tree.
          * All item returned should have the given filter contained in the item id.
          * All item returned should have the given filter contained in the item id.
         */
         */
-        public filterItem(filter:string){
+        public filterItem(filter: string) {
             this._tabbar.getActiveTab().filter(filter);
             this._tabbar.getActiveTab().filter(filter);
         }
         }
-        
+
         /** Display the mesh tab on the given object */
         /** Display the mesh tab on the given object */
-        public displayObjectDetails(mesh:BABYLON.AbstractMesh) {
+        public displayObjectDetails(mesh: BABYLON.AbstractMesh) {
             this._tabbar.switchMeshTab(mesh);
             this._tabbar.switchMeshTab(mesh);
         }
         }
 
 
@@ -234,39 +266,40 @@ module INSPECTOR {
             // Get the active tab and its items
             // Get the active tab and its items
             let activeTab = this._tabbar.getActiveTab();
             let activeTab = this._tabbar.getActiveTab();
             activeTab.update();
             activeTab.update();
-            this._tabPanel.appendChild(activeTab.getPanel());            
+            this._tabPanel.appendChild(activeTab.getPanel());
             Helpers.SEND_EVENT('resize');
             Helpers.SEND_EVENT('resize');
-            
-        }        
-        
+
+        }
+
         /** Remove the inspector panel when it's built as a right panel:
         /** Remove the inspector panel when it's built as a right panel:
          * remove the right panel and remove the wrapper
          * remove the right panel and remove the wrapper
          */
          */
         public dispose() {
         public dispose() {
             if (!this._popupMode) {
             if (!this._popupMode) {
                 // Get canvas
                 // Get canvas
-                let canvas         = this._scene.getEngine().getRenderingCanvas(); 
+                let canvas = this._scene.getEngine().getRenderingCanvas();
 
 
                 // restore canvas style
                 // restore canvas style
                 for (let prop in this._canvasStyle) {
                 for (let prop in this._canvasStyle) {
                     canvas.style[prop] = this._canvasStyle[prop];
                     canvas.style[prop] = this._canvasStyle[prop];
                 }
                 }
                 // Get parent of the wrapper 
                 // Get parent of the wrapper 
-                let canvasParent   = canvas.parentElement.parentElement;  
+                let canvasParent = canvas.parentElement.parentElement;
+
                 canvasParent.insertBefore(canvas, this._c2diwrapper);
                 canvasParent.insertBefore(canvas, this._c2diwrapper);
                 // Remove wrapper
                 // Remove wrapper
                 Helpers.CleanDiv(this._c2diwrapper);
                 Helpers.CleanDiv(this._c2diwrapper);
-                this._c2diwrapper.remove();                   
+                this._c2diwrapper.remove();
                 // Send resize event to the window
                 // Send resize event to the window
-                Helpers.SEND_EVENT('resize');              
+                Helpers.SEND_EVENT('resize');
             }
             }
         }
         }
-        
+
         /** Open the inspector in a new popup
         /** Open the inspector in a new popup
          * Set 'firstTime' to true if there is no inspector created beforehands
          * Set 'firstTime' to true if there is no inspector created beforehands
          */
          */
-        public openPopup(firstTime?:boolean) {    
-            
+        public openPopup(firstTime?: boolean) {
+
             if (Helpers.IsBrowserEdge()) {
             if (Helpers.IsBrowserEdge()) {
                 console.warn('Inspector - Popup mode is disabled in Edge, as the popup DOM cannot be updated from the main window for security reasons');
                 console.warn('Inspector - Popup mode is disabled in Edge, as the popup DOM cannot be updated from the main window for security reasons');
             } else {
             } else {
@@ -275,16 +308,16 @@ module INSPECTOR {
                 popup.document.title = 'Babylon.js INSPECTOR';
                 popup.document.title = 'Babylon.js INSPECTOR';
                 // Get the inspector style      
                 // Get the inspector style      
                 let styles = Inspector.DOCUMENT.querySelectorAll('style');
                 let styles = Inspector.DOCUMENT.querySelectorAll('style');
-                for (let s = 0; s<styles.length; s++) {
-                    popup.document.body.appendChild(styles[s].cloneNode(true));              
-                } 
+                for (let s = 0; s < styles.length; s++) {
+                    popup.document.body.appendChild(styles[s].cloneNode(true));
+                }
                 let links = document.querySelectorAll('link');
                 let links = document.querySelectorAll('link');
-                for (let l = 0; l<links.length; l++) {
-                    let link  = popup.document.createElement("link");
-                    link.rel  = "stylesheet";
+                for (let l = 0; l < links.length; l++) {
+                    let link = popup.document.createElement("link");
+                    link.rel = "stylesheet";
                     link.href = (links[l] as HTMLLinkElement).href;
                     link.href = (links[l] as HTMLLinkElement).href;
-                    popup.document.head.appendChild(link);              
-                } 
+                    popup.document.head.appendChild(link);
+                }
                 // Dispose the right panel if existing
                 // Dispose the right panel if existing
                 if (!firstTime) {
                 if (!firstTime) {
                     this.dispose();
                     this.dispose();
@@ -295,21 +328,21 @@ module INSPECTOR {
                 Inspector.DOCUMENT = popup.document;
                 Inspector.DOCUMENT = popup.document;
                 Inspector.WINDOW = popup;
                 Inspector.WINDOW = popup;
                 // Build the inspector wrapper
                 // Build the inspector wrapper
-                this._c2diwrapper  = Helpers.CreateDiv('insp-wrapper', popup.document.body);
+                this._c2diwrapper = Helpers.CreateDiv('insp-wrapper', popup.document.body);
                 // add inspector     
                 // add inspector     
-                let inspector      = Helpers.CreateDiv('insp-right-panel', this._c2diwrapper);
+                let inspector = Helpers.CreateDiv('insp-right-panel', this._c2diwrapper);
                 inspector.classList.add('popupmode');
                 inspector.classList.add('popupmode');
                 // and build it in the popup  
                 // and build it in the popup  
-                this._buildInspector(inspector); 
+                this._buildInspector(inspector);
                 // Rebuild it
                 // Rebuild it
-                this.refresh(); 
+                this.refresh();
 
 
-                popup.addEventListener('resize', () => {                    
+                popup.addEventListener('resize', () => {
                     if (this._tabbar) {
                     if (this._tabbar) {
                         this._tabbar.updateWidth()
                         this._tabbar.updateWidth()
                     }
                     }
                 });
                 });
-            }             
+            }
         }
         }
     }
     }
 }
 }

+ 25 - 18
inspector/src/adapters/Adapter.ts

@@ -1,36 +1,36 @@
 module INSPECTOR {
 module INSPECTOR {
-    
+
     export interface IHighlight {
     export interface IHighlight {
-        highlight : (b:boolean) => void
+        highlight: (b: boolean) => void
     }
     }
 
 
     export abstract class Adapter implements IHighlight {
     export abstract class Adapter implements IHighlight {
-        
-        protected _obj      : any;
+
+        protected _obj: any;
         // a unique name for this adapter, to retrieve its own key in the local storage
         // a unique name for this adapter, to retrieve its own key in the local storage
         private static _name: string = BABYLON.Geometry.RandomId();
         private static _name: string = BABYLON.Geometry.RandomId();
-        
-        constructor(obj:any) {
+
+        constructor(obj: any) {
             this._obj = obj;
             this._obj = obj;
         }
         }
-        
+
 
 
         /** Returns the name displayed in the tree */
         /** Returns the name displayed in the tree */
-        public abstract id()           : string;
-        
+        public abstract id(): string;
+
         /** Returns the type of this object - displayed in the tree */
         /** Returns the type of this object - displayed in the tree */
-        public abstract type()         : string;
-        
+        public abstract type(): string;
+
         /** Returns the list of properties to be displayed for this adapter */
         /** Returns the list of properties to be displayed for this adapter */
         public abstract getProperties(): Array<PropertyLine>;
         public abstract getProperties(): Array<PropertyLine>;
-        
+
         /** Returns the actual object behind this adapter */
         /** Returns the actual object behind this adapter */
-        public get actualObject()      : any {
-            return this._obj; 
+        public get actualObject(): any {
+            return this._obj;
         }
         }
-        
+
         /** Returns true if the given object correspond to this  */
         /** Returns true if the given object correspond to this  */
-        public correspondsTo(obj:any) {
+        public correspondsTo(obj: any) {
             return obj === this._obj;
             return obj === this._obj;
         }
         }
 
 
@@ -39,10 +39,17 @@ module INSPECTOR {
             return Adapter._name;
             return Adapter._name;
         }
         }
 
 
+        /**
+         * Returns the actual object used for this adapter
+         */
+        public get object(): any {
+            return this._obj;
+        }
+
         /** Returns the list of tools available for this adapter */
         /** Returns the list of tools available for this adapter */
-        public abstract getTools() : Array<AbstractTreeTool>;
+        public abstract getTools(): Array<AbstractTreeTool>;
 
 
         /** Should be overriden in subclasses */
         /** Should be overriden in subclasses */
-        public highlight(b:boolean) {};
+        public highlight(b: boolean) { };
     }
     }
 }
 }

+ 55 - 0
inspector/src/adapters/CameraAdapter.ts

@@ -0,0 +1,55 @@
+module INSPECTOR {
+    
+    export class CameraAdapter 
+        extends Adapter 
+         implements ICameraPOV{
+        
+        constructor(obj:BABYLON.Camera) {
+            super(obj);
+        }
+        
+        /** Returns the name displayed in the tree */
+        public id() : string {
+            let str = '';
+            if (this._obj.name) {
+                str = this._obj.name;
+            } // otherwise nothing displayed        
+            return str;
+        }
+        
+        /** Returns the type of this object - displayed in the tree */
+        public type() : string{
+            return Helpers.GET_TYPE(this._obj);
+        }
+        
+        /** Returns the list of properties to be displayed for this adapter */
+        public getProperties() : Array<PropertyLine> {
+           let propertiesLines : Array<PropertyLine> = [];
+           let camToDisplay = [];
+           // The if is there to work with the min version of babylon
+            if (this._obj instanceof BABYLON.ArcRotateCamera) {
+                camToDisplay =  PROPERTIES['ArcRotateCamera'].properties;
+            } else if (this._obj instanceof BABYLON.FreeCamera) {
+                camToDisplay =  PROPERTIES['FreeCamera'].properties; 
+            }
+                
+            for (let dirty of camToDisplay) {
+                let infos = new Property(dirty, this._obj);
+                propertiesLines.push(new PropertyLine(infos));
+            }
+            return propertiesLines; 
+        }
+        
+        public getTools() : Array<AbstractTreeTool> {
+            let tools = [];
+            // tools.push(new Checkbox(this));
+            tools.push(new CameraPOV(this));
+            return tools;
+        }
+
+        public setPOV() {
+           (this._obj as BABYLON.Camera).getScene().activeCamera = this._obj;
+        }
+        
+    }
+}

+ 37 - 0
inspector/src/adapters/TextureAdapter.ts

@@ -0,0 +1,37 @@
+module INSPECTOR {
+
+    export class TextureAdapter
+        extends Adapter {
+
+        constructor(obj: BABYLON.BaseTexture) {
+            super(obj);
+        }
+
+        /** Returns the name displayed in the tree */
+        public id(): string {
+            let str = '';
+            if (this._obj.name) {
+                str = this._obj.name;
+            } // otherwise nothing displayed        
+            return str;
+        }
+
+        /** Returns the type of this object - displayed in the tree */
+        public type(): string {
+            return Helpers.GET_TYPE(this._obj);
+        }
+
+        /** Returns the list of properties to be displayed for this adapter */
+        public getProperties(): Array<PropertyLine> {
+            // Not used in this tab
+            return [];
+        }
+
+        public getTools(): Array<AbstractTreeTool> {
+            let tools = [];
+            // tools.push(new CameraPOV(this));
+            return tools;
+        }
+
+    }
+}

+ 179 - 131
inspector/src/properties.ts

@@ -1,74 +1,90 @@
 module INSPECTOR {
 module INSPECTOR {
-    
+
     export const PROPERTIES = {
     export const PROPERTIES = {
         /** Format the given object : 
         /** Format the given object : 
          * If a format function exists, returns the result of this function.
          * If a format function exists, returns the result of this function.
          * If this function doesn't exists, return the object type instead */
          * If this function doesn't exists, return the object type instead */
-        format : (obj:any) => {
-            let type = Helpers.GET_TYPE(obj) ||  'type_not_defined';
+        format: (obj: any) => {
+            let type = Helpers.GET_TYPE(obj) || 'type_not_defined';
             if (PROPERTIES[type] && PROPERTIES[type].format) {
             if (PROPERTIES[type] && PROPERTIES[type].format) {
                 return PROPERTIES[type].format(obj);
                 return PROPERTIES[type].format(obj);
             } else {
             } else {
                 return Helpers.GET_TYPE(obj);
                 return Helpers.GET_TYPE(obj);
             }
             }
         },
         },
-        'type_not_defined' : {
-            properties : [],
+        'type_not_defined': {
+            properties: [],
             format: () => ''
             format: () => ''
         },
         },
-        
-        'Vector2' : {
+
+        'Vector2': {
             type: BABYLON.Vector2,
             type: BABYLON.Vector2,
             properties: ['x', 'y'],
             properties: ['x', 'y'],
-            format: (vec : BABYLON.Vector2) => {return `x:${Helpers.Trunc(vec.x)}, y:${Helpers.Trunc(vec.y)}`;}
+            format: (vec: BABYLON.Vector2) => { return `x:${Helpers.Trunc(vec.x)}, y:${Helpers.Trunc(vec.y)}`; }
         },
         },
-        'Vector3' : {
+        'Vector3': {
             type: BABYLON.Vector3,
             type: BABYLON.Vector3,
             properties: ['x', 'y', 'z'],
             properties: ['x', 'y', 'z'],
-            format: (vec : BABYLON.Vector3) => {return `x:${Helpers.Trunc(vec.x)}, y:${Helpers.Trunc(vec.y)}, z:${Helpers.Trunc(vec.z)}`} 
+            format: (vec: BABYLON.Vector3) => { return `x:${Helpers.Trunc(vec.x)}, y:${Helpers.Trunc(vec.y)}, z:${Helpers.Trunc(vec.z)}` }
         },
         },
-        'Color3' : {
+        'Color3': {
             type: BABYLON.Color3,
             type: BABYLON.Color3,
-            properties : ['r', 'g', 'b'],
-            format: (color: BABYLON.Color3) => { return `R:${color.r}, G:${color.g}, B:${color.b}`}
+            properties: ['r', 'g', 'b'],
+            format: (color: BABYLON.Color3) => { return `R:${color.r}, G:${color.g}, B:${color.b}` }
         },
         },
-        'Quaternion' : {
+        'Quaternion': {
             type: BABYLON.Quaternion,
             type: BABYLON.Quaternion,
-            properties : ['x', 'y', 'z', 'w']
+            properties: ['x', 'y', 'z', 'w']
         },
         },
-        'Size' : {
+        'Size': {
             type: BABYLON.Size,
             type: BABYLON.Size,
-            properties :['width', 'height'],
-            format: (size:BABYLON.Size) => { return `Size - w:${Helpers.Trunc(size.width)}, h:${Helpers.Trunc(size.height)}`} 
+            properties: ['width', 'height'],
+            format: (size: BABYLON.Size) => { return `Size - w:${Helpers.Trunc(size.width)}, h:${Helpers.Trunc(size.height)}` }
         },
         },
-        'Texture' : {
+        'Texture': {
             type: BABYLON.Texture,
             type: BABYLON.Texture,
-            properties :[
-                'hasAlpha', 
-                'level', 
-                'name', 
-                'wrapU', 
-                'wrapV', 
-                'uScale', 
-                'vScale', 
-                'uAng', 
-                'vAng', 
-                'wAng', 
-                'uOffset', 
+            properties: [
+                'hasAlpha',
+                'level',
+                'name',
+                'wrapU',
+                'wrapV',
+                'uScale',
+                'vScale',
+                'uAng',
+                'vAng',
+                'wAng',
+                'uOffset',
                 'vOffset'
                 'vOffset'
             ],
             ],
-            format: (tex:BABYLON.Texture) => { return tex.name} 
+            format: (tex: BABYLON.Texture) => { return tex.name }
+        },
+        'MapTexture': {
+            type: BABYLON.MapTexture
+        },
+        'RenderTargetTexture': {
+            type: BABYLON.RenderTargetTexture
         },
         },
-        
-        'ArcRotateCamera' : {
+        'DynamicTexture': {
+            type: BABYLON.DynamicTexture
+        },
+        'BaseTexture': {
+            type: BABYLON.BaseTexture
+        },
+        'FontTexture': {
+            type: BABYLON.FontTexture
+        },
+
+        'ArcRotateCamera': {
             type: BABYLON.ArcRotateCamera,
             type: BABYLON.ArcRotateCamera,
-            properties : [
-                'alpha', 
-                'beta', 
+            properties: [
+                'position',
+                'alpha',
+                'beta',
                 'radius',
                 'radius',
                 'angularSensibilityX',
                 'angularSensibilityX',
                 'angularSensibilityY',
                 'angularSensibilityY',
-                'target', 
+                'target',
 
 
                 'lowerAlphaLimit',
                 'lowerAlphaLimit',
                 'lowerBetaLimit',
                 'lowerBetaLimit',
@@ -81,53 +97,85 @@ module INSPECTOR {
                 'wheelPrecision',
                 'wheelPrecision',
                 'allowUpsideDown',
                 'allowUpsideDown',
                 'checkCollisions'
                 'checkCollisions'
-            ]  
+            ]
+        },
+
+        'FreeCamera': {
+            type: BABYLON.FreeCamera,
+            properties: [
+                'position',
+                'rotation',
+                'rotationQuaternion',
+                'cameraDirection',
+                'cameraRotation',
+
+                'ellipsoid',
+                'applyGravity',
+                'angularSensibility',
+                'keysUp',
+                'keysDown',
+                'keysLeft',
+                'keysRight',
+                'checkCollisions',
+                'speed',
+                'lockedTarget',
+                'noRotationConstraint',
+                'fov',
+                'inertia',
+                'minZ', 'maxZ',
+                'layerMask',
+                'mode',
+                'orthoBottom',
+                'orthoTop',
+                'orthoLeft',
+                'orthoRight'
+            ]
         },
         },
-        
-        'Scene' : {
+
+        'Scene': {
             type: BABYLON.Scene,
             type: BABYLON.Scene,
-            properties:[
-                'actionManager', 
-                'activeCamera', 
-                'ambientColor', 
+            properties: [
+                'actionManager',
+                'activeCamera',
+                'ambientColor',
                 'clearColor',
                 'clearColor',
                 'forceWireframe',
                 'forceWireframe',
                 'forcePointsCloud',
                 'forcePointsCloud',
                 'forceShowBoundingBoxes',
                 'forceShowBoundingBoxes',
                 'useRightHandedSystem',
                 'useRightHandedSystem',
                 'hoverCursor',
                 'hoverCursor',
-                'cameraToUseForPointers', 
-                'fogEnabled', 
-                'fogColor', 
-                'fogDensity', 
-                'fogStart', 
-                'fogEnd', 
-                'shadowsEnabled', 
-                'lightsEnabled', 
+                'cameraToUseForPointers',
+                'fogEnabled',
+                'fogColor',
+                'fogDensity',
+                'fogStart',
+                'fogEnd',
+                'shadowsEnabled',
+                'lightsEnabled',
                 'collisionsEnabled',
                 'collisionsEnabled',
                 'gravity',
                 'gravity',
-                'meshUnderPointer', 
-                'pointerX', 
-                'pointerY', 
+                'meshUnderPointer',
+                'pointerX',
+                'pointerY',
                 'uid'
                 'uid'
-            ]  
+            ]
         },
         },
         'Mesh': {
         'Mesh': {
             type: BABYLON.Mesh,
             type: BABYLON.Mesh,
-            properties : [
-                'name', 
-                'position', 
-                'rotation', 
-                'rotationQuaternion', 
-                'absolutePosition', 
+            properties: [
+                'name',
+                'position',
+                'rotation',
+                'rotationQuaternion',
+                'absolutePosition',
                 'material',
                 'material',
-                'actionManager', 
-                'visibility', 
-                'isVisible', 
-                'isPickable', 
+                'actionManager',
+                'visibility',
+                'isVisible',
+                'isPickable',
                 'renderingGroupId',
                 'renderingGroupId',
-                'receiveShadows', 
-                'renderOutline', 
+                'receiveShadows',
+                'renderOutline',
                 'outlineColor',
                 'outlineColor',
                 'outlineWidth',
                 'outlineWidth',
                 'renderOverlay',
                 'renderOverlay',
@@ -137,102 +185,102 @@ module INSPECTOR {
                 'useVertexColors',
                 'useVertexColors',
                 'layerMask',
                 'layerMask',
                 'alwaysSelectAsActiveMesh',
                 'alwaysSelectAsActiveMesh',
-                'ellipsoid', 
-                'ellipsoidOffset', 
-                'edgesWidth', 
-                'edgesColor', 
+                'ellipsoid',
+                'ellipsoidOffset',
+                'edgesWidth',
+                'edgesColor',
                 'checkCollisions',
                 'checkCollisions',
                 'hasLODLevels'
                 'hasLODLevels'
             ],
             ],
-            format : (m:BABYLON.Mesh) : string => {return m.name;}
-        },        
-        'StandardMaterial' : {
+            format: (m: BABYLON.Mesh): string => { return m.name; }
+        },
+        'StandardMaterial': {
             type: BABYLON.StandardMaterial,
             type: BABYLON.StandardMaterial,
-            properties : [
-                'name', 
+            properties: [
+                'name',
                 'alpha',
                 'alpha',
-                'alphaMode', 
-                'wireframe', 
-                'isFrozen', 
+                'alphaMode',
+                'wireframe',
+                'isFrozen',
                 'zOffset',
                 'zOffset',
-                
-                'ambientColor', 
-                'emissiveColor', 
-                'diffuseColor', 
+
+                'ambientColor',
+                'emissiveColor',
+                'diffuseColor',
                 'specularColor',
                 'specularColor',
-                
-                'specularPower',       
-                'useAlphaFromDiffuseTexture', 
+
+                'specularPower',
+                'useAlphaFromDiffuseTexture',
                 'linkEmissiveWithDiffuse',
                 'linkEmissiveWithDiffuse',
                 'useSpecularOverAlpha',
                 'useSpecularOverAlpha',
-                
-                'diffuseFresnelParameters', 
-                'opacityFresnelParameters', 
-                'reflectionFresnelParameters', 
-                'refractionFresnelParameters', 
+
+                'diffuseFresnelParameters',
+                'opacityFresnelParameters',
+                'reflectionFresnelParameters',
+                'refractionFresnelParameters',
                 'emissiveFresnelParameters',
                 'emissiveFresnelParameters',
-                
-                'diffuseTexture', 
-                'emissiveTexture', 
-                'specularTexture', 
+
+                'diffuseTexture',
+                'emissiveTexture',
+                'specularTexture',
                 'ambientTexture',
                 'ambientTexture',
                 'bumpTexture',
                 'bumpTexture',
-                'lightMapTexture', 
-                'opacityTexture', 
+                'lightMapTexture',
+                'opacityTexture',
                 'reflectionTexture',
                 'reflectionTexture',
-                'refractionTexture'                
+                'refractionTexture'
             ],
             ],
-            format : (mat:BABYLON.StandardMaterial) : string => {return mat.name;}
+            format: (mat: BABYLON.StandardMaterial): string => { return mat.name; }
         },
         },
-        'PrimitiveAlignment':{
+        'PrimitiveAlignment': {
             type: BABYLON.PrimitiveAlignment,
             type: BABYLON.PrimitiveAlignment,
-            properties:['horizontal', 'vertical']
+            properties: ['horizontal', 'vertical']
         },
         },
-        'PrimitiveThickness':{
+        'PrimitiveThickness': {
             type: BABYLON.PrimitiveThickness,
             type: BABYLON.PrimitiveThickness,
-            properties:['topPixels', 'leftPixels', 'rightPixels', 'bottomPixels']
+            properties: ['topPixels', 'leftPixels', 'rightPixels', 'bottomPixels']
         },
         },
-        'BoundingInfo2D':{
+        'BoundingInfo2D': {
             type: BABYLON.BoundingInfo2D,
             type: BABYLON.BoundingInfo2D,
-            properties:['radius','center', 'extent']
+            properties: ['radius', 'center', 'extent']
         },
         },
-        'SolidColorBrush2D':{
+        'SolidColorBrush2D': {
             type: BABYLON.SolidColorBrush2D,
             type: BABYLON.SolidColorBrush2D,
-            properties:['color']
+            properties: ['color']
         },
         },
-        'GradientColorBrush2D':{
+        'GradientColorBrush2D': {
             type: BABYLON.GradientColorBrush2D,
             type: BABYLON.GradientColorBrush2D,
-            properties:['color1', 'color2', 'translation', 'rotation', 'scale']
+            properties: ['color1', 'color2', 'translation', 'rotation', 'scale']
         },
         },
-        'PBRMaterial' : {
+        'PBRMaterial': {
             type: BABYLON.PBRMaterial,
             type: BABYLON.PBRMaterial,
             properties: [
             properties: [
-                'name', 
-                'albedoColor', 
-                'albedoTexture', 
+                'name',
+                'albedoColor',
+                'albedoTexture',
 
 
-                'opacityTexture', 
-                'reflectionTexture', 
-                'emissiveTexture', 
-                'bumpTexture', 
-                'lightmapTexture', 
+                'opacityTexture',
+                'reflectionTexture',
+                'emissiveTexture',
+                'bumpTexture',
+                'lightmapTexture',
 
 
-                'opacityFresnelParameters', 
-                'emissiveFresnelParameters', 
+                'opacityFresnelParameters',
+                'emissiveFresnelParameters',
 
 
-                'linkEmissiveWithAlbedo', 
-                'useLightmapAsShadowmap', 
+                'linkEmissiveWithAlbedo',
+                'useLightmapAsShadowmap',
 
 
-                'useAlphaFromAlbedoTexture', 
-                'useSpecularOverAlpha', 
-                'useAutoMicroSurfaceFromReflectivityMap', 
-                'useLogarithmicDepth', 
+                'useAlphaFromAlbedoTexture',
+                'useSpecularOverAlpha',
+                'useAutoMicroSurfaceFromReflectivityMap',
+                'useLogarithmicDepth',
 
 
                 'reflectivityColor',
                 'reflectivityColor',
                 'reflectivityTexture',
                 'reflectivityTexture',
                 'reflectionTexture',
                 'reflectionTexture',
                 'reflectionColor',
                 'reflectionColor',
-                
+
                 'alpha',
                 'alpha',
                 'linkRefractionWithTransparency',
                 'linkRefractionWithTransparency',
                 'indexOfRefraction',
                 'indexOfRefraction',
@@ -250,7 +298,7 @@ module INSPECTOR {
                 'cameraColorCurves'
                 'cameraColorCurves'
             ]
             ]
         }
         }
-        
+
     }
     }
-    
+
 }
 }

+ 22 - 0
inspector/src/tabs/CameraTab.ts

@@ -0,0 +1,22 @@
+module INSPECTOR{
+    
+    export class CameraTab extends PropertyTab {
+                
+        constructor(tabbar:TabBar, inspector:Inspector) {
+            super(tabbar, 'Camera', inspector); 
+        }
+    /* Overrides super */
+        protected _getTree() : Array<TreeItem> {
+            let arr = [];
+                        
+            // get all cameras from the first scene
+            let instances = this._inspector.scene;
+            for (let camera of instances.cameras) {
+                arr.push(new TreeItem(this, new CameraAdapter(camera)));
+            }
+            return arr;
+        }
+
+    }
+    
+}

+ 49 - 85
inspector/src/tabs/ShaderTab.ts

@@ -2,80 +2,81 @@ module INSPECTOR {
 
 
     export class ShaderTab extends Tab {
     export class ShaderTab extends Tab {
 
 
-        private _inspector : Inspector;
-        
-        private _vertexPanel : HTMLElement;
-        private _fragmentPanel : HTMLElement;
+        private _inspector: Inspector;
 
 
-        constructor(tabbar:TabBar, insp:Inspector) {
-            super(tabbar, 'Shader');            
+        private _vertexPanel: HTMLElement;
+        private _fragmentPanel: HTMLElement;
+
+        constructor(tabbar: TabBar, insp: Inspector) {
+            super(tabbar, 'Shader');
             this._inspector = insp;
             this._inspector = insp;
 
 
             // Build the shaders panel : a div that will contains the shaders tree and both shaders panels
             // Build the shaders panel : a div that will contains the shaders tree and both shaders panels
-            this._panel         = Helpers.CreateDiv('tab-panel') as HTMLDivElement;
+            this._panel = Helpers.CreateDiv('tab-panel') as HTMLDivElement;
 
 
-            let shaderPanel     = Helpers.CreateDiv('shader-tree-panel') as HTMLDivElement;
-            this._vertexPanel   = Helpers.CreateDiv('shader-panel') as HTMLDivElement;
+            let shaderPanel = Helpers.CreateDiv('shader-tree-panel') as HTMLDivElement;
+            this._vertexPanel = Helpers.CreateDiv('shader-panel') as HTMLDivElement;
             this._fragmentPanel = Helpers.CreateDiv('shader-panel') as HTMLDivElement;
             this._fragmentPanel = Helpers.CreateDiv('shader-panel') as HTMLDivElement;
 
 
             this._panel.appendChild(shaderPanel);
             this._panel.appendChild(shaderPanel);
             this._panel.appendChild(this._vertexPanel);
             this._panel.appendChild(this._vertexPanel);
             this._panel.appendChild(this._fragmentPanel);
             this._panel.appendChild(this._fragmentPanel);
-            
+
             Helpers.LoadScript();
             Helpers.LoadScript();
-            
+
             Split([this._vertexPanel, this._fragmentPanel], {
             Split([this._vertexPanel, this._fragmentPanel], {
-                blockDrag : this._inspector.popupMode,
-                sizes:[50, 50],
-                direction:'vertical'}
-            );  
-            
+                blockDrag: this._inspector.popupMode,
+                sizes: [50, 50],
+                direction: 'vertical'
+            }
+            );
+
             let comboBox = Helpers.CreateElement('select', '', shaderPanel);
             let comboBox = Helpers.CreateElement('select', '', shaderPanel);
             comboBox.addEventListener('change', this._selectShader.bind(this));
             comboBox.addEventListener('change', this._selectShader.bind(this));
-            
+
             let option = Helpers.CreateElement('option', '', comboBox);
             let option = Helpers.CreateElement('option', '', comboBox);
             option.textContent = 'Select a shader';
             option.textContent = 'Select a shader';
             option.setAttribute('value', "");
             option.setAttribute('value', "");
             option.setAttribute('disabled', 'true');
             option.setAttribute('disabled', 'true');
-            option.setAttribute('selected', 'true');            
-            
+            option.setAttribute('selected', 'true');
+
             // Build shaders combobox
             // Build shaders combobox
             for (let mat of this._inspector.scene.materials) {
             for (let mat of this._inspector.scene.materials) {
                 if (mat instanceof BABYLON.ShaderMaterial) {
                 if (mat instanceof BABYLON.ShaderMaterial) {
                     let option = Helpers.CreateElement('option', '', comboBox);
                     let option = Helpers.CreateElement('option', '', comboBox);
                     option.setAttribute('value', mat.id);
                     option.setAttribute('value', mat.id);
                     option.textContent = `${mat.name} - ${mat.id}`;
                     option.textContent = `${mat.name} - ${mat.id}`;
-                    
+
                 }
                 }
             }
             }
 
 
         }
         }
-        
-        private _selectShader(event:Event) {
+
+        private _selectShader(event: Event) {
             let id = (event.target as HTMLSelectElement).value;
             let id = (event.target as HTMLSelectElement).value;
-            let mat = this._inspector.scene.getMaterialByID(id); 
-            
+            let mat = this._inspector.scene.getMaterialByID(id);
+
             // Clean shader panel
             // Clean shader panel
             Helpers.CleanDiv(this._vertexPanel);
             Helpers.CleanDiv(this._vertexPanel);
             // add the title - vertex shader
             // add the title - vertex shader
             let title = Helpers.CreateDiv('shader-panel-title', this._vertexPanel);
             let title = Helpers.CreateDiv('shader-panel-title', this._vertexPanel);
             title.textContent = 'Vertex shader';
             title.textContent = 'Vertex shader';
             // add code
             // add code
-            let code = Helpers.CreateElement('code', 'glsl',  Helpers.CreateElement('pre', '', this._vertexPanel));
+            let code = Helpers.CreateElement('code', 'glsl', Helpers.CreateElement('pre', '', this._vertexPanel));
             code.textContent = this._beautify(mat.getEffect().getVertexShaderSource());
             code.textContent = this._beautify(mat.getEffect().getVertexShaderSource());
-            
+
             Helpers.CleanDiv(this._fragmentPanel);
             Helpers.CleanDiv(this._fragmentPanel);
             // add the title - fragment shader
             // add the title - fragment shader
             title = Helpers.CreateDiv('shader-panel-title', this._fragmentPanel);
             title = Helpers.CreateDiv('shader-panel-title', this._fragmentPanel);
             title.textContent = 'Frgament shader';
             title.textContent = 'Frgament shader';
             // add code
             // add code
-            code = Helpers.CreateElement('code', 'glsl',  Helpers.CreateElement('pre', '', this._fragmentPanel));
-            code.textContent = this._beautify(mat.getEffect().getFragmentShaderSource());         
-                                    
+            code = Helpers.CreateElement('code', 'glsl', Helpers.CreateElement('pre', '', this._fragmentPanel));
+            code.textContent = this._beautify(mat.getEffect().getFragmentShaderSource());
+
             // Init the syntax highlighting
             // Init the syntax highlighting
             let styleInit = Helpers.CreateElement('script', '', Inspector.DOCUMENT.body);
             let styleInit = Helpers.CreateElement('script', '', Inspector.DOCUMENT.body);
             styleInit.textContent = 'hljs.initHighlighting();';
             styleInit.textContent = 'hljs.initHighlighting();';
-            
+
         }
         }
 
 
         /** Overrides super.dispose */
         /** Overrides super.dispose */
@@ -85,9 +86,9 @@ module INSPECTOR {
         /** Returns the position of the first { and the corresponding } */
         /** Returns the position of the first { and the corresponding } */
         private _getBracket(str) {
         private _getBracket(str) {
             let fb = str.indexOf('{');
             let fb = str.indexOf('{');
-            let arr = str.substr(fb+1).split('');
+            let arr = str.substr(fb + 1).split('');
             let counter = 1;
             let counter = 1;
-            let currentPosInString  = fb;
+            let currentPosInString = fb;
             let lastBracketIndex = 0;
             let lastBracketIndex = 0;
             for (let char of arr) {
             for (let char of arr) {
                 currentPosInString++;
                 currentPosInString++;
@@ -99,82 +100,45 @@ module INSPECTOR {
                 }
                 }
                 if (counter == 0) {
                 if (counter == 0) {
                     lastBracketIndex = currentPosInString;
                     lastBracketIndex = currentPosInString;
-                    break;         
+                    break;
                 }
                 }
             }
             }
 
 
-            return {firstBracket : fb, lastBracket:lastBracketIndex};
+            return { firstBracket: fb, lastBracket: lastBracketIndex };
         }
         }
 
 
         /** 
         /** 
          * Beautify the given string : correct indentation
          * Beautify the given string : correct indentation
          */
          */
-        private _beautify(glsl:string, level: number = 0) {
-            
+        private _beautify(glsl: string, level: number = 0) {
+
             // return condition : no brackets at all
             // return condition : no brackets at all
             let brackets = this._getBracket(glsl);
             let brackets = this._getBracket(glsl);
-            let firstBracket       = brackets.firstBracket;
-            let lastBracket        = brackets.lastBracket;
+            let firstBracket = brackets.firstBracket;
+            let lastBracket = brackets.lastBracket;
 
 
             let spaces = "";
             let spaces = "";
-            for (let i=0 ;i<level; i++) {
+            for (let i = 0; i < level; i++) {
                 spaces += "    "; // 4 spaces
                 spaces += "    "; // 4 spaces
             }
             }
             // If no brackets, return the indented string
             // If no brackets, return the indented string
             if (firstBracket == -1) {
             if (firstBracket == -1) {
-                glsl = spaces+glsl; // indent first line
+                glsl = spaces + glsl; // indent first line
                 glsl = glsl
                 glsl = glsl
-                    .replace(/;./g, x => '\n'+x.substr(1)) // new line after ;  except the last one
-                    glsl = glsl.replace(/=/g, " = ") // space around =
-                    glsl = glsl.replace(/\n/g, "\n"+spaces); // indentation
+                    .replace(/;./g, x => '\n' + x.substr(1)) // new line after ;  except the last one
+                glsl = glsl.replace(/=/g, " = ") // space around =
+                glsl = glsl.replace(/\n/g, "\n" + spaces); // indentation
                 return glsl;
                 return glsl;
             } else {
             } else {
                 // if brackets, beautify the inside                                 
                 // if brackets, beautify the inside                                 
                 // let insideWithBrackets = glsl.substr(firstBracket, lastBracket-firstBracket+1);
                 // let insideWithBrackets = glsl.substr(firstBracket, lastBracket-firstBracket+1);
-                let left   = glsl.substr(0, firstBracket);
-                let right  = glsl.substr(lastBracket+1, glsl.length); 
-                let inside = glsl.substr(firstBracket+1, lastBracket-firstBracket-1);
-                inside     = this._beautify(inside, level+1);
-                return this._beautify(left, level)+'{\n'+inside+'\n'+spaces+'}\n'+this._beautify(right, level);
+                let left = glsl.substr(0, firstBracket);
+                let right = glsl.substr(lastBracket + 1, glsl.length);
+                let inside = glsl.substr(firstBracket + 1, lastBracket - firstBracket - 1);
+                inside = this._beautify(inside, level + 1);
+                return this._beautify(left, level) + '{\n' + inside + '\n' + spaces + '}\n' + this._beautify(right, level);
 
 
             }
             }
-
-                
-                // // Replace bracket with @1 and @2 with correct indentation
-                // let newInside          = "@1\n\t" + inside + "\n@2";
-                // newInside              = newInside.replace(/;\n/g, ";\n\t");
-                
-                // glsl                   = glsl.replace(insideWithBrackets, newInside);
-
-                // firstBracket       = glsl.indexOf('{');
-                // lastBracket        = glsl.lastIndexOf('}');
-
-            // }
-
-            // console.log(glsl);
-
-            // let regex = /(\{(?:\{??[^\{]*?}))+/gmi;
-
-            // let tmp = glsl;
-
-            // let m;
-            // while ((m = regex.exec(tmp)) !== null) {
-            //     // This is necessary to avoid infinite loops with zero-width matches
-            //     if (m.index === regex.lastIndex) {
-            //         regex.lastIndex++;
-            //     }                
-            //     // The result can be accessed through the `m`-variable.
-            //     m.forEach((match, groupIndex) => {
-            //         // Remove the first and the last bracket only
-            //         let matchWithoutBrackets = match.replace(/{/, "").replace(/}/, "");
-            //         // Indent the content inside brackets with tabs
-            //         glsl = glsl.replace(match, `{\n\t${matchWithoutBrackets}\n}\n`);
-            //         // removes the match from tmp
-            //         tmp = tmp.replace(match, "");
-            //         // and continue
-            //     });
-            // }
-            // return 
         }
         }
     }
     }
 
 

+ 42 - 31
inspector/src/tabs/Tab.ts

@@ -1,70 +1,81 @@
-module INSPECTOR{
-    
+module INSPECTOR {
+
     export abstract class Tab extends BasicElement {
     export abstract class Tab extends BasicElement {
-        protected _tabbar  : TabBar;
+        protected _tabbar: TabBar;
         // The tab name displayed in the tabbar
         // The tab name displayed in the tabbar
-        public name        : string;        
+        public name: string;
         protected _isActive: boolean = false;
         protected _isActive: boolean = false;
-        
+
         // The whole panel corresponding to this tab. It's what is displayed when the tab is activacted
         // The whole panel corresponding to this tab. It's what is displayed when the tab is activacted
-        protected _panel : HTMLDivElement;
-        
-        constructor(tabbar:TabBar, name:string) {
-            super();      
-            this._tabbar = tabbar;      
-            this.name   = name;
+        protected _panel: HTMLDivElement;
+
+        constructor(tabbar: TabBar, name: string) {
+            super();
+            this._tabbar = tabbar;
+            this.name = name;
             this._build();
             this._build();
         }
         }
-        
+
         /** True if the tab is active, false otherwise */
         /** True if the tab is active, false otherwise */
-        public isActive() : boolean {
+        public isActive(): boolean {
             return this._isActive;
             return this._isActive;
         }
         }
-        
-        protected _build() {            
-            this._div.className = 'tab';  
-            this._div.textContent = this.name;     
-            
+
+        protected _build() {
+            this._div.className = 'tab';
+            this._div.textContent = this.name;
+
             this._div.addEventListener('click', (evt) => {
             this._div.addEventListener('click', (evt) => {
                 // Set this tab as active
                 // Set this tab as active
                 this._tabbar.switchTab(this);
                 this._tabbar.switchTab(this);
             });
             });
         }
         }
-        
+
         /** Set this tab as active or not, depending on the current state */
         /** Set this tab as active or not, depending on the current state */
-        public active(b:boolean) {
-            if (b) {                
+        public active(b: boolean) {
+            if (b) {
                 this._div.classList.add('active');
                 this._div.classList.add('active');
             } else {
             } else {
                 this._div.classList.remove('active');
                 this._div.classList.remove('active');
             }
             }
             this._isActive = b;
             this._isActive = b;
         }
         }
-        
+
         public update() {
         public update() {
             // Nothing for the moment
             // Nothing for the moment
         }
         }
-        
-        /** Creates the tab panel for this tab. */   
-        public getPanel() : HTMLElement {
+
+        /** Creates the tab panel for this tab. */
+        public getPanel(): HTMLElement {
             return this._panel;
             return this._panel;
         }
         }
-        
+
         /** Add this in the propertytab with the searchbar */
         /** Add this in the propertytab with the searchbar */
-        public filter(str:string) {};
+        public filter(str: string) { };
 
 
         /** Dispose properly this tab */
         /** Dispose properly this tab */
         public abstract dispose();
         public abstract dispose();
 
 
+        /** Select an item in the tree */
+        public select(item: TreeItem) {
+            // To define in subclasses if needed 
+        }
+
+
+        /** Highlight the given node, and downplay all others */
+        public highlightNode(item?: TreeItem) {
+            // To define in subclasses if needed
+        }
+
         /** 
         /** 
          * Returns the total width in pixel of this tab, 0 by default
          * Returns the total width in pixel of this tab, 0 by default
         */
         */
-        public getPixelWidth() : number {
+        public getPixelWidth(): number {
             let style = Inspector.WINDOW.getComputedStyle(this._div);
             let style = Inspector.WINDOW.getComputedStyle(this._div);
-            let left = parseFloat(style.marginLeft.substr(0,style.marginLeft.length-2)) ||0;
-            let right = parseFloat(style.marginRight.substr(0,style.marginRight.length-2)) ||0;
+            let left = parseFloat(style.marginLeft.substr(0, style.marginLeft.length - 2)) || 0;
+            let right = parseFloat(style.marginRight.substr(0, style.marginRight.length - 2)) || 0;
             return (this._div.clientWidth || 0) + left + right;
             return (this._div.clientWidth || 0) + left + right;
         }
         }
     }
     }
-    
+
 }
 }

+ 44 - 35
inspector/src/tabs/TabBar.ts

@@ -4,30 +4,31 @@ module INSPECTOR {
      * The default active tab is the first one of the list.
      * The default active tab is the first one of the list.
      */
      */
     export class TabBar extends BasicElement {
     export class TabBar extends BasicElement {
-        
+
         // The list of available tabs
         // The list of available tabs
-        private _tabs         : Array<Tab> = [];
-        private _inspector    : Inspector;
+        private _tabs: Array<Tab> = [];
+        private _inspector: Inspector;
         /** The tab displaying all meshes */
         /** The tab displaying all meshes */
-        private _meshTab      : MeshTab;
+        private _meshTab: MeshTab;
         /** The toolbar */
         /** The toolbar */
-        private _toolBar      : Toolbar;
+        private _toolBar: Toolbar;
         /** The icon displayed at the end of the toolbar displaying a combo box of tabs not displayed */
         /** The icon displayed at the end of the toolbar displaying a combo box of tabs not displayed */
-        private _moreTabsIcon : HTMLElement;
+        private _moreTabsIcon: HTMLElement;
         /** The panel displayed when the 'more-tab' icon is selected */
         /** The panel displayed when the 'more-tab' icon is selected */
         private _moreTabsPanel: HTMLElement;
         private _moreTabsPanel: HTMLElement;
         /** The list of tab displayed by clicking on the remainingIcon */
         /** The list of tab displayed by clicking on the remainingIcon */
         private _invisibleTabs: Array<Tab> = [];
         private _invisibleTabs: Array<Tab> = [];
         /** The list of tabs visible, displayed in the tab bar */
         /** The list of tabs visible, displayed in the tab bar */
-        private _visibleTabs  : Array<Tab> = [];
-                
-        constructor(inspector:Inspector) {
+        private _visibleTabs: Array<Tab> = [];
+
+        constructor(inspector: Inspector, initialTab?: number) {
             super();
             super();
             this._inspector = inspector;
             this._inspector = inspector;
             this._tabs.push(new SceneTab(this, this._inspector));
             this._tabs.push(new SceneTab(this, this._inspector));
             this._tabs.push(new ConsoleTab(this, this._inspector));
             this._tabs.push(new ConsoleTab(this, this._inspector));
             this._tabs.push(new StatsTab(this, this._inspector));
             this._tabs.push(new StatsTab(this, this._inspector));
-            this._meshTab = new MeshTab(this, this._inspector); 
+            this._meshTab = new MeshTab(this, this._inspector);
+            this._tabs.push(new TextureTab(this, this._inspector));
             this._tabs.push(this._meshTab);
             this._tabs.push(this._meshTab);
             this._tabs.push(new ShaderTab(this, this._inspector));
             this._tabs.push(new ShaderTab(this, this._inspector));
             this._tabs.push(new LightTab(this, this._inspector));
             this._tabs.push(new LightTab(this, this._inspector));
@@ -37,24 +38,32 @@ module INSPECTOR {
             }
             }
             this._tabs.push(new MaterialTab(this, this._inspector));
             this._tabs.push(new MaterialTab(this, this._inspector));
 
 
+            this._tabs.push(new CameraTab(this, this._inspector));
+
             this._toolBar = new Toolbar(this._inspector);
             this._toolBar = new Toolbar(this._inspector);
 
 
             this._build();
             this._build();
-            // Active the first tab
-            this._tabs[0].active(true); 
+
+            //Check initialTab is defined and between tabs bounds
+            if (!initialTab || initialTab < 0 || initialTab >= this._tabs.length) {
+                initialTab = 0;
+                console.warn('');
+            }
+
+            this._tabs[initialTab].active(true);
 
 
             // set all tab as visible
             // set all tab as visible
             for (let tab of this._tabs) {
             for (let tab of this._tabs) {
                 this._visibleTabs.push(tab);
                 this._visibleTabs.push(tab);
             }
             }
         }
         }
-        
+
         // No update
         // No update
-        public update() {}
-        
-        protected _build() {            
+        public update() { }
+
+        protected _build() {
             this._div.className = 'tabbar';
             this._div.className = 'tabbar';
-            
+
             this._div.appendChild(this._toolBar.toHtml());
             this._div.appendChild(this._toolBar.toHtml());
             for (let tab of this._tabs) {
             for (let tab of this._tabs) {
                 this._div.appendChild(tab.toHtml());
                 this._div.appendChild(tab.toHtml());
@@ -62,7 +71,7 @@ module INSPECTOR {
 
 
 
 
             this._moreTabsIcon = Helpers.CreateElement('i', 'fa fa-angle-double-right more-tabs');
             this._moreTabsIcon = Helpers.CreateElement('i', 'fa fa-angle-double-right more-tabs');
-         
+
             this._moreTabsPanel = Helpers.CreateDiv('more-tabs-panel');
             this._moreTabsPanel = Helpers.CreateDiv('more-tabs-panel');
 
 
             this._moreTabsIcon.addEventListener('click', () => {
             this._moreTabsIcon.addEventListener('click', () => {
@@ -72,7 +81,7 @@ module INSPECTOR {
                 } else {
                 } else {
                     // Attach more-tabs-panel if not attached yet
                     // Attach more-tabs-panel if not attached yet
                     let topPanel = this._div.parentNode as HTMLElement;
                     let topPanel = this._div.parentNode as HTMLElement;
-                    if (! topPanel.contains(this._moreTabsPanel)) {
+                    if (!topPanel.contains(this._moreTabsPanel)) {
                         topPanel.appendChild(this._moreTabsPanel);
                         topPanel.appendChild(this._moreTabsPanel);
                     }
                     }
                     // Clean the 'more-tabs-panel'
                     // Clean the 'more-tabs-panel'
@@ -80,7 +89,7 @@ module INSPECTOR {
                     // Add each invisible tabs to this panel
                     // Add each invisible tabs to this panel
                     for (let tab of this._invisibleTabs) {
                     for (let tab of this._invisibleTabs) {
                         this._addInvisibleTabToPanel(tab);
                         this._addInvisibleTabToPanel(tab);
-                    }        
+                    }
                     // And display it
                     // And display it
                     this._moreTabsPanel.style.display = 'flex';
                     this._moreTabsPanel.style.display = 'flex';
                 }
                 }
@@ -91,7 +100,7 @@ module INSPECTOR {
          * Add a tab to the 'more-tabs' panel, displayed by clicking on the 
          * Add a tab to the 'more-tabs' panel, displayed by clicking on the 
          * 'more-tabs' icon
          * 'more-tabs' icon
          */
          */
-        private _addInvisibleTabToPanel(tab:Tab) {
+        private _addInvisibleTabToPanel(tab: Tab) {
             let div = Helpers.CreateDiv('invisible-tab', this._moreTabsPanel);
             let div = Helpers.CreateDiv('invisible-tab', this._moreTabsPanel);
             div.textContent = tab.name;
             div.textContent = tab.name;
             div.addEventListener('click', () => {
             div.addEventListener('click', () => {
@@ -99,9 +108,9 @@ module INSPECTOR {
                 this.switchTab(tab);
                 this.switchTab(tab);
             });
             });
         }
         }
-        
+
         /** Dispose the current tab, set the given tab as active, and refresh the treeview */
         /** Dispose the current tab, set the given tab as active, and refresh the treeview */
-        public switchTab(tab:Tab) {
+        public switchTab(tab: Tab) {
             // Dispose the active tab
             // Dispose the active tab
             this.getActiveTab().dispose();
             this.getActiveTab().dispose();
 
 
@@ -111,24 +120,24 @@ module INSPECTOR {
             }
             }
             // activate the given tab
             // activate the given tab
             tab.active(true);
             tab.active(true);
-            
+
             // Refresh the inspector
             // Refresh the inspector
             this._inspector.refresh();
             this._inspector.refresh();
         }
         }
-        
+
         /** Display the mesh tab.
         /** Display the mesh tab.
          * If a parameter is given, the given mesh details are displayed
          * If a parameter is given, the given mesh details are displayed
          */
          */
-        public switchMeshTab(mesh?:BABYLON.AbstractMesh) {
+        public switchMeshTab(mesh?: BABYLON.AbstractMesh) {
             this.switchTab(this._meshTab);
             this.switchTab(this._meshTab);
             if (mesh) {
             if (mesh) {
                 let item = this._meshTab.getItemFor(mesh);
                 let item = this._meshTab.getItemFor(mesh);
                 this._meshTab.select(item);
                 this._meshTab.select(item);
             }
             }
         }
         }
-        
+
         /** Returns the active tab */
         /** Returns the active tab */
-        public getActiveTab() : Tab {
+        public getActiveTab(): Tab {
             for (let tab of this._tabs) {
             for (let tab of this._tabs) {
                 if (tab.isActive()) {
                 if (tab.isActive()) {
                     return tab;
                     return tab;
@@ -136,7 +145,7 @@ module INSPECTOR {
             }
             }
         }
         }
 
 
-        public get inspector() : Inspector {
+        public get inspector(): Inspector {
             return this._inspector;
             return this._inspector;
         }
         }
 
 
@@ -144,7 +153,7 @@ module INSPECTOR {
          * Returns the total width in pixel of the tabbar, 
          * Returns the total width in pixel of the tabbar, 
          * that corresponds to the sum of the width of each visible tab + toolbar width
          * that corresponds to the sum of the width of each visible tab + toolbar width
         */
         */
-        public getPixelWidth() : number {
+        public getPixelWidth(): number {
             let sum = 0;
             let sum = 0;
             for (let tab of this._visibleTabs) {
             for (let tab of this._visibleTabs) {
                 sum += tab.getPixelWidth();
                 sum += tab.getPixelWidth();
@@ -162,7 +171,7 @@ module INSPECTOR {
         public updateWidth() {
         public updateWidth() {
             let parentSize = this._div.parentElement.clientWidth;
             let parentSize = this._div.parentElement.clientWidth;
             let lastTabWidth = 75;
             let lastTabWidth = 75;
-            let currentSize = this.getPixelWidth(); 
+            let currentSize = this.getPixelWidth();
 
 
             // Check if a tab should be removed : if the tab bar width is greater than
             // Check if a tab should be removed : if the tab bar width is greater than
             // its parent width
             // its parent width
@@ -173,7 +182,7 @@ module INSPECTOR {
                 this._invisibleTabs.push(tab);
                 this._invisibleTabs.push(tab);
                 // and removes it from the DOM
                 // and removes it from the DOM
                 this._div.removeChild(tab.toHtml());
                 this._div.removeChild(tab.toHtml());
-                currentSize = this.getPixelWidth() + lastTabWidth;                
+                currentSize = this.getPixelWidth() + lastTabWidth;
             }
             }
 
 
             // Check if a tab can be added to the tab bar : if the tab bar width
             // Check if a tab can be added to the tab bar : if the tab bar width
@@ -184,15 +193,15 @@ module INSPECTOR {
                     this._div.appendChild(lastTab.toHtml());
                     this._div.appendChild(lastTab.toHtml());
                     this._visibleTabs.push(lastTab);
                     this._visibleTabs.push(lastTab);
                     // Update more-tab icon in last position if needed
                     // Update more-tab icon in last position if needed
-                     if (this._div.contains(this._moreTabsIcon)) {
+                    if (this._div.contains(this._moreTabsIcon)) {
                         this._div.removeChild(this._moreTabsIcon);
                         this._div.removeChild(this._moreTabsIcon);
-                     }
+                    }
                 }
                 }
             }
             }
             if (this._invisibleTabs.length > 0 && !this._div.contains(this._moreTabsIcon)) {
             if (this._invisibleTabs.length > 0 && !this._div.contains(this._moreTabsIcon)) {
                 this._div.appendChild(this._moreTabsIcon);
                 this._div.appendChild(this._moreTabsIcon);
             }
             }
         }
         }
-        
+
     }
     }
 }
 }

+ 143 - 0
inspector/src/tabs/TextureTab.ts

@@ -0,0 +1,143 @@
+module INSPECTOR {
+
+    export class TextureTab extends Tab {
+
+        private _inspector: Inspector;
+        /** The panel containing a list of items */
+        protected _treePanel: HTMLElement;
+        protected _treeItems: Array<TreeItem> = [];
+
+        /* Panel containing the texture image */
+        private _imagePanel: HTMLElement;
+
+        constructor(tabbar: TabBar, inspector: Inspector) {
+            super(tabbar, 'Textures');
+            this._inspector = inspector;
+
+            // Build the properties panel : a div that will contains the tree and the detail panel
+            this._panel = Helpers.CreateDiv('tab-panel') as HTMLDivElement;
+
+            // Build the treepanel
+            this._treePanel = Helpers.CreateDiv('insp-tree', this._panel);
+
+            this._imagePanel = Helpers.CreateDiv('image-panel', this._panel) as HTMLDivElement;
+
+            Split([this._treePanel, this._imagePanel], {
+                blockDrag: this._inspector.popupMode,
+                direction: 'vertical'
+            });
+
+            this.update();
+        }
+
+        public dispose() {
+            // Nothing to dispose
+        }
+
+        public update(_items?: Array<TreeItem>) {
+
+            let items;
+            if (_items) {
+                items = _items;
+            } else {
+                // Rebuild the tree
+                this._treeItems = this._getTree();
+                items = this._treeItems;
+            }
+            // Clean the tree
+            Helpers.CleanDiv(this._treePanel);
+            Helpers.CleanDiv(this._imagePanel);
+
+            // Sort items alphabetically
+            items.sort((item1, item2) => {
+                return item1.compareTo(item2);
+            });
+
+            // Display items
+            for (let item of items) {
+                this._treePanel.appendChild(item.toHtml());
+            }
+        }
+
+        /* Overrides super */
+        private _getTree(): Array<TreeItem> {
+            let arr = [];
+
+            // get all cameras from the first scene
+            let instances = this._inspector.scene;
+            for (let tex of instances.textures) {
+                arr.push(new TreeItem(this, new TextureAdapter(tex)));
+            }
+            return arr;
+        }
+
+        /** Display the details of the given item */
+        public displayDetails(item: TreeItem) {
+            // Remove active state on all items
+            this.activateNode(item);
+            Helpers.CleanDiv(this._imagePanel);
+            // Get the texture object
+            let texture = item.adapter.object;
+
+            let img = Helpers.CreateElement('img', 'texture-image', this._imagePanel) as HTMLImageElement;
+
+            if (texture instanceof BABYLON.MapTexture) {
+                // instance of Map texture
+                texture.bindTextureForPosSize(new BABYLON.Vector2(0, 0), new BABYLON.Size(texture.getSize().width, texture.getSize().height), false);
+                BABYLON.Tools.DumpFramebuffer(texture.getSize().width, texture.getSize().height, this._inspector.scene.getEngine(), (data) => img.src = data);
+                texture.unbindTexture();
+
+            }
+            else if (texture instanceof BABYLON.RenderTargetTexture) {
+                // RenderTarget textures
+                BABYLON.Tools.CreateScreenshotUsingRenderTarget(this._inspector.scene.getEngine(), texture.activeCamera, { precision: 1 }, (data) => img.src = data);
+
+            } else if (texture.url) {
+                // If an url is present, the texture is an image
+                img.src = texture.url;
+
+            } else if (texture['_canvas']) {
+                // Dynamic texture
+                let base64Image = texture['_canvas'].toDataURL("image/png");
+                img.src = base64Image;
+
+            }
+
+
+        }
+
+        /** Select an item in the tree */
+        public select(item: TreeItem) {
+            // Remove the node highlight
+            this.highlightNode();
+            // Active the node
+            this.activateNode(item);
+            // Display its details
+            this.displayDetails(item);
+        }
+
+        /** Set the given item as active in the tree */
+        public activateNode(item: TreeItem) {
+            if (this._treeItems) {
+                for (let node of this._treeItems) {
+                    node.active(false);
+                }
+            }
+            item.active(true);
+        }
+
+        /** Highlight the given node, and downplay all others */
+        public highlightNode(item?: TreeItem) {
+            if (this._treeItems) {
+                for (let node of this._treeItems) {
+                    node.highlight(false);
+                }
+            }
+            if (item) {
+                item.highlight(true);
+            }
+        }
+
+    }
+
+}

+ 49 - 42
inspector/src/tree/TreeItem.ts

@@ -1,50 +1,57 @@
- module INSPECTOR {
-     
-    export class TreeItem extends BasicElement{
-    
+module INSPECTOR {
+
+    export class TreeItem extends BasicElement {
+
         // Reference to the tab
         // Reference to the tab
-        private _tab        : PropertyTab;
+        private _tab: Tab;
         // The object this item is linked to (should be a primitive or a canvas) TODO should be superclass of all primitives
         // The object this item is linked to (should be a primitive or a canvas) TODO should be superclass of all primitives
-        private _adapter    : Adapter;
-        private _tools      : Array<AbstractTreeTool>;
-        public children     : Array<TreeItem> = [];
+        private _adapter: Adapter;
+        private _tools: Array<AbstractTreeTool>;
+        public children: Array<TreeItem> = [];
         // Div element that contains all children of this node.
         // Div element that contains all children of this node.
-        private _lineContent: HTMLElement;  
+        private _lineContent: HTMLElement;
 
 
-        constructor(tab:PropertyTab, obj:Adapter ) {
+        constructor(tab: Tab, obj: Adapter) {
             super();
             super();
             this._tab = tab;
             this._tab = tab;
             this._adapter = obj;
             this._adapter = obj;
-            
+
             this._tools = this._adapter.getTools();
             this._tools = this._adapter.getTools();
-            
+
             this._build();
             this._build();
-            
+
         }
         }
 
 
         /** Returns the item ID == its adapter ID */
         /** Returns the item ID == its adapter ID */
-        public get id() : string {
+        public get id(): string {
             return this._adapter.id();
             return this._adapter.id();
         }
         }
 
 
         /** Add the given item as a child of this one */
         /** Add the given item as a child of this one */
-        public add(child:TreeItem) {
+        public add(child: TreeItem) {
             this.children.push(child);
             this.children.push(child);
             this.update();
             this.update();
         }
         }
 
 
         /**
         /**
+         * Returns the original adapter
+         */
+        public get adapter(): Adapter {
+            return this._adapter;
+        }
+
+        /**
          * Function used to compare this item to another tree item.
          * Function used to compare this item to another tree item.
          * Returns the alphabetical sort of the adapter ID
          * Returns the alphabetical sort of the adapter ID
          */
          */
-        public compareTo(item:TreeItem) : number {
+        public compareTo(item: TreeItem): number {
             let str1 = this.id;
             let str1 = this.id;
             let str2 = item.id;
             let str2 = item.id;
-            return str1.localeCompare(str2, [], {numeric:true});
+            return str1.localeCompare(str2, [], { numeric: true });
         }
         }
-        
+
         /** Returns true if the given obj correspond to the adapter linked to this tree item */
         /** Returns true if the given obj correspond to the adapter linked to this tree item */
-        public correspondsTo(obj:any) : boolean {
+        public correspondsTo(obj: any): boolean {
             return this._adapter.correspondsTo(obj);
             return this._adapter.correspondsTo(obj);
         }
         }
 
 
@@ -70,30 +77,30 @@
                 this._div.classList.remove('folded');
                 this._div.classList.remove('folded');
             }
             }
         }
         }
-        
+
         /** Build the HTML of this item */
         /** Build the HTML of this item */
         protected _build() {
         protected _build() {
-            this._div.className = 'line'; 
-            
-            
-            for (let tool of this._tools) { 
+            this._div.className = 'line';
+
+
+            for (let tool of this._tools) {
                 this._div.appendChild(tool.toHtml());
                 this._div.appendChild(tool.toHtml());
             }
             }
-            
-            
+
+
             // Id
             // Id
-            let text = Inspector.DOCUMENT.createElement('span');        
+            let text = Inspector.DOCUMENT.createElement('span');
             text.textContent = this._adapter.id();
             text.textContent = this._adapter.id();
             this._div.appendChild(text);
             this._div.appendChild(text);
-            
+
             // Type
             // Type
-            let type = Inspector.DOCUMENT.createElement('span'); 
+            let type = Inspector.DOCUMENT.createElement('span');
             type.className = 'property-type';
             type.className = 'property-type';
             if (this._adapter.type() !== 'type_not_defined') {
             if (this._adapter.type() !== 'type_not_defined') {
-                type.textContent = ' - '+this._adapter.type();
-            } 
+                type.textContent = ' - ' + this._adapter.type();
+            }
             this._div.appendChild(type);
             this._div.appendChild(type);
-            
+
             this._lineContent = Helpers.CreateDiv('line-content', this._div);
             this._lineContent = Helpers.CreateDiv('line-content', this._div);
 
 
             this._addEvent();
             this._addEvent();
@@ -102,10 +109,10 @@
         /**
         /**
          * Returns one HTML element (.details) containing all  details of this primitive
          * Returns one HTML element (.details) containing all  details of this primitive
          */
          */
-        public getDetails() : Array<PropertyLine> {
+        public getDetails(): Array<PropertyLine> {
             return this._adapter.getProperties();
             return this._adapter.getProperties();
         }
         }
-        
+
         public update() {
         public update() {
             // Clean division holding all children
             // Clean division holding all children
             Helpers.CleanDiv(this._lineContent);
             Helpers.CleanDiv(this._lineContent);
@@ -122,7 +129,7 @@
             }
             }
             this.fold();
             this.fold();
         }
         }
-        
+
         /**
         /**
          * Add an event listener on the item : 
          * Add an event listener on the item : 
          * - one click display details
          * - one click display details
@@ -133,10 +140,10 @@
                 this._tab.select(this);
                 this._tab.select(this);
                 // Fold/unfold the tree
                 // Fold/unfold the tree
                 if (this._isFolded()) {
                 if (this._isFolded()) {
-                    this.unfold();        
+                    this.unfold();
                 } else {
                 } else {
                     this.fold();
                     this.fold();
-                }                   
+                }
                 e.stopPropagation();
                 e.stopPropagation();
             });
             });
 
 
@@ -152,7 +159,7 @@
         }
         }
 
 
         /** Highlight or downplay this node */
         /** Highlight or downplay this node */
-        public highlight(b:boolean) {
+        public highlight(b: boolean) {
             // Remove highlight for all children 
             // Remove highlight for all children 
             if (!b) {
             if (!b) {
                 for (let child of this.children) {
                 for (let child of this.children) {
@@ -162,14 +169,14 @@
             // Highlight this node
             // Highlight this node
             this._adapter.highlight(b);
             this._adapter.highlight(b);
         }
         }
-        
+
         /** Returns true if the node is folded, false otherwise */
         /** Returns true if the node is folded, false otherwise */
-        private _isFolded() : boolean {
+        private _isFolded(): boolean {
             return !this._div.classList.contains('unfolded');
             return !this._div.classList.contains('unfolded');
         }
         }
 
 
         /** Set this item as active (background lighter) in the tree panel */
         /** Set this item as active (background lighter) in the tree panel */
-        public active(b:boolean) {
+        public active(b: boolean) {
             this._div.classList.remove('active');
             this._div.classList.remove('active');
             for (let child of this.children) {
             for (let child of this.children) {
                 child.active(false);
                 child.active(false);
@@ -179,4 +186,4 @@
             }
             }
         }
         }
     }
     }
- }
+}

+ 39 - 0
inspector/src/treetools/CameraPOV.ts

@@ -0,0 +1,39 @@
+module INSPECTOR {
+
+    export interface ICameraPOV {
+        setPOV: () => void
+    }
+
+    /**
+     * 
+     */
+    export class CameraPOV extends AbstractTreeTool {
+        private cameraPOV: ICameraPOV;
+
+        constructor(camera: ICameraPOV) {
+            super();
+            this.cameraPOV = camera;
+            this._elem.classList.add('fa-video-camera');
+        }
+
+        protected action() {
+            super.action();
+            this._gotoPOV();
+        }
+
+        private _gotoPOV() {
+
+            let actives = Inspector.DOCUMENT.querySelectorAll(".fa-video-camera.active");
+            console.log(actives);
+            for (let i = 0; i < actives.length; i++) {
+                actives[i].classList.remove('active');
+            }
+            //if (this._on) {
+                // set icon camera
+                this._elem.classList.add('active');
+            //}
+            this.cameraPOV.setPOV();
+
+        }
+    }
+}

+ 228 - 91
inspector/test/index.js

@@ -5,8 +5,8 @@ var Test = (function () {
     function Test(canvasId) {
     function Test(canvasId) {
         var _this = this;
         var _this = this;
         var canvas = document.getElementById(canvasId);
         var canvas = document.getElementById(canvasId);
-        this.engine = new BABYLON.Engine(canvas, true);					
-		BABYLONDEVTOOLS.Loader.debugShortcut(this.engine);
+        this.engine = new BABYLON.Engine(canvas, true);
+        BABYLONDEVTOOLS.Loader.debugShortcut(this.engine);
         this.scene = null;
         this.scene = null;
         window.addEventListener("resize", function () {
         window.addEventListener("resize", function () {
             _this.engine.resize();
             _this.engine.resize();
@@ -16,7 +16,7 @@ var Test = (function () {
     Test.prototype._run = function () {
     Test.prototype._run = function () {
         var _this = this;
         var _this = this;
         this._initScene();
         this._initScene();
-        this.scene.debugLayer.show();
+        this.scene.debugLayer.show({ popup: false, initialTab: 4 });
         this.scene.executeWhenReady(function () {
         this.scene.executeWhenReady(function () {
             _this._initGame();
             _this._initGame();
             _this.engine.runRenderLoop(function () {
             _this.engine.runRenderLoop(function () {
@@ -26,65 +26,192 @@ var Test = (function () {
     };
     };
     Test.prototype._initScene = function () {
     Test.prototype._initScene = function () {
         var scene = new BABYLON.Scene(this.engine);
         var scene = new BABYLON.Scene(this.engine);
-        var camera = new BABYLON.ArcRotateCamera("Camera", -Math.PI / 4, Math.PI / 2.5, 200, BABYLON.Vector3.Zero(), scene);
-        camera.attachControl(this.engine.getRenderingCanvas(), true);
-        camera.minZ = 0.1;
-        // Lights
-        var light0 = new BABYLON.PointLight("Omni0", new BABYLON.Vector3(0, 10, 0), scene);
-        var light1 = new BABYLON.PointLight("Omni1", new BABYLON.Vector3(0, -10, 0), scene);
-        var light2 = new BABYLON.PointLight("Omni2", new BABYLON.Vector3(10, 0, 0), scene);
-        var light3 = new BABYLON.DirectionalLight("Dir0", new BABYLON.Vector3(1, -1, 0), scene);
-        var material = new BABYLON.StandardMaterial("kosh", scene);
-        var sphere = BABYLON.Mesh.CreateSphere("Sphere", 16, 3, scene);
-        // Creating light sphere
-        var lightSphere0 = BABYLON.Mesh.CreateSphere("Sphere0", 16, 0.5, scene);
-        var lightSphere1 = BABYLON.Mesh.CreateSphere("Sphere1", 16, 0.5, scene);
-        var lightSphere2 = BABYLON.Mesh.CreateSphere("Sphere2", 16, 0.5, scene);
-        lightSphere0.material = new BABYLON.StandardMaterial("red", scene);
-        lightSphere0.material.diffuseColor = new BABYLON.Color3(0, 0, 0);
-        lightSphere0.material.specularColor = new BABYLON.Color3(0, 0, 0);
-        lightSphere0.material.emissiveColor = new BABYLON.Color3(1, 0, 0);
-        lightSphere1.material = new BABYLON.StandardMaterial("green", scene);
-        lightSphere1.material.diffuseColor = new BABYLON.Color3(0, 0, 0);
-        lightSphere1.material.specularColor = new BABYLON.Color3(0, 0, 0);
-        lightSphere1.material.emissiveColor = new BABYLON.Color3(0, 1, 0);
-        lightSphere2.material = new BABYLON.StandardMaterial("blue", scene);
-        lightSphere2.material.diffuseColor = new BABYLON.Color3(0, 0, 0);
-        lightSphere2.material.specularColor = new BABYLON.Color3(0, 0, 0);
-        lightSphere2.material.emissiveColor = new BABYLON.Color3(0, 0, 1);
-        // Sphere material
-        material.diffuseColor = new BABYLON.Color3(1, 1, 1);
-        sphere.material = material;
-        // Lights colors
-        light0.diffuse = new BABYLON.Color3(1, 0, 0);
-        light0.specular = new BABYLON.Color3(1, 0, 0);
-        light1.diffuse = new BABYLON.Color3(0, 1, 0);
-        light1.specular = new BABYLON.Color3(0, 1, 0);
-        light2.diffuse = new BABYLON.Color3(0, 0, 1);
-        light2.specular = new BABYLON.Color3(0, 0, 1);
-        light3.diffuse = new BABYLON.Color3(1, 1, 1);
-        light3.specular = new BABYLON.Color3(1, 1, 1);
-        BABYLON.Effect.ShadersStore["customVertexShader"] = 'precision highp float;attribute vec3 position;attribute vec2 uv;uniform mat4 worldViewProjection;varying vec2 vUV;varying vec3 vPos;void main(){gl_Position=worldViewProjection*vec4(position,1.),vPos=gl_Position.xyz;if(position.x >2.0) {gl_Position.x = 2.0;} else { gl_Position.y = 1.0;}}';
-        BABYLON.Effect.ShadersStore["customFragmentShader"] = 'precision highp float;varying vec3 vPos;uniform vec3 color;void main(){gl_FragColor=vec4(mix(color,vPos,.05),1.);}';
-        var shaderMaterial = new BABYLON.ShaderMaterial("shader", scene, {
-            vertex: "custom",
-            fragment: "custom",
-        }, {
-            attributes: ["position", "normal", "uv"],
-            uniforms: ["world", "worldView", "worldViewProjection", "view", "projection"]
+        var canvas = scene.getEngine().getRenderingCanvas();
+        var light = new BABYLON.HemisphericLight("hemi", new BABYLON.Vector3(0, 1, 0), scene);
+
+        var camera = new BABYLON.ArcRotateCamera("Camera", Math.PI / 2, 1.0, 110, new BABYLON.Vector3(0, -20, 0), scene);
+        camera.attachControl(canvas, true);
+
+        var camera1 = new BABYLON.ArcRotateCamera("Camera1", 1.58, 1.2, 110, BABYLON.Vector3.Zero(), scene);
+        var camera2 = new BABYLON.ArcRotateCamera("Camera2", Math.PI / 3, .8, 40, BABYLON.Vector3.Zero(), scene);
+        var camera3 = new BABYLON.ArcRotateCamera("Camera3", -Math.PI / 5, 1.0, 70, BABYLON.Vector3.Zero(), scene);
+        var camera4 = new BABYLON.ArcRotateCamera("Camera4", -Math.PI / 6, 1.3, 110, BABYLON.Vector3.Zero(), scene);
+
+        camera1.layerMask = 2;
+        camera2.layerMask = 2;
+        camera3.layerMask = 2;
+        camera4.layerMask = 2;
+        /*
+            camera1.parent = camera;
+            camera2.parent = camera;
+            camera3.parent = camera;
+            camera4.parent = camera;
+        */
+
+        var sphere1 = BABYLON.Mesh.CreateSphere("Sphere1", 10.0, 9.0, scene);
+        var sphere2 = BABYLON.Mesh.CreateSphere("Sphere2", 2.0, 9.0, scene);//Only two segments
+        var sphere3 = BABYLON.Mesh.CreateSphere("Sphere3", 10.0, 9.0, scene);
+        var sphere4 = BABYLON.Mesh.CreateSphere("Sphere4", 10.0, 9.0, scene);
+        var sphere5 = BABYLON.Mesh.CreateSphere("Sphere5", 10.0, 9.0, scene);
+        var sphere6 = BABYLON.Mesh.CreateSphere("Sphere6", 10.0, 9.0, scene);
+
+        sphere1.position.x = 40;
+        sphere2.position.x = 25;
+        sphere3.position.x = 10;
+        sphere4.position.x = -5;
+        sphere5.position.x = -20;
+        sphere6.position.x = -35;
+
+        var rt1 = new BABYLON.RenderTargetTexture("depth", 1024, scene, true, true);
+        scene.customRenderTargets.push(rt1);
+        rt1.activeCamera = camera1;
+        rt1.renderList = scene.meshes;
+
+        var rt2 = new BABYLON.RenderTargetTexture("depth", 1024, scene, true, true);
+        scene.customRenderTargets.push(rt2);
+        rt2.activeCamera = camera2;
+        rt2.renderList = scene.meshes;
+
+        var rt3 = new BABYLON.RenderTargetTexture("depth", 1024, scene, true, true);
+        scene.customRenderTargets.push(rt3);
+        rt3.activeCamera = camera3;
+        rt3.renderList = scene.meshes;
+
+        var rt4 = new BABYLON.RenderTargetTexture("depth", 1024, scene, true, true);
+        scene.customRenderTargets.push(rt4);
+        rt4.activeCamera = camera4;
+        rt4.renderList = scene.meshes;
+
+        var mon1 = BABYLON.Mesh.CreatePlane("plane", 5, scene);
+        mon1.position = new BABYLON.Vector3(-8.8, -7.8, 25)
+        // mon1.showBoundingBox = true;
+        var mon1mat = new BABYLON.StandardMaterial("texturePlane", scene);
+        mon1mat.diffuseTexture = rt1;
+        mon1.material = mon1mat;
+        mon1.parent = camera;
+        mon1.layerMask = 1;
+
+        var mon2 = BABYLON.Mesh.CreatePlane("plane", 5, scene);
+        mon2.position = new BABYLON.Vector3(-2.9, -7.8, 25)
+        // mon2.showBoundingBox = true;
+        var mon2mat = new BABYLON.StandardMaterial("texturePlane", scene);
+        mon2mat.diffuseTexture = rt2;
+        mon2.material = mon2mat;
+        mon2.parent = camera;
+        mon2.layerMask = 1;
+
+        var mon3 = BABYLON.Mesh.CreatePlane("plane", 5, scene);
+        mon3.position = new BABYLON.Vector3(2.9, -7.8, 25)
+        // mon3.showBoundingBox = true;
+        var mon3mat = new BABYLON.StandardMaterial("texturePlane", scene);
+        mon3mat.diffuseTexture = rt3;
+        mon3.material = mon3mat;
+        mon3.parent = camera;
+        mon3.layerMask = 1;
+
+
+        var mon4 = BABYLON.Mesh.CreatePlane("plane", 5, scene);
+        mon4.position = new BABYLON.Vector3(8.8, -7.8, 25)
+        // mon4.showBoundingBox = true;
+        var mon4mat = new BABYLON.StandardMaterial("texturePlane", scene);
+        mon4mat.diffuseTexture = rt4;
+        mon4.material = mon4mat;
+        mon4.parent = camera;
+        mon4.layerMask = 1;
+
+
+        var butback = BABYLON.MeshBuilder.CreatePlane("plane", { width: 25, height: 6 }, scene);
+        butback.position = new BABYLON.Vector3(0, -8.2, 26)
+        // butback.showBoundingBox = true;
+        var butbackmat = new BABYLON.StandardMaterial("texturePlane", scene);
+        butbackmat.diffuseColor = BABYLON.Color3.Black();
+        butback.material = butbackmat;
+        butback.parent = camera;
+        butback.layerMask = 1;
+
+        var plane = BABYLON.Mesh.CreatePlane("plane", 120, scene);
+        plane.position.y = -5;
+        plane.rotation.x = Math.PI / 2;
+
+        var materialSphere1 = new BABYLON.StandardMaterial("texture1", scene);
+        materialSphere1.wireframe = true;
+
+        //Creation of a red material with alpha
+        var materialSphere2 = new BABYLON.StandardMaterial("texture2", scene);
+        materialSphere2.diffuseColor = new BABYLON.Color3(1, 0, 0); //Red
+        materialSphere2.alpha = 0.3;
+
+        //Creation of a material with an image texture
+        var materialSphere3 = new BABYLON.StandardMaterial("texture3", scene);
+        materialSphere3.diffuseTexture = new BABYLON.Texture("/assets/textures/amiga.jpg", scene);
+
+        //Creation of a material with translated texture
+        var materialSphere4 = new BABYLON.StandardMaterial("texture4", scene);
+        materialSphere4.diffuseTexture = new BABYLON.Texture("/assets/textures/floor.png", scene);
+        materialSphere4.diffuseTexture.vOffset = 0.1;//Vertical offset of 10%
+        materialSphere4.diffuseTexture.uOffset = 0.4;//Horizontal offset of 40%
+
+        //Creation of a material with an alpha texture
+        var materialSphere5 = new BABYLON.StandardMaterial("texture5", scene);
+        materialSphere5.diffuseTexture = new BABYLON.Texture("/assets/textures/rock.png", scene);
+        materialSphere5.diffuseTexture.hasAlpha = true;//Has an alpha
+
+        //Creation of a material and show all the faces
+        var materialSphere6 = new BABYLON.StandardMaterial("texture6", scene);
+        materialSphere6.diffuseTexture = new BABYLON.Texture("/assets/textures/grass.png", scene);
+        materialSphere6.diffuseTexture.hasAlpha = true;//Have an alpha
+        materialSphere6.backFaceCulling = false;//Show all the faces of the element
+
+        //Creation of a repeated textured material
+        var materialPlane = new BABYLON.StandardMaterial("texturePlane", scene);
+        materialPlane.diffuseTexture = new BABYLON.Texture("/assets/textures/mixMap.png", scene);
+        materialPlane.diffuseTexture.uScale = 5.0;
+        materialPlane.diffuseTexture.vScale = 5.0;
+        materialPlane.backFaceCulling = false;
+
+        //Apply the materials to meshes
+        sphere1.material = materialSphere1;
+        sphere2.material = materialSphere2;
+
+        sphere3.material = materialSphere3;
+        sphere4.material = materialSphere4;
+
+        sphere5.material = materialSphere5;
+        sphere6.material = materialSphere6;
+
+        plane.material = materialPlane;
+
+        var d = 50;
+        var cubes = new Array();
+        for (var i = 0; i < 360; i += 20) {
+            var r = BABYLON.Tools.ToRadians(i);
+            var b = BABYLON.Mesh.CreateBox("Box #" + i / 20, 5, scene, false);
+            b.position.x = Math.cos(r) * d;
+            b.position.z = Math.sin(r) * d;
+            cubes.push(b);
+        }
+        var canvas = new BABYLON.ScreenSpaceCanvas2D(scene, {
+            id: "ScreenCanvas",
+            cachingStrategy: BABYLON.Canvas2D.CACHESTRATEGY_TOPLEVELGROUPS
+
         });
         });
-        sphere.material = shaderMaterial;
-        // Animations
-        var alpha = 0;
-        scene.beforeRender = function () {
-            light0.position = new BABYLON.Vector3(10 * Math.sin(alpha), 0, 10 * Math.cos(alpha));
-            light1.position = new BABYLON.Vector3(10 * Math.sin(alpha), 0, -10 * Math.cos(alpha));
-            light2.position = new BABYLON.Vector3(10 * Math.cos(alpha), 0, 10 * Math.sin(alpha));
-            lightSphere0.position = light0.position;
-            lightSphere1.position = light1.position;
-            lightSphere2.position = light2.position;
-            alpha += 0.01;
-        };
+        i = 0;
+        for (var _i = 0, cubes_1 = cubes; _i < cubes_1.length; _i++) {
+            var cube = cubes_1[_i];
+            new BABYLON.Group2D({
+                parent: canvas, id: "GroupTag #" + i, width: 80, height: 40, trackNode: cube, origin: BABYLON.Vector2.Zero(),
+                children: [
+                    new BABYLON.Rectangle2D({
+                        id: "firstRect", width: 80, height: 26, x: 0, y: 0, origin: BABYLON.Vector2.Zero(), border: "#FFFFFFFF", fill: "#808080FF", children: [
+                            new BABYLON.Text2D(cube.name, { marginAlignment: "h: center, v:center", fontName: "bold 12px Arial" })
+                        ]
+                    })
+                ]
+            });
+            ++i;
+        }
+
+
         this.scene = scene;
         this.scene = scene;
     };
     };
     Test.prototype._initGame = function () {
     Test.prototype._initGame = function () {
@@ -95,36 +222,46 @@ var Test = (function () {
      */
      */
     Test.prototype._createCanvas = function () {
     Test.prototype._createCanvas = function () {
         // object hierarchy  g1 -> g2 -> rect
         // object hierarchy  g1 -> g2 -> rect
-            
-            // when cachingStrategy is 1 or 2 - everything is rendered
-            // when it is 3 - only direct children of g1 are rendered
-            var canvas = new BABYLON.ScreenSpaceCanvas2D(this.scene, 
-                { id: "ScreenCanvas", 
-                cachingStrategy: BABYLON.Canvas2D.CACHESTRATEGY_DONTCACHE });           // 1
-                // cachingStrategy: BABYLON.Canvas2D.CACHESTRATEGY_TOPLEVELGROUPS });      // 2 
-                // cachingStrategy: BABYLON.Canvas2D.CACHESTRATEGY_ALLGROUPS });           // 3
-            
-            canvas.createCanvasProfileInfoCanvas();
-
-            // parent group            
-            var g1 = new BABYLON.Group2D({parent: canvas, id: "G1",
-                x: 50, y: 50, size: new BABYLON.Size(60, 60)});
-
-            // just to see it    
-            let frame1 = new BABYLON.Rectangle2D({parent: g1, 
-                         x : 0, y: 0,  size: g1.size, border: "#FF0000FF" });
-            
-            // child group
-            let g2 = new BABYLON.Group2D({parent: g1, id: "G2",  
-                        x: 10, y: 10, size: new BABYLON.Size(40, 40)});
-
-            // just to see it
-            let frame2 = new BABYLON.Rectangle2D({parent: g2, x : 0, y: 0, size: g2.size, border: "#0000FFFF" }); 
-            
-            let rect =   new BABYLON.Rectangle2D({parent: g2, x : 10, y: 10, size: new BABYLON.Size(20, 20), 
-                                fill: "#00FF00FF" }) ;              
-                      
-            return canvas;
+
+        // when cachingStrategy is 1 or 2 - everything is rendered
+        // when it is 3 - only direct children of g1 are rendered
+        var canvas = new BABYLON.ScreenSpaceCanvas2D(this.scene,
+            {
+                id: "ScreenCanvas",
+                cachingStrategy: BABYLON.Canvas2D.CACHESTRATEGY_DONTCACHE
+            });           // 1
+        // cachingStrategy: BABYLON.Canvas2D.CACHESTRATEGY_TOPLEVELGROUPS });      // 2 
+        // cachingStrategy: BABYLON.Canvas2D.CACHESTRATEGY_ALLGROUPS });           // 3
+
+        canvas.createCanvasProfileInfoCanvas();
+
+        // parent group            
+        var g1 = new BABYLON.Group2D({
+            parent: canvas, id: "G1",
+            x: 50, y: 50, size: new BABYLON.Size(60, 60)
+        });
+
+        // just to see it    
+        let frame1 = new BABYLON.Rectangle2D({
+            parent: g1,
+            x: 0, y: 0, size: g1.size, border: "#FF0000FF"
+        });
+
+        // child group
+        let g2 = new BABYLON.Group2D({
+            parent: g1, id: "G2",
+            x: 10, y: 10, size: new BABYLON.Size(40, 40)
+        });
+
+        // just to see it
+        let frame2 = new BABYLON.Rectangle2D({ parent: g2, x: 0, y: 0, size: g2.size, border: "#0000FFFF" });
+
+        let rect = new BABYLON.Rectangle2D({
+            parent: g2, x: 10, y: 10, size: new BABYLON.Size(20, 20),
+            fill: "#00FF00FF"
+        });
+
+        return canvas;
     };
     };
     return Test;
     return Test;
 }());
 }());

+ 1 - 1
loaders/src/glTF/babylon.glTFFileLoader.ts

@@ -934,7 +934,7 @@ module BABYLON {
                 var translation = node.translation || [0, 0, 0];
                 var translation = node.translation || [0, 0, 0];
                 var rotation = node.rotation || [0, 0, 0, 1];
                 var rotation = node.rotation || [0, 0, 0, 1];
                 var scale = node.scale || [1, 1, 1];
                 var scale = node.scale || [1, 1, 1];
-                configureNode(lastNode, Vector3.FromArray(translation), Quaternion.RotationAxis(Vector3.FromArray(rotation).normalize(), rotation[3]), Vector3.FromArray(scale));
+                configureNode(lastNode, Vector3.FromArray(translation), Quaternion.FromArray(rotation), Vector3.FromArray(scale));
             }
             }
 
 
             lastNode.updateCache(true);
             lastNode.updateCache(true);

+ 1 - 1
localDev/index.html

@@ -86,4 +86,4 @@
 			});
 			});
 	</script>
 	</script>
 </body>
 </body>
-</html>
+</html>

+ 6 - 2
materialsLibrary/index.html

@@ -168,7 +168,6 @@
 				std.diffuseTexture.uScale = 5;
 				std.diffuseTexture.uScale = 5;
 				std.diffuseTexture.vScale = 5;
 				std.diffuseTexture.vScale = 5;
 
 
-                // Lava
                 var lava = prepareLava();
                 var lava = prepareLava();
 
 
 				var simple = new BABYLON.SimpleMaterial("simple", scene);
 				var simple = new BABYLON.SimpleMaterial("simple", scene);
@@ -199,19 +198,24 @@
 				var sky = prepareSky();
 				var sky = prepareSky();
                 
                 
                 var grid = prepareGrid();
                 var grid = prepareGrid();
+
+				var shadowOnly = new BABYLON.ShadowOnlyMaterial();
 				
 				
 				// Default to std
 				// Default to std
 				var currentMaterial = std;
 				var currentMaterial = std;
 				sphere.material = std;				
 				sphere.material = std;				
 				sphere.receiveShadows = true;
 				sphere.receiveShadows = true;
 
 
-				gui.add(options, 'material', ['standard', 'simple', 'water', 'fire', 'lava', 'normal', 'terrain', 'pbr', 'fur', 'triPlanar', 'gradient', 'sky', 'grid']).onFinishChange(function () {
+				gui.add(options, 'material', ['standard', 'simple', 'water', 'fire', 'lava', 'normal', 'terrain', 'pbr', 'fur', 'triPlanar', 'gradient', 'sky', 'grid', 'shadowOnly']).onFinishChange(function () {
 					water.enableRenderTargets(false);
 					water.enableRenderTargets(false);
 					skybox.material = skyboxMaterial;
 					skybox.material = skyboxMaterial;
 					currentMesh.isVisible = true;
 					currentMesh.isVisible = true;
 					fur.resetFur();
 					fur.resetFur();
                     
                     
 					switch (options.material) {
 					switch (options.material) {
+						case "shadowOnly":
+							currentMaterial = shadowOnly;
+							break;						
 						case "simple":
 						case "simple":
 							currentMaterial = simple;
 							currentMaterial = simple;
 							break;
 							break;

+ 240 - 0
materialsLibrary/src/shadowOnly/babylon.shadowOnlyMaterial.ts

@@ -0,0 +1,240 @@
+/// <reference path="../../../dist/preview release/babylon.d.ts"/>
+
+module BABYLON {
+    class ShadowOnlyMaterialDefines extends MaterialDefines {
+        public CLIPPLANE = false;
+        public POINTSIZE = false;
+        public FOG = false;
+        public NORMAL = false;
+        public NUM_BONE_INFLUENCERS = 0;
+        public BonesPerMesh = 0;
+        public INSTANCES = false;
+
+        constructor() {
+            super();
+            this.rebuild();
+        }
+    }
+
+    export class ShadowOnlyMaterial extends Material {
+        @serialize()
+
+        private _worldViewProjectionMatrix = Matrix.Zero();
+        private _scaledDiffuse = new Color3();
+        private _renderId: number;
+
+        private _defines = new ShadowOnlyMaterialDefines();
+        private _cachedDefines = new ShadowOnlyMaterialDefines();
+
+        constructor(name: string, scene: Scene) {
+            super(name, scene);
+
+            this._cachedDefines.BonesPerMesh = -1;
+        }
+
+        public needAlphaBlending(): boolean {
+            return true;
+        }
+
+        public needAlphaTesting(): boolean {
+            return false;
+        }
+
+        public getAlphaTestTexture(): BaseTexture {
+            return null;
+        }
+
+        // Methods   
+        private _checkCache(scene: Scene, mesh?: AbstractMesh, useInstances?: boolean): boolean {
+            if (!mesh) {
+                return true;
+            }
+
+            if (this._defines.INSTANCES !== useInstances) {
+                return false;
+            }
+
+            if (mesh._materialDefines && mesh._materialDefines.isEqual(this._defines)) {
+                return true;
+            }
+
+            return false;
+        }
+
+        public isReady(mesh?: AbstractMesh, useInstances?: boolean): boolean {
+            if (this.checkReadyOnlyOnce) {
+                if (this._wasPreviouslyReady) {
+                    return true;
+                }
+            }
+
+            var scene = this.getScene();
+
+            if (!this.checkReadyOnEveryCall) {
+                if (this._renderId === scene.getRenderId()) {
+                    if (this._checkCache(scene, mesh, useInstances)) {
+                        return true;
+                    }
+                }
+            }
+
+            var engine = scene.getEngine();
+            var needNormals = false;
+
+            this._defines.reset();
+
+            // Effect
+            if (scene.clipPlane) {
+                this._defines.CLIPPLANE = true;
+            }
+
+            // Point size
+            if (this.pointsCloud || scene.forcePointsCloud) {
+                this._defines.POINTSIZE = true;
+            }
+
+            // Fog
+            if (scene.fogEnabled && mesh && mesh.applyFog && scene.fogMode !== Scene.FOGMODE_NONE && this.fogEnabled) {
+                this._defines.FOG = true;
+            }
+
+            if (scene.lightsEnabled) {
+                needNormals = MaterialHelper.PrepareDefinesForLights(scene, mesh, this._defines, 1);
+            }
+
+            // Attribs
+            if (mesh) {
+                if (needNormals && mesh.isVerticesDataPresent(VertexBuffer.NormalKind)) {
+                    this._defines.NORMAL = true;
+                }
+                if (mesh.useBones && mesh.computeBonesUsingShaders) {
+                    this._defines.NUM_BONE_INFLUENCERS = mesh.numBoneInfluencers;
+                    this._defines.BonesPerMesh = (mesh.skeleton.bones.length + 1);
+                }
+
+                // Instances
+                if (useInstances) {
+                    this._defines.INSTANCES = true;
+                }
+            }
+
+            // Get correct effect      
+            if (!this._defines.isEqual(this._cachedDefines)) {
+                this._defines.cloneTo(this._cachedDefines);
+
+                scene.resetCachedMaterial();
+
+                // Fallbacks
+                var fallbacks = new EffectFallbacks();             
+                if (this._defines.FOG) {
+                    fallbacks.addFallback(1, "FOG");
+                }
+
+                MaterialHelper.HandleFallbacksForShadows(this._defines, fallbacks, 1);
+                
+                if (this._defines.NUM_BONE_INFLUENCERS > 0) {
+                    fallbacks.addCPUSkinningFallback(0, mesh);
+                }
+
+                //Attributes
+                var attribs = [VertexBuffer.PositionKind];
+
+                if (this._defines.NORMAL) {
+                    attribs.push(VertexBuffer.NormalKind);
+                }
+
+                MaterialHelper.PrepareAttributesForBones(attribs, mesh, this._defines, fallbacks);
+                MaterialHelper.PrepareAttributesForInstances(attribs, this._defines);
+
+                var shaderName = "shadowOnly";
+                var join = this._defines.toString();
+                var uniforms = ["world", "view", "viewProjection", "vEyePosition", "vLightsType",
+                                "vFogInfos", "vFogColor", "pointSize",
+                                "mBones",
+                                "vClipPlane", "depthValues"
+                ];
+                var samplers = [];
+                    
+                MaterialHelper.PrepareUniformsAndSamplersList(uniforms, samplers, this._defines, 1);
+                
+                this._effect = scene.getEngine().createEffect(shaderName,
+                    attribs, uniforms, samplers,
+                    join, fallbacks, this.onCompiled, this.onError, {maxSimultaneousLights: 1});
+            }
+            if (!this._effect.isReady()) {
+                return false;
+            }
+
+            this._renderId = scene.getRenderId();
+            this._wasPreviouslyReady = true;
+
+            if (mesh) {
+                if (!mesh._materialDefines) {
+                    mesh._materialDefines = new ShadowOnlyMaterialDefines();
+                }
+
+                this._defines.cloneTo(mesh._materialDefines);
+            }
+
+            return true;
+        }
+
+        public bindOnlyWorldMatrix(world: Matrix): void {
+            this._effect.setMatrix("world", world);
+        }
+
+        public bind(world: Matrix, mesh?: Mesh): void {
+            var scene = this.getScene();
+
+            // Matrices        
+            this.bindOnlyWorldMatrix(world);
+            this._effect.setMatrix("viewProjection", scene.getTransformMatrix());
+
+            // Bones
+            MaterialHelper.BindBonesParameters(mesh, this._effect);
+
+            if (scene.getCachedMaterial() !== this) {
+                // Clip plane
+                MaterialHelper.BindClipPlane(this._effect, scene);
+
+                // Point size
+                if (this.pointsCloud) {
+                    this._effect.setFloat("pointSize", this.pointSize);
+                }
+
+                this._effect.setVector3("vEyePosition", scene._mirroredCameraPosition ? scene._mirroredCameraPosition : scene.activeCamera.position);                
+            }
+
+            // Lights
+            if (scene.lightsEnabled) {
+                MaterialHelper.BindLights(scene, mesh, this._effect, this._defines, 1);          
+            }
+
+            // View
+            if (scene.fogEnabled && mesh.applyFog && scene.fogMode !== Scene.FOGMODE_NONE) {
+                this._effect.setMatrix("view", scene.getViewMatrix());
+            }
+
+            // Fog
+            MaterialHelper.BindFogParameters(scene, mesh, this._effect);
+
+            super.bind(world, mesh);
+        }
+
+        public clone(name: string): ShadowOnlyMaterial {
+            return SerializationHelper.Clone<ShadowOnlyMaterial>(() => new ShadowOnlyMaterial(name, this.getScene()), this);
+        }
+        
+        public serialize(): any {
+            var serializationObject = SerializationHelper.Serialize(this);
+            serializationObject.customType = "BABYLON.ShadowOnlyMaterial";
+            return serializationObject;
+        }
+
+        // Statics
+        public static Parse(source: any, scene: Scene, rootUrl: string): ShadowOnlyMaterial {
+            return SerializationHelper.Parse(() => new ShadowOnlyMaterial(source.name, scene), source, scene, rootUrl);
+        }
+    }
+} 
+

+ 50 - 0
materialsLibrary/src/shadowOnly/shadowOnly.fragment.fx

@@ -0,0 +1,50 @@
+precision highp float;
+
+// Constants
+uniform vec3 vEyePosition;
+
+// Input
+varying vec3 vPositionW;
+
+#ifdef NORMAL
+varying vec3 vNormalW;
+#endif
+
+// Lights
+#include<lightFragmentDeclaration>[0..maxSimultaneousLights]
+
+#include<lightsFragmentFunctions>
+#include<shadowsFragmentFunctions>
+
+#include<clipPlaneFragmentDeclaration>
+
+// Fog
+#include<fogFragmentDeclaration>
+
+void main(void) {
+#include<clipPlaneFragment>
+
+	vec3 viewDirectionW = normalize(vEyePosition - vPositionW);
+
+	// Normal
+#ifdef NORMAL
+	vec3 normalW = normalize(vNormalW);
+#else
+	vec3 normalW = vec3(1.0, 1.0, 1.0);
+#endif
+
+	// Lighting
+	vec3 diffuseBase = vec3(0., 0., 0.);
+    lightingInfo info;
+	float shadow = 1.;
+    float glossiness = 0.;
+    
+#include<lightFragment>[0..1]
+
+	// Composition
+	vec4 color = vec4(0., 0., 0., 1.0 - clamp(shadow, 0., 1.));
+
+#include<fogFragment>
+
+	gl_FragColor = color;
+}

+ 62 - 0
materialsLibrary/src/shadowOnly/shadowOnly.vertex.fx

@@ -0,0 +1,62 @@
+precision highp float;
+
+// Attributes
+attribute vec3 position;
+#ifdef NORMAL
+attribute vec3 normal;
+#endif
+
+#include<bonesDeclaration>
+
+// Uniforms
+#include<instancesDeclaration>
+
+uniform mat4 view;
+uniform mat4 viewProjection;
+
+#ifdef POINTSIZE
+uniform float pointSize;
+#endif
+
+// Output
+varying vec3 vPositionW;
+#ifdef NORMAL
+varying vec3 vNormalW;
+#endif
+
+#ifdef VERTEXCOLOR
+varying vec4 vColor;
+#endif
+
+
+#include<clipPlaneVertexDeclaration>
+
+#include<fogVertexDeclaration>
+#include<shadowsVertexDeclaration>[0..maxSimultaneousLights]
+
+void main(void) {
+
+#include<instancesVertex>
+#include<bonesVertex>
+
+	gl_Position = viewProjection * finalWorld * vec4(position, 1.0);
+
+	vec4 worldPos = finalWorld * vec4(position, 1.0);
+	vPositionW = vec3(worldPos);
+
+#ifdef NORMAL
+	vNormalW = normalize(vec3(finalWorld * vec4(normal, 0.0)));
+#endif
+
+	// Clip plane
+#include<clipPlaneVertex>
+
+    // Fog
+#include<fogVertex>
+#include<shadowsVertex>[0..maxSimultaneousLights]
+
+	// Point size
+#ifdef POINTSIZE
+	gl_PointSize = pointSize;
+#endif
+}

+ 0 - 1
materialsLibrary/src/water/babylon.waterMaterial.ts

@@ -1,5 +1,4 @@
 /// <reference path="../../../dist/preview release/babylon.d.ts"/>
 /// <reference path="../../../dist/preview release/babylon.d.ts"/>
-/// <reference path="../simple/babylon.simpleMaterial.ts"/>
 
 
 module BABYLON {
 module BABYLON {
     class WaterMaterialDefines extends MaterialDefines {
     class WaterMaterialDefines extends MaterialDefines {

+ 78 - 13
src/Actions/babylon.actionManager.ts

@@ -62,16 +62,17 @@
         private static _OnRightPickTrigger = 3;
         private static _OnRightPickTrigger = 3;
         private static _OnCenterPickTrigger = 4;
         private static _OnCenterPickTrigger = 4;
         private static _OnPickDownTrigger = 5;
         private static _OnPickDownTrigger = 5;
-        private static _OnPickUpTrigger = 6;
-        private static _OnLongPressTrigger = 7;
-        private static _OnPointerOverTrigger = 8;
-        private static _OnPointerOutTrigger = 9;
-        private static _OnEveryFrameTrigger = 10;
-        private static _OnIntersectionEnterTrigger = 11;
-        private static _OnIntersectionExitTrigger = 12;
-        private static _OnKeyDownTrigger = 13;
-        private static _OnKeyUpTrigger = 14;
-        private static _OnPickOutTrigger = 15;
+        private static _OnDoublePickTrigger = 6;
+        private static _OnPickUpTrigger = 7;
+        private static _OnLongPressTrigger = 8;
+        private static _OnPointerOverTrigger = 9;
+        private static _OnPointerOutTrigger = 10;
+        private static _OnEveryFrameTrigger = 11;
+        private static _OnIntersectionEnterTrigger = 12;
+        private static _OnIntersectionExitTrigger = 13;
+        private static _OnKeyDownTrigger = 14;
+        private static _OnKeyUpTrigger = 15;
+        private static _OnPickOutTrigger = 16;
 
 
         public static get NothingTrigger(): number {
         public static get NothingTrigger(): number {
             return ActionManager._NothingTrigger;
             return ActionManager._NothingTrigger;
@@ -97,6 +98,10 @@
             return ActionManager._OnPickDownTrigger;
             return ActionManager._OnPickDownTrigger;
         }
         }
 
 
+        public static get OnDoublePickTrigger(): number {
+            return ActionManager._OnDoublePickTrigger;
+        }
+
         public static get OnPickUpTrigger(): number {
         public static get OnPickUpTrigger(): number {
             return ActionManager._OnPickUpTrigger;
             return ActionManager._OnPickUpTrigger;
         }
         }
@@ -138,9 +143,8 @@
             return ActionManager._OnKeyUpTrigger;
             return ActionManager._OnKeyUpTrigger;
         }
         }
 
 
-        public static DragMovementThreshold = 10; // in pixels
-        public static LongPressDelay = 500; // in milliseconds
-        
+        public static Triggers = {};
+
         // Members
         // Members
         public actions = new Array<Action>();
         public actions = new Array<Action>();
 
 
@@ -158,6 +162,14 @@
         public dispose(): void {
         public dispose(): void {
             var index = this._scene._actionManagers.indexOf(this);
             var index = this._scene._actionManagers.indexOf(this);
 
 
+            for (var i = 0; i < this.actions.length; i++) {
+                var action = this.actions[i];
+                ActionManager.Triggers[action.trigger]--;
+                if (ActionManager.Triggers[action.trigger] === 0) {
+                    delete ActionManager.Triggers[action.trigger]
+                }
+            }
+
             if (index > -1) {
             if (index > -1) {
                 this._scene._actionManagers.splice(index, 1);
                 this._scene._actionManagers.splice(index, 1);
             }
             }
@@ -234,6 +246,52 @@
         }
         }
 
 
         /**
         /**
+         * Does exist one action manager with at least one trigger 
+         * @return {boolean} whether or not it exists one action manager with one trigger
+        **/
+        public static get HasTriggers(): boolean {
+            for (var t in ActionManager.Triggers) {
+                if (ActionManager.Triggers.hasOwnProperty(t)) {
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        /**
+         * Does exist one action manager with at least one pick trigger 
+         * @return {boolean} whether or not it exists one action manager with one pick trigger
+        **/
+        public static get HasPickTriggers(): boolean {
+            for (var t in ActionManager.Triggers) {
+                if (ActionManager.Triggers.hasOwnProperty(t)) {
+                    let t_int = parseInt(t);
+                    if (t_int >= ActionManager._OnPickTrigger && t_int <= ActionManager._OnPickUpTrigger) {
+                        return true;
+                    }
+                }
+            }
+            return false;
+        }
+
+        /**
+         * Does exist one action manager that handles actions of a given trigger
+         * @param {number} trigger - the trigger to be tested
+         * @return {boolean} whether the trigger is handeled by at least one action manager
+        **/
+        public static HasSpecificTrigger(trigger: number): boolean {
+            for (var t in ActionManager.Triggers) {
+                if (ActionManager.Triggers.hasOwnProperty(t)) {
+                    let t_int = parseInt(t);
+                    if (t_int === trigger) {
+                        return true;
+                    }
+                }
+            }
+            return false;
+        }
+
+        /**
          * Registers an action to this action manager
          * Registers an action to this action manager
          * @param {BABYLON.Action} action - the action to be registered
          * @param {BABYLON.Action} action - the action to be registered
          * @return {BABYLON.Action} the action amended (prepared) after registration
          * @return {BABYLON.Action} the action amended (prepared) after registration
@@ -248,6 +306,13 @@
 
 
             this.actions.push(action);
             this.actions.push(action);
 
 
+          if(ActionManager.Triggers[action.trigger]) {
+              ActionManager.Triggers[action.trigger]++;
+            }
+            else{
+              ActionManager.Triggers[action.trigger] = 1;
+            }
+
             action._actionManager = this;
             action._actionManager = this;
             action._prepare();
             action._prepare();
 
 

+ 28 - 8
src/Cameras/VR/babylon.webVRCamera.ts

@@ -31,9 +31,10 @@ module BABYLON {
     }
     }
 
 
     export interface WebVROptions {
     export interface WebVROptions {
-        trackPosition?: boolean; //update the camera's position
+        trackPosition?: boolean; //for the sake of your users - set it to true.
         positionScale?: number;
         positionScale?: number;
         displayName?: string; //if there are more than one VRDisplays.
         displayName?: string; //if there are more than one VRDisplays.
+        controllerMeshes?: boolean; // should the native controller meshes be initialized
     }
     }
 
 
     export class WebVRFreeCamera extends FreeCamera implements PoseControlled {
     export class WebVRFreeCamera extends FreeCamera implements PoseControlled {
@@ -58,9 +59,22 @@ module BABYLON {
         public controllers: Array<WebVRController> = [];
         public controllers: Array<WebVRController> = [];
         public onControllersAttached: (controllers: Array<WebVRController>) => void;
         public onControllersAttached: (controllers: Array<WebVRController>) => void;
 
 
-        constructor(name: string, position: Vector3, scene: Scene, compensateDistortion = false, private webVROptions: WebVROptions = {}) {
+        constructor(name: string, position: Vector3, scene: Scene, private webVROptions: WebVROptions = {}) {
             super(name, position, scene);
             super(name, position, scene);
 
 
+            //legacy support - the compensation boolean was removed.
+            if (arguments.length === 5) {
+                this.webVROptions = arguments[4];
+            }
+
+            // default webVR options
+            if (this.webVROptions.trackPosition == undefined) {
+                this.webVROptions.trackPosition = true;
+            }
+            if (this.webVROptions.controllerMeshes == undefined) {
+                this.webVROptions.controllerMeshes = true;
+            }
+
             this.rotationQuaternion = new Quaternion();
             this.rotationQuaternion = new Quaternion();
             this.deviceRotationQuaternion = new Quaternion();
             this.deviceRotationQuaternion = new Quaternion();
 
 
@@ -208,13 +222,16 @@ module BABYLON {
                 this._webvrViewMatrix.m[12] += parentCamera.position.x;
                 this._webvrViewMatrix.m[12] += parentCamera.position.x;
                 this._webvrViewMatrix.m[13] += parentCamera.position.y;
                 this._webvrViewMatrix.m[13] += parentCamera.position.y;
                 this._webvrViewMatrix.m[14] += parentCamera.position.z;
                 this._webvrViewMatrix.m[14] += parentCamera.position.z;
+
+                // is rotation offset set? 
+                if (!Quaternion.IsIdentity(this.rotationQuaternion)) {
+                    this._webvrViewMatrix.decompose(Tmp.Vector3[0], Tmp.Quaternion[0], Tmp.Vector3[1]);
+                    this.rotationQuaternion.multiplyToRef(Tmp.Quaternion[0], Tmp.Quaternion[0]);
+                    Matrix.ComposeToRef(Tmp.Vector3[0], Tmp.Quaternion[0], Tmp.Vector3[1], this._webvrViewMatrix);
+                }
+
                 this._webvrViewMatrix.invert();
                 this._webvrViewMatrix.invert();
             }
             }
-            // is rotation offset set? 
-            if (!Quaternion.IsIdentity(this.rotationQuaternion)) {
-                this.rotationQuaternion.toRotationMatrix(this._tempMatrix);
-                this._tempMatrix.multiplyToRef(this._webvrViewMatrix, this._webvrViewMatrix);
-            }
 
 
             this._updateCameraRotationMatrix();
             this._updateCameraRotationMatrix();
             Vector3.TransformCoordinatesToRef(this._referencePoint, this._cameraRotationMatrix, this._transformedReferencePoint);
             Vector3.TransformCoordinatesToRef(this._referencePoint, this._cameraRotationMatrix, this._transformedReferencePoint);
@@ -227,7 +244,7 @@ module BABYLON {
             return this._webvrViewMatrix;
             return this._webvrViewMatrix;
         }
         }
 
 
-        protected _updateCameraRotationMatrix() {
+        public _updateWebVRCameraRotationMatrix() {
             this._webvrViewMatrix.getRotationMatrixToRef(this._cameraRotationMatrix);
             this._webvrViewMatrix.getRotationMatrixToRef(this._cameraRotationMatrix);
         }
         }
 
 
@@ -252,6 +269,9 @@ module BABYLON {
             new BABYLON.Gamepads((gp) => {
             new BABYLON.Gamepads((gp) => {
                 if (gp.type === BABYLON.Gamepad.POSE_ENABLED) {
                 if (gp.type === BABYLON.Gamepad.POSE_ENABLED) {
                     let webVrController: WebVRController = <WebVRController>gp;
                     let webVrController: WebVRController = <WebVRController>gp;
+                    if (this.webVROptions.controllerMeshes) {
+                        webVrController.initControllerMesh(this.getScene());
+                    }
                     webVrController.attachToPoseControlledCamera(this);
                     webVrController.attachToPoseControlledCamera(this);
 
 
                     // since this is async - sanity check. Is the controller already stored?
                     // since this is async - sanity check. Is the controller already stored?

+ 16 - 10
src/Cameras/babylon.camera.ts

@@ -599,38 +599,39 @@
                     this._rigCameras[1]._cameraRigParams.vrPreViewMatrix = metrics.rightPreViewMatrix;
                     this._rigCameras[1]._cameraRigParams.vrPreViewMatrix = metrics.rightPreViewMatrix;
                     this._rigCameras[1].getProjectionMatrix = this._rigCameras[1]._getVRProjectionMatrix;
                     this._rigCameras[1].getProjectionMatrix = this._rigCameras[1]._getVRProjectionMatrix;
 
 
-   
-                   if (metrics.compensateDistortion) {
+
+                    if (metrics.compensateDistortion) {
                         this._rigCameras[0]._rigPostProcess = new VRDistortionCorrectionPostProcess("VR_Distort_Compensation_Left", this._rigCameras[0], false, metrics);
                         this._rigCameras[0]._rigPostProcess = new VRDistortionCorrectionPostProcess("VR_Distort_Compensation_Left", this._rigCameras[0], false, metrics);
                         this._rigCameras[1]._rigPostProcess = new VRDistortionCorrectionPostProcess("VR_Distort_Compensation_Right", this._rigCameras[1], true, metrics);
                         this._rigCameras[1]._rigPostProcess = new VRDistortionCorrectionPostProcess("VR_Distort_Compensation_Right", this._rigCameras[1], true, metrics);
                     }
                     }
                     break;
                     break;
                 case Camera.RIG_MODE_WEBVR:
                 case Camera.RIG_MODE_WEBVR:
                     if (rigParams.vrDisplay) {
                     if (rigParams.vrDisplay) {
-                        //var leftEye = rigParams.vrDisplay.getEyeParameters('left');
-                        //var rightEye = rigParams.vrDisplay.getEyeParameters('right');
+                        var leftEye = rigParams.vrDisplay.getEyeParameters('left');
+                        var rightEye = rigParams.vrDisplay.getEyeParameters('right');
 
 
                         //Left eye
                         //Left eye
                         this._rigCameras[0].viewport = new Viewport(0, 0, 0.5, 1.0);
                         this._rigCameras[0].viewport = new Viewport(0, 0, 0.5, 1.0);
                         this._rigCameras[0].setCameraRigParameter("left", true);
                         this._rigCameras[0].setCameraRigParameter("left", true);
+                        this._rigCameras[0].setCameraRigParameter("eyeParameters", leftEye);
                         this._rigCameras[0].setCameraRigParameter("frameData", rigParams.frameData);
                         this._rigCameras[0].setCameraRigParameter("frameData", rigParams.frameData);
                         this._rigCameras[0].setCameraRigParameter("parentCamera", rigParams.parentCamera);
                         this._rigCameras[0].setCameraRigParameter("parentCamera", rigParams.parentCamera);
-                        //this._rigCameras[0].setCameraRigParameter('eyeParameters', leftEye);
                         this._rigCameras[0]._cameraRigParams.vrWorkMatrix = new Matrix();
                         this._rigCameras[0]._cameraRigParams.vrWorkMatrix = new Matrix();
                         this._rigCameras[0].getProjectionMatrix = this._getWebVRProjectionMatrix;
                         this._rigCameras[0].getProjectionMatrix = this._getWebVRProjectionMatrix;
                         this._rigCameras[0]._getViewMatrix = this._getWebVRViewMatrix;
                         this._rigCameras[0]._getViewMatrix = this._getWebVRViewMatrix;
                         this._rigCameras[0]._isSynchronizedViewMatrix = this._isSynchronizedViewMatrix;
                         this._rigCameras[0]._isSynchronizedViewMatrix = this._isSynchronizedViewMatrix;
-                        this._rigCameras[0]._updateCameraRotationMatrix = this._updateCameraRotationMatrix;
+                        this._rigCameras[0]._updateCameraRotationMatrix = this._updateWebVRCameraRotationMatrix;
+
                         //Right eye
                         //Right eye
                         this._rigCameras[1].viewport = new Viewport(0.5, 0, 0.5, 1.0);
                         this._rigCameras[1].viewport = new Viewport(0.5, 0, 0.5, 1.0);
-                        //this._rigCameras[1].setCameraRigParameter('eyeParameters', rightEye);
+                        this._rigCameras[1].setCameraRigParameter('eyeParameters', rightEye);
                         this._rigCameras[1].setCameraRigParameter("frameData", rigParams.frameData);
                         this._rigCameras[1].setCameraRigParameter("frameData", rigParams.frameData);
                         this._rigCameras[1].setCameraRigParameter("parentCamera", rigParams.parentCamera);
                         this._rigCameras[1].setCameraRigParameter("parentCamera", rigParams.parentCamera);
                         this._rigCameras[1]._cameraRigParams.vrWorkMatrix = new Matrix();
                         this._rigCameras[1]._cameraRigParams.vrWorkMatrix = new Matrix();
                         this._rigCameras[1].getProjectionMatrix = this._getWebVRProjectionMatrix;
                         this._rigCameras[1].getProjectionMatrix = this._getWebVRProjectionMatrix;
                         this._rigCameras[1]._getViewMatrix = this._getWebVRViewMatrix;
                         this._rigCameras[1]._getViewMatrix = this._getWebVRViewMatrix;
                         this._rigCameras[1]._isSynchronizedViewMatrix = this._isSynchronizedViewMatrix;
                         this._rigCameras[1]._isSynchronizedViewMatrix = this._isSynchronizedViewMatrix;
-                        this._rigCameras[1]._updateCameraRotationMatrix = this._updateCameraRotationMatrix;
+                        this._rigCameras[1]._updateCameraRotationMatrix = this._updateWebVRCameraRotationMatrix;
                     }
                     }
                     break;
                     break;
 
 
@@ -646,10 +647,15 @@
             this._cameraRigParams.vrWorkMatrix.multiplyToRef(this._cameraRigParams.vrHMatrix, this._projectionMatrix);
             this._cameraRigParams.vrWorkMatrix.multiplyToRef(this._cameraRigParams.vrHMatrix, this._projectionMatrix);
             return this._projectionMatrix;
             return this._projectionMatrix;
         }
         }
-        
+
         protected _updateCameraRotationMatrix() {
         protected _updateCameraRotationMatrix() {
-           // only here for webvr
+            //Here for WebVR
         }
         }
+
+        protected _updateWebVRCameraRotationMatrix() {
+            //Here for WebVR
+        }
+
         /**
         /**
          * This function MUST be overwritten by the different WebVR cameras available.
          * This function MUST be overwritten by the different WebVR cameras available.
          * The context in which it is running is the RIG camera. So 'this' is the TargetCamera, left or right.
          * The context in which it is running is the RIG camera. So 'this' is the TargetCamera, left or right.

+ 8 - 0
src/Cameras/babylon.targetCamera.ts

@@ -177,6 +177,14 @@ module BABYLON {
                 this.rotation.x += this.cameraRotation.x;
                 this.rotation.x += this.cameraRotation.x;
                 this.rotation.y += this.cameraRotation.y;
                 this.rotation.y += this.cameraRotation.y;
 
 
+                //rotate, if quaternion is set and rotation was used
+                if (this.rotationQuaternion) {
+                    var len = this.rotation.length();
+                    if (len) {
+                        Quaternion.RotationYawPitchRollToRef(this.rotation.y, this.rotation.x, this.rotation.z, this.rotationQuaternion);
+                    }
+                }
+
 
 
                 if (!this.noRotationConstraint) {
                 if (!this.noRotationConstraint) {
                     var limit = (Math.PI / 2) * 0.95;
                     var limit = (Math.PI / 2) * 0.95;

+ 12 - 9
src/Debug/babylon.debugLayer.ts

@@ -1,25 +1,28 @@
 module BABYLON {
 module BABYLON {
 
 
     // declare INSPECTOR namespace for compilation issue
     // declare INSPECTOR namespace for compilation issue
-    declare var INSPECTOR : any;
+    declare var INSPECTOR: any;
 
 
     export class DebugLayer {
     export class DebugLayer {
         private _scene: Scene;
         private _scene: Scene;
         public static InspectorURL = 'http://www.babylonjs.com/babylon.inspector.bundle.js';
         public static InspectorURL = 'http://www.babylonjs.com/babylon.inspector.bundle.js';
         // The inspector instance
         // The inspector instance
-        private _inspector : any;
+        private _inspector: any;
 
 
         constructor(scene: Scene) {
         constructor(scene: Scene) {
             this._scene = scene;
             this._scene = scene;
         }
         }
 
 
         /** Creates the inspector window. */
         /** Creates the inspector window. */
-        private _createInspector(popup?:boolean) {
+        private _createInspector(config: { popup?: boolean, initialTab?: number, parentElement?: HTMLElement } = {}) {
+            let popup = config.popup || false;
+            let initialTab = config.initialTab || 0;
+            let parentElement = config.parentElement || null;
             if (!this._inspector) {
             if (!this._inspector) {
-                this._inspector = new INSPECTOR.Inspector(this._scene, popup);
+                this._inspector = new INSPECTOR.Inspector(this._scene, popup, initialTab, parentElement);
             } // else nothing to do,; instance is already existing
             } // else nothing to do,; instance is already existing
         }
         }
-        
+
         public isVisible(): boolean {
         public isVisible(): boolean {
             if (!this._inspector) {
             if (!this._inspector) {
                 return false;
                 return false;
@@ -33,14 +36,14 @@ module BABYLON {
                 this._inspector = null;
                 this._inspector = null;
             }
             }
         }
         }
-        
-        public show(popup?:boolean) {
+
+        public show(config: { popup?: boolean, initialTab?: number, parentElement?: HTMLElement } = {}) {
             if (typeof INSPECTOR == 'undefined') {
             if (typeof INSPECTOR == 'undefined') {
                 // Load inspector and add it to the DOM
                 // Load inspector and add it to the DOM
-                Tools.LoadScript(DebugLayer.InspectorURL, this._createInspector.bind(this, popup));
+                Tools.LoadScript(DebugLayer.InspectorURL, this._createInspector.bind(this, config));
             } else {
             } else {
                 // Otherwise creates the inspector
                 // Otherwise creates the inspector
-                this._createInspector(popup);
+                this._createInspector(config);
             }
             }
         }
         }
 
 

+ 5 - 1
src/Loading/babylon.sceneLoader.ts

@@ -209,7 +209,11 @@
 
 
                 Tools.LoadFile(rootUrl + sceneFilename, data => {
                 Tools.LoadFile(rootUrl + sceneFilename, data => {
                     importMeshFromData(data);
                     importMeshFromData(data);
-                }, progressCallBack, database, useArrayBuffer);
+                }, progressCallBack, database, useArrayBuffer, () => {
+                    if (onerror) {
+                        onerror(scene, 'Unable to load file ' + rootUrl + sceneFilename)
+                    }
+                });
             };
             };
 
 
             if (scene.getEngine().enableOfflineSupport && !directLoad) {
             if (scene.getEngine().enableOfflineSupport && !directLoad) {

+ 2 - 0
src/Materials/babylon.pbrMaterial.ts

@@ -1479,6 +1479,8 @@
                 }
                 }
             }
             }
 
 
+            this._renderTargets.dispose();
+
             super.dispose(forceDisposeEffect, forceDisposeTextures);
             super.dispose(forceDisposeEffect, forceDisposeTextures);
         }
         }
 
 

+ 2 - 0
src/Materials/babylon.standardMaterial.ts

@@ -987,6 +987,8 @@
                 }
                 }
             }
             }
 
 
+            this._renderTargets.dispose();
+
             super.dispose(forceDisposeEffect, forceDisposeTextures);
             super.dispose(forceDisposeEffect, forceDisposeTextures);
         }
         }
 
 

+ 7 - 10
src/Mesh/babylon.abstractMesh.ts

@@ -865,13 +865,7 @@
             // Composing transformations
             // Composing transformations
             this._pivotMatrix.multiplyToRef(Tmp.Matrix[1], Tmp.Matrix[4]);
             this._pivotMatrix.multiplyToRef(Tmp.Matrix[1], Tmp.Matrix[4]);
             Tmp.Matrix[4].multiplyToRef(Tmp.Matrix[0], Tmp.Matrix[5]);
             Tmp.Matrix[4].multiplyToRef(Tmp.Matrix[0], Tmp.Matrix[5]);
-
-            // Mesh referal
-            var completeMeshReferalMatrix = Tmp.Matrix[6];
-            if (this._meshToBoneReferal && this.parent && this.parent.getWorldMatrix) {
-                this.parent.getWorldMatrix().multiplyToRef(this._meshToBoneReferal.getWorldMatrix(), completeMeshReferalMatrix);
-            }
-
+            
             // Billboarding (testing PG:http://www.babylonjs-playground.com/#UJEIL#13)
             // Billboarding (testing PG:http://www.babylonjs-playground.com/#UJEIL#13)
             if (this.billboardMode !== AbstractMesh.BILLBOARDMODE_NONE && this.getScene().activeCamera) {
             if (this.billboardMode !== AbstractMesh.BILLBOARDMODE_NONE && this.getScene().activeCamera) {
                 if ((this.billboardMode & AbstractMesh.BILLBOARDMODE_ALL) !== AbstractMesh.BILLBOARDMODE_ALL) {
                 if ((this.billboardMode & AbstractMesh.BILLBOARDMODE_ALL) !== AbstractMesh.BILLBOARDMODE_ALL) {
@@ -880,7 +874,8 @@
 
 
                     if (this.parent && this.parent.getWorldMatrix) {
                     if (this.parent && this.parent.getWorldMatrix) {
                         if (this._meshToBoneReferal) {
                         if (this._meshToBoneReferal) {
-                            Vector3.TransformCoordinatesToRef(this.position, completeMeshReferalMatrix, currentPosition);
+                            this.parent.getWorldMatrix().multiplyToRef(this._meshToBoneReferal.getWorldMatrix(), Tmp.Matrix[6]);
+                            Vector3.TransformCoordinatesToRef(this.position, Tmp.Matrix[6], currentPosition);
                         } else {
                         } else {
                             Vector3.TransformCoordinatesToRef(this.position, this.parent.getWorldMatrix(), currentPosition);
                             Vector3.TransformCoordinatesToRef(this.position, this.parent.getWorldMatrix(), currentPosition);
                         }
                         }
@@ -927,7 +922,8 @@
 
 
                 if (this.billboardMode !== AbstractMesh.BILLBOARDMODE_NONE) {
                 if (this.billboardMode !== AbstractMesh.BILLBOARDMODE_NONE) {
                     if (this._meshToBoneReferal) {
                     if (this._meshToBoneReferal) {
-                        Tmp.Matrix[5].copyFrom(completeMeshReferalMatrix);
+                        this.parent.getWorldMatrix().multiplyToRef(this._meshToBoneReferal.getWorldMatrix(), Tmp.Matrix[6]);
+                        Tmp.Matrix[5].copyFrom(Tmp.Matrix[6]);
                     } else {
                     } else {
                         Tmp.Matrix[5].copyFrom(this.parent.getWorldMatrix());
                         Tmp.Matrix[5].copyFrom(this.parent.getWorldMatrix());
                     }
                     }
@@ -939,7 +935,8 @@
                     
                     
                 } else {
                 } else {
                     if (this._meshToBoneReferal) {
                     if (this._meshToBoneReferal) {
-                        this._localWorld.multiplyToRef(completeMeshReferalMatrix, this._worldMatrix);
+                        this._localWorld.multiplyToRef(this.parent.getWorldMatrix(), Tmp.Matrix[6]);
+                        Tmp.Matrix[6].multiplyToRef(this._meshToBoneReferal.getWorldMatrix(), this._worldMatrix);
                     } else {
                     } else {
                         this._localWorld.multiplyToRef(this.parent.getWorldMatrix(), this._worldMatrix);
                         this._localWorld.multiplyToRef(this.parent.getWorldMatrix(), this._worldMatrix);
                     }
                     }

+ 2 - 2
src/PostProcess/babylon.postProcess.ts

@@ -251,14 +251,14 @@
         }
         }
 
 
         public dispose(camera?: Camera): void {
         public dispose(camera?: Camera): void {
-            camera = camera || this._camera;
+            camera = camera || this._camera;            
 
 
             if (this._textures.length > 0) {
             if (this._textures.length > 0) {
                 for (var i = 0; i < this._textures.length; i++) {
                 for (var i = 0; i < this._textures.length; i++) {
                     this._engine._releaseTexture(this._textures.data[i]);
                     this._engine._releaseTexture(this._textures.data[i]);
                 }
                 }
-                this._textures.reset();
             }
             }
+            this._textures.dispose();
 
 
             if (!camera) {
             if (!camera) {
                 return;
                 return;

+ 2 - 0
src/Rendering/babylon.boundingBoxRenderer.ts

@@ -94,6 +94,8 @@
                 return;
                 return;
             }
             }
 
 
+            this.renderList.dispose();
+
             this._colorShader.dispose();
             this._colorShader.dispose();
 
 
             var buffer = this._vertexBuffers[VertexBuffer.PositionKind];
             var buffer = this._vertexBuffers[VertexBuffer.PositionKind];

+ 8 - 0
src/Rendering/babylon.renderingGroup.ts

@@ -256,6 +256,14 @@
             this._spriteManagers.reset();
             this._spriteManagers.reset();
         }
         }
 
 
+        public dispose(): void {
+            this._opaqueSubMeshes.dispose();
+            this._transparentSubMeshes.dispose();
+            this._alphaTestSubMeshes.dispose();
+            this._particleSystems.dispose();
+            this._spriteManagers.dispose();
+        }
+
         /**
         /**
          * Inserts the submesh in its correct queue depending on its material.
          * Inserts the submesh in its correct queue depending on its material.
          * @param subMesh The submesh to dispatch
          * @param subMesh The submesh to dispatch

+ 11 - 0
src/Rendering/babylon.renderingManager.ts

@@ -127,6 +127,17 @@
             }
             }
         }
         }
 
 
+        public dispose(): void {
+            for (let index = RenderingManager.MIN_RENDERINGGROUPS; index < RenderingManager.MAX_RENDERINGGROUPS; index++) {
+                var renderingGroup = this._renderingGroups[index];
+                if (renderingGroup) {
+                    renderingGroup.dispose();
+                }
+            }
+
+            this._renderingGroups.length = 0;
+        }
+
         private _prepareRenderingGroup(renderingGroupId: number): void {
         private _prepareRenderingGroup(renderingGroupId: number): void {
             if (!this._renderingGroups[renderingGroupId]) {
             if (!this._renderingGroups[renderingGroupId]) {
                 this._renderingGroups[renderingGroupId] = new RenderingGroup(renderingGroupId, this._scene,
                 this._renderingGroups[renderingGroupId] = new RenderingGroup(renderingGroupId, this._scene,

+ 91 - 19
src/Tools/babylon.extendedGamepad.ts

@@ -38,8 +38,10 @@ module BABYLON {
 
 
         public rawPose: DevicePose; //GamepadPose;
         public rawPose: DevicePose; //GamepadPose;
 
 
-        private _mesh: AbstractMesh; // a node that will be attached to this Gamepad
-        private _poseControlledCamera: PoseControlled;
+        public _mesh: AbstractMesh; // a node that will be attached to this Gamepad
+        private _poseControlledCamera: TargetCamera;
+
+        private _leftHandSystemQuaternion: Quaternion = new Quaternion();
 
 
         constructor(public vrGamepad) {
         constructor(public vrGamepad) {
             super(vrGamepad.id, vrGamepad.index, vrGamepad);
             super(vrGamepad.id, vrGamepad.index, vrGamepad);
@@ -52,16 +54,17 @@ module BABYLON {
 
 
             this._calculatedPosition = Vector3.Zero();
             this._calculatedPosition = Vector3.Zero();
             this._calculatedRotation = new Quaternion();
             this._calculatedRotation = new Quaternion();
+            Quaternion.RotationYawPitchRollToRef(Math.PI, 0, 0, this._leftHandSystemQuaternion);
         }
         }
 
 
         public update() {
         public update() {
             super.update();
             super.update();
             // update this device's offset position from the attached camera, if provided
             // update this device's offset position from the attached camera, if provided
-            if (this._poseControlledCamera && this._poseControlledCamera.deviceScaleFactor) {
-                //this.position.copyFrom(this._poseControlledCamera.position);
-                //this.rotationQuaternion.copyFrom(this._poseControlledCamera.rotationQuaternion);
-                this.deviceScaleFactor = this._poseControlledCamera.deviceScaleFactor;
-            }
+            //if (this._poseControlledCamera && this._poseControlledCamera.deviceScaleFactor) {
+            //this.position.copyFrom(this._poseControlledCamera.position);
+            //this.rotationQuaternion.copyFrom(this._poseControlledCamera.rotationQuaternion);
+            //this.deviceScaleFactor = this._poseControlledCamera.deviceScaleFactor;
+            //}
             var pose: GamepadPose = this.vrGamepad.pose;
             var pose: GamepadPose = this.vrGamepad.pose;
             this.updateFromDevice(pose);
             this.updateFromDevice(pose);
 
 
@@ -84,38 +87,65 @@ module BABYLON {
                     this._calculatedPosition.addInPlace(this.position);
                     this._calculatedPosition.addInPlace(this.position);
 
 
                     // scale the position using the scale factor, add the device's position
                     // scale the position using the scale factor, add the device's position
-                    if (this._poseControlledCamera) {
+                    /*if (this._poseControlledCamera) {
                         // this allows total positioning freedom - the device, the camera and the mesh can be individually controlled.
                         // this allows total positioning freedom - the device, the camera and the mesh can be individually controlled.
                         this._calculatedPosition.addInPlace(this._poseControlledCamera.position);
                         this._calculatedPosition.addInPlace(this._poseControlledCamera.position);
-                    }
+                    }*/
                 }
                 }
                 if (poseData.orientation) {
                 if (poseData.orientation) {
                     this.deviceRotationQuaternion.copyFromFloats(this.rawPose.orientation[0], this.rawPose.orientation[1], -this.rawPose.orientation[2], -this.rawPose.orientation[3]);
                     this.deviceRotationQuaternion.copyFromFloats(this.rawPose.orientation[0], this.rawPose.orientation[1], -this.rawPose.orientation[2], -this.rawPose.orientation[3]);
-                    if (this._mesh && this._mesh.getScene().useRightHandedSystem) {
-                        this.deviceRotationQuaternion.z *= -1;
-                        this.deviceRotationQuaternion.w *= -1;
+                    if (this._mesh) {
+                        if (this._mesh.getScene().useRightHandedSystem) {
+                            this.deviceRotationQuaternion.z *= -1;
+                            this.deviceRotationQuaternion.w *= -1;
+                        } else {
+                            this.deviceRotationQuaternion.multiplyToRef(this._leftHandSystemQuaternion, this.deviceRotationQuaternion);
+                        }
                     }
                     }
 
 
                     // if the camera is set, rotate to the camera's rotation
                     // if the camera is set, rotate to the camera's rotation
-                    this.rotationQuaternion.multiplyToRef(this.deviceRotationQuaternion, this._calculatedRotation);
-                    if (this._poseControlledCamera) {
-                        this._calculatedRotation.multiplyToRef(this._poseControlledCamera.rotationQuaternion, this._calculatedRotation);
-                    }
+                    this.deviceRotationQuaternion.multiplyToRef(this.rotationQuaternion, this._calculatedRotation);
+
+                    /*if (this._poseControlledCamera) {
+                        Matrix.ScalingToRef(1, 1, 1, Tmp.Matrix[1]);
+                        this._calculatedRotation.toRotationMatrix(Tmp.Matrix[0]);
+                        Matrix.TranslationToRef(this._calculatedPosition.x, this._calculatedPosition.y, this._calculatedPosition.z, Tmp.Matrix[2]);
+
+                        //Matrix.Identity().multiplyToRef(Tmp.Matrix[1], Tmp.Matrix[4]);
+                        Tmp.Matrix[1].multiplyToRef(Tmp.Matrix[0], Tmp.Matrix[5]);
+
+                        this._poseControlledCamera.getWorldMatrix().getTranslationToRef(Tmp.Vector3[0])
+
+                        Matrix.ComposeToRef(new Vector3(this.deviceScaleFactor, this.deviceScaleFactor, this.deviceScaleFactor), this._poseControlledCamera.rotationQuaternion, Tmp.Vector3[0], Tmp.Matrix[4]);
+                        Tmp.Matrix[5].multiplyToRef(Tmp.Matrix[2], Tmp.Matrix[1]);
+
+                        Tmp.Matrix[1].multiplyToRef(Tmp.Matrix[4], Tmp.Matrix[2]);
+                        Tmp.Matrix[2].decompose(Tmp.Vector3[0], this._calculatedRotation, this._calculatedPosition);
+
+                    }*/
                 }
                 }
             }
             }
         }
         }
 
 
 
 
         public attachToMesh(mesh: AbstractMesh) {
         public attachToMesh(mesh: AbstractMesh) {
+            if (this._mesh) {
+                this._mesh.parent = undefined;
+            }
             this._mesh = mesh;
             this._mesh = mesh;
+            if (this._poseControlledCamera) {
+                this._mesh.parent = this._poseControlledCamera;
+            }
             if (!this._mesh.rotationQuaternion) {
             if (!this._mesh.rotationQuaternion) {
                 this._mesh.rotationQuaternion = new Quaternion();
                 this._mesh.rotationQuaternion = new Quaternion();
             }
             }
         }
         }
 
 
-        public attachToPoseControlledCamera(camera: PoseControlled) {
+        public attachToPoseControlledCamera(camera: TargetCamera) {
             this._poseControlledCamera = camera;
             this._poseControlledCamera = camera;
-            this.deviceScaleFactor = camera.deviceScaleFactor;
+            if (this._mesh) {
+                this._mesh.parent = this._poseControlledCamera;
+            }
         }
         }
 
 
         public detachMesh() {
         public detachMesh() {
@@ -136,7 +166,6 @@ module BABYLON {
 
 
         public onTriggerStateChangedObservable = new Observable<ExtendedGamepadButton>();
         public onTriggerStateChangedObservable = new Observable<ExtendedGamepadButton>();
 
 
-
         public onMainButtonStateChangedObservable = new Observable<ExtendedGamepadButton>();
         public onMainButtonStateChangedObservable = new Observable<ExtendedGamepadButton>();
 
 
         public onSecondaryButtonStateChangedObservable = new Observable<ExtendedGamepadButton>();
         public onSecondaryButtonStateChangedObservable = new Observable<ExtendedGamepadButton>();
@@ -176,6 +205,8 @@ module BABYLON {
 
 
         protected abstract handleButtonChange(buttonIdx: number, value: ExtendedGamepadButton, changes: GamepadButtonChanges);
         protected abstract handleButtonChange(buttonIdx: number, value: ExtendedGamepadButton, changes: GamepadButtonChanges);
 
 
+        public abstract initControllerMesh(scene: Scene)
+
         private _setButtonValue(newState: ExtendedGamepadButton, currentState: ExtendedGamepadButton, buttonIndex: number) {
         private _setButtonValue(newState: ExtendedGamepadButton, currentState: ExtendedGamepadButton, buttonIndex: number) {
             if (!currentState) {
             if (!currentState) {
                 this._buttons[buttonIndex] = {
                 this._buttons[buttonIndex] = {
@@ -225,6 +256,27 @@ module BABYLON {
             this.controllerType = PoseEnabledControllerType.OCULUS;
             this.controllerType = PoseEnabledControllerType.OCULUS;
         }
         }
 
 
+        public initControllerMesh(scene: Scene) {
+
+            let meshName = this.hand === 'right' ? 'RightTouch.babylon' : 'LeftTouch.babylon';
+            SceneLoader.ImportMesh("", "http://cdn.babylonjs.com/models/", meshName, scene, (newMeshes) => {
+                /*
+                Parent Mesh name: oculus_touch_left
+                - body
+                - trigger
+                - thumbstick
+                - grip
+                - button_y 
+                - button_x
+                - button_enter
+                */
+
+                var mesh = newMeshes[7];
+                this.attachToMesh(mesh);
+            });
+        }
+
+
         // helper getters for left and right hand.
         // helper getters for left and right hand.
         public get onAButtonStateChangedObservable() {
         public get onAButtonStateChangedObservable() {
             if (this.hand === 'right') {
             if (this.hand === 'right') {
@@ -300,6 +352,26 @@ module BABYLON {
             this.controllerType = PoseEnabledControllerType.VIVE;
             this.controllerType = PoseEnabledControllerType.VIVE;
         }
         }
 
 
+        public initControllerMesh(scene: Scene) {
+            SceneLoader.ImportMesh("", "http://cdn.babylonjs.com/models/", "ViveWand.babylon", scene, (newMeshes) => {
+                /*
+                Parent Mesh name: ViveWand
+                - body
+                - r_gripper
+                - l_gripper
+                - menu_button
+                - system_button
+                - trackpad
+                - trigger
+                - LED
+                */
+
+                var mesh = newMeshes[1];
+                this.attachToMesh(mesh);
+            });
+        }
+
+
         public get onLeftButtonStateChangedObservable() {
         public get onLeftButtonStateChangedObservable() {
             return this.onMainButtonStateChangedObservable;
             return this.onMainButtonStateChangedObservable;
         }
         }

+ 14 - 0
src/Tools/babylon.observable.ts

@@ -154,6 +154,20 @@
 
 
             return result;
             return result;
         }
         }
+
+        /**
+         * Does this observable handles observer registered with a given mask
+         * @param {number} trigger - the mask to be tested
+         * @return {boolean} whether or not one observer registered with the given mask is handeled 
+        **/
+        public hasSpecificMask(mask: number = -1): boolean {
+            for (var obs of this._observers) {
+                if (obs.mask & mask && obs.mask === mask) {
+                    return true;
+                }
+            }
+            return false;
+        }
     }
     }
 
 
 }
 }

+ 5 - 0
src/Tools/babylon.smartArray.ts

@@ -48,6 +48,11 @@
             this._duplicateId++;
             this._duplicateId++;
         }
         }
 
 
+        public dispose(): void {
+            this.reset();
+            this.data.length = 0;
+        }
+
         public concat(array: any): void {
         public concat(array: any): void {
             if (array.length === 0) {
             if (array.length === 0) {
                 return;
                 return;

+ 12 - 0
src/Tools/babylon.tools.ts

@@ -1184,6 +1184,8 @@
      * For count you first have to call fetchNewFrame() to notify the start of a new frame to monitor, then call addCount() how many time required to increment the count value you monitor.
      * For count you first have to call fetchNewFrame() to notify the start of a new frame to monitor, then call addCount() how many time required to increment the count value you monitor.
      */
      */
     export class PerfCounter {
     export class PerfCounter {
+        public static Enabled = true;
+
         /**
         /**
          * Returns the smallest value ever
          * Returns the smallest value ever
          */
          */
@@ -1253,6 +1255,9 @@
          * @param fetchResult true when it's the last time in the frame you add to the counter and you wish to update the statistics properties (min/max/average), false if you only want to update statistics.
          * @param fetchResult true when it's the last time in the frame you add to the counter and you wish to update the statistics properties (min/max/average), false if you only want to update statistics.
          */
          */
         public addCount(newCount: number, fetchResult: boolean) {
         public addCount(newCount: number, fetchResult: boolean) {
+            if (!PerfCounter.Enabled) {
+                return;
+            }
             this._current += newCount;
             this._current += newCount;
             if (fetchResult) {
             if (fetchResult) {
                 this._fetchResult();
                 this._fetchResult();
@@ -1263,6 +1268,9 @@
          * Start monitoring this performance counter
          * Start monitoring this performance counter
          */
          */
         public beginMonitoring() {
         public beginMonitoring() {
+            if (!PerfCounter.Enabled) {
+                return;
+            }
             this._startMonitoringTime = Tools.Now;
             this._startMonitoringTime = Tools.Now;
         }
         }
 
 
@@ -1271,6 +1279,10 @@
          * @param newFrame true by default to fetch the result and monitor a new frame, if false the time monitored will be added to the current frame counter
          * @param newFrame true by default to fetch the result and monitor a new frame, if false the time monitored will be added to the current frame counter
          */
          */
         public endMonitoring(newFrame: boolean = true) {
         public endMonitoring(newFrame: boolean = true) {
+            if (!PerfCounter.Enabled) {
+                return;
+            }
+                        
             if (newFrame) {
             if (newFrame) {
                 this.fetchNewFrame();
                 this.fetchNewFrame();
             }
             }

+ 16 - 4
src/babylon.engine.ts

@@ -190,6 +190,7 @@
         limitDeviceRatio?: number;
         limitDeviceRatio?: number;
         autoEnableWebVR?: boolean;
         autoEnableWebVR?: boolean;
         disableWebGL2Support?: boolean;
         disableWebGL2Support?: boolean;
+        audioEngine?: boolean;
     }
     }
 
 
     /**
     /**
@@ -421,6 +422,7 @@
         public isPointerLock = false;
         public isPointerLock = false;
         public cullBackFaces = true;
         public cullBackFaces = true;
         public renderEvenInBackground = true;
         public renderEvenInBackground = true;
+        public preventCacheWipeBetweenFrames = false;
         // To enable/disable IDB support and avoid XHR on .manifest
         // To enable/disable IDB support and avoid XHR on .manifest
         public enableOfflineSupport = true;
         public enableOfflineSupport = true;
         public scenes = new Array<Scene>();
         public scenes = new Array<Scene>();
@@ -550,6 +552,10 @@
                 options.preserveDrawingBuffer = false;
                 options.preserveDrawingBuffer = false;
             }
             }
 
 
+            if (options.audioEngine === undefined) {
+                options.audioEngine = true;
+            }
+
             // GL
             // GL
             if (!options.disableWebGL2Support) {
             if (!options.disableWebGL2Support) {
                 try {
                 try {
@@ -751,7 +757,7 @@
             document.addEventListener("mozpointerlockchange", this._onPointerLockChange, false);
             document.addEventListener("mozpointerlockchange", this._onPointerLockChange, false);
             document.addEventListener("webkitpointerlockchange", this._onPointerLockChange, false);
             document.addEventListener("webkitpointerlockchange", this._onPointerLockChange, false);
 
 
-            if (AudioEngine && !Engine.audioEngine) {
+            if (options.audioEngine && AudioEngine && !Engine.audioEngine) {
                 Engine.audioEngine = new AudioEngine();
                 Engine.audioEngine = new AudioEngine();
             }
             }
 
 
@@ -1126,10 +1132,13 @@
          *   });
          *   });
          */
          */
         public resize(): void {
         public resize(): void {
-            var width = navigator.isCocoonJS ? window.innerWidth : this._renderingCanvas.clientWidth;
-            var height = navigator.isCocoonJS ? window.innerHeight : this._renderingCanvas.clientHeight;
+            // We're not resizing the size of the canvas while in VR mode & presenting
+            if (!(this._vrDisplayEnabled && this._vrDisplayEnabled.isPresenting)) {
+                var width = navigator.isCocoonJS ? window.innerWidth : this._renderingCanvas.clientWidth;
+                var height = navigator.isCocoonJS ? window.innerHeight : this._renderingCanvas.clientHeight;
 
 
-            this.setSize(width / this._hardwareScalingLevel, height / this._hardwareScalingLevel);
+                this.setSize(width / this._hardwareScalingLevel, height / this._hardwareScalingLevel);
+            }
         }
         }
 
 
         /**
         /**
@@ -2057,6 +2066,9 @@
 
 
         // Textures
         // Textures
         public wipeCaches(): void {
         public wipeCaches(): void {
+            if (this.preventCacheWipeBetweenFrames) {
+                return;
+            }
             this.resetTextureCache();
             this.resetTextureCache();
             this._currentEffect = null;
             this._currentEffect = null;
 
 

+ 7 - 0
src/babylon.node.ts

@@ -277,6 +277,13 @@ module BABYLON {
             return results;
             return results;
         }
         }
 
 
+        /**
+         * Get all direct children of this node.
+        */
+        public getChildren(predicate?: (node: Node) => boolean): Node[] {
+            return this.getDescendants(true, predicate);
+        }
+
         public _setReady(state: boolean): void {
         public _setReady(state: boolean): void {
             if (state === this._isReady) {
             if (state === this._isReady) {
                 return;
                 return;

+ 346 - 77
src/babylon.scene.ts

@@ -3,12 +3,47 @@
         dispose(): void;
         dispose(): void;
     }
     }
 
 
+    class ClickInfo {
+        private _singleClick = false;
+        private _doubleClick = false;
+        private _hasSwiped = false;
+        private _ignore = false;
+
+        public get singleClick(): boolean {
+            return this._singleClick;
+        }
+        public get doubleClick(): boolean {
+            return this._doubleClick;
+        }
+        public get hasSwiped(): boolean{
+            return this._hasSwiped;
+        }
+        public get ignore(): boolean{
+            return this._ignore;
+        }
+
+        public set singleClick(b: boolean) {
+            this._singleClick = b;
+        }
+        public set doubleClick(b: boolean) {
+            this._doubleClick = b;
+        }
+        public set hasSwiped(b: boolean) {
+            this._hasSwiped = b;
+        }
+        public set ignore(b: boolean) {
+            this._ignore = b;
+        }
+    }
+
     export class PointerEventTypes {
     export class PointerEventTypes {
         static _POINTERDOWN = 0x01;
         static _POINTERDOWN = 0x01;
         static _POINTERUP = 0x02;
         static _POINTERUP = 0x02;
         static _POINTERMOVE = 0x04;
         static _POINTERMOVE = 0x04;
         static _POINTERWHEEL = 0x08;
         static _POINTERWHEEL = 0x08;
         static _POINTERPICK = 0x10;
         static _POINTERPICK = 0x10;
+        static _POINTERTAP = 0x20;
+        static _POINTERDOUBLETAP = 0x40;
 
 
         public static get POINTERDOWN(): number {
         public static get POINTERDOWN(): number {
             return PointerEventTypes._POINTERDOWN;
             return PointerEventTypes._POINTERDOWN;
@@ -29,6 +64,14 @@
         public static get POINTERPICK(): number {
         public static get POINTERPICK(): number {
             return PointerEventTypes._POINTERPICK;
             return PointerEventTypes._POINTERPICK;
         }
         }
+        
+        public static get POINTERTAP(): number {
+            return PointerEventTypes._POINTERTAP;
+        }
+
+        public static get POINTERDOUBLETAP(): number {
+            return PointerEventTypes._POINTERDOUBLETAP;
+        }
     }
     }
 
 
     export class PointerInfoBase {
     export class PointerInfoBase {
@@ -324,13 +367,34 @@
             return new Vector2(this._unTranslatedPointerX, this._unTranslatedPointerY);
             return new Vector2(this._unTranslatedPointerX, this._unTranslatedPointerY);
         }
         }
 
 
+        public static DragMovementThreshold = 10; // in pixels
+        public static LongPressDelay = 500; // in milliseconds
+        public static DoubleClickDelay = 300; // in milliseconds
+        public static ExclusiveDoubleClickMode = false; // If you need to check double click without raising a single click at first click, enable this flag
+
+        private _initClickEvent: (obs1: Observable<PointerInfoPre>, obs2: Observable<PointerInfo>, evt: PointerEvent, cb: (clickInfo: ClickInfo, pickResult: PointerInfo) => void) => void;
+        private _initActionManager: (act: ActionManager, clickInfo: ClickInfo) => ActionManager;
+        private _delayedSimpleClick: (btn: number, clickInfo: ClickInfo, cb: (clickInfo: ClickInfo, pickResult: PointerInfo) => void) => void;
+        private _delayedSimpleClickTimeout;
+        private _previousDelayedSimpleClickTimeout;
+        private _meshPickProceed = false;
+
+        private _previousButtonPressed;
+        private _previousHasSwiped = false;
+        private _currentPickResult = null;
+        private _previousPickResult = null;
+        private _isButtonPressed = false;
+        private _doubleClickOccured = false;
+
         public cameraToUseForPointers: Camera = null; // Define this parameter if you are using multiple cameras and you want to specify which one should be used for pointer position
         public cameraToUseForPointers: Camera = null; // Define this parameter if you are using multiple cameras and you want to specify which one should be used for pointer position
         private _pointerX: number;
         private _pointerX: number;
         private _pointerY: number;
         private _pointerY: number;
         private _unTranslatedPointerX: number;
         private _unTranslatedPointerX: number;
         private _unTranslatedPointerY: number;
         private _unTranslatedPointerY: number;
         private _startingPointerPosition = new Vector2(0, 0);
         private _startingPointerPosition = new Vector2(0, 0);
+        private _previousStartingPointerPosition = new Vector2(0, 0);
         private _startingPointerTime = 0;
         private _startingPointerTime = 0;
+        private _previousStartingPointerTime = 0;
         // Mirror
         // Mirror
         public _mirroredCameraPosition: Vector3;
         public _mirroredCameraPosition: Vector3;
 
 
@@ -549,6 +613,7 @@
         private _uniqueIdCounter = 0;
         private _uniqueIdCounter = 0;
 
 
         private _pickedDownMesh: AbstractMesh;
         private _pickedDownMesh: AbstractMesh;
+        private _pickedUpMesh: AbstractMesh;
         private _pickedDownSprite: Sprite;
         private _pickedDownSprite: Sprite;
         private _externalData: StringDictionary<Object>;
         private _externalData: StringDictionary<Object>;
         private _uid: string;
         private _uid: string;
@@ -779,6 +844,136 @@
         * @param attachMove defines if you want to attach events to pointermove
         * @param attachMove defines if you want to attach events to pointermove
         */
         */
         public attachControl(attachUp = true, attachDown = true, attachMove = true) {
         public attachControl(attachUp = true, attachDown = true, attachMove = true) {
+            this._initActionManager = (act: ActionManager, clickInfo: ClickInfo): ActionManager => {
+                if (!this._meshPickProceed) {
+                    let pickResult = this.pick(this._unTranslatedPointerX, this._unTranslatedPointerY, this.pointerDownPredicate, false, this.cameraToUseForPointers);
+                    this._currentPickResult = pickResult;
+                    act = (pickResult.hit && pickResult.pickedMesh) ? pickResult.pickedMesh.actionManager : null;
+                    this._meshPickProceed = true;
+                }
+                return act;
+            };
+
+            this._delayedSimpleClick = (btn: number, clickInfo: ClickInfo, cb: (clickInfo: ClickInfo, pickResult: PointerInfo) => void) => {
+                // double click delay is over and that no double click has been raised since, or the 2 consecutive keys pressed are different
+                if ((new Date().getTime() - this._previousStartingPointerTime > Scene.DoubleClickDelay && !this._doubleClickOccured) ||
+                btn !== this._previousButtonPressed ) {
+                    this._doubleClickOccured = false;
+                    clickInfo.singleClick = true;
+                    clickInfo.ignore = false;
+                    cb(clickInfo, this._currentPickResult);
+                }
+            }
+
+            this._initClickEvent = (obs1: Observable<PointerInfoPre>, obs2: Observable<PointerInfo>, evt: PointerEvent, cb: (clickInfo: ClickInfo, pickResult: PointerInfo) => void): void => {
+                    let clickInfo = new ClickInfo();
+                    this._currentPickResult = null;
+                    let act;
+
+                    let checkPicking = obs1.hasSpecificMask(PointerEventTypes.POINTERPICK) || obs2.hasSpecificMask(PointerEventTypes.POINTERPICK)
+                                    || obs1.hasSpecificMask(PointerEventTypes.POINTERTAP) || obs2.hasSpecificMask(PointerEventTypes.POINTERTAP)
+                                    || obs1.hasSpecificMask(PointerEventTypes.POINTERDOUBLETAP) || obs2.hasSpecificMask(PointerEventTypes.POINTERDOUBLETAP);
+                    if (!checkPicking && ActionManager.HasPickTriggers) {
+                        act = this._initActionManager(act, clickInfo);
+                        if (act)
+                            checkPicking = act.hasPickTriggers;
+                    }
+                    if (checkPicking) {
+                        let btn = evt.button;
+                        clickInfo.hasSwiped = Math.abs(this._startingPointerPosition.x - this._pointerX) > Scene.DragMovementThreshold ||
+                                              Math.abs(this._startingPointerPosition.y - this._pointerY) > Scene.DragMovementThreshold;
+
+                        if (!clickInfo.hasSwiped) {
+                            let checkSingleClickImmediately = !Scene.ExclusiveDoubleClickMode;
+
+                            if (!checkSingleClickImmediately) {
+                                checkSingleClickImmediately = !obs1.hasSpecificMask(PointerEventTypes.POINTERDOUBLETAP) &&
+                                                              !obs2.hasSpecificMask(PointerEventTypes.POINTERDOUBLETAP);
+
+                                if (checkSingleClickImmediately && !ActionManager.HasSpecificTrigger(ActionManager.OnDoublePickTrigger)) {
+                                    act = this._initActionManager(act, clickInfo);
+                                    if (act)
+                                        checkSingleClickImmediately = !act.hasSpecificTrigger(ActionManager.OnDoublePickTrigger);
+                                }
+                            }
+
+                            if (checkSingleClickImmediately) {
+                                // single click detected if double click delay is over or two different successive keys pressed without exclusive double click or no double click required
+                                if (new Date().getTime() - this._previousStartingPointerTime > Scene.DoubleClickDelay ||
+                                    btn !== this._previousButtonPressed ) {
+                                        clickInfo.singleClick = true;
+                                        cb(clickInfo, this._currentPickResult);
+                                }
+                            }
+                            // at least one double click is required to be check and exclusive double click is enabled
+                            else {
+                                // wait that no double click has been raised during the double click delay
+                                this._previousDelayedSimpleClickTimeout = this._delayedSimpleClickTimeout;
+                                this._delayedSimpleClickTimeout = window.setTimeout(this._delayedSimpleClick.bind(this, btn, clickInfo, cb), Scene.DoubleClickDelay);
+                            }
+
+                            let checkDoubleClick = obs1.hasSpecificMask(PointerEventTypes.POINTERDOUBLETAP) ||
+                                                   obs2.hasSpecificMask(PointerEventTypes.POINTERDOUBLETAP);
+                            if (!checkDoubleClick && ActionManager.HasSpecificTrigger(ActionManager.OnDoublePickTrigger)){
+                                act = this._initActionManager(act, clickInfo);
+                                if (act)
+                                    checkDoubleClick = act.hasSpecificTrigger(ActionManager.OnDoublePickTrigger);
+                            }
+                            if (checkDoubleClick) {
+                                // two successive keys pressed are equal, double click delay is not over and double click has not just occurred
+                                if (btn === this._previousButtonPressed &&
+                                    new Date().getTime() - this._previousStartingPointerTime < Scene.DoubleClickDelay &&
+                                    !this._doubleClickOccured
+                                ) {
+                                    // pointer has not moved for 2 clicks, it's a double click
+                                    if (!clickInfo.hasSwiped &&
+                                        Math.abs(this._previousStartingPointerPosition.x - this._startingPointerPosition.x) < Scene.DragMovementThreshold &&
+                                        Math.abs(this._previousStartingPointerPosition.y - this._startingPointerPosition.y) < Scene.DragMovementThreshold) {
+                                        this._previousStartingPointerTime = 0;
+                                        this._doubleClickOccured = true;
+                                        clickInfo.doubleClick = true;
+                                        clickInfo.ignore = false;
+                                        if (Scene.ExclusiveDoubleClickMode && this._previousDelayedSimpleClickTimeout && this._previousDelayedSimpleClickTimeout.clearTimeout)
+                                            this._previousDelayedSimpleClickTimeout.clearTimeout();
+                                        this._previousDelayedSimpleClickTimeout = this._delayedSimpleClickTimeout;
+                                        cb(clickInfo, this._currentPickResult);
+                                    }
+                                    // if the two successive clicks are too far, it's just two simple clicks
+                                    else {
+                                        this._doubleClickOccured = false;
+                                        this._previousStartingPointerTime = this._startingPointerTime;
+                                        this._previousStartingPointerPosition.x = this._startingPointerPosition.x;
+                                        this._previousStartingPointerPosition.y = this._startingPointerPosition.y;
+                                        this._previousButtonPressed = btn;
+                                        this._previousHasSwiped = clickInfo.hasSwiped;
+                                        if (Scene.ExclusiveDoubleClickMode){
+                                            if (this._previousDelayedSimpleClickTimeout && this._previousDelayedSimpleClickTimeout.clearTimeout) {
+                                                this._previousDelayedSimpleClickTimeout.clearTimeout();
+                                            }
+                                            this._previousDelayedSimpleClickTimeout = this._delayedSimpleClickTimeout;
+                                            cb(clickInfo, this._previousPickResult);
+                                        }
+                                        else {
+                                            cb(clickInfo, this._currentPickResult);
+                                        }
+                                    }
+                                }
+                                // just the first click of the double has been raised
+                                else {
+                                    this._doubleClickOccured = false;
+                                    this._previousStartingPointerTime = this._startingPointerTime;
+                                    this._previousStartingPointerPosition.x = this._startingPointerPosition.x;
+                                    this._previousStartingPointerPosition.y = this._startingPointerPosition.y;
+                                    this._previousButtonPressed = btn;
+                                    this._previousHasSwiped = clickInfo.hasSwiped;
+                                }
+                            }
+                        }
+                    }
+                    clickInfo.ignore = true;
+                    cb(clickInfo, this._currentPickResult);
+            };
+
             var spritePredicate = (sprite: Sprite): boolean => {
             var spritePredicate = (sprite: Sprite): boolean => {
                 return sprite.isPickable && sprite.actionManager && sprite.actionManager.hasPointerTriggers;
                 return sprite.isPickable && sprite.actionManager && sprite.actionManager.hasPointerTriggers;
             };
             };
@@ -855,6 +1050,10 @@
             };
             };
 
 
             this._onPointerDown = (evt: PointerEvent) => {
             this._onPointerDown = (evt: PointerEvent) => {
+                this._isButtonPressed = true;
+                this._pickedDownMesh = null;
+                this._meshPickProceed = false;
+
                 this._updatePointerPosition(evt);
                 this._updatePointerPosition(evt);
 
 
                 // PreObservable support
                 // PreObservable support
@@ -887,40 +1086,39 @@
 
 
                 if (pickResult.hit && pickResult.pickedMesh) {
                 if (pickResult.hit && pickResult.pickedMesh) {
                     this._pickedDownMesh = pickResult.pickedMesh;
                     this._pickedDownMesh = pickResult.pickedMesh;
-                    if (pickResult.pickedMesh.actionManager) {
-                        if (pickResult.pickedMesh.actionManager.hasPickTriggers) {
+                    var actionManager = pickResult.pickedMesh.actionManager;
+                    if (actionManager) {
+                        if (actionManager.hasPickTriggers) {
+                            actionManager.processTrigger(ActionManager.OnPickDownTrigger, ActionEvent.CreateNew(pickResult.pickedMesh, evt));
                             switch (evt.button) {
                             switch (evt.button) {
                                 case 0:
                                 case 0:
-                                    pickResult.pickedMesh.actionManager.processTrigger(ActionManager.OnLeftPickTrigger, ActionEvent.CreateNew(pickResult.pickedMesh, evt));
+                                    actionManager.processTrigger(ActionManager.OnLeftPickTrigger, ActionEvent.CreateNew(pickResult.pickedMesh, evt));
                                     break;
                                     break;
                                 case 1:
                                 case 1:
-                                    pickResult.pickedMesh.actionManager.processTrigger(ActionManager.OnCenterPickTrigger, ActionEvent.CreateNew(pickResult.pickedMesh, evt));
+                                    actionManager.processTrigger(ActionManager.OnCenterPickTrigger, ActionEvent.CreateNew(pickResult.pickedMesh, evt));
                                     break;
                                     break;
                                 case 2:
                                 case 2:
-                                    pickResult.pickedMesh.actionManager.processTrigger(ActionManager.OnRightPickTrigger, ActionEvent.CreateNew(pickResult.pickedMesh, evt));
+                                    actionManager.processTrigger(ActionManager.OnRightPickTrigger, ActionEvent.CreateNew(pickResult.pickedMesh, evt));
                                     break;
                                     break;
                             }
                             }
-                            if (pickResult.pickedMesh.actionManager) {
-                                pickResult.pickedMesh.actionManager.processTrigger(ActionManager.OnPickDownTrigger, ActionEvent.CreateNew(pickResult.pickedMesh, evt));
-                            }
                         }
                         }
 
 
-                        if (pickResult.pickedMesh.actionManager && pickResult.pickedMesh.actionManager.hasSpecificTrigger(ActionManager.OnLongPressTrigger)) {
-                            var that = this;
-                            window.setTimeout(function () {
-                                var pickResult = that.pick(that._unTranslatedPointerX, that._unTranslatedPointerY,
-                                    (mesh: AbstractMesh): boolean => mesh.isPickable && mesh.isVisible && mesh.isReady() && mesh.actionManager && mesh.actionManager.hasSpecificTrigger(ActionManager.OnLongPressTrigger),
-                                    false, that.cameraToUseForPointers);
+                        if (actionManager.hasSpecificTrigger(ActionManager.OnLongPressTrigger)) {
+                            window.setTimeout((function () {
+                                var pickResult = this.pick(this._unTranslatedPointerX, this._unTranslatedPointerY,
+                                    (mesh: AbstractMesh): boolean => mesh.isPickable && mesh.isVisible && mesh.isReady() && mesh.actionManager && mesh.actionManager.hasSpecificTrigger(ActionManager.OnLongPressTrigger) && mesh == this._pickedDownMesh,
+                                    false, this.cameraToUseForPointers);
 
 
                                 if (pickResult.hit && pickResult.pickedMesh) {
                                 if (pickResult.hit && pickResult.pickedMesh) {
-                                    if (pickResult.pickedMesh.actionManager) {
-                                        if (that._startingPointerTime !== 0 && ((new Date().getTime() - that._startingPointerTime) > ActionManager.LongPressDelay) && (Math.abs(that._startingPointerPosition.x - that._pointerX) < ActionManager.DragMovementThreshold && Math.abs(that._startingPointerPosition.y - that._pointerY) < ActionManager.DragMovementThreshold)) {
-                                            that._startingPointerTime = 0;
-                                            pickResult.pickedMesh.actionManager.processTrigger(ActionManager.OnLongPressTrigger, ActionEvent.CreateNew(pickResult.pickedMesh, evt));
-                                        }
+                                    if (this._isButtonPressed &&
+                                        ((new Date().getTime() - this._startingPointerTime) > Scene.LongPressDelay) &&
+                                        (Math.abs(this._startingPointerPosition.x - this._pointerX) < Scene.DragMovementThreshold &&
+                                         Math.abs(this._startingPointerPosition.y - this._pointerY) < Scene.DragMovementThreshold)) {
+                                            this._startingPointerTime = 0;
+                                            actionManager.processTrigger(ActionManager.OnLongPressTrigger, ActionEvent.CreateNew(pickResult.pickedMesh, evt));
                                     }
                                     }
                                 }
                                 }
-                            }, ActionManager.LongPressDelay);
+                            }).bind(this), Scene.LongPressDelay);
                         }
                         }
                     }
                     }
                 }
                 }
@@ -963,85 +1161,140 @@
             };
             };
 
 
             this._onPointerUp = (evt: PointerEvent) => {
             this._onPointerUp = (evt: PointerEvent) => {
+                this._isButtonPressed = false;
+                this._pickedUpMesh = null;
+                this._meshPickProceed = false;
+
                 this._updatePointerPosition(evt);
                 this._updatePointerPosition(evt);
 
 
-                // PreObservable support
-                if (this.onPrePointerObservable.hasObservers()) {
-                    let type = PointerEventTypes.POINTERUP;
-                    let pi = new PointerInfoPre(type, evt, this._unTranslatedPointerX, this._unTranslatedPointerY);
-                    this.onPrePointerObservable.notifyObservers(pi, type);
-                    if (pi.skipOnPointerObservable) {
-                        return;
+                this._initClickEvent(this.onPrePointerObservable, this.onPointerObservable,  evt, (function(clickInfo, pickResult){
+                    // PreObservable support
+                    if (this.onPrePointerObservable.hasObservers()) {
+                        if (!clickInfo.ignore) {
+                            if (!clickInfo.hasSwiped) {
+                                if (clickInfo.singleClick && this.onPrePointerObservable.hasSpecificMask(PointerEventTypes.POINTERTAP)) {
+                                    let type = PointerEventTypes.POINTERTAP;
+                                    let pi = new PointerInfoPre(type, evt, this._unTranslatedPointerX, this._unTranslatedPointerY);
+                                    this.onPrePointerObservable.notifyObservers(pi, type);
+                                    if (pi.skipOnPointerObservable) {
+                                        return;
+                                    }
+                                }
+                                if (clickInfo.doubleClick && this.onPrePointerObservable.hasSpecificMask(PointerEventTypes.POINTERDOUBLETAP)) {
+                                    let type = PointerEventTypes.POINTERDOUBLETAP;
+                                    let pi = new PointerInfoPre(type, evt, this._unTranslatedPointerX, this._unTranslatedPointerY);
+                                    this.onPrePointerObservable.notifyObservers(pi, type);
+                                    if (pi.skipOnPointerObservable) {
+                                        return;
+                                    }
+                                }
+                            }
+                        }
+                        else {
+                            let type = PointerEventTypes.POINTERUP;
+                            let pi = new PointerInfoPre(type, evt, this._unTranslatedPointerX, this._unTranslatedPointerY);
+                            this.onPrePointerObservable.notifyObservers(pi, type);
+                            if (pi.skipOnPointerObservable) {
+                                return;
+                            }
+                        }
                     }
                     }
-                }
 
 
-                if (!this.cameraToUseForPointers && !this.activeCamera) {
-                    return;
-                }
+                    if (!this.cameraToUseForPointers && !this.activeCamera) {
+                        return;
+                    }
 
 
-                if (!this.pointerUpPredicate) {
-                    this.pointerUpPredicate = (mesh: AbstractMesh): boolean => {
-                        return mesh.isPickable && mesh.isVisible && mesh.isReady();
-                    };
-                }
+                    if (!this.pointerUpPredicate) {
+                        this.pointerUpPredicate = (mesh: AbstractMesh): boolean => {
+                            return mesh.isPickable && mesh.isVisible && mesh.isReady();
+                        };
+                    }
 
 
-                // Meshes
-                var pickResult = this.pick(this._unTranslatedPointerX, this._unTranslatedPointerY, this.pointerUpPredicate, false, this.cameraToUseForPointers);
+                    // Meshes
+                    if (!this._meshPickProceed && ActionManager.HasTriggers) {
+                        this._initActionManager(null, clickInfo);
+                    }
+                    if (!pickResult) {
+                        pickResult = this._currentPickResult;
+                    }
 
 
-                if (pickResult.hit && pickResult.pickedMesh) {
-                    if (this._pickedDownMesh != null && pickResult.pickedMesh == this._pickedDownMesh) {
-                        if (this.onPointerPick) {
-                            this.onPointerPick(evt, pickResult);
-                        }
-                        if (this.onPointerObservable.hasObservers()) {
-                            let type = PointerEventTypes.POINTERPICK;
-                            let pi = new PointerInfo(type, evt, pickResult);
-                            this.onPointerObservable.notifyObservers(pi, type);
+                    if (pickResult && pickResult.pickedMesh) {
+                        this._pickedUpMesh = pickResult.pickedMesh;
+                        if (this._pickedDownMesh === this._pickedUpMesh) {
+                            if (this.onPointerPick) {
+                                this.onPointerPick(evt, pickResult);
+                            }
+                            if (clickInfo.singleClick && !clickInfo.ignore && this.onPointerObservable.hasObservers()) {
+                                let type = PointerEventTypes.POINTERPICK;
+                                let pi = new PointerInfo(type, evt, pickResult);
+                                this.onPointerObservable.notifyObservers(pi, type);
+                            }
                         }
                         }
-                    }
-                    if (pickResult.pickedMesh.actionManager) {
-                        pickResult.pickedMesh.actionManager.processTrigger(ActionManager.OnPickUpTrigger, ActionEvent.CreateNew(pickResult.pickedMesh, evt));
                         if (pickResult.pickedMesh.actionManager) {
                         if (pickResult.pickedMesh.actionManager) {
-                            if (Math.abs(this._startingPointerPosition.x - this._pointerX) < ActionManager.DragMovementThreshold && Math.abs(this._startingPointerPosition.y - this._pointerY) < ActionManager.DragMovementThreshold) {
+                            if (clickInfo.ignore) {
+                                pickResult.pickedMesh.actionManager.processTrigger(ActionManager.OnPickUpTrigger, ActionEvent.CreateNew(pickResult.pickedMesh, evt));
+                            }
+                            if (!clickInfo.hasSwiped && !clickInfo.ignore && clickInfo.singleClick) {
                                 pickResult.pickedMesh.actionManager.processTrigger(ActionManager.OnPickTrigger, ActionEvent.CreateNew(pickResult.pickedMesh, evt));
                                 pickResult.pickedMesh.actionManager.processTrigger(ActionManager.OnPickTrigger, ActionEvent.CreateNew(pickResult.pickedMesh, evt));
                             }
                             }
+                            if (clickInfo.doubleClick && !clickInfo.ignore && pickResult.pickedMesh.actionManager.hasSpecificTrigger(ActionManager.OnDoublePickTrigger)) {
+                                pickResult.pickedMesh.actionManager.processTrigger(ActionManager.OnDoublePickTrigger, ActionEvent.CreateNew(pickResult.pickedMesh, evt));
+                            }
                         }
                         }
                     }
                     }
-                }
-                if (this._pickedDownMesh && this._pickedDownMesh.actionManager && this._pickedDownMesh !== pickResult.pickedMesh) {
-                    this._pickedDownMesh.actionManager.processTrigger(ActionManager.OnPickOutTrigger, ActionEvent.CreateNew(this._pickedDownMesh, evt));
-                }
-
-                if (this.onPointerUp) {
-                    this.onPointerUp(evt, pickResult);
-                }
+                    if (this._pickedDownMesh &&
+                        this._pickedDownMesh.actionManager && 
+                        this._pickedDownMesh.actionManager.hasSpecificTrigger(ActionManager.OnPickOutTrigger) &&
+                        this._pickedDownMesh !== this._pickedUpMesh) {
+                        this._pickedDownMesh.actionManager.processTrigger(ActionManager.OnPickOutTrigger, ActionEvent.CreateNew(this._pickedDownMesh, evt));
+                    }
 
 
-                if (this.onPointerObservable.hasObservers()) {
-                    let type = PointerEventTypes.POINTERUP;
-                    let pi = new PointerInfo(type, evt, pickResult);
-                    this.onPointerObservable.notifyObservers(pi, type);
-                }
+                    if (this.onPointerUp) {
+                        this.onPointerUp(evt, pickResult);
+                    }
 
 
-                this._startingPointerTime = 0;
+                    if (this.onPointerObservable.hasObservers()) {
+                        if (!clickInfo.ignore) {
+                            if (!clickInfo.hasSwiped) {
+                                if (clickInfo.singleClick && this.onPointerObservable.hasSpecificMask(PointerEventTypes.POINTERTAP)) {
+                                    let type = PointerEventTypes.POINTERTAP;
+                                    let pi = new PointerInfo(type, evt, pickResult);
+                                    this.onPointerObservable.notifyObservers(pi, type);
+                                }
+                                if (clickInfo.doubleClick && this.onPointerObservable.hasSpecificMask(PointerEventTypes.POINTERDOUBLETAP)) {
+                                    let type = PointerEventTypes.POINTERDOUBLETAP;
+                                    let pi = new PointerInfo(type, evt, pickResult);
+                                    this.onPointerObservable.notifyObservers(pi, type);
+                                }
+                            }
+                        }
+                        else {
+                            let type = PointerEventTypes.POINTERUP;
+                            let pi = new PointerInfo(type, evt, pickResult);
+                            this.onPointerObservable.notifyObservers(pi, type);
+                        }
+                    }
 
 
-                // Sprites
-                if (this.spriteManagers.length > 0) {
-                    pickResult = this.pickSprite(this._unTranslatedPointerX, this._unTranslatedPointerY, spritePredicate, false, this.cameraToUseForPointers);
+                    // Sprites
+                    if (this.spriteManagers.length > 0) {
+                        pickResult = this.pickSprite(this._unTranslatedPointerX, this._unTranslatedPointerY, spritePredicate, false, this.cameraToUseForPointers);
 
 
-                    if (pickResult.hit && pickResult.pickedSprite) {
-                        if (pickResult.pickedSprite.actionManager) {
-                            pickResult.pickedSprite.actionManager.processTrigger(ActionManager.OnPickUpTrigger, ActionEvent.CreateNewFromSprite(pickResult.pickedSprite, this, evt));
+                        if (pickResult.hit && pickResult.pickedSprite) {
                             if (pickResult.pickedSprite.actionManager) {
                             if (pickResult.pickedSprite.actionManager) {
-                                if (Math.abs(this._startingPointerPosition.x - this._pointerX) < ActionManager.DragMovementThreshold && Math.abs(this._startingPointerPosition.y - this._pointerY) < ActionManager.DragMovementThreshold) {
-                                    pickResult.pickedSprite.actionManager.processTrigger(ActionManager.OnPickTrigger, ActionEvent.CreateNewFromSprite(pickResult.pickedSprite, this, evt));
+                                pickResult.pickedSprite.actionManager.processTrigger(ActionManager.OnPickUpTrigger, ActionEvent.CreateNewFromSprite(pickResult.pickedSprite, this, evt));
+                                if (pickResult.pickedSprite.actionManager) {
+                                    if (Math.abs(this._startingPointerPosition.x - this._pointerX) < Scene.DragMovementThreshold && Math.abs(this._startingPointerPosition.y - this._pointerY) < Scene.DragMovementThreshold) {
+                                        pickResult.pickedSprite.actionManager.processTrigger(ActionManager.OnPickTrigger, ActionEvent.CreateNewFromSprite(pickResult.pickedSprite, this, evt));
+                                    }
                                 }
                                 }
                             }
                             }
                         }
                         }
+                        if (this._pickedDownSprite && this._pickedDownSprite.actionManager && this._pickedDownSprite !== pickResult.pickedSprite) {
+                            this._pickedDownSprite.actionManager.processTrigger(ActionManager.OnPickOutTrigger, ActionEvent.CreateNewFromSprite(this._pickedDownSprite, this, evt));
+                        }
                     }
                     }
-                    if (this._pickedDownSprite && this._pickedDownSprite.actionManager && this._pickedDownSprite !== pickResult.pickedSprite) {
-                        this._pickedDownSprite.actionManager.processTrigger(ActionManager.OnPickOutTrigger, ActionEvent.CreateNewFromSprite(this._pickedDownSprite, this, evt));
-                    }
-                }
+                    this._previousPickResult = this._currentPickResult;
+                }).bind(this));
             };
             };
 
 
             this._onKeyDown = (evt: Event) => {
             this._onKeyDown = (evt: Event) => {
@@ -2682,6 +2935,22 @@
                 this._depthRenderer.dispose();
                 this._depthRenderer.dispose();
             }
             }
 
 
+            // Smart arrays            
+            if (this.activeCamera) {
+                this.activeCamera._activeMeshes.dispose();
+                this.activeCamera = null;
+            }
+            this._activeMeshes.dispose();
+            this._renderingManager.dispose();
+            this._processedMaterials.dispose();
+            this._activeParticleSystems.dispose();
+            this._activeSkeletons.dispose();
+            this._softwareSkinnedMeshes.dispose();
+            this._boundingBoxRenderer.dispose();
+            this._edgesRenderers.dispose();
+            this._meshesForIntersections.dispose();
+            this._toBeDisposed.dispose();
+
             // Debug layer
             // Debug layer
             if (this._debugLayer) {
             if (this._debugLayer) {
                 this._debugLayer.hide();
                 this._debugLayer.hide();

+ 1 - 0
what's new.md

@@ -89,3 +89,4 @@
   - `WorldSpaceCanvas2D`:
   - `WorldSpaceCanvas2D`:
 	- WorldSpaceRenderScale is no longer supported (deprecated because of adaptive feature added).
 	- WorldSpaceRenderScale is no longer supported (deprecated because of adaptive feature added).
 
 
+