Browse Source

Merge remote-tracking branch 'origin/master' into dev_Observable-ActionManager-PointerEvent

yuccai 8 years ago
parent
commit
b2b0022908
100 changed files with 17303 additions and 13267 deletions
  1. 1 0
      Playground/debug.html
  2. 1 0
      Playground/frame.html
  3. 1 0
      Playground/index.html
  4. 2 1
      Playground/scripts/scripts.txt
  5. 21 2
      Tools/Gulp/config.json
  6. BIN
      assets/sounds/explosion.wav
  7. BIN
      assets/sounds/jump.wav
  8. 44 33
      canvas2D/src/Engine/babylon.canvas2d.ts
  9. 4 4
      canvas2D/src/Engine/babylon.ellipse2d.ts
  10. 5 3
      canvas2D/src/Engine/babylon.fontTexture.ts
  11. 28 10
      canvas2D/src/Engine/babylon.group2d.ts
  12. 19 14
      canvas2D/src/Engine/babylon.prim2dBase.ts
  13. 4 4
      canvas2D/src/Engine/babylon.rectangle2d.ts
  14. 5 1
      canvas2D/src/Engine/babylon.renderablePrim2d.ts
  15. 3 3
      canvas2D/src/Engine/babylon.shape2d.ts
  16. 8 2
      canvas2D/src/Engine/babylon.text2d.ts
  17. 10 8
      canvas2D/src/shaders/sprite2d.vertex.fx
  18. 6 5
      canvas2D/src/shaders/text2d.vertex.fx
  19. 29 28
      dist/preview release/babylon.core.js
  20. 6206 6046
      dist/preview release/babylon.d.ts
  21. 39 38
      dist/preview release/babylon.js
  22. 923 220
      dist/preview release/babylon.max.js
  23. 6206 6046
      dist/preview release/babylon.module.d.ts
  24. 39 38
      dist/preview release/babylon.noworker.js
  25. 6 3
      dist/preview release/canvas2D/babylon.canvas2d.d.ts
  26. 114 70
      dist/preview release/canvas2D/babylon.canvas2d.js
  27. 12 12
      dist/preview release/canvas2D/babylon.canvas2d.min.js
  28. 251 251
      dist/preview release/inspector/babylon.inspector.bundle.js
  29. 45 2
      dist/preview release/inspector/babylon.inspector.d.ts
  30. 194 18
      dist/preview release/inspector/babylon.inspector.js
  31. 3 3
      dist/preview release/inspector/babylon.inspector.min.js
  32. 1 1
      dist/preview release/loaders/babylon.glTFFileLoader.js
  33. 2 2
      dist/preview release/loaders/babylon.glTFFileLoader.min.js
  34. 16 0
      dist/preview release/materialsLibrary/babylon.customMaterial.d.ts
  35. 398 0
      dist/preview release/materialsLibrary/babylon.customMaterial.js
  36. 1 0
      dist/preview release/materialsLibrary/babylon.customMaterial.min.js
  37. 21 0
      dist/preview release/materialsLibrary/babylon.shadowOnlyMaterial.d.ts
  38. 209 0
      dist/preview release/materialsLibrary/babylon.shadowOnlyMaterial.js
  39. 1 0
      dist/preview release/materialsLibrary/babylon.shadowOnlyMaterial.min.js
  40. 0 1
      dist/preview release/materialsLibrary/babylon.waterMaterial.d.ts
  41. 0 1
      dist/preview release/materialsLibrary/babylon.waterMaterial.js
  42. 10 1
      dist/preview release/what's new.md
  43. 139 107
      inspector/src/Inspector.ts
  44. 59 0
      inspector/src/adapters/SoundAdapter.ts
  45. 18 0
      inspector/src/properties.ts
  46. 26 0
      inspector/src/tabs/SoundTab.ts
  47. 10 3
      inspector/src/tabs/TabBar.ts
  48. 42 0
      inspector/src/treetools/SoundInteractions.ts
  49. 13 1
      inspector/test/index.js
  50. 1 1
      localDev/index.html
  51. 0 34
      localDev/template/index.js
  52. 6 2
      materialsLibrary/index.html
  53. 1 0
      materialsLibrary/src/custom/Babylon.CustomMaterial.js.map
  54. 398 0
      materialsLibrary/src/custom/babylon.customMaterial.js
  55. 474 0
      materialsLibrary/src/custom/babylon.customMaterial.ts
  56. 240 0
      materialsLibrary/src/shadowOnly/babylon.shadowOnlyMaterial.ts
  57. 50 0
      materialsLibrary/src/shadowOnly/shadowOnly.fragment.fx
  58. 62 0
      materialsLibrary/src/shadowOnly/shadowOnly.vertex.fx
  59. 0 1
      materialsLibrary/src/water/babylon.waterMaterial.ts
  60. 33 23
      src/Bones/babylon.boneIKController.ts
  61. 1 1
      src/Cameras/Inputs/babylon.freecamera.input.gamepad.ts
  62. 79 34
      src/Cameras/VR/babylon.webVRCamera.ts
  63. 1 1
      src/Cameras/babylon.arcRotateCamera.ts
  64. 2 4
      src/Cameras/babylon.camera.ts
  65. 1 2
      src/Cameras/babylon.targetCamera.ts
  66. 11 2
      src/Culling/babylon.boundingBox.ts
  67. 1 1
      src/Culling/babylon.boundingInfo.ts
  68. 12 9
      src/Debug/babylon.debugLayer.ts
  69. 8 0
      src/Culling/babylon.rayHelper.ts
  70. 31 12
      src/Lights/Shadows/babylon.shadowGenerator.ts
  71. 13 2
      src/Loading/babylon.sceneLoader.ts
  72. 2 2
      src/Materials/Textures/babylon.mapTexture.ts
  73. 10 2
      src/Materials/Textures/babylon.videoTexture.ts
  74. 14 4
      src/Materials/babylon.materialHelper.ts
  75. 8 0
      src/Materials/babylon.pbrMaterial.ts
  76. 11 13
      src/Materials/babylon.standardMaterial.ts
  77. 37 3
      src/Math/babylon.math.ts
  78. 3 2
      src/Mesh/babylon.abstractMesh.ts
  79. 1 1
      src/Mesh/babylon.instancedMesh.ts
  80. 1 1
      src/Mesh/babylon.mesh.ts
  81. 51 8
      src/Mesh/babylon.mesh.vertexData.ts
  82. 6 0
      src/Mesh/babylon.vertexBuffer.ts
  83. 3 3
      src/Physics/babylon.physicsImpostor.ts
  84. 1 1
      src/PostProcess/babylon.fxaaPostProcess.ts
  85. 5 1
      src/Shaders/ShadersInclude/bumpFragment.fx
  86. 3 0
      src/Shaders/ShadersInclude/bumpFragmentFunctions.fx
  87. 8 0
      src/Shaders/ShadersInclude/bumpVertex.fx
  88. 5 0
      src/Shaders/ShadersInclude/bumpVertexDeclaration.fx
  89. 16 12
      src/Shaders/ShadersInclude/lightFragment.fx
  90. 1 1
      src/Shaders/ShadersInclude/lightFragmentDeclaration.fx
  91. 57 30
      src/Shaders/ShadersInclude/shadowsFragmentFunctions.fx
  92. 6 0
      src/Shaders/default.vertex.fx
  93. 230 44
      src/Shaders/fxaa.fragment.fx
  94. 7 0
      src/Shaders/pbr.vertex.fx
  95. 10 1
      src/Shaders/shadowMap.fragment.fx
  96. 99 3
      src/Tools/babylon.extendedGamepad.ts
  97. 65 24
      src/Tools/babylon.rectPackingMap.ts
  98. 12 0
      src/Tools/babylon.tools.ts
  99. 11 0
      src/babylon.engine.ts
  100. 0 0
      src/babylon.scene.ts

+ 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.furMaterial.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.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.furMaterial.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.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.furMaterial.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.cloudProceduralTexture.min.js"></script>

+ 2 - 1
Playground/scripts/scripts.txt

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

+ 21 - 2
Tools/Gulp/config.json

@@ -35,7 +35,7 @@
             "../../src/Culling/babylon.boundingBox.js",
             "../../src/Culling/babylon.boundingInfo.js",
             "../../src/Culling/babylon.ray.js",
-            "../../src/Culling/babylon.rayHelper.js",
+            "../../src/Debug/babylon.rayHelper.js",
             "../../src/Mesh/babylon.abstractMesh.js",
             "../../src/Lights/babylon.light.js",
             "../../src/Lights/babylon.pointLight.js",
@@ -243,6 +243,16 @@
         "libraries": [
             {
                 "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"
                 ],
                 "shaderFiles": [
@@ -352,6 +362,12 @@
                     "../../materialsLibrary/src/grid/legacygrid.fragment.fx"
                 ],
                 "output": "babylon.gridMaterial.js"
+            },
+            {
+                "files": [
+                    "../../materialsLibrary/src/custom/babylon.customMaterial.ts"
+                ], 
+                "output": "babylon.customMaterial.js"
             }
         ],
         "build": {
@@ -578,6 +594,7 @@
                     "../../inspector/src/gui/BasicElement.ts",
                     "../../inspector/src/adapters/Adapter.ts",
                     "../../inspector/src/adapters/CameraAdapter.ts",
+                    "../../inspector/src/adapters/SoundAdapter.ts",
                     "../../inspector/src/adapters/TextureAdapter.ts",
                     "../../inspector/src/adapters/Canvas2DAdapter.ts",
                     "../../inspector/src/adapters/LightAdapter.ts",
@@ -597,6 +614,7 @@
                     "../../inspector/src/tabs/Tab.ts",
                     "../../inspector/src/tabs/PropertyTab.ts",
                     "../../inspector/src/tabs/CameraTab.ts",
+                    "../../inspector/src/tabs/SoundTab.ts",
                     "../../inspector/src/tabs/TextureTab.ts",
                     "../../inspector/src/tabs/Canvas2DTab.ts",
                     "../../inspector/src/tabs/LightTab.ts",
@@ -619,6 +637,7 @@
                     "../../inspector/src/treetools/AbstractTreeTool.ts",
                     "../../inspector/src/treetools/BoundingBox.ts",
                     "../../inspector/src/treetools/CameraPOV.ts",
+                    "../../inspector/src/treetools/SoundInteractions.ts",
                     "../../inspector/src/treetools/Checkbox.ts",
                     "../../inspector/src/treetools/DebugArea.ts",
                     "../../inspector/src/treetools/Info.ts",
@@ -636,4 +655,4 @@
             "distOutputDirectory": "/inspector/"
         }
     }
-}
+}

BIN
assets/sounds/explosion.wav


BIN
assets/sounds/jump.wav


+ 44 - 33
canvas2D/src/Engine/babylon.canvas2d.ts

@@ -156,7 +156,7 @@
             this._engine = engine;
             this._renderingSize = new Size(0, 0);
             this._curHWScale = 0;
-            this._canvasLevelScale = new Vector3(1, 1, 1);
+            this._canvasLevelScale = new Vector2(1, 1);
             this._designSize = settings.designSize || null;
             this._designUseHorizAxis = settings.designUseHorizAxis === true;
             if (!this._trackedGroups) {
@@ -359,9 +359,7 @@
                     if (this.isVisible === false) {
                         return;
                     }
-                    let hs = 1 / this.engine.getHardwareScalingLevel();
-                    let localPos = e.localPosition.multiplyByFloats(hs, hs);
-                    this._handlePointerEventForInteraction(e, localPos, s);
+                    this._handlePointerEventForInteraction(e, e.localPosition, s);
                 });
             }
 
@@ -555,7 +553,7 @@
         }
 
         private _updatePointerInfo(eventData: PointerInfoBase, localPosition: Vector2): boolean {
-            let s = this.scale;
+            let s = this._canvasLevelScale.multiplyByFloats(this.scaleX, this.scaleY);
             let pii = this._primPointerInfo;
             pii.cancelBubble = false;
             if (!pii.canvasPointerPos) {
@@ -570,17 +568,20 @@
 
             if (this._isScreenSpace) {
                 var cameraViewport = camera.viewport;
-                var viewport = cameraViewport.toGlobal(engine.getRenderWidth(), engine.getRenderHeight());
+                let renderWidth = engine.getRenderWidth();
+                let renderHeight = engine.getRenderHeight();
+//                console.log(`Render Width: ${renderWidth} Height: ${renderHeight}, localX: ${localPosition.x}, localY: ${localPosition.y}`);
+                var viewport = cameraViewport.toGlobal(renderWidth, renderHeight);
 
                 // Moving coordinates to local viewport world
                 var x = localPosition.x - viewport.x;
                 var y = localPosition.y - viewport.y;
 
-                pii.canvasPointerPos.x = (x - this.actualPosition.x) / s;
-                pii.canvasPointerPos.y = (engine.getRenderHeight() - y - this.actualPosition.y) / s;
+                pii.canvasPointerPos.x = (x - this.actualPosition.x) / s.x;
+                pii.canvasPointerPos.y = (renderHeight - y - this.actualPosition.y) / s.y;
             } else {
-                pii.canvasPointerPos.x = localPosition.x / s;
-                pii.canvasPointerPos.y = localPosition.y / s;
+                pii.canvasPointerPos.x = localPosition.x / s.x;
+                pii.canvasPointerPos.y = localPosition.y / s.x;
             }
             //console.log(`UpdatePointerInfo for ${this.id}, X:${pii.canvasPointerPos.x}, Y:${pii.canvasPointerPos.y}`);
             pii.mouseWheelDelta = 0;
@@ -830,13 +831,13 @@
 
                             if (ii.isPrimIntersected(prim) !== null) {
                                 if (prim.actionManager) {
-                                    if (this._pickStartingTime !== 0 && ((new Date().getTime() - this._pickStartingTime) > ActionManager.LongPressDelay) && (Math.abs(this._pickStartingPosition.x - ii.pickPosition.x) < ActionManager.DragMovementThreshold && Math.abs(this._pickStartingPosition.y - ii.pickPosition.y) < ActionManager.DragMovementThreshold)) {
+                                    if (this._pickStartingTime !== 0 && ((new Date().getTime() - this._pickStartingTime) > Scene.LongPressDelay) && (Math.abs(this._pickStartingPosition.x - ii.pickPosition.x) < Scene.DragMovementThreshold && Math.abs(this._pickStartingPosition.y - ii.pickPosition.y) < Scene.DragMovementThreshold)) {
                                         this._pickStartingTime = 0;
                                         prim.actionManager.processTrigger(ActionManager.OnLongPressTrigger, ActionEvent.CreateNewFromPrimitive(prim, ppi.primitivePointerPos, eventData));
                                     }
                                 }
                             }
-                        }, ActionManager.LongPressDelay);
+                        }, Scene.LongPressDelay);
                     }
                 }
             }
@@ -851,7 +852,7 @@
                     prim.actionManager.processTrigger(ActionManager.OnPickUpTrigger, actionEvent);
 
                     // OnPickTrigger
-                    if (Math.abs(this._pickStartingPosition.x - ppi.canvasPointerPos.x) < ActionManager.DragMovementThreshold && Math.abs(this._pickStartingPosition.y - ppi.canvasPointerPos.y) < ActionManager.DragMovementThreshold) {
+                    if (Math.abs(this._pickStartingPosition.x - ppi.canvasPointerPos.x) < Scene.DragMovementThreshold && Math.abs(this._pickStartingPosition.y - ppi.canvasPointerPos.y) < Scene.DragMovementThreshold) {
                         prim.actionManager.processTrigger(ActionManager.OnPickTrigger, actionEvent);
                     }
                 }
@@ -1320,7 +1321,7 @@
         private _designUseHorizAxis: boolean;
         public  _primitiveCollisionManager: PrimitiveCollisionManagerBase;
 
-        public _canvasLevelScale: Vector3;
+        public _canvasLevelScale: Vector2;
         public  _renderingSize: Size;
         private _curHWScale;
 
@@ -1342,6 +1343,7 @@
         private _profileInfoText: Text2D;
 
         private static _v = Vector3.Zero(); // Must stay zero
+        private static _cv1 = Vector2.Zero(); // Must stay zero
         private static _m = Matrix.Identity();
         private static _mI = Matrix.Identity(); // Must stay identity
         private static tS = Vector3.Zero();
@@ -1383,8 +1385,8 @@
                 group.levelVisible = proj.z >= 0 && proj.z < 1.0;
 
                 let s = this.scale;
-                group.x = Math.round(proj.x/s);
-                group.y = Math.round((rh - proj.y)/s);
+                group.x = Math.round(proj.x / s);
+                group.y = Math.round((rh - proj.y) / s);
             }
 
             // If it's a WorldSpaceCanvas and it's tracking a node, let's update the WSC transformation data
@@ -1481,7 +1483,7 @@
                 this._setRenderingScale(scale);
             }
         }
-        private static _pCLS = Vector3.Zero();
+        private static _pCLS = Vector2.Zero();
 
         private _updateCanvasState(forceRecompute: boolean) {
             // Check if the update has already been made for this render Frame
@@ -1519,10 +1521,10 @@
                     scale = this._renderingSize.height / (this._designSize.height * hwsl);
                 }
                 this.size = this._designSize.clone();
-                this._canvasLevelScale.copyFromFloats(scale, scale, 1);
+                this._canvasLevelScale.copyFromFloats(scale, scale);
             } else {
                 let ratio = 1 / this._curHWScale;
-                this._canvasLevelScale.copyFromFloats(ratio, ratio, 1);
+                this._canvasLevelScale.copyFromFloats(ratio, ratio);
             }
 
             if (!prevCLS.equals(this._canvasLevelScale)) {
@@ -1627,18 +1629,19 @@
             let isCanvas = parent == null;
             let scale: Vector2;
             if (noResizeScale) {
-                scale = isCanvas ? Canvas2D._unS : group.parent.actualScale;
+                scale = isCanvas ? Canvas2D._unS : group.parent.actualScale.multiply(this._canvasLevelScale);
             } else {
-                scale = group.actualScale;
+                scale = group.actualScale.multiply(this._canvasLevelScale);
             }
 
             // Determine size
             let size = group.actualSize;
-            size = new Size(Math.ceil(size.width * scale.x), Math.ceil(size.height * scale.y));
-            let originalSize = size.clone();
+            let scaledSize = new Size(size.width * scale.x, size.height * scale.y);
+            let roundedScaledSize = new Size(Math.ceil(scaledSize.width), Math.ceil(scaledSize.height));
+            let originalSize = scaledSize.clone();
             if (minSize) {
-                size.width = Math.max(minSize.width, size.width);
-                size.height = Math.max(minSize.height, size.height);
+                roundedScaledSize.width = Math.max(minSize.width, roundedScaledSize.width);
+                roundedScaledSize.height = Math.max(minSize.height, roundedScaledSize.height);
             }
 
             let mapArray = this._groupCacheMaps.getOrAddWithFactory(key, () => new Array<MapTexture>());
@@ -1648,7 +1651,7 @@
             var map: MapTexture;
             for (var _map of mapArray) {
                 map = _map;
-                let node = map.allocateRect(size);
+                let node = map.allocateRect(roundedScaledSize);
                 if (node) {
                     res = { node: node, texture: map }
                     break;
@@ -1660,18 +1663,24 @@
                 let mapSize = new Size(Canvas2D._groupTextureCacheSize, Canvas2D._groupTextureCacheSize);
 
                 // Check if the predefined size would fit, other create a custom size using the nearest bigger power of 2
-                if (size.width > mapSize.width || size.height > mapSize.height) {
-                    mapSize.width = Math.pow(2, Math.ceil(Math.log(size.width) / Math.log(2)));
-                    mapSize.height = Math.pow(2, Math.ceil(Math.log(size.height) / Math.log(2)));
+                if (roundedScaledSize.width > mapSize.width || roundedScaledSize.height > mapSize.height) {
+                    mapSize.width = Math.pow(2, Math.ceil(Math.log(roundedScaledSize.width) / Math.log(2)));
+                    mapSize.height = Math.pow(2, Math.ceil(Math.log(roundedScaledSize.height) / Math.log(2)));
                 }
 
                 let id = `groupsMapChache${this._mapCounter++}forCanvas${this.id}`;
-                map = new MapTexture(id, this._scene, mapSize, useMipMap ? Texture.TRILINEAR_SAMPLINGMODE : Texture.BILINEAR_SAMPLINGMODE, useMipMap);
+                map = new MapTexture(id, this._scene, mapSize, useMipMap ? Texture.TRILINEAR_SAMPLINGMODE : Texture.BILINEAR_SAMPLINGMODE, useMipMap, 2);
                 map.hasAlpha = true;
                 map.anisotropicFilteringLevel = 4;
                 mapArray.splice(0, 0, map);
 
-                let node = map.allocateRect(size);
+                //let debug = false;
+
+                //if (debug) {
+                //    let sprite = new Sprite2D(map, { parent: this, x: 10, y: 10, id: "__cachedSpriteOfGroup__Debug", alignToPixel: true });
+                //}
+
+                let node = map.allocateRect(roundedScaledSize);
                 res = { node: node, texture: map }
             }
 
@@ -1679,6 +1688,8 @@
             // Don't do it in case of the group being a worldspace canvas (because its texture is bound to a WorldSpaceCanvas node)
             if (group !== <any>this || this._isScreenSpace) {
                 let node: PackedRect = res.node;
+                let pos = Canvas2D._cv1;
+                node.getInnerPosToRef(pos);
 
                 // Special case if the canvas is entirely cached: create a group that will have a single sprite it will be rendered specifically at the very end of the rendering process
 
@@ -1688,14 +1699,14 @@
                         this._cachedCanvasGroup.dispose();
                     }
                     this._cachedCanvasGroup = Group2D._createCachedCanvasGroup(this);
-                    sprite = new Sprite2D(map, { parent: this._cachedCanvasGroup, id: "__cachedCanvasSprite__", spriteSize: originalSize, spriteLocation: node.pos });
+                    sprite = new Sprite2D(map, { parent: this._cachedCanvasGroup, id: "__cachedCanvasSprite__", spriteSize: originalSize, size: size, alignToPixel: true, spriteLocation: pos });
                     sprite.zOrder = 1;
                     sprite.origin = Vector2.Zero();
                 }
 
                 // Create a Sprite that will be used to render this cache, the "__cachedSpriteOfGroup__" starting id is a hack to bypass exception throwing in case of the Canvas doesn't normally allows direct primitives
                 else {
-                    sprite = new Sprite2D(map, { parent: parent, id: `__cachedSpriteOfGroup__${group.id}`, x: group.actualPosition.x, y: group.actualPosition.y, spriteSize: originalSize, spriteLocation: node.pos, dontInheritParentScale: true });
+                    sprite = new Sprite2D(map, { parent: parent, id: `__cachedSpriteOfGroup__${group.id}`, x: group.x, y: group.y, spriteSize: originalSize, size: size, spriteLocation: pos, alignToPixel: true, dontInheritParentScale: true });
                     sprite.origin = group.origin.clone();
                     sprite.addExternalData("__cachedGroup__", group);
                     sprite.pointerEventObservable.add((e, s) => {

+ 4 - 4
canvas2D/src/Engine/babylon.ellipse2d.ts

@@ -427,18 +427,18 @@
                 return false;
             }
 
-            let s = Ellipse2D._riv0;
-            this.getActualGlobalScaleToRef(s);
+            //let s = Ellipse2D._riv0;
+            //this.getActualGlobalScaleToRef(s);
 
             if (part.id === Shape2D.SHAPE2D_BORDERPARTID) {
                 let d = <Ellipse2DInstanceData>part;
                 let size = this.actualSize;
-                d.properties = new Vector3(size.width * s.x, size.height * s.y, this.subdivisions);
+                d.properties = new Vector3(size.width/* * s.x*/, size.height/* * s.y*/, this.subdivisions);
             }
             else if (part.id === Shape2D.SHAPE2D_FILLPARTID) {
                 let d = <Ellipse2DInstanceData>part;
                 let size = this.actualSize;
-                d.properties = new Vector3(size.width * s.x, size.height * s.y, this.subdivisions);
+                d.properties = new Vector3(size.width/* * s.x*/, size.height/* * s.y*/, this.subdivisions);
             }
             return true;
         }

+ 5 - 3
canvas2D/src/Engine/babylon.fontTexture.ts

@@ -415,6 +415,7 @@
             this._signedDistanceField = signedDistanceField;
             this._superSample = false;
             this._isPremultipliedAlpha = !signedDistanceField;
+            this.name = `FontTexture ${font}`;
 
             // SDF will use super sample no matter what, the resolution is otherwise too poor to produce correct result
             if (superSample || signedDistanceField) {
@@ -556,7 +557,7 @@
             var textureSize = this.getSize();
 
             // we reached the end of the current line?
-            let width = Math.ceil(measure.width);
+            let width = Math.ceil(measure.width + 0.5);
             if (this._currentFreePosition.x + width + this._xMargin > textureSize.width) {
                 this._currentFreePosition.x = 0;
                 this._currentFreePosition.y += Math.ceil(this._lineHeightSuper + this._yMargin*2);
@@ -626,9 +627,10 @@
             }
 
             // Fill the CharInfo object
-            info.topLeftUV = new Vector2((curPosXMargin) / textureSize.width, (this._currentFreePosition.y + this._yMargin) / textureSize.height);
-            info.bottomRightUV = new Vector2((curPosXMargin + width) / textureSize.width, info.topLeftUV.y + ((this._lineHeightSuper + this._yMargin) / textureSize.height));
+            info.topLeftUV = new Vector2((curPosXMargin-0.5) / textureSize.width, (this._currentFreePosition.y-0.5 + this._yMargin) / textureSize.height);
+            info.bottomRightUV = new Vector2((curPosXMargin-0.5 + width) / textureSize.width, info.topLeftUV.y + (this._lineHeightSuper / textureSize.height));
             info.yOffset = info.xOffset = 0;
+            //console.log(`Char: ${char}, Offset: ${curPosX}, ${this._currentFreePosition.y + this._yMargin}, Size: ${width}, ${this._lineHeightSuper}, UV: ${info.topLeftUV}, ${info.bottomRightUV}`);
 
             if (this._signedDistanceField) {
                 let off = 1/textureSize.width;

+ 28 - 10
canvas2D/src/Engine/babylon.group2d.ts

@@ -357,9 +357,12 @@
 
             let s = this.actualSize;
             let a = this.actualScale;
+            let ss = this.owner._canvasLevelScale;
             let hwsl = 1/this.owner.engine.getHardwareScalingLevel();
-            let sw = Math.ceil(s.width * a.x * hwsl);
-            let sh = Math.ceil(s.height * a.y * hwsl);
+            //let sw = Math.ceil(s.width * a.x * ss.x/* * hwsl*/);
+            //let sh = Math.ceil(s.height * a.y *ss.y/* *  hwsl*/);
+            let sw = s.width * a.x * ss.x;
+            let sh = s.height * a.y *ss.y;
 
             // The dimension must be overridden when using the designSize feature, the ratio is maintain to compute a uniform scale, which is mandatory but if the designSize's ratio is different from the rendering surface's ratio, content will be clipped in some cases.
             // So we set the width/height to the rendering's one because that's what we want for the viewport!
@@ -803,6 +806,8 @@
 
         private static _uV = new Vector2(1, 1);
         private static _s = Size.Zero();
+        private static _v1 = Vector2.Zero();
+        private static _s2 = Size.Zero();
         private _bindCacheTarget() {
             let curWidth: number;
             let curHeight: number;
@@ -813,11 +818,11 @@
             let isCanvas = this.parent == null;
             let scale: Vector2;
             if (noResizeScale) {
-                scale = isCanvas ? Group2D._uV: this.parent.actualScale;
+                scale = isCanvas ? Group2D._uV: this.parent.actualScale.multiply(this.owner._canvasLevelScale);
             } else {
-                scale = this.actualScale;
+                scale = this.actualScale.multiply(this.owner._canvasLevelScale);
             }
-
+            let actualSize = this.actualSize;
             if (isCanvas && this.owner.cachingStrategy===Canvas2D.CACHESTRATEGY_CANVAS && this.owner.isScreenSpace) {
                 if(this.owner.designSize || this.owner.fitRenderingDevice){
                     Group2D._s.width = this.owner.engine.getRenderWidth();
@@ -827,14 +832,15 @@
                     Group2D._s.copyFrom(this.owner.size);
                 }
             } else {
-                Group2D._s.width = Math.ceil(this.actualSize.width * scale.x * rs);
-                Group2D._s.height = Math.ceil(this.actualSize.height * scale.y * rs);
+                Group2D._s.width  = Math.ceil(actualSize.width  * scale.x * rs);
+                Group2D._s.height = Math.ceil(actualSize.height * scale.y * rs);
             }
 
             let sizeChanged = !Group2D._s.equals(rd._cacheSize);
 
             if (rd._cacheNode) {
-                let size = rd._cacheNode.contentSize;
+                let size = Group2D._s;
+                rd._cacheNode.getInnerSizeToRef(size);
 
                 // Check if we have to deallocate because the size is too small
                 if ((size.width < Group2D._s.width) || (size.height < Group2D._s.height)) {
@@ -859,6 +865,12 @@
                 }
                 rd._cacheRenderSprite = res.sprite;
                 sizeChanged = true;
+            } else if (sizeChanged) {
+                let sprite = rd._cacheRenderSprite;
+                if (sprite) {
+                    sprite.size = actualSize;
+                    sprite.spriteSize = new Size(actualSize.width * scale.x * rs, actualSize.height * scale.y * rs);
+                }
             }
 
             if (sizeChanged) {
@@ -871,8 +883,9 @@
                 this._setFlags(SmartPropertyPrim.flagWorldCacheChanged);
             }
 
-            let n = rd._cacheNode;
-            rd._cacheTexture.bindTextureForPosSize(n.pos, Group2D._s, true);
+            let pos = Group2D._v1;
+            rd._cacheNode.getInnerPosToRef(pos);
+            rd._cacheTexture.bindTextureForPosSize(pos, Group2D._s, true);
         }
 
         private _unbindCacheTarget() {
@@ -924,6 +937,11 @@
                 case Group2D.actualSizeProperty.id:
                     cachedSprite.size = this.actualSize.clone();
                     break;
+                case Group2D.xProperty.id:
+                    cachedSprite.x = this.x;
+                    break;
+                case Group2D.yProperty.id:
+                    cachedSprite.y = this.y;
             }
         }
 

+ 19 - 14
canvas2D/src/Engine/babylon.prim2dBase.ts

@@ -2746,7 +2746,7 @@
          */
         public getActualGlobalScaleToRef(res: Vector2) {
             let as = this.actualScale;
-            let cls = this.owner._canvasLevelScale || Canvas2D._iv3;
+            let cls = this.owner._canvasLevelScale || Prim2DBase._iv2;
             res.x = as.x * cls.x;
             res.y = as.y * cls.y;
         }
@@ -3027,7 +3027,9 @@
                 }
 
                 if (this._isFlagSet(SmartPropertyPrim.flagLayoutDirty)) {
-                    this.owner.addUpdateLayoutCounter(1);
+                    if (this._owner) {
+                        this._owner.addUpdateLayoutCounter(1);
+                    }
                     this._layoutEngine.updateLayout(this);
 
                     this._clearFlags(SmartPropertyPrim.flagLayoutDirty);
@@ -3459,6 +3461,9 @@
                 try {
                     Prim2DBase._bypassGroup2DExclusion = true;
                     let ownerGroup = this.getExternalData<Group2D>("__cachedGroup__");
+                    if (!ownerGroup) {
+                        return false;
+                    }
                     return ownerGroup.intersect(intersectInfo);
                 } finally  {
                     Prim2DBase._bypassGroup2DExclusion = false;
@@ -3824,9 +3829,9 @@
         private static _t0: Matrix2D = new Matrix2D();
         private static _t1: Matrix2D = new Matrix2D();
         private static _t2: Matrix2D = new Matrix2D();
-        private static _v0: Vector2 = Vector2.Zero();   // Must stay with the value 0,0
+        private static _v0: Vector2 = Vector2.Zero();    // Must stay with the value 0,0
         private static _v30: Vector3 = Vector3.Zero();   // Must stay with the value 0,0,0
-        private static _iv3: Vector3 = new Vector3(1,1,1); // Must stay identity vector
+        private static _iv2: Vector2 = new Vector2(1,1); // Must stay identity vector
         private static _ts0 = Size.Zero();
 
         private _updateLocalTransform(): boolean {
@@ -3846,12 +3851,12 @@
                 var local: Matrix2D;
                 let pos = this._position ? this.position : (this.layoutAreaPos || Prim2DBase._v0);
                 let postScale = this._postScale;
-                let canvasScale = Prim2DBase._iv3;
-                let hasCanvasScale = false;
-                if (this._parent instanceof Canvas2D) {
-                    hasCanvasScale = true;
-                    canvasScale = (this._parent as Canvas2D)._canvasLevelScale || Prim2DBase._iv3;
-                }
+                let canvasScale = Prim2DBase._iv2;
+                //let hasCanvasScale = false;
+                //if (this._parent instanceof Canvas2D) {
+                //    hasCanvasScale = true;
+                //    canvasScale = (this._parent as Canvas2D)._canvasLevelScale || Prim2DBase._iv2;
+                //}
                 let globalScale = this._scale.multiplyByFloats(/*postScale.x**/canvasScale.x, /*postScale.y**/canvasScale.y);
 
                 if ((this._origin.x === 0 && this._origin.y === 0) || this._hasMargin) {
@@ -3885,10 +3890,10 @@
                     Matrix2D.TranslationToRef(pos.x + this._marginOffset.x, pos.y + this._marginOffset.y, t0);
                     t2.multiplyToRef(t0, this._localTransform);
 
-                    if (hasCanvasScale) {
-                        Matrix2D.ScalingToRef(canvasScale.x, canvasScale.y, Prim2DBase._t1);
-                        this._localTransform.multiplyToRef(Prim2DBase._t1, this._localTransform);
-                    }
+                    //if (hasCanvasScale) {
+                    //    Matrix2D.ScalingToRef(canvasScale.x, canvasScale.y, Prim2DBase._t1);
+                    //    this._localTransform.multiplyToRef(Prim2DBase._t1, this._localTransform);
+                    //}
 
                     this._localLayoutTransform = Matrix2D.Compose(globalScale, rot, pos);
                 }

+ 4 - 4
canvas2D/src/Engine/babylon.rectangle2d.ts

@@ -593,18 +593,18 @@
                 return false;
             }
 
-            let s = Rectangle2D._riv0;
-            this.getActualGlobalScaleToRef(s);
+            //let s = Rectangle2D._riv0;
+            //this.getActualGlobalScaleToRef(s);
 
             if (part.id === Shape2D.SHAPE2D_BORDERPARTID) {
                 let d = <Rectangle2DInstanceData>part;
                 let size = this.actualSize;
-                d.properties = new Vector3(size.width * s.x, size.height * s.y, this.roundRadius || 0);
+                d.properties = new Vector3(size.width/* * s.x*/, size.height/* * s.y*/, this.roundRadius || 0);
             }
             else if (part.id === Shape2D.SHAPE2D_FILLPARTID) {
                 let d = <Rectangle2DInstanceData>part;
                 let size = this.actualSize;
-                d.properties = new Vector3(size.width * s.x, size.height * s.y, this.roundRadius || 0);
+                d.properties = new Vector3(size.width/* * s.x*/, size.height/* * s.y*/, this.roundRadius || 0);
             }
             return true;
         }

+ 5 - 1
canvas2D/src/Engine/babylon.renderablePrim2d.ts

@@ -951,11 +951,15 @@
             let trn = RenderablePrim2D._t;
             let rot = t.decompose(scl, trn);
             let pas = this.actualScale;
-            let canvasScale = this.owner._canvasLevelScale;
+            //let cachedGroup = (this.getExternalData<Group2D>("__cachedGroup__") !== null);
+            let canvasScale = /*cachedGroup ? RenderablePrim2D._iV2 :  */this.owner._canvasLevelScale;
             scl.x = pas.x * canvasScale.x * this._postScale.x;
             scl.y = pas.y * canvasScale.y * this._postScale.y;
+            trn.multiplyInPlace(canvasScale);
             t = Matrix2D.Compose(this.applyActualScaleOnTransform() ? scl : RenderablePrim2D._iV2, rot, trn);
 
+            //console.log(`Update Instance Data Part: ${this.id}`);
+
             let size = (<Size>this.renderGroup.viewportSize);
             let zBias = this.actualZOffset;
 

+ 3 - 3
canvas2D/src/Engine/babylon.shape2d.ts

@@ -126,9 +126,9 @@
             return cat;
         }
 
-        protected applyActualScaleOnTransform(): boolean {
-            return false;
-        }
+        //protected applyActualScaleOnTransform(): boolean {
+        //    return false;
+        //}
 
         protected refreshInstanceDataPart(part: InstanceDataBase): boolean {
             if (!super.refreshInstanceDataPart(part)) {

+ 8 - 2
canvas2D/src/Engine/babylon.text2d.ts

@@ -150,6 +150,7 @@
         public static fontSuperSampleProperty: Prim2DPropInfo;
         public static fontSignedDistanceFieldProperty: Prim2DPropInfo;
         public static textureIsPremulAlphaProperty: Prim2DPropInfo;
+        public static fontTextureProperty: Prim2DPropInfo;
 
         /**
          * Alignment is made relative to the left edge of the Content Area. Valid for horizontal alignment only.
@@ -333,6 +334,7 @@
             }
         }
 
+        @modelLevelProperty(RenderablePrim2D.RENDERABLEPRIM2D_PROPCOUNT + 8, pi => Text2D.fontTextureProperty = pi)
         public get fontTexture(): BaseFontTexture {
             if (this._fontTexture) {
                 return this._fontTexture;
@@ -769,7 +771,7 @@
                     offsetX += (contentAreaWidth - maxLineLen) * .5;
                 }
 
-                offset.x += offsetX;
+                offset.x += Math.floor(offsetX);
 
                 offset.y += contentAreaHeight + textHeight - lh;
                 offset.y += this.padding.bottomPixels;
@@ -800,13 +802,17 @@
                         if(char !== "\t" && !this._isWhiteSpaceCharVert(char)){ 
                             //make sure space char gets processed here or overlapping can occur when text is set
                             let ci = texture.getChar(char);
-                            this.updateInstanceDataPart(d, new Vector2(offset.x + ci.xOffset, offset.y +ci.yOffset));
+                            let partOffset = new Vector2(offset.x + ci.xOffset, offset.y + ci.yOffset);
+                            this.updateInstanceDataPart(d, partOffset);
                             d.topLeftUV = ci.topLeftUV;
                             let suv = ci.bottomRightUV.subtract(ci.topLeftUV);
                             d.sizeUV = suv;
                             d.textureSize = new BABYLON.Vector2(ts.width, ts.height);
                             d.color = this.defaultFontColor;
                             d.superSampleFactor = superSampleFactor;
+
+                            //console.log(`Char: ${char}, Offset: ${partOffset}`);
+
                             ++d.curElement;
                         }
 

+ 10 - 8
canvas2D/src/shaders/sprite2d.vertex.fx

@@ -77,13 +77,15 @@ void main(void) {
 		vUV.y = 1.0 - vUV.y;
 	}
 
+	//vUV.x += 0.5 / textureSize.x;
+
 	vec4 pos;
-	if (alignToPixel == 1.0)
-	{
-		pos.xy = floor(pos2.xy * sizeUV * textureSize);
-	} else {
+	//if (alignToPixel == 1.0)
+	//{
+	//	pos.xy = floor(pos2.xy * sizeUV * textureSize);
+	//} else {
 		pos.xy = pos2.xy * sizeUV * textureSize;
-	}
+	//}
 
 #ifdef Scale9
 	if (invertY == 1.0) {
@@ -111,9 +113,9 @@ void main(void) {
 		float irw = 2.0 / rw;
 		float irh = 2.0 / rh;
 
-		x = floor((x / irw) + 0.5) * irw;
-		y = floor((y / irh) + 0.5) * irh;
+		x = (floor((x / irw)) * irw) + irw / 2.0;
+		y = (floor((y / irh)) * irh) + irh / 2.0;
 	}
 
-	gl_Position = vec4(x, y, zBias.x, 1);
+	gl_Position = vec4(x, y, zBias.x, 1.0);
 }	

+ 6 - 5
canvas2D/src/shaders/text2d.vertex.fx

@@ -53,12 +53,13 @@ void main(void) {
 	}
 
 	// Align texture coordinate to texel to enhance rendering quality
-	vUV = (floor(vUV*textureSize) + vec2(0.0, 0.0)) / textureSize;
+//	vUV = (floor(vUV*textureSize) + vec2(0.5, 0.5)) / textureSize;
+	//vUV.x += 0.5 / textureSize.x;
 
 	vColor = color;
 	vColor.a *= opacity;
 	vec4 pos;
-	pos.xy = floor(pos2.xy * superSampleFactor * sizeUV * textureSize);	// Align on target pixel to avoid bad interpolation
+	pos.xy = pos2.xy * superSampleFactor * sizeUV * textureSize;
 	pos.z = 1.0;
 	pos.w = 1.0;
 
@@ -70,9 +71,9 @@ void main(void) {
 		float irw = 2.0 / rw;
 		float irh = 2.0 / rh;
 
-		x = floor((x / irw) + 0.5) * irw;
-		y = floor((y / irh) + 0.5) * irh;
+		x = (floor((x / irw)) * irw) + irw / 2.0;
+		y = (floor((y / irh)) * irh) + irh / 2.0;
 	}
 
-	gl_Position = vec4(x, y, zBias.x, 1);
+	gl_Position = vec4(x, y, zBias.x, 1.0);
 }

File diff suppressed because it is too large
+ 29 - 28
dist/preview release/babylon.core.js


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


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


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


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


File diff suppressed because it is too large
+ 39 - 38
dist/preview release/babylon.noworker.js


+ 6 - 3
dist/preview release/canvas2D/babylon.canvas2d.d.ts

@@ -2496,7 +2496,7 @@ declare module BABYLON {
         private static _t2;
         private static _v0;
         private static _v30;
-        private static _iv3;
+        private static _iv2;
         private static _ts0;
         private _updateLocalTransform();
         private static _transMtx;
@@ -2850,7 +2850,6 @@ declare module BABYLON {
             borderThickness?: number;
         });
         protected getUsedShaderCategories(dataPart: InstanceDataBase): string[];
-        protected applyActualScaleOnTransform(): boolean;
         protected refreshInstanceDataPart(part: InstanceDataBase): boolean;
         private _updateTransparencyStatus();
         protected _mustUpdateInstance(): boolean;
@@ -3040,6 +3039,8 @@ declare module BABYLON {
         protected _setRenderingScale(scale: number): void;
         private static _uV;
         private static _s;
+        private static _v1;
+        private static _s2;
         private _bindCacheTarget();
         private _unbindCacheTarget();
         protected _spreadActualScaleDirty(): void;
@@ -3861,6 +3862,7 @@ declare module BABYLON {
         static fontSuperSampleProperty: Prim2DPropInfo;
         static fontSignedDistanceFieldProperty: Prim2DPropInfo;
         static textureIsPremulAlphaProperty: Prim2DPropInfo;
+        static fontTextureProperty: Prim2DPropInfo;
         /**
          * Alignment is made relative to the left edge of the Content Area. Valid for horizontal alignment only.
          */
@@ -4502,7 +4504,7 @@ declare module BABYLON {
         private _designSize;
         private _designUseHorizAxis;
         _primitiveCollisionManager: PrimitiveCollisionManagerBase;
-        _canvasLevelScale: Vector3;
+        _canvasLevelScale: Vector2;
         _renderingSize: Size;
         private _curHWScale;
         private _drawCallsOpaqueCounter;
@@ -4521,6 +4523,7 @@ declare module BABYLON {
         private _profilingCanvas;
         private _profileInfoText;
         private static _v;
+        private static _cv1;
         private static _m;
         private static _mI;
         private static tS;

File diff suppressed because it is too large
+ 114 - 70
dist/preview release/canvas2D/babylon.canvas2d.js


File diff suppressed because it is too large
+ 12 - 12
dist/preview release/canvas2D/babylon.canvas2d.min.js


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


+ 45 - 2
dist/preview release/inspector/babylon.inspector.d.ts

@@ -18,11 +18,13 @@ declare module INSPECTOR {
         private _popupMode;
         /** The original canvas style, before applying the inspector*/
         private _canvasStyle;
+        private _initialTab;
+        private _parentElement;
         /** 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 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',
          * returns the first parent of the given element that has a position 'relative' or 'absolute'.
@@ -105,6 +107,10 @@ declare module INSPECTOR {
         'FontTexture': {
             type: typeof BABYLON.FontTexture;
         };
+        'Sound': {
+            type: typeof BABYLON.Sound;
+            properties: string[];
+        };
         'ArcRotateCamera': {
             type: typeof BABYLON.ArcRotateCamera;
             properties: string[];
@@ -222,6 +228,20 @@ declare module INSPECTOR {
 }
 
 declare module INSPECTOR {
+    class SoundAdapter extends Adapter implements ISoundInteractions {
+        constructor(obj: BABYLON.Sound);
+        /** 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>;
+        setPlaying(callback: Function): void;
+    }
+}
+
+declare module INSPECTOR {
     class TextureAdapter extends Adapter {
         constructor(obj: BABYLON.BaseTexture);
         /** Returns the name displayed in the tree */
@@ -700,6 +720,13 @@ declare module INSPECTOR {
 }
 
 declare module INSPECTOR {
+    class SoundTab 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 */
@@ -852,7 +879,7 @@ declare module INSPECTOR {
         private _invisibleTabs;
         /** The list of tabs visible, displayed in the tab bar */
         private _visibleTabs;
-        constructor(inspector: Inspector);
+        constructor(inspector: Inspector, initialTab?: number);
         update(): void;
         protected _build(): void;
         /**
@@ -1085,6 +1112,22 @@ declare module INSPECTOR {
 }
 
 declare module INSPECTOR {
+    interface ISoundInteractions {
+        setPlaying: (callback: Function) => void;
+    }
+    /**
+     *
+     */
+    class SoundInteractions extends AbstractTreeTool {
+        private playSound;
+        private b;
+        constructor(playSound: ISoundInteractions);
+        protected action(): void;
+        private _playSound();
+    }
+}
+
+declare module INSPECTOR {
     /** Any object implementing this interface should
      * provide methods to toggle its visibility
      */

+ 194 - 18
dist/preview release/inspector/babylon.inspector.js

@@ -5,10 +5,14 @@ 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 true, the inspector is created in another popup.
          */
-        function Inspector(scene, popup) {
+        function Inspector(scene, popup, initialTab, parentElement) {
             var _this = this;
             /** True if the inspector is built as a popup tab */
             this._popupMode = false;
+            //get Tabbar initialTab
+            this._initialTab = initialTab;
+            //get parentElement of our Inspector
+            this._parentElement = parentElement;
             // get canvas parent only if needed.
             this._scene = scene;
             // Save HTML document and window
@@ -88,22 +92,39 @@ var INSPECTOR;
                 canvas.style.marginTop = "0";
                 canvas.style.marginRight = "0";
                 // Replace canvas with the wrapper...
+                // if (this._parentElement) {
+                //     canvasParent.replaceChild(this._parentElement, canvas);
+                //     this._parentElement.appendChild(canvas);
+                // }
+                // else {
                 canvasParent.replaceChild(this._c2diwrapper, canvas);
                 // ... and add canvas to the wrapper
                 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);
+                }
                 // 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
                 this._buildInspector(inspector);
                 // Send resize event to the window
@@ -151,7 +172,7 @@ var INSPECTOR;
         /** Build the inspector panel in the given HTML element */
         Inspector.prototype._buildInspector = function (parent) {
             // tabbar
-            this._tabbar = new INSPECTOR.TabBar(this);
+            this._tabbar = new INSPECTOR.TabBar(this, this._initialTab);
             // Top panel
             this._topPanel = INSPECTOR.Helpers.CreateDiv('top-panel', parent);
             // Add tabbar
@@ -348,6 +369,23 @@ var INSPECTOR;
         'FontTexture': {
             type: BABYLON.FontTexture
         },
+        'Sound': {
+            type: BABYLON.Sound,
+            properties: [
+                'name',
+                'autoplay',
+                'loop',
+                'useCustomAttenuation',
+                'soundTrackId',
+                'spatialSound',
+                'refDistance',
+                'rolloffFactor',
+                'maxDistance',
+                'distanceModel',
+                'isPlaying',
+                'isPaused'
+            ]
+        },
         'ArcRotateCamera': {
             type: BABYLON.ArcRotateCamera,
             properties: [
@@ -703,6 +741,66 @@ var __extends = (this && this.__extends) || function (d, b) {
 };
 var INSPECTOR;
 (function (INSPECTOR) {
+    var SoundAdapter = (function (_super) {
+        __extends(SoundAdapter, _super);
+        function SoundAdapter(obj) {
+            return _super.call(this, obj) || this;
+        }
+        /** Returns the name displayed in the tree */
+        SoundAdapter.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 */
+        SoundAdapter.prototype.type = function () {
+            return INSPECTOR.Helpers.GET_TYPE(this._obj);
+        };
+        /** Returns the list of properties to be displayed for this adapter */
+        SoundAdapter.prototype.getProperties = function () {
+            var propertiesLines = [];
+            var camToDisplay = [];
+            // The if is there to work with the min version of babylon
+            var soundProperties = INSPECTOR.PROPERTIES['Sound'].properties;
+            for (var _i = 0, soundProperties_1 = soundProperties; _i < soundProperties_1.length; _i++) {
+                var dirty = soundProperties_1[_i];
+                var infos = new INSPECTOR.Property(dirty, this._obj);
+                propertiesLines.push(new INSPECTOR.PropertyLine(infos));
+            }
+            return propertiesLines;
+        };
+        SoundAdapter.prototype.getTools = function () {
+            var tools = [];
+            tools.push(new INSPECTOR.SoundInteractions(this));
+            return tools;
+        };
+        SoundAdapter.prototype.setPlaying = function (callback) {
+            if (this._obj.isPlaying) {
+                this._obj.pause();
+            }
+            else {
+                this._obj.play();
+            }
+            this._obj.onended = function () {
+                callback();
+            };
+        };
+        return SoundAdapter;
+    }(INSPECTOR.Adapter));
+    INSPECTOR.SoundAdapter = SoundAdapter;
+})(INSPECTOR || (INSPECTOR = {}));
+
+//# sourceMappingURL=SoundAdapter.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) {
@@ -1805,8 +1903,6 @@ var INSPECTOR;
     INSPECTOR.HDRCubeTextureElement = HDRCubeTextureElement;
 })(INSPECTOR || (INSPECTOR = {}));
 
-//# sourceMappingURL=HDRCubeTextureElement.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; }
@@ -2358,6 +2454,38 @@ var __extends = (this && this.__extends) || function (d, b) {
 };
 var INSPECTOR;
 (function (INSPECTOR) {
+    var SoundTab = (function (_super) {
+        __extends(SoundTab, _super);
+        function SoundTab(tabbar, inspector) {
+            return _super.call(this, tabbar, 'Audio', inspector) || this;
+        }
+        /* Overrides super */
+        SoundTab.prototype._getTree = function () {
+            var _this = this;
+            var arr = [];
+            // get all cameras from the first scene
+            var instances = this._inspector.scene;
+            for (var _i = 0, _a = instances.soundTracks; _i < _a.length; _i++) {
+                var sounds = _a[_i];
+                var sound = sounds.soundCollection;
+                sound.forEach(function (element) {
+                    arr.push(new INSPECTOR.TreeItem(_this, new INSPECTOR.SoundAdapter(element)));
+                });
+            }
+            return arr;
+        };
+        return SoundTab;
+    }(INSPECTOR.PropertyTab));
+    INSPECTOR.SoundTab = SoundTab;
+})(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) {
@@ -3370,7 +3498,7 @@ var INSPECTOR;
      */
     var TabBar = (function (_super) {
         __extends(TabBar, _super);
-        function TabBar(inspector) {
+        function TabBar(inspector, initialTab) {
             var _this = _super.call(this) || this;
             // The list of available tabs
             _this._tabs = [];
@@ -3393,10 +3521,15 @@ var INSPECTOR;
             }
             _this._tabs.push(new INSPECTOR.MaterialTab(_this, _this._inspector));
             _this._tabs.push(new INSPECTOR.CameraTab(_this, _this._inspector));
+            _this._tabs.push(new INSPECTOR.SoundTab(_this, _this._inspector));
             _this._toolBar = new INSPECTOR.Toolbar(_this._inspector);
             _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
             for (var _i = 0, _a = _this._tabs; _i < _a.length; _i++) {
                 var tab = _a[_i];
@@ -4247,6 +4380,49 @@ var __extends = (this && this.__extends) || function (d, b) {
 var INSPECTOR;
 (function (INSPECTOR) {
     /**
+     *
+     */
+    var SoundInteractions = (function (_super) {
+        __extends(SoundInteractions, _super);
+        function SoundInteractions(playSound) {
+            var _this = _super.call(this) || this;
+            _this.playSound = playSound;
+            _this.b = false;
+            _this._elem.classList.add('fa-play');
+            return _this;
+        }
+        SoundInteractions.prototype.action = function () {
+            _super.prototype.action.call(this);
+            this._playSound();
+        };
+        SoundInteractions.prototype._playSound = function () {
+            var _this = this;
+            if (this._elem.classList.contains('fa-play')) {
+                this._elem.classList.remove('fa-play');
+                this._elem.classList.add('fa-pause');
+            }
+            else {
+                this._elem.classList.remove('fa-pause');
+                this._elem.classList.add('fa-play');
+            }
+            this.playSound.setPlaying(function () {
+                _this._elem.classList.remove('fa-pause');
+                _this._elem.classList.add('fa-play');
+            });
+        };
+        return SoundInteractions;
+    }(INSPECTOR.AbstractTreeTool));
+    INSPECTOR.SoundInteractions = SoundInteractions;
+})(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
      */
     var Checkbox = (function (_super) {

File diff suppressed because it is too large
+ 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 rotation = node.rotation || [0, 0, 0, 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);
             node.babylonNode = lastNode;

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


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

@@ -0,0 +1,16 @@
+/// <reference path="../../../dist/preview release/babylon.d.ts" />
+declare module BABYLON {
+    class CustomShaderHelper {
+    }
+    interface ICustomMaterialBuilder {
+        (builder: CustomShaderHelper, name: string, mainPart: string, diffusePart: string, vertexPositionPart: string): string;
+    }
+    class CustomMaterial extends StandardMaterial {
+        builder: ICustomMaterialBuilder;
+        private _mainPart;
+        private _diffusePart;
+        private _vertexPositionPart;
+        constructor(name: string, builder: ICustomMaterialBuilder, scene: Scene);
+        isReady(mesh?: AbstractMesh, useInstances?: boolean): boolean;
+    }
+}

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

@@ -0,0 +1,398 @@
+/// <reference path="../../../dist/preview release/babylon.d.ts"/>
+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 BABYLON;
+(function (BABYLON) {
+    var CustomShaderHelper = (function () {
+        function CustomShaderHelper() {
+        }
+        return CustomShaderHelper;
+    }());
+    BABYLON.CustomShaderHelper = CustomShaderHelper;
+    var CustomMaterial = (function (_super) {
+        __extends(CustomMaterial, _super);
+        function CustomMaterial(name, builder, scene) {
+            var _this = _super.call(this, name, scene) || this;
+            _this._mainPart = 'void main(void) {';
+            _this._diffusePart = 'vec3 diffuseColor=vDiffuseColor.rgb;';
+            _this._vertexPositionPart = 'gl_Position=viewProjection*finalWorld*vec4(position,1.0);';
+            _this.builder = builder;
+            return _this;
+        }
+        CustomMaterial.prototype.isReady = function (mesh, useInstances) {
+            if (this.isFrozen) {
+                if (this._wasPreviouslyReady) {
+                    return true;
+                }
+            }
+            var scene = this.getScene();
+            var engine = scene.getEngine();
+            var needUVs = false;
+            var needNormals = false;
+            this._defines.reset();
+            // Lights
+            if (scene.lightsEnabled && !this.disableLighting) {
+                needNormals = BABYLON.MaterialHelper.PrepareDefinesForLights(scene, mesh, this._defines, this.maxSimultaneousLights);
+            }
+            if (!this.checkReadyOnEveryCall) {
+                if (this._renderId === scene.getRenderId()) {
+                    if (this._checkCache(scene, mesh, useInstances)) {
+                        return true;
+                    }
+                }
+            }
+            // Textures
+            if (scene.texturesEnabled) {
+                if (this.diffuseTexture && BABYLON.StandardMaterial.DiffuseTextureEnabled) {
+                    if (!this.diffuseTexture.isReady()) {
+                        return false;
+                    }
+                    else {
+                        needUVs = true;
+                        this._defines.DIFFUSE = true;
+                    }
+                }
+                if (this.ambientTexture && BABYLON.StandardMaterial.AmbientTextureEnabled) {
+                    if (!this.ambientTexture.isReady()) {
+                        return false;
+                    }
+                    else {
+                        needUVs = true;
+                        this._defines.AMBIENT = true;
+                    }
+                }
+                if (this.opacityTexture && BABYLON.StandardMaterial.OpacityTextureEnabled) {
+                    if (!this.opacityTexture.isReady()) {
+                        return false;
+                    }
+                    else {
+                        needUVs = true;
+                        this._defines.OPACITY = true;
+                        if (this.opacityTexture.getAlphaFromRGB) {
+                            this._defines.OPACITYRGB = true;
+                        }
+                    }
+                }
+                if (this.reflectionTexture && BABYLON.StandardMaterial.ReflectionTextureEnabled) {
+                    if (!this.reflectionTexture.isReady()) {
+                        return false;
+                    }
+                    else {
+                        needNormals = true;
+                        this._defines.REFLECTION = true;
+                        if (this.roughness > 0) {
+                            this._defines.ROUGHNESS = true;
+                        }
+                        if (this.useReflectionOverAlpha) {
+                            this._defines.REFLECTIONOVERALPHA = true;
+                        }
+                        if (this.reflectionTexture.coordinatesMode === BABYLON.Texture.INVCUBIC_MODE) {
+                            this._defines.INVERTCUBICMAP = true;
+                        }
+                        this._defines.REFLECTIONMAP_3D = this.reflectionTexture.isCube;
+                        switch (this.reflectionTexture.coordinatesMode) {
+                            case BABYLON.Texture.CUBIC_MODE:
+                            case BABYLON.Texture.INVCUBIC_MODE:
+                                this._defines.REFLECTIONMAP_CUBIC = true;
+                                break;
+                            case BABYLON.Texture.EXPLICIT_MODE:
+                                this._defines.REFLECTIONMAP_EXPLICIT = true;
+                                break;
+                            case BABYLON.Texture.PLANAR_MODE:
+                                this._defines.REFLECTIONMAP_PLANAR = true;
+                                break;
+                            case BABYLON.Texture.PROJECTION_MODE:
+                                this._defines.REFLECTIONMAP_PROJECTION = true;
+                                break;
+                            case BABYLON.Texture.SKYBOX_MODE:
+                                this._defines.REFLECTIONMAP_SKYBOX = true;
+                                break;
+                            case BABYLON.Texture.SPHERICAL_MODE:
+                                this._defines.REFLECTIONMAP_SPHERICAL = true;
+                                break;
+                            case BABYLON.Texture.EQUIRECTANGULAR_MODE:
+                                this._defines.REFLECTIONMAP_EQUIRECTANGULAR = true;
+                                break;
+                            case BABYLON.Texture.FIXED_EQUIRECTANGULAR_MODE:
+                                this._defines.REFLECTIONMAP_EQUIRECTANGULAR_FIXED = true;
+                                break;
+                        }
+                    }
+                }
+                if (this.emissiveTexture && BABYLON.StandardMaterial.EmissiveTextureEnabled) {
+                    if (!this.emissiveTexture.isReady()) {
+                        return false;
+                    }
+                    else {
+                        needUVs = true;
+                        this._defines.EMISSIVE = true;
+                    }
+                }
+                if (this.lightmapTexture && BABYLON.StandardMaterial.LightmapTextureEnabled) {
+                    if (!this.lightmapTexture.isReady()) {
+                        return false;
+                    }
+                    else {
+                        needUVs = true;
+                        this._defines.LIGHTMAP = true;
+                        this._defines.USELIGHTMAPASSHADOWMAP = this.useLightmapAsShadowmap;
+                    }
+                }
+                if (this.specularTexture && BABYLON.StandardMaterial.SpecularTextureEnabled) {
+                    if (!this.specularTexture.isReady()) {
+                        return false;
+                    }
+                    else {
+                        needUVs = true;
+                        this._defines.SPECULAR = true;
+                        this._defines.GLOSSINESS = this.useGlossinessFromSpecularMapAlpha;
+                    }
+                }
+                if (scene.getEngine().getCaps().standardDerivatives && this.bumpTexture && BABYLON.StandardMaterial.BumpTextureEnabled) {
+                    if (!this.bumpTexture.isReady()) {
+                        return false;
+                    }
+                    else {
+                        needUVs = true;
+                        this._defines.BUMP = true;
+                        if (this.useParallax) {
+                            this._defines.PARALLAX = true;
+                            if (this.useParallaxOcclusion) {
+                                this._defines.PARALLAXOCCLUSION = true;
+                            }
+                        }
+                        if (this.invertNormalMapX) {
+                            this._defines.INVERTNORMALMAPX = true;
+                        }
+                        if (this.invertNormalMapY) {
+                            this._defines.INVERTNORMALMAPY = true;
+                        }
+                        if (scene._mirroredCameraPosition) {
+                            this._defines.INVERTNORMALMAPX = !this._defines.INVERTNORMALMAPX;
+                            this._defines.INVERTNORMALMAPY = !this._defines.INVERTNORMALMAPY;
+                        }
+                    }
+                }
+                if (this.refractionTexture && BABYLON.StandardMaterial.RefractionTextureEnabled) {
+                    if (!this.refractionTexture.isReady()) {
+                        return false;
+                    }
+                    else {
+                        needUVs = true;
+                        this._defines.REFRACTION = true;
+                        this._defines.REFRACTIONMAP_3D = this.refractionTexture.isCube;
+                    }
+                }
+                if (this.cameraColorGradingTexture && BABYLON.StandardMaterial.ColorGradingTextureEnabled) {
+                    if (!this.cameraColorGradingTexture.isReady()) {
+                        return false;
+                    }
+                    else {
+                        this._defines.CAMERACOLORGRADING = true;
+                    }
+                }
+            }
+            // Effect
+            if (scene.clipPlane) {
+                this._defines.CLIPPLANE = true;
+            }
+            if (engine.getAlphaTesting()) {
+                this._defines.ALPHATEST = true;
+            }
+            if (this._shouldUseAlphaFromDiffuseTexture()) {
+                this._defines.ALPHAFROMDIFFUSE = true;
+            }
+            if (this.useEmissiveAsIllumination) {
+                this._defines.EMISSIVEASILLUMINATION = true;
+            }
+            if (this.linkEmissiveWithDiffuse) {
+                this._defines.LINKEMISSIVEWITHDIFFUSE = true;
+            }
+            if (this.useLogarithmicDepth) {
+                this._defines.LOGARITHMICDEPTH = true;
+            }
+            if (this.cameraColorCurves) {
+                this._defines.CAMERACOLORCURVES = true;
+            }
+            // Point size
+            if (this.pointsCloud || scene.forcePointsCloud) {
+                this._defines.POINTSIZE = true;
+            }
+            // Fog
+            if (scene.fogEnabled && mesh && mesh.applyFog && scene.fogMode !== BABYLON.Scene.FOGMODE_NONE && this.fogEnabled) {
+                this._defines.FOG = true;
+            }
+            if (BABYLON.StandardMaterial.FresnelEnabled) {
+                // Fresnel
+                if (this.diffuseFresnelParameters && this.diffuseFresnelParameters.isEnabled ||
+                    this.opacityFresnelParameters && this.opacityFresnelParameters.isEnabled ||
+                    this.emissiveFresnelParameters && this.emissiveFresnelParameters.isEnabled ||
+                    this.refractionFresnelParameters && this.refractionFresnelParameters.isEnabled ||
+                    this.reflectionFresnelParameters && this.reflectionFresnelParameters.isEnabled) {
+                    if (this.diffuseFresnelParameters && this.diffuseFresnelParameters.isEnabled) {
+                        this._defines.DIFFUSEFRESNEL = true;
+                    }
+                    if (this.opacityFresnelParameters && this.opacityFresnelParameters.isEnabled) {
+                        this._defines.OPACITYFRESNEL = true;
+                    }
+                    if (this.reflectionFresnelParameters && this.reflectionFresnelParameters.isEnabled) {
+                        this._defines.REFLECTIONFRESNEL = true;
+                        if (this.useReflectionFresnelFromSpecular) {
+                            this._defines.REFLECTIONFRESNELFROMSPECULAR = true;
+                        }
+                    }
+                    if (this.refractionFresnelParameters && this.refractionFresnelParameters.isEnabled) {
+                        this._defines.REFRACTIONFRESNEL = true;
+                    }
+                    if (this.emissiveFresnelParameters && this.emissiveFresnelParameters.isEnabled) {
+                        this._defines.EMISSIVEFRESNEL = true;
+                    }
+                    needNormals = true;
+                    this._defines.FRESNEL = true;
+                }
+            }
+            if (this._defines.SPECULARTERM && this.useSpecularOverAlpha) {
+                this._defines.SPECULAROVERALPHA = true;
+            }
+            // Attribs
+            if (mesh) {
+                if (needNormals && mesh.isVerticesDataPresent(BABYLON.VertexBuffer.NormalKind)) {
+                    this._defines.NORMAL = true;
+                }
+                if (needUVs) {
+                    if (mesh.isVerticesDataPresent(BABYLON.VertexBuffer.UVKind)) {
+                        this._defines.UV1 = true;
+                    }
+                    if (mesh.isVerticesDataPresent(BABYLON.VertexBuffer.UV2Kind)) {
+                        this._defines.UV2 = true;
+                    }
+                }
+                if (mesh.useVertexColors && mesh.isVerticesDataPresent(BABYLON.VertexBuffer.ColorKind)) {
+                    this._defines.VERTEXCOLOR = true;
+                    if (mesh.hasVertexAlpha) {
+                        this._defines.VERTEXALPHA = 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 BABYLON.EffectFallbacks();
+                if (this._defines.REFLECTION) {
+                    fallbacks.addFallback(0, "REFLECTION");
+                }
+                if (this._defines.SPECULAR) {
+                    fallbacks.addFallback(0, "SPECULAR");
+                }
+                if (this._defines.BUMP) {
+                    fallbacks.addFallback(0, "BUMP");
+                }
+                if (this._defines.PARALLAX) {
+                    fallbacks.addFallback(1, "PARALLAX");
+                }
+                if (this._defines.PARALLAXOCCLUSION) {
+                    fallbacks.addFallback(0, "PARALLAXOCCLUSION");
+                }
+                if (this._defines.SPECULAROVERALPHA) {
+                    fallbacks.addFallback(0, "SPECULAROVERALPHA");
+                }
+                if (this._defines.FOG) {
+                    fallbacks.addFallback(1, "FOG");
+                }
+                if (this._defines.POINTSIZE) {
+                    fallbacks.addFallback(0, "POINTSIZE");
+                }
+                if (this._defines.LOGARITHMICDEPTH) {
+                    fallbacks.addFallback(0, "LOGARITHMICDEPTH");
+                }
+                BABYLON.MaterialHelper.HandleFallbacksForShadows(this._defines, fallbacks, this.maxSimultaneousLights);
+                if (this._defines.SPECULARTERM) {
+                    fallbacks.addFallback(0, "SPECULARTERM");
+                }
+                if (this._defines.DIFFUSEFRESNEL) {
+                    fallbacks.addFallback(1, "DIFFUSEFRESNEL");
+                }
+                if (this._defines.OPACITYFRESNEL) {
+                    fallbacks.addFallback(2, "OPACITYFRESNEL");
+                }
+                if (this._defines.REFLECTIONFRESNEL) {
+                    fallbacks.addFallback(3, "REFLECTIONFRESNEL");
+                }
+                if (this._defines.EMISSIVEFRESNEL) {
+                    fallbacks.addFallback(4, "EMISSIVEFRESNEL");
+                }
+                if (this._defines.FRESNEL) {
+                    fallbacks.addFallback(4, "FRESNEL");
+                }
+                //Attributes
+                var attribs = [BABYLON.VertexBuffer.PositionKind];
+                if (this._defines.NORMAL) {
+                    attribs.push(BABYLON.VertexBuffer.NormalKind);
+                }
+                if (this._defines.UV1) {
+                    attribs.push(BABYLON.VertexBuffer.UVKind);
+                }
+                if (this._defines.UV2) {
+                    attribs.push(BABYLON.VertexBuffer.UV2Kind);
+                }
+                if (this._defines.VERTEXCOLOR) {
+                    attribs.push(BABYLON.VertexBuffer.ColorKind);
+                }
+                BABYLON.MaterialHelper.PrepareAttributesForBones(attribs, mesh, this._defines, fallbacks);
+                BABYLON.MaterialHelper.PrepareAttributesForInstances(attribs, this._defines);
+                var shaderName = "default";
+                if (this.builder) {
+                    shaderName = this.builder(new CustomShaderHelper(), shaderName, this._mainPart, this._diffusePart, this._vertexPositionPart);
+                }
+                var join = this._defines.toString();
+                var uniforms = ["world", "view", "viewProjection", "vEyePosition", "vLightsType", "vAmbientColor", "vDiffuseColor", "vSpecularColor", "vEmissiveColor",
+                    "vFogInfos", "vFogColor", "pointSize",
+                    "vDiffuseInfos", "vAmbientInfos", "vOpacityInfos", "vReflectionInfos", "vEmissiveInfos", "vSpecularInfos", "vBumpInfos", "vLightmapInfos", "vRefractionInfos",
+                    "mBones",
+                    "vClipPlane", "diffuseMatrix", "ambientMatrix", "opacityMatrix", "reflectionMatrix", "emissiveMatrix", "specularMatrix", "bumpMatrix", "lightmapMatrix", "refractionMatrix",
+                    "depthValues",
+                    "diffuseLeftColor", "diffuseRightColor", "opacityParts", "reflectionLeftColor", "reflectionRightColor", "emissiveLeftColor", "emissiveRightColor", "refractionLeftColor", "refractionRightColor",
+                    "logarithmicDepthConstant"
+                ];
+                var samplers = ["diffuseSampler", "ambientSampler", "opacitySampler", "reflectionCubeSampler", "reflection2DSampler", "emissiveSampler", "specularSampler", "bumpSampler", "lightmapSampler", "refractionCubeSampler", "refraction2DSampler"];
+                if (this._defines.CAMERACOLORCURVES) {
+                    BABYLON.ColorCurves.PrepareUniforms(uniforms);
+                }
+                if (this._defines.CAMERACOLORGRADING) {
+                    BABYLON.ColorGradingTexture.PrepareUniformsAndSamplers(uniforms, samplers);
+                }
+                BABYLON.MaterialHelper.PrepareUniformsAndSamplersList(uniforms, samplers, this._defines, this.maxSimultaneousLights);
+                this._effect = scene.getEngine().createEffect(shaderName, attribs, uniforms, samplers, join, fallbacks, this.onCompiled, this.onError, { maxSimultaneousLights: this.maxSimultaneousLights - 1 });
+            }
+            if (!this._effect.isReady()) {
+                return false;
+            }
+            this._renderId = scene.getRenderId();
+            this._wasPreviouslyReady = true;
+            if (mesh) {
+                if (!mesh._materialDefines) {
+                    mesh._materialDefines = new BABYLON.StandardMaterialDefines();
+                }
+                this._defines.cloneTo(mesh._materialDefines);
+            }
+            return true;
+        };
+        return CustomMaterial;
+    }(BABYLON.StandardMaterial));
+    BABYLON.CustomMaterial = CustomMaterial;
+})(BABYLON || (BABYLON = {}));
+
+//# sourceMappingURL=babylon.customMaterial.js.map

File diff suppressed because it is too large
+ 1 - 0
dist/preview release/materialsLibrary/babylon.customMaterial.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;
+    }
+}

File diff suppressed because it is too large
+ 209 - 0
dist/preview release/materialsLibrary/babylon.shadowOnlyMaterial.js


File diff suppressed because it is too large
+ 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="../simple/babylon.simpleMaterial.d.ts" />
 declare module BABYLON {
     class WaterMaterial extends Material {
         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="../simple/babylon.simpleMaterial.ts"/>
 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; }

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

@@ -16,6 +16,8 @@
  - All deprecated functions and properties were removed ([deltakosh](https://github.com/deltakosh))
 
 ### Updates
+- Introduced `boundingBox.centerWorld` and `boundingBox.extendSizeWorld` ([deltakosh](https://github.com/deltakosh))
+- Improved FXAA post-process ([deltakosh](https://github.com/deltakosh))
 - Added `Light.customProjectionMatrixBuilder` to allow developers to define their own projection matrix for shadows ([deltakosh](https://github.com/deltakosh))
 - Added `set()` function to all basic types ([deltakosh](https://github.com/deltakosh))
 - Added `HDRCubeTextureAssetTask` to AssetManager ([deltakosh](https://github.com/deltakosh))
@@ -30,12 +32,17 @@
 - `GroundMesh`, `facetData` and `SolidParticleSystem` improvement in normal computations ([jerome](https://github.com/jbousquie))   
 - Added `AbstractMesh.addRotation()` ([jerome](https://github.com/jbousquie))  
 - Added `Quaternion.RotationQuaternionFromAxis()` and `Quaternion.RotationQuaternionFromAxisToRef()` ([jerome](https://github.com/jbousquie), thanks to [abow](https://github.com/abow))   
+- Added parameters `uvs` and `colors` to `MeshBuilder.CreateRibbon()` ([jerome](https://github.com/jbousquie))  
 - Added `Curve3.CreateCatmullRomSpline()` ([jerome](https://github.com/jbousquie) and [BitOfGold](https://github.com/BitOfGold))  
 - Added the optional parameter`colorFilter` to `CreateGroundFromHeightMap()` ([jerome](https://github.com/jbousquie))  
 - 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))
 - 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)) 
+- Added `VertexBuffer.TangentKind` to specify tangents in place of shader-calculated tangents ([dewadswo](https://github.com/dewadswo), [bghgary](https://github.com/bghgary))
  
 ### Bug fixes
 - Fixed a bug with spotlight direction ([deltakosh](https://github.com/deltakosh)) 
@@ -83,6 +90,8 @@
 - 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
 

+ 139 - 107
inspector/src/Inspector.ts

@@ -1,119 +1,129 @@
 module INSPECTOR {
     export class Inspector {
 
-        private _c2diwrapper    : HTMLElement;
+        private _c2diwrapper: HTMLElement;
         // private _detailsPanel: DetailPanel;
         /** The panel displayed at the top of the inspector */
-        private _topPanel       : HTMLElement;
+        private _topPanel: HTMLElement;
         /** The div containing the content of the active tab */
-        private _tabPanel       : HTMLElement;
+        private _tabPanel: HTMLElement;
         /** The panel containing the list if items */
         // private _treePanel   : HTMLElement;
         /** 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) */
-        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 */
-        public static WINDOW : Window;
+        public static WINDOW: Window;
         /** 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*/
-        private _canvasStyle :any ;
+        private _canvasStyle: any;
+
+        private _initialTab: number;
+
+        private _parentElement: HTMLElement;
 
         /** 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 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.
-            this._scene     = scene;
-            
+            this._scene = scene;
+
             // 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
             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
-            if (popup) { 
+            if (popup) {
                 // 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
-            } else {        
+            } else {
                 // 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);
 
                 // 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,
-                    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
-                this._c2diwrapper  = Helpers.CreateDiv('insp-wrapper');
-                
+                this._c2diwrapper = Helpers.CreateDiv('insp-wrapper');
+
                 // copy style from canvas to wrapper
                 for (let prop in this._canvasStyle) {
                     this._c2diwrapper.style[prop] = this._canvasStyle[prop];
                 }
-                
+
                 // 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 (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)
-                    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) {
-                        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
                 let parent = this._getRelativeParent(canvas);
 
-                let parentWidthPx  = parent.clientWidth;
+                let parentWidthPx = parent.clientWidth;
                 let parentHeightPx = parent.clientHeight;
-                
+
                 let pWidth = widthPx / parentWidthPx * 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
                 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.paddingLeft = "0";
                 canvas.style.paddingTop = "0";
@@ -127,25 +137,46 @@ module INSPECTOR {
 
 
                 // Replace canvas with the wrapper...
+                // if (this._parentElement) {
+                //     canvasParent.replaceChild(this._parentElement, canvas);
+                //     this._parentElement.appendChild(canvas);
+                // }
+                // else {
                 canvasParent.replaceChild(this._c2diwrapper, canvas);
                 // ... and add canvas to the wrapper
                 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);
+                }
+
                 // 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
-                this._buildInspector(inspector);   
+                this._buildInspector(inspector);
                 // Send resize event to the window
                 Helpers.SEND_EVENT('resize');
                 this._tabbar.updateWidth();
@@ -156,25 +187,25 @@ module INSPECTOR {
                 this.refresh();
             }
         }
-        
+
         /**
          * 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'.
          * 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 (!elem.parentElement) {
                 return elem;
-            } 
+            }
             let computedStyle = Inspector.WINDOW.getComputedStyle(elem);
             // looking for the first element absolute or relative
             if (lookForAbsoluteOrRelative) {
                 // if found, return this one
                 if (computedStyle.position === "relative" || computedStyle.position === "absolute") {
                     return elem;
-                }else {
+                } else {
                     // otherwise keep looking
                     return this._getRelativeParent(elem.parentElement, true);
                 }
@@ -186,30 +217,30 @@ module INSPECTOR {
                 } else {
                     // the elem has a position relative or absolute, look for the closest relative/absolute parent
                     return this._getRelativeParent(elem.parentElement, true);
-                }         
-            }   
+                }
+            }
         }
-        
+
         /** Build the inspector panel in the given HTML element */
-        private _buildInspector(parent:HTMLElement) {            
+        private _buildInspector(parent: HTMLElement) {
             // tabbar
-            this._tabbar = new TabBar(this);
+            this._tabbar = new TabBar(this, this._initialTab);
 
             // Top panel
             this._topPanel = Helpers.CreateDiv('top-panel', parent);
             // Add tabbar
             this._topPanel.appendChild(this._tabbar.toHtml());
             this._tabbar.updateWidth();
-            
+
             // Tab panel
             this._tabPanel = Helpers.CreateDiv('tab-panel-content', this._topPanel);
-            
+
         }
 
-        public get scene() : BABYLON.Scene {
+        public get scene(): BABYLON.Scene {
             return this._scene;
         }
-        public get popupMode() : boolean {
+        public get popupMode(): boolean {
             return this._popupMode;
         }
 
@@ -217,12 +248,12 @@ module INSPECTOR {
          * Filter the list of item present in the tree.
          * 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);
         }
-        
+
         /** Display the mesh tab on the given object */
-        public displayObjectDetails(mesh:BABYLON.AbstractMesh) {
+        public displayObjectDetails(mesh: BABYLON.AbstractMesh) {
             this._tabbar.switchMeshTab(mesh);
         }
 
@@ -234,39 +265,40 @@ module INSPECTOR {
             // Get the active tab and its items
             let activeTab = this._tabbar.getActiveTab();
             activeTab.update();
-            this._tabPanel.appendChild(activeTab.getPanel());            
+            this._tabPanel.appendChild(activeTab.getPanel());
             Helpers.SEND_EVENT('resize');
-            
-        }        
-        
+
+        }
+
         /** Remove the inspector panel when it's built as a right panel:
          * remove the right panel and remove the wrapper
          */
         public dispose() {
             if (!this._popupMode) {
                 // Get canvas
-                let canvas         = this._scene.getEngine().getRenderingCanvas(); 
+                let canvas = this._scene.getEngine().getRenderingCanvas();
 
                 // restore canvas style
                 for (let prop in this._canvasStyle) {
                     canvas.style[prop] = this._canvasStyle[prop];
                 }
                 // Get parent of the wrapper 
-                let canvasParent   = canvas.parentElement.parentElement;  
+                let canvasParent = canvas.parentElement.parentElement;
+
                 canvasParent.insertBefore(canvas, this._c2diwrapper);
                 // Remove wrapper
                 Helpers.CleanDiv(this._c2diwrapper);
-                this._c2diwrapper.remove();                   
+                this._c2diwrapper.remove();
                 // Send resize event to the window
-                Helpers.SEND_EVENT('resize');              
+                Helpers.SEND_EVENT('resize');
             }
         }
-        
+
         /** Open the inspector in a new popup
          * Set 'firstTime' to true if there is no inspector created beforehands
          */
-        public openPopup(firstTime?:boolean) {    
-            
+        public openPopup(firstTime?: boolean) {
+
             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');
             } else {
@@ -275,16 +307,16 @@ module INSPECTOR {
                 popup.document.title = 'Babylon.js INSPECTOR';
                 // Get the inspector 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');
-                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;
-                    popup.document.head.appendChild(link);              
-                } 
+                    popup.document.head.appendChild(link);
+                }
                 // Dispose the right panel if existing
                 if (!firstTime) {
                     this.dispose();
@@ -295,21 +327,21 @@ module INSPECTOR {
                 Inspector.DOCUMENT = popup.document;
                 Inspector.WINDOW = popup;
                 // Build the inspector wrapper
-                this._c2diwrapper  = Helpers.CreateDiv('insp-wrapper', popup.document.body);
+                this._c2diwrapper = Helpers.CreateDiv('insp-wrapper', popup.document.body);
                 // add inspector     
-                let inspector      = Helpers.CreateDiv('insp-right-panel', this._c2diwrapper);
+                let inspector = Helpers.CreateDiv('insp-right-panel', this._c2diwrapper);
                 inspector.classList.add('popupmode');
                 // and build it in the popup  
-                this._buildInspector(inspector); 
+                this._buildInspector(inspector);
                 // Rebuild it
-                this.refresh(); 
+                this.refresh();
 
-                popup.addEventListener('resize', () => {                    
+                popup.addEventListener('resize', () => {
                     if (this._tabbar) {
                         this._tabbar.updateWidth()
                     }
                 });
-            }             
+            }
         }
     }
 }

+ 59 - 0
inspector/src/adapters/SoundAdapter.ts

@@ -0,0 +1,59 @@
+module INSPECTOR {
+
+    export class SoundAdapter
+        extends Adapter
+        implements ISoundInteractions {
+
+        constructor(obj: BABYLON.Sound) {
+            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
+
+            let soundProperties = PROPERTIES['Sound'].properties;
+
+
+            for (let dirty of soundProperties) {
+                let infos = new Property(dirty, this._obj);
+                propertiesLines.push(new PropertyLine(infos));
+            }
+            return propertiesLines;
+        }
+
+        public getTools(): Array<AbstractTreeTool> {
+            let tools = [];
+            tools.push(new SoundInteractions(this));
+            return tools;
+        }
+
+        public setPlaying(callback: Function) {
+            if ((this._obj as BABYLON.Sound).isPlaying) {
+                (this._obj as BABYLON.Sound).pause();
+            }
+            else {
+                (this._obj as BABYLON.Sound).play();
+            }
+            (this._obj as BABYLON.Sound).onended = () => {
+                callback();
+            }
+        }
+    }
+}

+ 18 - 0
inspector/src/properties.ts

@@ -75,6 +75,24 @@ module INSPECTOR {
             type: BABYLON.FontTexture
         },
 
+        'Sound': {
+            type: BABYLON.Sound,
+            properties: [
+                'name',
+                'autoplay',
+                'loop',
+                'useCustomAttenuation',
+                'soundTrackId',
+                'spatialSound',
+                'refDistance',
+                'rolloffFactor',
+                'maxDistance',
+                'distanceModel',
+                'isPlaying',
+                'isPaused'
+            ]
+        },
+
         'ArcRotateCamera': {
             type: BABYLON.ArcRotateCamera,
             properties: [

+ 26 - 0
inspector/src/tabs/SoundTab.ts

@@ -0,0 +1,26 @@
+module INSPECTOR {
+
+    export class SoundTab extends PropertyTab {
+
+        constructor(tabbar: TabBar, inspector: Inspector) {
+            super(tabbar, 'Audio', inspector);
+        }
+        /* Overrides super */
+        protected _getTree(): Array<TreeItem> {
+            let arr = [];
+
+            // get all cameras from the first scene
+            let instances = this._inspector.scene;
+            for (let sounds of instances.soundTracks) {
+                let sound = sounds.soundCollection;
+                sound.forEach(element => {
+                    arr.push(new TreeItem(this, new SoundAdapter(element)));
+                });
+
+            }
+            return arr;
+        }
+
+    }
+
+}

+ 10 - 3
inspector/src/tabs/TabBar.ts

@@ -21,7 +21,7 @@ module INSPECTOR {
         /** The list of tabs visible, displayed in the tab bar */
         private _visibleTabs: Array<Tab> = [];
 
-        constructor(inspector: Inspector) {
+        constructor(inspector: Inspector, initialTab?: number) {
             super();
             this._inspector = inspector;
             this._tabs.push(new SceneTab(this, this._inspector));
@@ -39,12 +39,19 @@ module INSPECTOR {
             this._tabs.push(new MaterialTab(this, this._inspector));
 
             this._tabs.push(new CameraTab(this, this._inspector));
+            this._tabs.push(new SoundTab(this, this._inspector));
 
             this._toolBar = new Toolbar(this._inspector);
 
             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
             for (let tab of this._tabs) {

+ 42 - 0
inspector/src/treetools/SoundInteractions.ts

@@ -0,0 +1,42 @@
+module INSPECTOR {
+
+    export interface ISoundInteractions {
+        setPlaying: (callback: Function) => void;
+    }
+
+    /**
+     * 
+     */
+    export class SoundInteractions extends AbstractTreeTool {
+        private playSound: ISoundInteractions;
+        private b: boolean;
+
+        constructor(playSound: ISoundInteractions) {
+            super();
+            this.playSound = playSound;
+            this.b = false;
+            this._elem.classList.add('fa-play');
+        }
+
+        protected action() {
+            super.action();
+            this._playSound();
+        }
+
+        private _playSound() {
+
+            if (this._elem.classList.contains('fa-play')) {
+                this._elem.classList.remove('fa-play');
+                this._elem.classList.add('fa-pause');
+            }
+            else {
+                this._elem.classList.remove('fa-pause');
+                this._elem.classList.add('fa-play');
+            }
+            this.playSound.setPlaying(() => {
+                this._elem.classList.remove('fa-pause');
+                this._elem.classList.add('fa-play');
+            });
+        }
+    }
+}

+ 13 - 1
inspector/test/index.js

@@ -16,7 +16,7 @@ var Test = (function () {
     Test.prototype._run = function () {
         var _this = this;
         this._initScene();
-        this.scene.debugLayer.show();
+        this.scene.debugLayer.show({ popup: false, initialTab: 4 });
         this.scene.executeWhenReady(function () {
             _this._initGame();
             _this.engine.runRenderLoop(function () {
@@ -48,6 +48,16 @@ var Test = (function () {
             camera4.parent = camera;
         */
 
+        //Sounds
+        var jump = new BABYLON.Sound("Jump", "/assets/sounds/jump.wav", scene);
+        var explosion = new BABYLON.Sound("Explosion", "/assets/sounds/explosion.wav", scene);
+        jump.setVolume(0.1);
+        window.addEventListener("keydown", function (evt) {
+            if (evt.keyCode === 32) {
+                jump.play();
+            }
+        });
+
         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);
@@ -181,6 +191,8 @@ var Test = (function () {
 
         plane.material = materialPlane;
 
+
+
         var d = 50;
         var cubes = new Array();
         for (var i = 0; i < 360; i += 20) {

+ 1 - 1
localDev/index.html

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

+ 0 - 34
localDev/template/index.js

@@ -1,34 +0,0 @@
-/// <reference path="../../dist/preview release/babylon.d.ts"/>
-
-// Playground like creation of the scene
-var createScene = function () {
-
-    // This creates a basic Babylon Scene object (non-mesh)
-    var scene = new BABYLON.Scene(engine);
-
-    // This creates and positions a free camera (non-mesh)
-    var camera = new BABYLON.FreeCamera("camera1", new BABYLON.Vector3(0, 5, -10), scene);
-
-    // This targets the camera to scene origin
-    camera.setTarget(BABYLON.Vector3.Zero());
-
-    // This attaches the camera to the canvas
-    camera.attachControl(canvas, true);
-
-    // This creates a light, aiming 0,1,0 - to the sky (non-mesh)
-    var light = new BABYLON.HemisphericLight("light1", new BABYLON.Vector3(0, 1, 0), scene);
-
-    // Default intensity is 1. Let's dim the light a small amount
-    light.intensity = 0.7;
-
-    // Our built-in 'sphere' shape. Params: name, subdivs, size, scene
-    var sphere = BABYLON.Mesh.CreateSphere("sphere1", 16, 2, scene);
-
-    // Move the sphere upward 1/2 its height
-    sphere.position.y = 1;
-
-    // Our built-in 'ground' shape. Params: name, width, depth, subdivs, scene
-    var ground = BABYLON.Mesh.CreateGround("ground1", 6, 6, 2, scene);
-
-    return scene;
-};

+ 6 - 2
materialsLibrary/index.html

@@ -168,7 +168,6 @@
 				std.diffuseTexture.uScale = 5;
 				std.diffuseTexture.vScale = 5;
 
-                // Lava
                 var lava = prepareLava();
 
 				var simple = new BABYLON.SimpleMaterial("simple", scene);
@@ -199,19 +198,24 @@
 				var sky = prepareSky();
                 
                 var grid = prepareGrid();
+
+				var shadowOnly = new BABYLON.ShadowOnlyMaterial();
 				
 				// Default to std
 				var currentMaterial = std;
 				sphere.material = std;				
 				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);
 					skybox.material = skyboxMaterial;
 					currentMesh.isVisible = true;
 					fur.resetFur();
                     
 					switch (options.material) {
+						case "shadowOnly":
+							currentMaterial = shadowOnly;
+							break;						
 						case "simple":
 							currentMaterial = simple;
 							break;

File diff suppressed because it is too large
+ 1 - 0
materialsLibrary/src/custom/Babylon.CustomMaterial.js.map


+ 398 - 0
materialsLibrary/src/custom/babylon.customMaterial.js

@@ -0,0 +1,398 @@
+/// <reference path="../../../dist/preview release/babylon.d.ts"/>
+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 BABYLON;
+(function (BABYLON) {
+    var CustomShaderHelper = (function () {
+        function CustomShaderHelper() {
+        }
+        return CustomShaderHelper;
+    }());
+    BABYLON.CustomShaderHelper = CustomShaderHelper;
+    var CustomMaterial = (function (_super) {
+        __extends(CustomMaterial, _super);
+        function CustomMaterial(name, builder, scene) {
+            var _this = _super.call(this, name, scene) || this;
+            _this._mainPart = 'void main(void) {';
+            _this._diffusePart = 'vec3 diffuseColor=vDiffuseColor.rgb;';
+            _this._vertexPositionPart = 'gl_Position=viewProjection*finalWorld*vec4(position,1.0);';
+            _this.builder = builder;
+            return _this;
+        }
+        CustomMaterial.prototype.isReady = function (mesh, useInstances) {
+            if (this.isFrozen) {
+                if (this._wasPreviouslyReady) {
+                    return true;
+                }
+            }
+            var scene = this.getScene();
+            var engine = scene.getEngine();
+            var needUVs = false;
+            var needNormals = false;
+            this._defines.reset();
+            // Lights
+            if (scene.lightsEnabled && !this.disableLighting) {
+                needNormals = BABYLON.MaterialHelper.PrepareDefinesForLights(scene, mesh, this._defines, this.maxSimultaneousLights);
+            }
+            if (!this.checkReadyOnEveryCall) {
+                if (this._renderId === scene.getRenderId()) {
+                    if (this._checkCache(scene, mesh, useInstances)) {
+                        return true;
+                    }
+                }
+            }
+            // Textures
+            if (scene.texturesEnabled) {
+                if (this.diffuseTexture && BABYLON.StandardMaterial.DiffuseTextureEnabled) {
+                    if (!this.diffuseTexture.isReady()) {
+                        return false;
+                    }
+                    else {
+                        needUVs = true;
+                        this._defines.DIFFUSE = true;
+                    }
+                }
+                if (this.ambientTexture && BABYLON.StandardMaterial.AmbientTextureEnabled) {
+                    if (!this.ambientTexture.isReady()) {
+                        return false;
+                    }
+                    else {
+                        needUVs = true;
+                        this._defines.AMBIENT = true;
+                    }
+                }
+                if (this.opacityTexture && BABYLON.StandardMaterial.OpacityTextureEnabled) {
+                    if (!this.opacityTexture.isReady()) {
+                        return false;
+                    }
+                    else {
+                        needUVs = true;
+                        this._defines.OPACITY = true;
+                        if (this.opacityTexture.getAlphaFromRGB) {
+                            this._defines.OPACITYRGB = true;
+                        }
+                    }
+                }
+                if (this.reflectionTexture && BABYLON.StandardMaterial.ReflectionTextureEnabled) {
+                    if (!this.reflectionTexture.isReady()) {
+                        return false;
+                    }
+                    else {
+                        needNormals = true;
+                        this._defines.REFLECTION = true;
+                        if (this.roughness > 0) {
+                            this._defines.ROUGHNESS = true;
+                        }
+                        if (this.useReflectionOverAlpha) {
+                            this._defines.REFLECTIONOVERALPHA = true;
+                        }
+                        if (this.reflectionTexture.coordinatesMode === BABYLON.Texture.INVCUBIC_MODE) {
+                            this._defines.INVERTCUBICMAP = true;
+                        }
+                        this._defines.REFLECTIONMAP_3D = this.reflectionTexture.isCube;
+                        switch (this.reflectionTexture.coordinatesMode) {
+                            case BABYLON.Texture.CUBIC_MODE:
+                            case BABYLON.Texture.INVCUBIC_MODE:
+                                this._defines.REFLECTIONMAP_CUBIC = true;
+                                break;
+                            case BABYLON.Texture.EXPLICIT_MODE:
+                                this._defines.REFLECTIONMAP_EXPLICIT = true;
+                                break;
+                            case BABYLON.Texture.PLANAR_MODE:
+                                this._defines.REFLECTIONMAP_PLANAR = true;
+                                break;
+                            case BABYLON.Texture.PROJECTION_MODE:
+                                this._defines.REFLECTIONMAP_PROJECTION = true;
+                                break;
+                            case BABYLON.Texture.SKYBOX_MODE:
+                                this._defines.REFLECTIONMAP_SKYBOX = true;
+                                break;
+                            case BABYLON.Texture.SPHERICAL_MODE:
+                                this._defines.REFLECTIONMAP_SPHERICAL = true;
+                                break;
+                            case BABYLON.Texture.EQUIRECTANGULAR_MODE:
+                                this._defines.REFLECTIONMAP_EQUIRECTANGULAR = true;
+                                break;
+                            case BABYLON.Texture.FIXED_EQUIRECTANGULAR_MODE:
+                                this._defines.REFLECTIONMAP_EQUIRECTANGULAR_FIXED = true;
+                                break;
+                        }
+                    }
+                }
+                if (this.emissiveTexture && BABYLON.StandardMaterial.EmissiveTextureEnabled) {
+                    if (!this.emissiveTexture.isReady()) {
+                        return false;
+                    }
+                    else {
+                        needUVs = true;
+                        this._defines.EMISSIVE = true;
+                    }
+                }
+                if (this.lightmapTexture && BABYLON.StandardMaterial.LightmapTextureEnabled) {
+                    if (!this.lightmapTexture.isReady()) {
+                        return false;
+                    }
+                    else {
+                        needUVs = true;
+                        this._defines.LIGHTMAP = true;
+                        this._defines.USELIGHTMAPASSHADOWMAP = this.useLightmapAsShadowmap;
+                    }
+                }
+                if (this.specularTexture && BABYLON.StandardMaterial.SpecularTextureEnabled) {
+                    if (!this.specularTexture.isReady()) {
+                        return false;
+                    }
+                    else {
+                        needUVs = true;
+                        this._defines.SPECULAR = true;
+                        this._defines.GLOSSINESS = this.useGlossinessFromSpecularMapAlpha;
+                    }
+                }
+                if (scene.getEngine().getCaps().standardDerivatives && this.bumpTexture && BABYLON.StandardMaterial.BumpTextureEnabled) {
+                    if (!this.bumpTexture.isReady()) {
+                        return false;
+                    }
+                    else {
+                        needUVs = true;
+                        this._defines.BUMP = true;
+                        if (this.useParallax) {
+                            this._defines.PARALLAX = true;
+                            if (this.useParallaxOcclusion) {
+                                this._defines.PARALLAXOCCLUSION = true;
+                            }
+                        }
+                        if (this.invertNormalMapX) {
+                            this._defines.INVERTNORMALMAPX = true;
+                        }
+                        if (this.invertNormalMapY) {
+                            this._defines.INVERTNORMALMAPY = true;
+                        }
+                        if (scene._mirroredCameraPosition) {
+                            this._defines.INVERTNORMALMAPX = !this._defines.INVERTNORMALMAPX;
+                            this._defines.INVERTNORMALMAPY = !this._defines.INVERTNORMALMAPY;
+                        }
+                    }
+                }
+                if (this.refractionTexture && BABYLON.StandardMaterial.RefractionTextureEnabled) {
+                    if (!this.refractionTexture.isReady()) {
+                        return false;
+                    }
+                    else {
+                        needUVs = true;
+                        this._defines.REFRACTION = true;
+                        this._defines.REFRACTIONMAP_3D = this.refractionTexture.isCube;
+                    }
+                }
+                if (this.cameraColorGradingTexture && BABYLON.StandardMaterial.ColorGradingTextureEnabled) {
+                    if (!this.cameraColorGradingTexture.isReady()) {
+                        return false;
+                    }
+                    else {
+                        this._defines.CAMERACOLORGRADING = true;
+                    }
+                }
+            }
+            // Effect
+            if (scene.clipPlane) {
+                this._defines.CLIPPLANE = true;
+            }
+            if (engine.getAlphaTesting()) {
+                this._defines.ALPHATEST = true;
+            }
+            if (this._shouldUseAlphaFromDiffuseTexture()) {
+                this._defines.ALPHAFROMDIFFUSE = true;
+            }
+            if (this.useEmissiveAsIllumination) {
+                this._defines.EMISSIVEASILLUMINATION = true;
+            }
+            if (this.linkEmissiveWithDiffuse) {
+                this._defines.LINKEMISSIVEWITHDIFFUSE = true;
+            }
+            if (this.useLogarithmicDepth) {
+                this._defines.LOGARITHMICDEPTH = true;
+            }
+            if (this.cameraColorCurves) {
+                this._defines.CAMERACOLORCURVES = true;
+            }
+            // Point size
+            if (this.pointsCloud || scene.forcePointsCloud) {
+                this._defines.POINTSIZE = true;
+            }
+            // Fog
+            if (scene.fogEnabled && mesh && mesh.applyFog && scene.fogMode !== BABYLON.Scene.FOGMODE_NONE && this.fogEnabled) {
+                this._defines.FOG = true;
+            }
+            if (BABYLON.StandardMaterial.FresnelEnabled) {
+                // Fresnel
+                if (this.diffuseFresnelParameters && this.diffuseFresnelParameters.isEnabled ||
+                    this.opacityFresnelParameters && this.opacityFresnelParameters.isEnabled ||
+                    this.emissiveFresnelParameters && this.emissiveFresnelParameters.isEnabled ||
+                    this.refractionFresnelParameters && this.refractionFresnelParameters.isEnabled ||
+                    this.reflectionFresnelParameters && this.reflectionFresnelParameters.isEnabled) {
+                    if (this.diffuseFresnelParameters && this.diffuseFresnelParameters.isEnabled) {
+                        this._defines.DIFFUSEFRESNEL = true;
+                    }
+                    if (this.opacityFresnelParameters && this.opacityFresnelParameters.isEnabled) {
+                        this._defines.OPACITYFRESNEL = true;
+                    }
+                    if (this.reflectionFresnelParameters && this.reflectionFresnelParameters.isEnabled) {
+                        this._defines.REFLECTIONFRESNEL = true;
+                        if (this.useReflectionFresnelFromSpecular) {
+                            this._defines.REFLECTIONFRESNELFROMSPECULAR = true;
+                        }
+                    }
+                    if (this.refractionFresnelParameters && this.refractionFresnelParameters.isEnabled) {
+                        this._defines.REFRACTIONFRESNEL = true;
+                    }
+                    if (this.emissiveFresnelParameters && this.emissiveFresnelParameters.isEnabled) {
+                        this._defines.EMISSIVEFRESNEL = true;
+                    }
+                    needNormals = true;
+                    this._defines.FRESNEL = true;
+                }
+            }
+            if (this._defines.SPECULARTERM && this.useSpecularOverAlpha) {
+                this._defines.SPECULAROVERALPHA = true;
+            }
+            // Attribs
+            if (mesh) {
+                if (needNormals && mesh.isVerticesDataPresent(BABYLON.VertexBuffer.NormalKind)) {
+                    this._defines.NORMAL = true;
+                }
+                if (needUVs) {
+                    if (mesh.isVerticesDataPresent(BABYLON.VertexBuffer.UVKind)) {
+                        this._defines.UV1 = true;
+                    }
+                    if (mesh.isVerticesDataPresent(BABYLON.VertexBuffer.UV2Kind)) {
+                        this._defines.UV2 = true;
+                    }
+                }
+                if (mesh.useVertexColors && mesh.isVerticesDataPresent(BABYLON.VertexBuffer.ColorKind)) {
+                    this._defines.VERTEXCOLOR = true;
+                    if (mesh.hasVertexAlpha) {
+                        this._defines.VERTEXALPHA = 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 BABYLON.EffectFallbacks();
+                if (this._defines.REFLECTION) {
+                    fallbacks.addFallback(0, "REFLECTION");
+                }
+                if (this._defines.SPECULAR) {
+                    fallbacks.addFallback(0, "SPECULAR");
+                }
+                if (this._defines.BUMP) {
+                    fallbacks.addFallback(0, "BUMP");
+                }
+                if (this._defines.PARALLAX) {
+                    fallbacks.addFallback(1, "PARALLAX");
+                }
+                if (this._defines.PARALLAXOCCLUSION) {
+                    fallbacks.addFallback(0, "PARALLAXOCCLUSION");
+                }
+                if (this._defines.SPECULAROVERALPHA) {
+                    fallbacks.addFallback(0, "SPECULAROVERALPHA");
+                }
+                if (this._defines.FOG) {
+                    fallbacks.addFallback(1, "FOG");
+                }
+                if (this._defines.POINTSIZE) {
+                    fallbacks.addFallback(0, "POINTSIZE");
+                }
+                if (this._defines.LOGARITHMICDEPTH) {
+                    fallbacks.addFallback(0, "LOGARITHMICDEPTH");
+                }
+                BABYLON.MaterialHelper.HandleFallbacksForShadows(this._defines, fallbacks, this.maxSimultaneousLights);
+                if (this._defines.SPECULARTERM) {
+                    fallbacks.addFallback(0, "SPECULARTERM");
+                }
+                if (this._defines.DIFFUSEFRESNEL) {
+                    fallbacks.addFallback(1, "DIFFUSEFRESNEL");
+                }
+                if (this._defines.OPACITYFRESNEL) {
+                    fallbacks.addFallback(2, "OPACITYFRESNEL");
+                }
+                if (this._defines.REFLECTIONFRESNEL) {
+                    fallbacks.addFallback(3, "REFLECTIONFRESNEL");
+                }
+                if (this._defines.EMISSIVEFRESNEL) {
+                    fallbacks.addFallback(4, "EMISSIVEFRESNEL");
+                }
+                if (this._defines.FRESNEL) {
+                    fallbacks.addFallback(4, "FRESNEL");
+                }
+                //Attributes
+                var attribs = [BABYLON.VertexBuffer.PositionKind];
+                if (this._defines.NORMAL) {
+                    attribs.push(BABYLON.VertexBuffer.NormalKind);
+                }
+                if (this._defines.UV1) {
+                    attribs.push(BABYLON.VertexBuffer.UVKind);
+                }
+                if (this._defines.UV2) {
+                    attribs.push(BABYLON.VertexBuffer.UV2Kind);
+                }
+                if (this._defines.VERTEXCOLOR) {
+                    attribs.push(BABYLON.VertexBuffer.ColorKind);
+                }
+                BABYLON.MaterialHelper.PrepareAttributesForBones(attribs, mesh, this._defines, fallbacks);
+                BABYLON.MaterialHelper.PrepareAttributesForInstances(attribs, this._defines);
+                var shaderName = "default";
+                if (this.builder) {
+                    shaderName = this.builder(new CustomShaderHelper(), shaderName, this._mainPart, this._diffusePart, this._vertexPositionPart);
+                }
+                var join = this._defines.toString();
+                var uniforms = ["world", "view", "viewProjection", "vEyePosition", "vLightsType", "vAmbientColor", "vDiffuseColor", "vSpecularColor", "vEmissiveColor",
+                    "vFogInfos", "vFogColor", "pointSize",
+                    "vDiffuseInfos", "vAmbientInfos", "vOpacityInfos", "vReflectionInfos", "vEmissiveInfos", "vSpecularInfos", "vBumpInfos", "vLightmapInfos", "vRefractionInfos",
+                    "mBones",
+                    "vClipPlane", "diffuseMatrix", "ambientMatrix", "opacityMatrix", "reflectionMatrix", "emissiveMatrix", "specularMatrix", "bumpMatrix", "lightmapMatrix", "refractionMatrix",
+                    "depthValues",
+                    "diffuseLeftColor", "diffuseRightColor", "opacityParts", "reflectionLeftColor", "reflectionRightColor", "emissiveLeftColor", "emissiveRightColor", "refractionLeftColor", "refractionRightColor",
+                    "logarithmicDepthConstant"
+                ];
+                var samplers = ["diffuseSampler", "ambientSampler", "opacitySampler", "reflectionCubeSampler", "reflection2DSampler", "emissiveSampler", "specularSampler", "bumpSampler", "lightmapSampler", "refractionCubeSampler", "refraction2DSampler"];
+                if (this._defines.CAMERACOLORCURVES) {
+                    BABYLON.ColorCurves.PrepareUniforms(uniforms);
+                }
+                if (this._defines.CAMERACOLORGRADING) {
+                    BABYLON.ColorGradingTexture.PrepareUniformsAndSamplers(uniforms, samplers);
+                }
+                BABYLON.MaterialHelper.PrepareUniformsAndSamplersList(uniforms, samplers, this._defines, this.maxSimultaneousLights);
+                this._effect = scene.getEngine().createEffect(shaderName, attribs, uniforms, samplers, join, fallbacks, this.onCompiled, this.onError, { maxSimultaneousLights: this.maxSimultaneousLights - 1 });
+            }
+            if (!this._effect.isReady()) {
+                return false;
+            }
+            this._renderId = scene.getRenderId();
+            this._wasPreviouslyReady = true;
+            if (mesh) {
+                if (!mesh._materialDefines) {
+                    mesh._materialDefines = new BABYLON.StandardMaterialDefines();
+                }
+                this._defines.cloneTo(mesh._materialDefines);
+            }
+            return true;
+        };
+        return CustomMaterial;
+    }(BABYLON.StandardMaterial));
+    BABYLON.CustomMaterial = CustomMaterial;
+})(BABYLON || (BABYLON = {}));
+
+//# sourceMappingURL=babylon.customMaterial.js.map

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

@@ -0,0 +1,474 @@
+/// <reference path="../../../dist/preview release/babylon.d.ts"/>
+
+module BABYLON { 
+
+  export class CustomShaderHelper{
+ 
+  }
+
+   export interface ICustomMaterialBuilder {
+         (builder:CustomShaderHelper , name: string ,mainPart: string , diffusePart:string ,vertexPositionPart:string ): string;
+   } 
+ 
+   export class CustomMaterial extends StandardMaterial  {
+        
+        public builder: ICustomMaterialBuilder;
+        private _mainPart = 'void main(void) {';
+        private _diffusePart = 'vec3 diffuseColor=vDiffuseColor.rgb;';
+        private _vertexPositionPart = 'gl_Position=viewProjection*finalWorld*vec4(position,1.0);';
+        
+        constructor (name: string, builder:ICustomMaterialBuilder, scene: Scene) {
+            super(name, scene);  
+            this.builder = builder;             
+        }   
+ 
+        public isReady(mesh?: AbstractMesh, useInstances?: boolean): boolean {
+            if (this.isFrozen) {
+                if (this._wasPreviouslyReady) {
+                    return true;
+                }
+            }
+
+            var scene = this.getScene();
+            var engine = scene.getEngine();
+            var needUVs = false;
+            var needNormals = false;
+
+            this._defines.reset();
+
+            // Lights
+            if (scene.lightsEnabled && !this.disableLighting) {
+                needNormals = MaterialHelper.PrepareDefinesForLights(scene, mesh, this._defines, this.maxSimultaneousLights);
+            }
+
+            if (!this.checkReadyOnEveryCall) {
+                if (this._renderId === scene.getRenderId()) {
+                    if (this._checkCache(scene, mesh, useInstances)) {
+                        return true;
+                    }
+                }
+            }
+
+            // Textures
+            if (scene.texturesEnabled) {
+                if (this.diffuseTexture && StandardMaterial.DiffuseTextureEnabled) {
+                    if (!this.diffuseTexture.isReady()) {
+                        return false;
+                    } else {
+                        needUVs = true;
+                        this._defines.DIFFUSE = true;
+                    }
+                }
+
+                if (this.ambientTexture && StandardMaterial.AmbientTextureEnabled) {
+                    if (!this.ambientTexture.isReady()) {
+                        return false;
+                    } else {
+                        needUVs = true;
+                        this._defines.AMBIENT = true;
+                    }
+                }
+
+                if (this.opacityTexture && StandardMaterial.OpacityTextureEnabled) {
+                    if (!this.opacityTexture.isReady()) {
+                        return false;
+                    } else {
+                        needUVs = true;
+                        this._defines.OPACITY = true;
+
+                        if (this.opacityTexture.getAlphaFromRGB) {
+                            this._defines.OPACITYRGB = true;
+                        }
+                    }
+                }
+
+                if (this.reflectionTexture && StandardMaterial.ReflectionTextureEnabled) {
+                    if (!this.reflectionTexture.isReady()) {
+                        return false;
+                    } else {
+                        needNormals = true;
+                        this._defines.REFLECTION = true;
+
+                        if (this.roughness > 0) {
+                            this._defines.ROUGHNESS = true;
+                        }
+
+                        if (this.useReflectionOverAlpha) {
+                            this._defines.REFLECTIONOVERALPHA = true;
+                        }
+
+                        if (this.reflectionTexture.coordinatesMode === Texture.INVCUBIC_MODE) {
+                            this._defines.INVERTCUBICMAP = true;
+                        }
+
+                        this._defines.REFLECTIONMAP_3D = this.reflectionTexture.isCube;
+
+                        switch (this.reflectionTexture.coordinatesMode) {
+                            case Texture.CUBIC_MODE:
+                            case Texture.INVCUBIC_MODE:
+                                this._defines.REFLECTIONMAP_CUBIC = true;
+                                break;
+                            case Texture.EXPLICIT_MODE:
+                                this._defines.REFLECTIONMAP_EXPLICIT = true;
+                                break;
+                            case Texture.PLANAR_MODE:
+                                this._defines.REFLECTIONMAP_PLANAR = true;
+                                break;
+                            case Texture.PROJECTION_MODE:
+                                this._defines.REFLECTIONMAP_PROJECTION = true;
+                                break;
+                            case Texture.SKYBOX_MODE:
+                                this._defines.REFLECTIONMAP_SKYBOX = true;
+                                break;
+                            case Texture.SPHERICAL_MODE:
+                                this._defines.REFLECTIONMAP_SPHERICAL = true;
+                                break;
+                            case Texture.EQUIRECTANGULAR_MODE:
+                                this._defines.REFLECTIONMAP_EQUIRECTANGULAR = true;
+                                break;
+                            case Texture.FIXED_EQUIRECTANGULAR_MODE:
+                                this._defines.REFLECTIONMAP_EQUIRECTANGULAR_FIXED = true;
+                                break;
+                        }
+                    }
+                }
+
+                if (this.emissiveTexture && StandardMaterial.EmissiveTextureEnabled) {
+                    if (!this.emissiveTexture.isReady()) {
+                        return false;
+                    } else {
+                        needUVs = true;
+                        this._defines.EMISSIVE = true;
+                    }
+                }
+
+                if (this.lightmapTexture && StandardMaterial.LightmapTextureEnabled) {
+                    if (!this.lightmapTexture.isReady()) {
+                        return false;
+                    } else {
+                        needUVs = true;
+                        this._defines.LIGHTMAP = true;
+                        this._defines.USELIGHTMAPASSHADOWMAP = this.useLightmapAsShadowmap;
+                    }
+                }
+
+                if (this.specularTexture && StandardMaterial.SpecularTextureEnabled) {
+                    if (!this.specularTexture.isReady()) {
+                        return false;
+                    } else {
+                        needUVs = true;
+                        this._defines.SPECULAR = true;
+                        this._defines.GLOSSINESS = this.useGlossinessFromSpecularMapAlpha;
+                    }
+                }
+
+                if (scene.getEngine().getCaps().standardDerivatives && this.bumpTexture && StandardMaterial.BumpTextureEnabled) {
+                    if (!this.bumpTexture.isReady()) {
+                        return false;
+                    } else {
+                        needUVs = true;
+                        this._defines.BUMP = true;
+
+                        if (this.useParallax) {
+                            this._defines.PARALLAX = true;
+                            if (this.useParallaxOcclusion) {
+                                this._defines.PARALLAXOCCLUSION = true;
+                            }
+                        }
+
+                        if (this.invertNormalMapX) {
+                            this._defines.INVERTNORMALMAPX = true;
+                        }
+
+                        if (this.invertNormalMapY) {
+                            this._defines.INVERTNORMALMAPY = true;
+                        }
+
+                        if (scene._mirroredCameraPosition) {
+                            this._defines.INVERTNORMALMAPX = !this._defines.INVERTNORMALMAPX;
+                            this._defines.INVERTNORMALMAPY = !this._defines.INVERTNORMALMAPY;
+                        }
+                    }
+                }
+
+                if (this.refractionTexture && StandardMaterial.RefractionTextureEnabled) {
+                    if (!this.refractionTexture.isReady()) {
+                        return false;
+                    } else {
+                        needUVs = true;
+                        this._defines.REFRACTION = true;
+
+                        this._defines.REFRACTIONMAP_3D = this.refractionTexture.isCube;
+                    }
+                }
+
+                if (this.cameraColorGradingTexture && StandardMaterial.ColorGradingTextureEnabled) {
+                    if (!this.cameraColorGradingTexture.isReady()) {
+                        return false;
+                    } else {
+                        this._defines.CAMERACOLORGRADING = true;
+                    }
+                }
+            }
+
+            // Effect
+            if (scene.clipPlane) {
+                this._defines.CLIPPLANE = true;
+            }
+
+            if (engine.getAlphaTesting()) {
+                this._defines.ALPHATEST = true;
+            }
+
+            if (this._shouldUseAlphaFromDiffuseTexture()) {
+                this._defines.ALPHAFROMDIFFUSE = true;
+            }
+
+            if (this.useEmissiveAsIllumination) {
+                this._defines.EMISSIVEASILLUMINATION = true;
+            }
+
+            if (this.linkEmissiveWithDiffuse) {
+                this._defines.LINKEMISSIVEWITHDIFFUSE = true;
+            }
+
+            if (this.useLogarithmicDepth) {
+                this._defines.LOGARITHMICDEPTH = true;
+            }
+            
+            if (this.cameraColorCurves) {
+                this._defines.CAMERACOLORCURVES = 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 (StandardMaterial.FresnelEnabled) {
+                // Fresnel
+                if (this.diffuseFresnelParameters && this.diffuseFresnelParameters.isEnabled ||
+                    this.opacityFresnelParameters && this.opacityFresnelParameters.isEnabled ||
+                    this.emissiveFresnelParameters && this.emissiveFresnelParameters.isEnabled ||
+                    this.refractionFresnelParameters && this.refractionFresnelParameters.isEnabled ||
+                    this.reflectionFresnelParameters && this.reflectionFresnelParameters.isEnabled) {
+
+                    if (this.diffuseFresnelParameters && this.diffuseFresnelParameters.isEnabled) {
+                        this._defines.DIFFUSEFRESNEL = true;
+                    }
+
+                    if (this.opacityFresnelParameters && this.opacityFresnelParameters.isEnabled) {
+                        this._defines.OPACITYFRESNEL = true;
+                    }
+
+                    if (this.reflectionFresnelParameters && this.reflectionFresnelParameters.isEnabled) {
+                        this._defines.REFLECTIONFRESNEL = true;
+
+                        if (this.useReflectionFresnelFromSpecular) {
+                            this._defines.REFLECTIONFRESNELFROMSPECULAR = true;
+                        }
+                    }
+
+                    if (this.refractionFresnelParameters && this.refractionFresnelParameters.isEnabled) {
+                        this._defines.REFRACTIONFRESNEL = true;
+                    }
+
+                    if (this.emissiveFresnelParameters && this.emissiveFresnelParameters.isEnabled) {
+                        this._defines.EMISSIVEFRESNEL = true;
+                    }
+
+                    needNormals = true;
+                    this._defines.FRESNEL = true;
+                }
+            }
+
+            if (this._defines.SPECULARTERM && this.useSpecularOverAlpha) {
+                this._defines.SPECULAROVERALPHA = true;
+            }
+
+            // Attribs
+            if (mesh) {
+                if (needNormals && mesh.isVerticesDataPresent(VertexBuffer.NormalKind)) {
+                    this._defines.NORMAL = true;
+                }
+                if (needUVs) {
+                    if (mesh.isVerticesDataPresent(VertexBuffer.UVKind)) {
+                        this._defines.UV1 = true;
+                    }
+                    if (mesh.isVerticesDataPresent(VertexBuffer.UV2Kind)) {
+                        this._defines.UV2 = true;
+                    }
+                }
+                if (mesh.useVertexColors && mesh.isVerticesDataPresent(VertexBuffer.ColorKind)) {
+                    this._defines.VERTEXCOLOR = true;
+
+                    if (mesh.hasVertexAlpha) {
+                        this._defines.VERTEXALPHA = 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.REFLECTION) {
+                    fallbacks.addFallback(0, "REFLECTION");
+                }
+
+                if (this._defines.SPECULAR) {
+                    fallbacks.addFallback(0, "SPECULAR");
+                }
+
+                if (this._defines.BUMP) {
+                    fallbacks.addFallback(0, "BUMP");
+                }
+
+                if (this._defines.PARALLAX) {
+                    fallbacks.addFallback(1, "PARALLAX");
+                }
+
+                if (this._defines.PARALLAXOCCLUSION) {
+                    fallbacks.addFallback(0, "PARALLAXOCCLUSION");
+                }
+
+                if (this._defines.SPECULAROVERALPHA) {
+                    fallbacks.addFallback(0, "SPECULAROVERALPHA");
+                }
+
+                if (this._defines.FOG) {
+                    fallbacks.addFallback(1, "FOG");
+                }
+
+                if (this._defines.POINTSIZE) {
+                    fallbacks.addFallback(0, "POINTSIZE");
+                }
+
+                if (this._defines.LOGARITHMICDEPTH) {
+                    fallbacks.addFallback(0, "LOGARITHMICDEPTH");
+                }
+
+                MaterialHelper.HandleFallbacksForShadows(this._defines, fallbacks, this.maxSimultaneousLights);
+
+                if (this._defines.SPECULARTERM) {
+                    fallbacks.addFallback(0, "SPECULARTERM");
+                }
+
+                if (this._defines.DIFFUSEFRESNEL) {
+                    fallbacks.addFallback(1, "DIFFUSEFRESNEL");
+                }
+
+                if (this._defines.OPACITYFRESNEL) {
+                    fallbacks.addFallback(2, "OPACITYFRESNEL");
+                }
+
+                if (this._defines.REFLECTIONFRESNEL) {
+                    fallbacks.addFallback(3, "REFLECTIONFRESNEL");
+                }
+
+                if (this._defines.EMISSIVEFRESNEL) {
+                    fallbacks.addFallback(4, "EMISSIVEFRESNEL");
+                }
+
+                if (this._defines.FRESNEL) {
+                    fallbacks.addFallback(4, "FRESNEL");
+                }
+
+                //Attributes
+                var attribs = [VertexBuffer.PositionKind];
+
+                if (this._defines.NORMAL) {
+                    attribs.push(VertexBuffer.NormalKind);
+                }
+
+                if (this._defines.UV1) {
+                    attribs.push(VertexBuffer.UVKind);
+                }
+
+                if (this._defines.UV2) {
+                    attribs.push(VertexBuffer.UV2Kind);
+                }
+
+                if (this._defines.VERTEXCOLOR) {
+                    attribs.push(VertexBuffer.ColorKind);
+                }
+
+                MaterialHelper.PrepareAttributesForBones(attribs, mesh, this._defines, fallbacks);
+                MaterialHelper.PrepareAttributesForInstances(attribs, this._defines);
+                
+                var shaderName = "default";
+               
+                if (this.builder) {
+ 
+                     shaderName = this.builder(
+                         new CustomShaderHelper(),
+                         shaderName, 
+                         this._mainPart,
+                         this._diffusePart, 
+                         this._vertexPositionPart ); 
+               }
+
+                var join = this._defines.toString();
+                var uniforms = ["world", "view", "viewProjection", "vEyePosition", "vLightsType", "vAmbientColor", "vDiffuseColor", "vSpecularColor", "vEmissiveColor",
+                    "vFogInfos", "vFogColor", "pointSize",
+                    "vDiffuseInfos", "vAmbientInfos", "vOpacityInfos", "vReflectionInfos", "vEmissiveInfos", "vSpecularInfos", "vBumpInfos", "vLightmapInfos", "vRefractionInfos",
+                    "mBones",
+                    "vClipPlane", "diffuseMatrix", "ambientMatrix", "opacityMatrix", "reflectionMatrix", "emissiveMatrix", "specularMatrix", "bumpMatrix", "lightmapMatrix", "refractionMatrix",
+                    "depthValues",
+                    "diffuseLeftColor", "diffuseRightColor", "opacityParts", "reflectionLeftColor", "reflectionRightColor", "emissiveLeftColor", "emissiveRightColor", "refractionLeftColor", "refractionRightColor",
+                    "logarithmicDepthConstant"
+                ];
+
+                var samplers = ["diffuseSampler", "ambientSampler", "opacitySampler", "reflectionCubeSampler", "reflection2DSampler", "emissiveSampler", "specularSampler", "bumpSampler", "lightmapSampler", "refractionCubeSampler", "refraction2DSampler"]
+
+                if (this._defines.CAMERACOLORCURVES) {
+                    ColorCurves.PrepareUniforms(uniforms);
+                }
+                if (this._defines.CAMERACOLORGRADING) {
+                    ColorGradingTexture.PrepareUniformsAndSamplers(uniforms, samplers);
+                }
+                MaterialHelper.PrepareUniformsAndSamplersList(uniforms, samplers, this._defines, this.maxSimultaneousLights);
+
+                this._effect = scene.getEngine().createEffect(shaderName,
+                    attribs, uniforms, samplers,
+                    join, fallbacks, this.onCompiled, this.onError, { maxSimultaneousLights: this.maxSimultaneousLights - 1 });
+            }
+            if (!this._effect.isReady()) {
+                return false;
+            }
+
+            this._renderId = scene.getRenderId();
+            this._wasPreviouslyReady = true;
+
+            if (mesh) {
+                if (!mesh._materialDefines) {
+                    mesh._materialDefines = new StandardMaterialDefines();
+                }
+
+                this._defines.cloneTo(mesh._materialDefines);
+            }
+
+            return true;
+        }
+    
+    }
+}
+     

+ 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="../simple/babylon.simpleMaterial.ts"/>
 
 module BABYLON {
     class WaterMaterialDefines extends MaterialDefines {

+ 33 - 23
src/Bones/babylon.boneIKController.ts

@@ -1,6 +1,10 @@
 module BABYLON {
     export class BoneIKController {
 
+        private static _tmpVecs: Vector3[] = [Vector3.Zero(), Vector3.Zero(), Vector3.Zero(), Vector3.Zero(), Vector3.Zero(), Vector3.Zero()];
+        private static _tmpQuat = Quaternion.Identity();
+        private static _tmpMats: Matrix[] = [Matrix.Identity(), Matrix.Identity()];
+        
         public targetMesh: AbstractMesh;
         public poleTargetMesh: AbstractMesh;
         public poleTargetBone: Bone;
@@ -22,15 +26,6 @@ module BABYLON {
         private _maxAngle = Math.PI;
         private _maxReach: number;
 
-        private _tmpVec1 = Vector3.Zero();
-        private _tmpVec2 = Vector3.Zero();
-        private _tmpVec3 = Vector3.Zero();
-        private _tmpVec4 = Vector3.Zero();
-        private _tmpVec5 = Vector3.Zero();
-        private _tmpMat1 = Matrix.Identity();
-        private _tmpMat2 = Matrix.Identity();
-        private _tmpQuat1 = Quaternion.Identity();
-
         private _rightHandedSystem = false;
 
         private _bendAxis = Vector3.Right();
@@ -50,7 +45,18 @@ module BABYLON {
 
         }
 
-        constructor(mesh: AbstractMesh, bone: Bone, options?: { targetMesh?: AbstractMesh, poleTargetMesh?: AbstractMesh, poleTargetBone?: Bone, poleTargetLocalOffset?:Vector3, poleAngle?: number, bendAxis?: Vector3, maxAngle?:number, slerpAmount?:number }){
+        constructor(mesh: AbstractMesh, 
+                    bone: Bone, 
+                    options?: { 
+                        targetMesh?: AbstractMesh, 
+                        poleTargetMesh?: AbstractMesh, 
+                        poleTargetBone?: Bone, 
+                        poleTargetLocalOffset?:Vector3, 
+                        poleAngle?: number, 
+                        bendAxis?: Vector3, 
+                        maxAngle?:number, 
+                        slerpAmount?:number 
+                    }){
 
             this._bone2 = bone;
             this._bone1 = bone.getParent();
@@ -160,14 +166,14 @@ module BABYLON {
 
         }
 
-        public update (): void {
+        public update(): void {
 	
             var bone1 = this._bone1;
             var target = this.targetPosition;
             var poleTarget = this.poleTargetPosition;
 
-            var mat1 = this._tmpMat1;
-            var mat2 = this._tmpMat2;
+            var mat1 = BoneIKController._tmpMats[0];
+            var mat2 = BoneIKController._tmpMats[1];
 
             if(this.targetMesh){
                 target.copyFrom(this.targetMesh.getAbsolutePosition());
@@ -179,11 +185,13 @@ module BABYLON {
                 Vector3.TransformCoordinatesToRef(this.poleTargetLocalOffset, this.poleTargetMesh.getWorldMatrix(), poleTarget);
             }
 
-            var bonePos = this._tmpVec1;
-            var zaxis = this._tmpVec2;
-            var xaxis = this._tmpVec3;
-            var yaxis = this._tmpVec4;
-            var upAxis = this._tmpVec5;
+            var bonePos = BoneIKController._tmpVecs[0];
+            var zaxis = BoneIKController._tmpVecs[1];
+            var xaxis = BoneIKController._tmpVecs[2];
+            var yaxis = BoneIKController._tmpVecs[3];
+            var upAxis = BoneIKController._tmpVecs[4];
+
+            var _tmpQuat = BoneIKController._tmpQuat;
             
             bone1.getAbsolutePositionToRef(this.mesh, bonePos);
 
@@ -249,10 +257,12 @@ module BABYLON {
 
             } else {
 
-                this._tmpVec1.copyFrom(this._bendAxis);
-                this._tmpVec1.x *= -1;
+                var _tmpVec = BoneIKController._tmpVecs[5];
+
+                _tmpVec.copyFrom(this._bendAxis);
+                _tmpVec.x *= -1;
 
-                Matrix.RotationAxisToRef(this._tmpVec1, -angB, mat2);
+                Matrix.RotationAxisToRef(_tmpVec, -angB, mat2);
                 mat2.multiplyToRef(mat1, mat1);
                 
             }
@@ -266,8 +276,8 @@ module BABYLON {
                 if(!this._slerping){
                     Quaternion.FromRotationMatrixToRef(this._bone1Mat, this._bone1Quat);
                 }
-                Quaternion.FromRotationMatrixToRef(mat1, this._tmpQuat1);
-                Quaternion.SlerpToRef(this._bone1Quat, this._tmpQuat1, this.slerpAmount, this._bone1Quat);
+                Quaternion.FromRotationMatrixToRef(mat1, _tmpQuat);
+                Quaternion.SlerpToRef(this._bone1Quat, _tmpQuat, this.slerpAmount, this._bone1Quat);
                 angC = this._bone2Ang * (1.0 - this.slerpAmount) + angC * this.slerpAmount;
                 this._bone1.setRotationQuaternion(this._bone1Quat, Space.WORLD, this.mesh);
                 this._slerping = true;

+ 1 - 1
src/Cameras/Inputs/babylon.freecamera.input.gamepad.ts

@@ -29,7 +29,7 @@ module BABYLON {
         }
 
         checkInputs() {
-            if (this.gamepad) {
+            if (this.gamepad && this.gamepad.leftStick) {
                 var camera = this.camera;
                 var LSValues = this.gamepad.leftStick;
                 var normalizedLX = LSValues.x / this.gamepadMoveSensibility;

+ 79 - 34
src/Cameras/VR/babylon.webVRCamera.ts

@@ -31,9 +31,10 @@ module BABYLON {
     }
 
     export interface WebVROptions {
-        trackPosition?: boolean; //update the camera's position
+        trackPosition?: boolean; //for the sake of your users - set it to true.
         positionScale?: number;
         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 {
@@ -51,6 +52,8 @@ module BABYLON {
 
         private _positionOffset: Vector3 = Vector3.Zero();
 
+        protected _descendants: Array<Node> = [];
+
         public devicePosition = Vector3.Zero();
         public deviceRotationQuaternion;
         public deviceScaleFactor: number = 1;
@@ -58,9 +61,24 @@ module BABYLON {
         public controllers: Array<WebVRController> = [];
         public onControllersAttached: (controllers: Array<WebVRController>) => void;
 
-        constructor(name: string, position: Vector3, scene: Scene, compensateDistortion = false, private webVROptions: WebVROptions = {}) {
+        public rigParenting: boolean = true; // should the rig cameras be used as parent instead of this camera.
+
+        constructor(name: string, position: Vector3, scene: Scene, private webVROptions: WebVROptions = {}) {
             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.deviceRotationQuaternion = new Quaternion();
 
@@ -110,6 +128,39 @@ module BABYLON {
 
             // try to attach the controllers, if found.
             this.initControllers();
+
+            /**
+             * The idea behind the following lines:
+             * objects that have the camera as parent should actually have the rig cameras as a parent.
+             * BUT, each of those cameras has a different view matrix, which means that if we set the parent to the first rig camera,
+             * the second will not show it correctly.
+             * 
+             * To solve this - each object that has the camera as parent will be added to a protected array.
+             * When the rig camera renders, it will take this array and set all of those to be its children.
+             * This way, the right camera will be used as a parent, and the mesh will be rendered correctly.
+             * Amazing!
+             */
+            scene.onBeforeCameraRenderObservable.add((camera) => {
+                if (camera.parent === this && this.rigParenting) {
+                    this._descendants = this.getDescendants(true, (n) => {
+                        // don't take the cameras or the controllers!
+                        let isController = this.controllers.some(controller => { return controller._mesh === n });
+                        let isRigCamera = this._rigCameras.indexOf(<Camera>n) !== -1
+                        return !isController && !isRigCamera;
+                    });
+                    this._descendants.forEach(node => {
+                        node.parent = camera;
+                    });
+                }
+            });
+
+            scene.onAfterCameraRenderObservable.add((camera) => {
+                if (camera.parent === this && this.rigParenting) {
+                    this._descendants.forEach(node => {
+                        node.parent = this;
+                    });
+                }
+            });
         }
 
         public _checkInputs(): void {
@@ -179,6 +230,16 @@ module BABYLON {
             this._vrDevice.resetPose();
         }
 
+        public _updateRigCameras() {
+            var camLeft = <TargetCamera>this._rigCameras[0];
+            var camRight = <TargetCamera>this._rigCameras[1];
+            camLeft.rotationQuaternion.copyFrom(this.deviceRotationQuaternion);
+            camRight.rotationQuaternion.copyFrom(this.deviceRotationQuaternion);
+
+            camLeft.position.copyFrom(this.devicePosition);
+            camRight.position.copyFrom(this.devicePosition);
+        }
+
         /**
          * This function is called by the two RIG cameras.
          * 'this' is the left or right camera (and NOT (!!!) the WebVRFreeCamera instance)
@@ -186,17 +247,18 @@ module BABYLON {
         protected _getWebVRViewMatrix(): Matrix {
             var viewArray = this._cameraRigParams["left"] ? this._cameraRigParams["frameData"].leftViewMatrix : this._cameraRigParams["frameData"].rightViewMatrix;
 
+            Matrix.FromArrayToRef(viewArray, 0, this._webvrViewMatrix);
+
             if (!this.getScene().useRightHandedSystem) {
-                [2, 6, 8, 9, 14].forEach(function (num) {
-                    viewArray[num] *= -1;
+                [2, 6, 8, 9, 14].forEach((num) => {
+                    this._webvrViewMatrix.m[num] *= -1;
                 });
             }
-            Matrix.FromArrayToRef(viewArray, 0, this._webvrViewMatrix);
 
             let parentCamera: WebVRFreeCamera = this._cameraRigParams["parentCamera"];
 
             // should the view matrix be updated with scale and position offset?
-            if (parentCamera.position.lengthSquared() || parentCamera.deviceScaleFactor !== 1) {
+            if (parentCamera.deviceScaleFactor !== 1) {
                 this._webvrViewMatrix.invert();
                 // scale the position, if set
                 if (parentCamera.deviceScaleFactor) {
@@ -204,49 +266,29 @@ module BABYLON {
                     this._webvrViewMatrix.m[13] *= parentCamera.deviceScaleFactor;
                     this._webvrViewMatrix.m[14] *= parentCamera.deviceScaleFactor;
                 }
-                // change the position (for "teleporting");
-                this._webvrViewMatrix.m[12] += parentCamera.position.x;
-                this._webvrViewMatrix.m[13] += parentCamera.position.y;
-                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._updateCameraRotationMatrix();
+            // update the camera rotation matrix
+            this._webvrViewMatrix.getRotationMatrixToRef(this._cameraRotationMatrix);
             Vector3.TransformCoordinatesToRef(this._referencePoint, this._cameraRotationMatrix, this._transformedReferencePoint);
 
-            // Computing target for getTarget()
-            this._positionOffset = this._positionOffset || Vector3.Zero();
-            this._webvrViewMatrix.getTranslationToRef(this._positionOffset);
-            this._positionOffset.addToRef(this._transformedReferencePoint, this._currentTarget);
-
+            // Computing target and final matrix
+            this.position.addToRef(this._transformedReferencePoint, this._currentTarget);
             return this._webvrViewMatrix;
         }
 
-        public _updateWebVRCameraRotationMatrix() {
-            this._webvrViewMatrix.getRotationMatrixToRef(this._cameraRotationMatrix);
-        }
-
-        public _isSynchronizedViewMatrix() {
-            return false;
-        }
-
         protected _getWebVRProjectionMatrix(): Matrix {
             var projectionArray = this._cameraRigParams["left"] ? this._cameraRigParams["frameData"].leftProjectionMatrix : this._cameraRigParams["frameData"].rightProjectionMatrix;
+            Matrix.FromArrayToRef(projectionArray, 0, this._projectionMatrix);
+
             //babylon compatible matrix
             if (!this.getScene().useRightHandedSystem) {
-                [8, 9, 10, 11].forEach(function (num) {
-                    projectionArray[num] *= -1;
+                [8, 9, 10, 11].forEach((num) => {
+                    this._projectionMatrix.m[num] *= -1;
                 });
             }
-            Matrix.FromArrayToRef(projectionArray, 0, this._projectionMatrix);
             return this._projectionMatrix;
         }
 
@@ -255,6 +297,9 @@ module BABYLON {
             new BABYLON.Gamepads((gp) => {
                 if (gp.type === BABYLON.Gamepad.POSE_ENABLED) {
                     let webVrController: WebVRController = <WebVRController>gp;
+                    if (this.webVROptions.controllerMeshes) {
+                        webVrController.initControllerMesh(this.getScene());
+                    }
                     webVrController.attachToPoseControlledCamera(this);
 
                     // since this is async - sanity check. Is the controller already stored?

+ 1 - 1
src/Cameras/babylon.arcRotateCamera.ts

@@ -415,7 +415,7 @@ module BABYLON {
             }
             
             if (toBoundingCenter && (<any>target).getBoundingInfo){
-                this._targetBoundingCenter = (<any>target).getBoundingInfo().boundingBox.center.clone();
+                this._targetBoundingCenter = (<any>target).getBoundingInfo().boundingBox.centerWorld.clone();
             }else{
                 this._targetBoundingCenter = null;
             }

+ 2 - 4
src/Cameras/babylon.camera.ts

@@ -618,9 +618,8 @@
                         this._rigCameras[0].setCameraRigParameter("parentCamera", rigParams.parentCamera);
                         this._rigCameras[0]._cameraRigParams.vrWorkMatrix = new Matrix();
                         this._rigCameras[0].getProjectionMatrix = this._getWebVRProjectionMatrix;
+                        this._rigCameras[0].parent = this;
                         this._rigCameras[0]._getViewMatrix = this._getWebVRViewMatrix;
-                        this._rigCameras[0]._isSynchronizedViewMatrix = this._isSynchronizedViewMatrix;
-                        this._rigCameras[0]._updateCameraRotationMatrix = this._updateWebVRCameraRotationMatrix;
 
                         //Right eye
                         this._rigCameras[1].viewport = new Viewport(0.5, 0, 0.5, 1.0);
@@ -629,9 +628,8 @@
                         this._rigCameras[1].setCameraRigParameter("parentCamera", rigParams.parentCamera);
                         this._rigCameras[1]._cameraRigParams.vrWorkMatrix = new Matrix();
                         this._rigCameras[1].getProjectionMatrix = this._getWebVRProjectionMatrix;
+                        this._rigCameras[1].parent = this;
                         this._rigCameras[1]._getViewMatrix = this._getWebVRViewMatrix;
-                        this._rigCameras[1]._isSynchronizedViewMatrix = this._isSynchronizedViewMatrix;
-                        this._rigCameras[1]._updateCameraRotationMatrix = this._updateWebVRCameraRotationMatrix;
                     }
                     break;
 

+ 1 - 2
src/Cameras/babylon.targetCamera.ts

@@ -179,7 +179,7 @@ module BABYLON {
 
                 //rotate, if quaternion is set and rotation was used
                 if (this.rotationQuaternion) {
-                    var len = this.rotation.length();
+                    var len = this.rotation.lengthSquared();
                     if (len) {
                         Quaternion.RotationYawPitchRollToRef(this.rotation.y, this.rotation.x, this.rotation.z, this.rotationQuaternion);
                     }
@@ -302,7 +302,6 @@ module BABYLON {
                     break;
 
                 case Camera.RIG_MODE_VR:
-                case Camera.RIG_MODE_WEBVR:
                     if (camLeft.rotationQuaternion) {
                         camLeft.rotationQuaternion.copyFrom(this.rotationQuaternion);
                         camRight.rotationQuaternion.copyFrom(this.rotationQuaternion);

+ 11 - 2
src/Culling/babylon.boundingBox.ts

@@ -2,12 +2,15 @@
     export class BoundingBox implements ICullable {
         public vectors: Vector3[] = new Array<Vector3>();
         public center: Vector3;
+        public centerWorld: Vector3;
         public extendSize: Vector3;
+        public extendSizeWorld: Vector3;
         public directions: Vector3[];
         public vectorsWorld: Vector3[] = new Array<Vector3>();
         public minimumWorld: Vector3;
         public maximumWorld: Vector3;
 
+
         private _worldMatrix: Matrix;
 
         constructor(public minimum: Vector3, public maximum: Vector3) {
@@ -44,6 +47,8 @@
             }
             this.minimumWorld = Vector3.Zero();
             this.maximumWorld = Vector3.Zero();
+            this.centerWorld = Vector3.Zero();
+            this.extendSizeWorld = Vector3.Zero();
 
             this._update(Matrix.Identity());
         }
@@ -81,9 +86,13 @@
                     this.maximumWorld.z = v.z;
             }
 
+            // Extend
+            this.maximumWorld.subtractToRef(this.minimumWorld, this.extendSizeWorld);
+            this.extendSizeWorld.scaleInPlace(0.5);
+
             // OBB
-            this.maximumWorld.addToRef(this.minimumWorld, this.center);
-            this.center.scaleInPlace(0.5);
+            this.maximumWorld.addToRef(this.minimumWorld, this.centerWorld);
+            this.centerWorld.scaleInPlace(0.5);
 
             Vector3.FromFloatArrayToRef(world.m, 0, this.directions[0]);
             Vector3.FromFloatArrayToRef(world.m, 4, this.directions[1]);

+ 1 - 1
src/Culling/babylon.boundingInfo.ts

@@ -1,6 +1,6 @@
 module BABYLON {
     var computeBoxExtents = (axis: Vector3, box: BoundingBox) => {
-        var p = Vector3.Dot(box.center, axis);
+        var p = Vector3.Dot(box.centerWorld, axis);
 
         var r0 = Math.abs(Vector3.Dot(box.directions[0], axis)) * box.extendSize.x;
         var r1 = Math.abs(Vector3.Dot(box.directions[1], axis)) * box.extendSize.y;

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

@@ -1,25 +1,28 @@
 module BABYLON {
 
     // declare INSPECTOR namespace for compilation issue
-    declare var INSPECTOR : any;
+    declare var INSPECTOR: any;
 
     export class DebugLayer {
         private _scene: Scene;
         public static InspectorURL = 'http://www.babylonjs.com/babylon.inspector.bundle.js';
         // The inspector instance
-        private _inspector : any;
+        private _inspector: any;
 
         constructor(scene: Scene) {
             this._scene = scene;
         }
 
         /** 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) {
-                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
         }
-        
+
         public isVisible(): boolean {
             if (!this._inspector) {
                 return false;
@@ -33,14 +36,14 @@ module BABYLON {
                 this._inspector = null;
             }
         }
-        
-        public show(popup?:boolean) {
+
+        public show(config: { popup?: boolean, initialTab?: number, parentElement?: HTMLElement } = {}) {
             if (typeof INSPECTOR == 'undefined') {
                 // 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 {
                 // Otherwise creates the inspector
-                this._createInspector(popup);
+                this._createInspector(config);
             }
         }
 

+ 8 - 0
src/Culling/babylon.rayHelper.ts

@@ -13,6 +13,14 @@ module BABYLON {
         private _meshSpaceDirection: Vector3;
         private _meshSpaceOrigin: Vector3;
 
+        public static CreateAndShow(ray: Ray, scene: Scene, color:Color3): RayHelper {
+            var helper = new RayHelper(ray);
+
+            helper.show(scene, color);
+
+            return helper;
+        }
+
         constructor(ray:Ray) {
             this.ray = ray;
         }

+ 31 - 12
src/Lights/Shadows/babylon.shadowGenerator.ts

@@ -10,6 +10,7 @@
         private static _FILTER_VARIANCESHADOWMAP = 1;
         private static _FILTER_POISSONSAMPLING = 2;
         private static _FILTER_BLURVARIANCESHADOWMAP = 3;
+        private static _FILTER_EXPONENTIALSHADOWMAP = 4;
 
         // Static
         public static get FILTER_NONE(): number {
@@ -28,6 +29,10 @@
             return ShadowGenerator._FILTER_BLURVARIANCESHADOWMAP;
         }
 
+        public static get FILTER_EXPONENTIALSHADOWMAP(): number {
+            return ShadowGenerator._FILTER_EXPONENTIALSHADOWMAP;
+        }
+
         // Members
         private _filter = ShadowGenerator.FILTER_NONE;
         public blurScale = 2;
@@ -76,7 +81,7 @@
 
             this._filter = value;
 
-            if (this.useVarianceShadowMap || this.useBlurVarianceShadowMap || this.usePoissonSampling) {
+            if (this.useVarianceShadowMap || this.useBlurVarianceShadowMap || this.usePoissonSampling || this.useExponentialShadowMap) {
                 this._shadowMap.anisotropicFilteringLevel = 16;
                 this._shadowMap.updateSamplingMode(Texture.BILINEAR_SAMPLINGMODE);
             } else {
@@ -110,6 +115,13 @@
             this.filter = (value ? ShadowGenerator.FILTER_BLURVARIANCESHADOWMAP : ShadowGenerator.FILTER_NONE);
         }
 
+        public get useExponentialShadowMap(): boolean {
+            return this.filter === ShadowGenerator.FILTER_EXPONENTIALSHADOWMAP;
+        }
+        public set useExponentialShadowMap(value: boolean) {
+            this.filter = (value ? ShadowGenerator.FILTER_EXPONENTIALSHADOWMAP : ShadowGenerator.FILTER_NONE);
+        }
+
         private _light: IShadowLight;
         private _scene: Scene;
         private _shadowMap: RenderTargetTexture;
@@ -167,7 +179,7 @@
             this._shadowMap.wrapU = Texture.CLAMP_ADDRESSMODE;
             this._shadowMap.wrapV = Texture.CLAMP_ADDRESSMODE;
             this._shadowMap.anisotropicFilteringLevel = 1;
-            this._shadowMap.updateSamplingMode(Texture.NEAREST_SAMPLINGMODE);
+            this._shadowMap.updateSamplingMode(Texture.BILINEAR_SAMPLINGMODE);
             this._shadowMap.renderParticles = false;
 
             this._shadowMap.onBeforeRenderObservable.add((faceIndex: number) => {
@@ -175,7 +187,7 @@
             });
 
             this._shadowMap.onAfterUnbindObservable.add(() => {
-                if (!this.useBlurVarianceShadowMap) {
+                if (!this.useBlurVarianceShadowMap && !this.useExponentialShadowMap) {
                     return;
                 }
 
@@ -183,7 +195,7 @@
                     this._shadowMap2 = new RenderTargetTexture(light.name + "_shadowMap", mapSize, this._scene, false, true, textureType);
                     this._shadowMap2.wrapU = Texture.CLAMP_ADDRESSMODE;
                     this._shadowMap2.wrapV = Texture.CLAMP_ADDRESSMODE;
-                    this._shadowMap2.updateSamplingMode(Texture.TRILINEAR_SAMPLINGMODE);
+                    this._shadowMap2.updateSamplingMode(Texture.BILINEAR_SAMPLINGMODE);
 
                     this._downSamplePostprocess = new PassPostProcess("downScale", 1.0 / this.blurScale, null, Texture.BILINEAR_SAMPLINGMODE, this._scene.getEngine());
                     this._downSamplePostprocess.onApplyObservable.add(effect => {
@@ -219,6 +231,8 @@
                     mesh._bind(subMesh, this._effect, Material.TriangleFillMode);
                     var material = subMesh.getMaterial();
 
+                    this._effect.setFloat("bias", this.bias);
+
                     this._effect.setMatrix("viewProjection", this.getTransformMatrix());
                     this._effect.setVector3("lightPosition", this.getLight().position);
 
@@ -293,6 +307,8 @@
 
             if (this.useVarianceShadowMap || this.useBlurVarianceShadowMap) {
                 defines.push("#define VSM");
+            } else if (this.useExponentialShadowMap) {
+                defines.push("#define ESM");
             }
 
             if (this.getLight().needCube()) {
@@ -350,7 +366,7 @@
                 this._cachedDefines = join;
                 this._effect = this._scene.getEngine().createEffect("shadowMap",
                     attribs,
-                    ["world", "mBones", "viewProjection", "diffuseMatrix", "lightPosition", "depthValues"],
+                    ["world", "mBones", "viewProjection", "diffuseMatrix", "lightPosition", "depthValues", "bias"],
                     ["diffuseSampler"], join);
             }
 
@@ -516,16 +532,19 @@
                 shadowGenerator.useVarianceShadowMap = true;
             } else if (parsedShadowGenerator.useBlurVarianceShadowMap) {
                 shadowGenerator.useBlurVarianceShadowMap = true;
+            }
+            else if (parsedShadowGenerator.useExponentialShadowMap) {
+                shadowGenerator.useExponentialShadowMap = true;
+            }
 
-                if (parsedShadowGenerator.blurScale) {
-                    shadowGenerator.blurScale = parsedShadowGenerator.blurScale;
-                }
-
-                if (parsedShadowGenerator.blurBoxOffset) {
-                    shadowGenerator.blurBoxOffset = parsedShadowGenerator.blurBoxOffset;
-                }
+            if (parsedShadowGenerator.blurScale) {
+                shadowGenerator.blurScale = parsedShadowGenerator.blurScale;
             }
 
+            if (parsedShadowGenerator.blurBoxOffset) {
+                shadowGenerator.blurBoxOffset = parsedShadowGenerator.blurBoxOffset;
+            }
+                
             if (parsedShadowGenerator.bias !== undefined) {
                 shadowGenerator.bias = parsedShadowGenerator.bias;
             }

+ 13 - 2
src/Loading/babylon.sceneLoader.ts

@@ -135,7 +135,7 @@
             }
         }
 
-        public static ImportMesh(meshesNames: any, rootUrl: string, sceneFilename: string, scene: Scene, onsuccess?: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, progressCallBack?: () => void, onerror?: (scene: Scene, message: string, exception?: any) => void): void {
+        public static ImportMesh(meshesNames: any, rootUrl: string, sceneFilename: string, scene: Scene, onsuccess?: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, progressCallBack?: () => void, onerror?: (scene: Scene, message: string, exception?: any) => void): void {            
             if (sceneFilename.substr && sceneFilename.substr(0, 1) === "/") {
                 Tools.Error("Wrong sceneFilename parameter");
                 return;
@@ -163,6 +163,13 @@
                     var particleSystems = [];
                     var skeletons = [];
 
+                    if (scene.isDisposed) {
+                        if (onerror) {
+                            onerror(scene, 'Scene was disposed before being able to load ' + rootUrl + sceneFilename);
+                        }
+                        return;
+                    }
+
                     try {
                         if ((<any>plugin).importMesh) {
                             var syncedPlugin = <ISceneLoaderPlugin>plugin;
@@ -209,7 +216,11 @@
 
                 Tools.LoadFile(rootUrl + sceneFilename, data => {
                     importMeshFromData(data);
-                }, progressCallBack, database, useArrayBuffer);
+                }, progressCallBack, database, useArrayBuffer, () => {
+                    if (onerror) {
+                        onerror(scene, 'Unable to load file ' + rootUrl + sceneFilename)
+                    }
+                });
             };
 
             if (scene.getEngine().enableOfflineSupport && !directLoad) {

+ 2 - 2
src/Materials/Textures/babylon.mapTexture.ts

@@ -6,7 +6,7 @@
 
         private _replacedViewport: Viewport;
 
-        constructor(name: string, scene: Scene, size: ISize, samplingMode: number = Texture.TRILINEAR_SAMPLINGMODE, useMipMap: boolean=false) {
+        constructor(name: string, scene: Scene, size: ISize, samplingMode: number = Texture.TRILINEAR_SAMPLINGMODE, useMipMap: boolean=false, margin=0) {
             super(null, scene, !useMipMap, false, samplingMode);
 
             this.name = name;
@@ -15,7 +15,7 @@
             this.wrapV = Texture.CLAMP_ADDRESSMODE;
 
             // Create the rectPackMap that will allocate portion of the texture
-            this._rectPackingMap = new RectPackingMap(new Size(size.width, size.height));
+            this._rectPackingMap = new RectPackingMap(new Size(size.width, size.height), margin);
 
             // Create the texture that will store the content
             this._texture = scene.getEngine().createRenderTargetTexture(size, { generateMipMaps: !this.noMipmap, type: Engine.TEXTURETYPE_UNSIGNED_INT });

+ 10 - 2
src/Materials/Textures/babylon.videoTexture.ts

@@ -85,17 +85,25 @@
                 minWidth: number, 
                 maxWidth: number, 
                 minHeight: number, 
-                maxHeight: number
+                maxHeight: number,
+                deviceId: string
             }): void {
             var video = document.createElement("video");
+            var constraintsDeviceId;
+            if (constraints && constraints.deviceId){
+                constraintsDeviceId = { 
+                    exact: constraints.deviceId                     
+                }
+            }
 
 		    navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia;
 		    window.URL = window.URL || window.webkitURL || window.mozURL || window.msURL;
 
 
 		    if (navigator.getUserMedia) {
-			    navigator.getUserMedia({ 
+			    navigator.getUserMedia({                     
                     video: {
+                        deviceId: constraintsDeviceId,
                         width: {
                             min: (constraints && constraints.minWidth) || 256,
                             max: (constraints && constraints.maxWidth) || 640

+ 14 - 4
src/Materials/babylon.materialHelper.ts

@@ -90,14 +90,20 @@
                             }
 
                             defines["SHADOWVSM" + lightIndex] = true;
-                        }
-
-                        if (shadowGenerator.usePoissonSampling) {
+                        } 
+                        else if (shadowGenerator.usePoissonSampling) {
                             if (defines["SHADOWPCF" + lightIndex] === undefined) {
                                 needRebuild = true;
                             }
 
                             defines["SHADOWPCF" + lightIndex] = true;
+                        } 
+                        else if (shadowGenerator.useExponentialShadowMap) {
+                            if (defines["SHADOWESM" + lightIndex] === undefined) {
+                                needRebuild = true;
+                            }
+
+                            defines["SHADOWESM" + lightIndex] = true;
                         }
 
                         needShadows = true;
@@ -187,6 +193,10 @@
                 if (defines["SHADOWVSM" + lightIndex]) {
                     fallbacks.addFallback(0, "SHADOWVSM" + lightIndex);
                 }
+
+                if (defines["SHADOWESM" + lightIndex]) {
+                    fallbacks.addFallback(0, "SHADOWESM" + lightIndex);
+                }
             }
         }
 
@@ -225,7 +235,7 @@
                     }
                 }
                 effect.setTexture("shadowSampler" + lightIndex, shadowGenerator.getShadowMapForRendering());
-                effect.setFloat3("shadowsInfo" + lightIndex, shadowGenerator.getDarkness(), shadowGenerator.blurScale / shadowGenerator.getShadowMap().getSize().width, shadowGenerator.bias);
+                effect.setFloat2("shadowsInfo" + lightIndex, shadowGenerator.getDarkness(), shadowGenerator.blurScale / shadowGenerator.getShadowMap().getSize().width);
             }
 
             return depthValuesAlreadySet;

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

@@ -21,6 +21,7 @@
         public EMISSIVEFRESNEL = false;
         public FRESNEL = false;
         public NORMAL = false;
+        public TANGENT = false;
         public UV1 = false;
         public UV2 = false;
         public VERTEXCOLOR = false;
@@ -946,6 +947,9 @@
             if (mesh) {
                 if (needNormals && mesh.isVerticesDataPresent(VertexBuffer.NormalKind)) {
                     this._defines.NORMAL = true;
+                    if (mesh.isVerticesDataPresent(VertexBuffer.TangentKind)) {
+                        this._defines.TANGENT = true;
+                    }
                 }
                 if (needUVs) {
                     if (mesh.isVerticesDataPresent(VertexBuffer.UVKind)) {
@@ -1050,6 +1054,10 @@
                     attribs.push(VertexBuffer.NormalKind);
                 }
 
+                if (this._defines.TANGENT) {
+                    attribs.push(VertexBuffer.TangentKind);
+                }
+
                 if (this._defines.UV1) {
                     attribs.push(VertexBuffer.UVKind);
                 }

+ 11 - 13
src/Materials/babylon.standardMaterial.ts

@@ -1,5 +1,5 @@
-module BABYLON {
-    class StandardMaterialDefines extends MaterialDefines {
+module BABYLON {
+   export class StandardMaterialDefines extends MaterialDefines {
         public DIFFUSE = false;
         public AMBIENT = false;
         public OPACITY = false;
@@ -198,15 +198,15 @@
         @serializeAsColorCurves()
         public cameraColorCurves: ColorCurves = null;
 
-        private _renderTargets = new SmartArray<RenderTargetTexture>(16);
-        private _worldViewProjectionMatrix = Matrix.Zero();
-        private _globalAmbientColor = new Color3(0, 0, 0);
-        private _renderId: number;
+        protected _renderTargets = new SmartArray<RenderTargetTexture>(16);
+        protected _worldViewProjectionMatrix = Matrix.Zero();
+        protected _globalAmbientColor = new Color3(0, 0, 0);
+        protected _renderId: number;
 
-        private _defines = new StandardMaterialDefines();
-        private _cachedDefines = new StandardMaterialDefines();
+        protected _defines = new StandardMaterialDefines();
+        protected _cachedDefines = new StandardMaterialDefines();
 
-        private _useLogarithmicDepth: boolean;
+        protected _useLogarithmicDepth: boolean;
 
         constructor(name: string, scene: Scene) {
             super(name, scene);
@@ -249,7 +249,7 @@
             return this.diffuseTexture != null && this.diffuseTexture.hasAlpha;
         }
 
-        private _shouldUseAlphaFromDiffuseTexture(): boolean {
+        protected _shouldUseAlphaFromDiffuseTexture(): boolean {
             return this.diffuseTexture != null && this.diffuseTexture.hasAlpha && this.useAlphaFromDiffuseTexture;
         }
 
@@ -258,7 +258,7 @@
         }
 
         // Methods   
-        private _checkCache(scene: Scene, mesh?: AbstractMesh, useInstances?: boolean): boolean {
+        protected _checkCache(scene: Scene, mesh?: AbstractMesh, useInstances?: boolean): boolean {
             if (!mesh) {
                 return true;
             }
@@ -987,8 +987,6 @@
                 }
             }
 
-            this._renderTargets.dispose();
-
             super.dispose(forceDisposeEffect, forceDisposeTextures);
         }
 

+ 37 - 3
src/Math/babylon.math.ts

@@ -2144,7 +2144,7 @@
         /**
          * Returns a new Vector4 set from the starting index of the passed array.  
          */
-        public static FromArray(array: number[], offset?: number): Vector4 {
+        public static FromArray(array: number[]  | Float32Array, offset?: number): Vector4 {
             if (!offset) {
                 offset = 0;
             }
@@ -2153,7 +2153,7 @@
         /**
          * Updates the passed vector "result" from the starting index of the passed array.  
          */
-        public static FromArrayToRef(array: number[], offset: number, result: Vector4): void {
+        public static FromArrayToRef(array: number[] | Float32Array, offset: number, result: Vector4): void {
             result.x = array[offset];
             result.y = array[offset + 1];
             result.z = array[offset + 2];
@@ -2219,7 +2219,6 @@
         /**
          * Returns the squared distance (float) between the vectors "value1" and "value2".  
          */
-        publi
         public static DistanceSquared(value1: Vector4, value2: Vector4): number {
             var x = value1.x - value2.x;
             var y = value1.y - value2.y;
@@ -2236,6 +2235,41 @@
             center.scaleInPlace(0.5);
             return center;
         }
+
+        /**
+         * Returns a new Vector4 set with the result of the normal transformation by the passed matrix of the passed vector.  
+         * This methods computes transformed normalized direction vectors only.  
+         */
+        public static TransformNormal(vector: Vector4, transformation: Matrix): Vector4 {
+            var result = Vector4.Zero();
+            Vector4.TransformNormalToRef(vector, transformation, result);
+            return result;
+        }
+
+        /**
+         * Sets the passed vector "result" with the result of the normal transformation by the passed matrix of the passed vector.  
+         * This methods computes transformed normalized direction vectors only. 
+         */
+        public static TransformNormalToRef(vector: Vector4, transformation: Matrix, result: Vector4): void {
+            var x = (vector.x * transformation.m[0]) + (vector.y * transformation.m[4]) + (vector.z * transformation.m[8]);
+            var y = (vector.x * transformation.m[1]) + (vector.y * transformation.m[5]) + (vector.z * transformation.m[9]);
+            var z = (vector.x * transformation.m[2]) + (vector.y * transformation.m[6]) + (vector.z * transformation.m[10]);
+            result.x = x;
+            result.y = y;
+            result.z = z;
+            result.w = vector.w;
+        }
+
+        /**
+         * Sets the passed vector "result" with the result of the normal transformation by the passed matrix of the passed floats (x, y, z, w).  
+         * This methods computes transformed normalized direction vectors only. 
+         */
+        public static TransformNormalFromFloatsToRef(x: number, y: number, z: number, w: number, transformation: Matrix, result: Vector4): void {
+            result.x = (x * transformation.m[0]) + (y * transformation.m[4]) + (z * transformation.m[8]);
+            result.y = (x * transformation.m[1]) + (y * transformation.m[5]) + (z * transformation.m[9]);
+            result.z = (x * transformation.m[2]) + (y * transformation.m[6]) + (z * transformation.m[10]);
+            result.w = w;
+        }
     }
 
     export interface ISize {

+ 3 - 2
src/Mesh/babylon.abstractMesh.ts

@@ -460,7 +460,8 @@
             if (this._masterMesh) {
                 return this._masterMesh.getWorldMatrix();
             }
-            if (this._currentRenderId !== this.getScene().getRenderId()) {
+            
+            if (this._currentRenderId !== this.getScene().getRenderId() || !this.isSynchronized()) {
                 this.computeWorldMatrix();
             }
             return this._worldMatrix;
@@ -813,7 +814,7 @@
                 return this._worldMatrix;
             }
 
-            if (!force && (this._currentRenderId === this.getScene().getRenderId() || this.isSynchronized(true))) {
+            if (!force && ((this._currentRenderId === this.getScene().getRenderId() && this.isSynchronized(true)))) {
                 this._currentRenderId = this.getScene().getRenderId();
                 return this._worldMatrix;
             }

+ 1 - 1
src/Mesh/babylon.instancedMesh.ts

@@ -160,7 +160,7 @@
             var result = this._sourceMesh.createInstance(name);
 
             // Deep copy
-            Tools.DeepCopy(this, result, ["name", "subMeshes"], []);
+            Tools.DeepCopy(this, result, ["name", "subMeshes", "uniqueId"], []);
 
             // Bounding info
             this.refreshBoundingInfo();

+ 1 - 1
src/Mesh/babylon.mesh.ts

@@ -151,7 +151,7 @@
                 }
 
                 // Deep copy
-                Tools.DeepCopy(source, this, ["name", "material", "skeleton", "instances", "parent"], ["_poseMatrix"]);
+                Tools.DeepCopy(source, this, ["name", "material", "skeleton", "instances", "parent", "uniqueId"], ["_poseMatrix"]);
 
                 // Parent
                 this.parent = source.parent;

+ 51 - 8
src/Mesh/babylon.mesh.vertexData.ts

@@ -14,6 +14,7 @@
     export class VertexData {
         public positions: number[] | Float32Array;
         public normals: number[] | Float32Array;
+        public tangents: number[] | Float32Array;
         public uvs: number[] | Float32Array;
         public uvs2: number[] | Float32Array;
         public uvs3: number[] | Float32Array;
@@ -35,6 +36,9 @@
                 case VertexBuffer.NormalKind:
                     this.normals = data;
                     break;
+                case VertexBuffer.TangentKind:
+                    this.tangents = data;
+                    break;
                 case VertexBuffer.UVKind:
                     this.uvs = data;
                     break;
@@ -118,6 +122,10 @@
                 meshOrGeometry.setVerticesData(VertexBuffer.NormalKind, this.normals, updatable);
             }
 
+            if (this.tangents) {
+                meshOrGeometry.setVerticesData(VertexBuffer.TangentKind, this.tangents, updatable);
+            }
+
             if (this.uvs) {
                 meshOrGeometry.setVerticesData(VertexBuffer.UVKind, this.uvs, updatable);
             }
@@ -177,6 +185,10 @@
                 meshOrGeometry.updateVerticesData(VertexBuffer.NormalKind, this.normals, updateExtends, makeItUnique);
             }
 
+            if (this.tangents) {
+                meshOrGeometry.updateVerticesData(VertexBuffer.TangentKind, this.tangents, updateExtends, makeItUnique);
+            }
+
             if (this.uvs) {
                 meshOrGeometry.updateVerticesData(VertexBuffer.UVKind, this.uvs, updateExtends, makeItUnique);
             }
@@ -259,6 +271,22 @@
                     this.normals[index + 2] = transformed.z;
                 }
             }
+
+            if (this.tangents) {
+                var tangent = Vector4.Zero();
+                var tangentTransformed = Vector4.Zero();
+
+                for (index = 0; index < this.tangents.length; index += 4) {
+                    Vector4.FromArrayToRef(this.tangents, index, tangent);
+
+                    Vector4.TransformNormalToRef(tangent, matrix, tangentTransformed);
+                    this.tangents[index] = tangentTransformed.x;
+                    this.tangents[index + 1] = tangentTransformed.y;
+                    this.tangents[index + 2] = tangentTransformed.z;
+                    this.tangents[index + 3] = tangentTransformed.w;
+                }
+            }
+
             return this;
         }
 
@@ -281,6 +309,7 @@
 
             this.positions = this._mergeElement(this.positions, other.positions);
             this.normals = this._mergeElement(this.normals, other.normals);
+            this.tangents = this._mergeElement(this.tangents, other.tangents);
             this.uvs = this._mergeElement(this.uvs, other.uvs);
             this.uvs2 = this._mergeElement(this.uvs2, other.uvs2);
             this.uvs3 = this._mergeElement(this.uvs3, other.uvs3);
@@ -339,6 +368,10 @@
                 serializationObject.normals = this.normals;
             }
 
+            if (this.tangents) {
+                serializationObject.tangents = this.tangents;
+            }
+
             if (this.uvs) {
                 serializationObject.uvs = this.uvs;
             }
@@ -416,6 +449,10 @@
                 result.normals = meshOrGeometry.getVerticesData(VertexBuffer.NormalKind, copyWhenShared);
             }
 
+            if (meshOrGeometry.isVerticesDataPresent(VertexBuffer.TangentKind)) {
+                result.tangents = meshOrGeometry.getVerticesData(VertexBuffer.TangentKind, copyWhenShared);
+            }
+
             if (meshOrGeometry.isVerticesDataPresent(VertexBuffer.UVKind)) {
                 result.uvs = meshOrGeometry.getVerticesData(VertexBuffer.UVKind, copyWhenShared);
             }
@@ -2085,7 +2122,7 @@
          * bbSize : optional bounding box size data, required for facetPartitioning computation
          * bInfo : optional bounding info, required for facetPartitioning computation
          */
-        public static ComputeNormals(positions: any, indices: any, normals: any, 
+        public static ComputeNormals(positions: any, indices: any, normals: any,
             options?: { facetNormals?: any, facetPositions?: any, facetPartitioning?: any, ratio?: number, bInfo?: any, bbSize?: Vector3, subDiv?: any}): void {
 
             // temporary scalar variables
@@ -2119,7 +2156,7 @@
             }
 
             // facetPartitioning reinit if needed
-            if (computeFacetPartitioning) {  
+            if (computeFacetPartitioning) {
                 var ox = 0;                 // X partitioning index for facet position
                 var oy = 0;                 // Y partinioning index for facet position
                 var oz = 0;                 // Z partinioning index for facet position
@@ -2145,7 +2182,7 @@
                 var subSq = options.subDiv.max * options.subDiv.max;
                 options.facetPartitioning.length = 0;
             }
-        
+
             // reset the normals
             for (index = 0; index < positions.length; index++) {
                 normals[index] = 0.0;
@@ -2164,7 +2201,7 @@
                 v2z = v2x + 2;
                 v3x = indices[index * 3 + 2] * 3;
                 v3y = v3x + 1;
-                v3z = v3x + 2;        
+                v3z = v3x + 2;
 
                 p1p2x = positions[v1x] - positions[v2x];          // compute two vectors per facet : p1p2 and p3p2
                 p1p2y = positions[v1y] - positions[v2y];
@@ -2175,7 +2212,7 @@
                 p3p2z = positions[v3z] - positions[v2z];
 
                 // compute the face normal with the cross product
-                faceNormalx = p1p2y * p3p2z - p1p2z * p3p2y;            
+                faceNormalx = p1p2y * p3p2z - p1p2z * p3p2y;
                 faceNormaly = p1p2z * p3p2x - p1p2x * p3p2z;
                 faceNormalz = p1p2x * p3p2y - p1p2y * p3p2x;
                 // normalize this normal and store it in the array facetData
@@ -2186,7 +2223,7 @@
                 faceNormalz /= length;
 
                 if (computeFacetNormals) {
-                    options.facetNormals[index].x = faceNormalx;                                  
+                    options.facetNormals[index].x = faceNormalx;
                     options.facetNormals[index].y = faceNormaly;
                     options.facetNormals[index].z = faceNormalz;
                 }
@@ -2213,7 +2250,7 @@
                     b3x = Math.floor((positions[v3x] - options.bInfo.minimum.x * options.ratio) * xSubRatio);
                     b3y = Math.floor((positions[v3y] - options.bInfo.minimum.y * options.ratio) * ySubRatio);
                     b3z = Math.floor((positions[v3z] - options.bInfo.minimum.z * options.ratio) * zSubRatio);
-                    
+
                     block_idx_v1 = b1x + options.subDiv.max * b1y + subSq * b1z;
                     block_idx_v2 = b2x + options.subDiv.max * b2y + subSq * b2z;
                     block_idx_v3 = b3x + options.subDiv.max * b3y + subSq * b3z;
@@ -2233,7 +2270,7 @@
                         options.facetPartitioning[block_idx_v3].push(index);
                     }
                     if (!(block_idx_o == block_idx_v1 || block_idx_o == block_idx_v2 || block_idx_o == block_idx_v3)) {
-                        options.facetPartitioning[block_idx_o].push(index); 
+                        options.facetPartitioning[block_idx_o].push(index);
                     }
                 }
 
@@ -2338,6 +2375,12 @@
                 vertexData.set(normals, VertexBuffer.NormalKind);
             }
 
+            // tangents
+            var tangents = parsedVertexData.tangents;
+            if (tangents) {
+                vertexData.set(tangents, VertexBuffer.TangentKind);
+            }
+
             // uvs
             var uvs = parsedVertexData.uvs;
             if (uvs) {

+ 6 - 0
src/Mesh/babylon.vertexBuffer.ts

@@ -25,6 +25,7 @@
                     case VertexBuffer.UV6Kind:
                         stride = 2;
                         break;
+                    case VertexBuffer.TangentKind:
                     case VertexBuffer.ColorKind:
                         stride = 4;
                         break;
@@ -154,6 +155,7 @@
         // Enums
         private static _PositionKind = "position";
         private static _NormalKind = "normal";
+        private static _TangentKind = "tangent";
         private static _UVKind = "uv";
         private static _UV2Kind = "uv2";
         private static _UV3Kind = "uv3";
@@ -174,6 +176,10 @@
             return VertexBuffer._NormalKind;
         }
 
+        public static get TangentKind(): string {
+            return VertexBuffer._TangentKind;
+        }
+
         public static get UVKind(): string {
             return VertexBuffer._UVKind;
         }

+ 3 - 3
src/Physics/babylon.physicsImpostor.ts

@@ -169,7 +169,7 @@ module BABYLON {
         public getObjectExtendSize(): Vector3 {
             if (this.object.getBoundingInfo) {
                 this.object.computeWorldMatrix && this.object.computeWorldMatrix(true);
-                return this.object.getBoundingInfo().boundingBox.extendSize.scale(2).multiply(this.object.scaling)
+                return this.object.getBoundingInfo().boundingBox.extendSizeWorld.scale(2).multiply(this.object.scaling)
             } else {
                 return PhysicsImpostor.DEFAULT_OBJECT_SIZE;
             }
@@ -177,7 +177,7 @@ module BABYLON {
 
         public getObjectCenter(): Vector3 {
             if (this.object.getBoundingInfo) {
-                return this.object.getBoundingInfo().boundingBox.center;
+                return this.object.getBoundingInfo().boundingBox.centerWorld;
             } else {
                 return this.object.position;
             }
@@ -327,7 +327,7 @@ module BABYLON {
         /**
          * Legacy collision detection event support
          */
-        public onCollideEvent: (collider:BABYLON.PhysicsImpostor, collidedWith:BABYLON.PhysicsImpostor) => void = null;
+        public onCollideEvent: (collider: BABYLON.PhysicsImpostor, collidedWith: BABYLON.PhysicsImpostor) => void = null;
 
         //event and body object due to cannon's event-based architecture.
         public onCollide = (e: { body: any }) => {

+ 1 - 1
src/PostProcess/babylon.fxaaPostProcess.ts

@@ -4,7 +4,7 @@
         public texelHeight: number;
 
         constructor(name: string, options: number | PostProcessOptions, camera: Camera, samplingMode?: number, engine?: Engine, reusable?: boolean) {
-            super(name, "fxaa", ["texelSize"], null, options, camera, samplingMode, engine, reusable);
+            super(name, "fxaa", ["texelSize"], null, options, camera, samplingMode || BABYLON.Texture.BILINEAR_SAMPLINGMODE, engine, reusable);
 
             this.onSizeChangedObservable.add(() => {
                 this.texelWidth = 1.0 / this.width;

+ 5 - 1
src/Shaders/ShadersInclude/bumpFragment.fx

@@ -1,7 +1,11 @@
 vec2 uvOffset = vec2(0.0, 0.0);
 
 #if defined(BUMP) || defined(PARALLAX)
-	mat3 TBN = cotangent_frame(normalW * vBumpInfos.y, -viewDirectionW, vBumpUV);
+	#if defined(TANGENT) && defined(NORMAL)
+		mat3 TBN = vTBN;
+	#else
+		mat3 TBN = cotangent_frame(normalW * vBumpInfos.y, -viewDirectionW, vBumpUV);
+	#endif
 #endif
 
 #ifdef PARALLAX

+ 3 - 0
src/Shaders/ShadersInclude/bumpFragmentFunctions.fx

@@ -2,6 +2,9 @@
 	varying vec2 vBumpUV;
 	uniform vec3 vBumpInfos;
 	uniform sampler2D bumpSampler;
+#if defined(TANGENT) && defined(NORMAL) 
+	varying mat3 vTBN;
+#endif
 
 	// Thanks to http://www.thetenthplanet.de/archives/1180
 	mat3 cotangent_frame(vec3 normal, vec3 p, vec2 uv)

+ 8 - 0
src/Shaders/ShadersInclude/bumpVertex.fx

@@ -0,0 +1,8 @@
+#if defined(BUMP) || defined(PARALLAX)
+	#if defined(TANGENT) && defined(NORMAL)
+		vec3 normalW = normalize(vec3(finalWorld * vec4(normal, 0.0)));
+		vec3 tangentW = normalize(vec3(finalWorld * vec4(tangent.xyz, 0.0)));
+		vec3 bitangentW = cross(normalW, tangentW) * tangent.w;
+		vTBN = mat3(tangentW, bitangentW, normalW);
+	#endif
+#endif

+ 5 - 0
src/Shaders/ShadersInclude/bumpVertexDeclaration.fx

@@ -0,0 +1,5 @@
+#if defined(BUMP) || defined(PARALLAX)
+	#if defined(TANGENT) && defined(NORMAL) 
+		varying mat3 vTBN;
+	#endif
+#endif

+ 16 - 12
src/Shaders/ShadersInclude/lightFragment.fx

@@ -16,20 +16,24 @@
         #endif
     #endif
 	#ifdef SHADOW{X}
-		#ifdef SHADOWVSM{X}
-			shadow = computeShadowWithVSM(vPositionFromLight{X}, shadowSampler{X}, shadowsInfo{X}.z, shadowsInfo{X}.x);
-		#else
-		#ifdef SHADOWPCF{X}
-			#if defined(POINTLIGHT{X})
-				shadow = computeShadowWithPCFCube(vLightData{X}.xyz, shadowSampler{X}, shadowsInfo{X}.y, shadowsInfo{X}.z, shadowsInfo{X}.x);
+		#ifdef SHADOWESM{X}
+			shadow = computeShadowWithESM(vPositionFromLight{X}, shadowSampler{X}, shadowsInfo{X}.x);
+		#else	
+			#ifdef SHADOWVSM{X}
+				shadow = computeShadowWithVSM(vPositionFromLight{X}, shadowSampler{X}, shadowsInfo{X}.x);
 			#else
-				shadow = computeShadowWithPCF(vPositionFromLight{X}, shadowSampler{X}, shadowsInfo{X}.y, shadowsInfo{X}.z, shadowsInfo{X}.x);
-			#endif
-		#else
-			#if defined(POINTLIGHT{X})
-				shadow = computeShadowCube(vLightData{X}.xyz, shadowSampler{X}, shadowsInfo{X}.x, shadowsInfo{X}.z);
+			#ifdef SHADOWPCF{X}
+				#if defined(POINTLIGHT{X})
+					shadow = computeShadowWithPCFCube(vLightData{X}.xyz, shadowSampler{X}, shadowsInfo{X}.y, shadowsInfo{X}.x);
+				#else
+					shadow = computeShadowWithPCF(vPositionFromLight{X}, shadowSampler{X}, shadowsInfo{X}.y, shadowsInfo{X}.x);
+				#endif
 			#else
-				shadow = computeShadow(vPositionFromLight{X}, shadowSampler{X}, shadowsInfo{X}.x, shadowsInfo{X}.z);
+				#if defined(POINTLIGHT{X})
+					shadow = computeShadowCube(vLightData{X}.xyz, shadowSampler{X}, shadowsInfo{X}.x);
+				#else
+					shadow = computeShadow(vPositionFromLight{X}, shadowSampler{X}, shadowsInfo{X}.x);
+				#endif
 			#endif
 		#endif
 	#endif

+ 1 - 1
src/Shaders/ShadersInclude/lightFragmentDeclaration.fx

@@ -11,7 +11,7 @@
 		#else
 			uniform samplerCube shadowSampler{X};
 		#endif
-		uniform vec3 shadowsInfo{X};
+		uniform vec2 shadowsInfo{X};
 	#endif
 	#ifdef SPOTLIGHT{X}
 		uniform vec4 vLightDirection{X};

+ 57 - 30
src/Shaders/ShadersInclude/shadowsFragmentFunctions.fx

@@ -9,7 +9,7 @@
 
 	uniform vec2 depthValues;
 
-	float computeShadowCube(vec3 lightPosition, samplerCube shadowSampler, float darkness, float bias)
+	float computeShadowCube(vec3 lightPosition, samplerCube shadowSampler, float darkness)
 	{
 		vec3 directionToLight = vPositionW - lightPosition;
 		float depth = length(directionToLight);
@@ -20,9 +20,9 @@
 		directionToLight.y = -directionToLight.y;
 		
 		#ifndef SHADOWFULLFLOAT
-			float shadow = unpack(textureCube(shadowSampler, directionToLight)) + bias;
+			float shadow = unpack(textureCube(shadowSampler, directionToLight));
 		#else
-			float shadow = textureCube(shadowSampler, directionToLight).x + bias;
+			float shadow = textureCube(shadowSampler, directionToLight).x;
 		#endif
 
 		if (depth > shadow)
@@ -32,7 +32,7 @@
 		return 1.0;
 	}
 
-	float computeShadowWithPCFCube(vec3 lightPosition, samplerCube shadowSampler, float mapSize, float bias, float darkness)
+	float computeShadowWithPCFCube(vec3 lightPosition, samplerCube shadowSampler, float mapSize, float darkness)
 	{
 		vec3 directionToLight = vPositionW - lightPosition;
 		float depth = length(directionToLight);
@@ -52,24 +52,23 @@
 		poissonDisk[3] = vec3(1.0, -1.0, 1.0);
 
 		// Poisson Sampling
-		float biasedDepth = depth - bias;
 
 		#ifndef SHADOWFULLFLOAT
-			if (unpack(textureCube(shadowSampler, directionToLight + poissonDisk[0] * mapSize)) < biasedDepth) visibility -= 0.25;
-			if (unpack(textureCube(shadowSampler, directionToLight + poissonDisk[1] * mapSize)) < biasedDepth) visibility -= 0.25;
-			if (unpack(textureCube(shadowSampler, directionToLight + poissonDisk[2] * mapSize)) < biasedDepth) visibility -= 0.25;
-			if (unpack(textureCube(shadowSampler, directionToLight + poissonDisk[3] * mapSize)) < biasedDepth) visibility -= 0.25;
+			if (unpack(textureCube(shadowSampler, directionToLight + poissonDisk[0] * mapSize)) < depth) visibility -= 0.25;
+			if (unpack(textureCube(shadowSampler, directionToLight + poissonDisk[1] * mapSize)) < depth) visibility -= 0.25;
+			if (unpack(textureCube(shadowSampler, directionToLight + poissonDisk[2] * mapSize)) < depth) visibility -= 0.25;
+			if (unpack(textureCube(shadowSampler, directionToLight + poissonDisk[3] * mapSize)) < depth) visibility -= 0.25;
 		#else
-			if (textureCube(shadowSampler, directionToLight + poissonDisk[0] * mapSize).x < biasedDepth) visibility -= 0.25;
-			if (textureCube(shadowSampler, directionToLight + poissonDisk[1] * mapSize).x < biasedDepth) visibility -= 0.25;
-			if (textureCube(shadowSampler, directionToLight + poissonDisk[2] * mapSize).x < biasedDepth) visibility -= 0.25;
-			if (textureCube(shadowSampler, directionToLight + poissonDisk[3] * mapSize).x < biasedDepth) visibility -= 0.25;
+			if (textureCube(shadowSampler, directionToLight + poissonDisk[0] * mapSize).x < depth) visibility -= 0.25;
+			if (textureCube(shadowSampler, directionToLight + poissonDisk[1] * mapSize).x < depth) visibility -= 0.25;
+			if (textureCube(shadowSampler, directionToLight + poissonDisk[2] * mapSize).x < depth) visibility -= 0.25;
+			if (textureCube(shadowSampler, directionToLight + poissonDisk[3] * mapSize).x < depth) visibility -= 0.25;
 		#endif
 
 		return  min(1.0, visibility + darkness);
 	}
 
-	float computeShadow(vec4 vPositionFromLight, sampler2D shadowSampler, float darkness, float bias)
+	float computeShadow(vec4 vPositionFromLight, sampler2D shadowSampler, float darkness)
 	{
 		vec3 depth = vPositionFromLight.xyz / vPositionFromLight.w;
 		depth = 0.5 * depth + vec3(0.5);
@@ -81,9 +80,9 @@
 		}
 
 		#ifndef SHADOWFULLFLOAT
-			float shadow = unpack(texture2D(shadowSampler, uv)) + bias;
+			float shadow = unpack(texture2D(shadowSampler, uv));
 		#else
-			float shadow = texture2D(shadowSampler, uv).x + bias;
+			float shadow = texture2D(shadowSampler, uv).x;
 		#endif
 
 		if (depth.z > shadow)
@@ -93,7 +92,7 @@
 		return 1.;
 	}
 
-	float computeShadowWithPCF(vec4 vPositionFromLight, sampler2D shadowSampler, float mapSize, float bias, float darkness)
+	float computeShadowWithPCF(vec4 vPositionFromLight, sampler2D shadowSampler, float mapSize, float darkness)
 	{
 		vec3 depth = vPositionFromLight.xyz / vPositionFromLight.w;
 		depth = 0.5 * depth + vec3(0.5);
@@ -113,18 +112,17 @@
 		poissonDisk[3] = vec2(0.34495938, 0.29387760);
 
 		// Poisson Sampling
-		float biasedDepth = depth.z - bias;
 
 		#ifndef SHADOWFULLFLOAT
-			if (unpack(texture2D(shadowSampler, uv + poissonDisk[0] * mapSize)) < biasedDepth) visibility -= 0.25;
-			if (unpack(texture2D(shadowSampler, uv + poissonDisk[1] * mapSize)) < biasedDepth) visibility -= 0.25;
-			if (unpack(texture2D(shadowSampler, uv + poissonDisk[2] * mapSize)) < biasedDepth) visibility -= 0.25;
-			if (unpack(texture2D(shadowSampler, uv + poissonDisk[3] * mapSize)) < biasedDepth) visibility -= 0.25;
+			if (unpack(texture2D(shadowSampler, uv + poissonDisk[0] * mapSize)) < depth.z) visibility -= 0.25;
+			if (unpack(texture2D(shadowSampler, uv + poissonDisk[1] * mapSize)) < depth.z) visibility -= 0.25;
+			if (unpack(texture2D(shadowSampler, uv + poissonDisk[2] * mapSize)) < depth.z) visibility -= 0.25;
+			if (unpack(texture2D(shadowSampler, uv + poissonDisk[3] * mapSize)) < depth.z) visibility -= 0.25;
 		#else
-			if (texture2D(shadowSampler, uv + poissonDisk[0] * mapSize).x < biasedDepth) visibility -= 0.25;
-			if (texture2D(shadowSampler, uv + poissonDisk[1] * mapSize).x < biasedDepth) visibility -= 0.25;
-			if (texture2D(shadowSampler, uv + poissonDisk[2] * mapSize).x < biasedDepth) visibility -= 0.25;
-			if (texture2D(shadowSampler, uv + poissonDisk[3] * mapSize).x < biasedDepth) visibility -= 0.25;
+			if (texture2D(shadowSampler, uv + poissonDisk[0] * mapSize).x < depth.z) visibility -= 0.25;
+			if (texture2D(shadowSampler, uv + poissonDisk[1] * mapSize).x < depth.z) visibility -= 0.25;
+			if (texture2D(shadowSampler, uv + poissonDisk[2] * mapSize).x < depth.z) visibility -= 0.25;
+			if (texture2D(shadowSampler, uv + poissonDisk[3] * mapSize).x < depth.z) visibility -= 0.25;
 		#endif
 
 		return  min(1.0, visibility + darkness);
@@ -142,9 +140,9 @@
 		return clamp((v - low) / (high - low), 0.0, 1.0);
 	}
 
-	float ChebychevInequality(vec2 moments, float compare, float bias)
+	float ChebychevInequality(vec2 moments, float compare)
 	{
-		float p = smoothstep(compare - bias, compare, moments.x);
+		float p = smoothstep(compare, compare, moments.x);
 		float variance = max(moments.y - moments.x * moments.x, 0.02);
 		float d = compare - moments.x;
 		float p_max = linstep(0.2, 1.0, variance / (variance + d * d));
@@ -152,7 +150,7 @@
 		return clamp(max(p, p_max), 0.0, 1.0);
 	}
 
-	float computeShadowWithVSM(vec4 vPositionFromLight, sampler2D shadowSampler, float bias, float darkness)
+	float computeShadowWithVSM(vec4 vPositionFromLight, sampler2D shadowSampler, float darkness)
 	{
 		vec3 depth = vPositionFromLight.xyz / vPositionFromLight.w;
 		depth = 0.5 * depth + vec3(0.5);
@@ -171,6 +169,35 @@
 			vec2 moments = texel.xy;
 		#endif
 
-		return min(1.0, 1.0 - ChebychevInequality(moments, depth.z, bias) + darkness);
+		return min(1.0, 1.0 - ChebychevInequality(moments, depth.z) + darkness);
+	}
+
+	float computeShadowWithESM(vec4 vPositionFromLight, sampler2D shadowSampler, float darkness)
+	{
+		vec3 clipSpace = vPositionFromLight.xyz / vPositionFromLight.w;
+		vec3 depth = 0.5 * clipSpace + vec3(0.5);
+		vec2 uv = depth.xy;
+		float shadowPixelDepth = clipSpace.z;
+
+		if (uv.x < 0. || uv.x > 1.0 || uv.y < 0. || uv.y > 1.0)
+		{
+			return 1.0;
+		}
+	
+		#ifndef SHADOWFULLFLOAT
+			float shadowMapSample = unpack(texture2D(shadowSampler, uv));
+		#else
+			float shadowMapSample = texture2D(shadowSampler, uv).x;
+		#endif
+
+		const float shadowStrength = 50.0;
+		float esm = clamp(exp(shadowStrength * shadowPixelDepth) * shadowMapSample + darkness, 0., 1.);
+
+		// Apply fade out at frustum edge
+		const float fadeDistance = 0.07;
+		vec2 cs2 = clipSpace.xy * clipSpace.xy; //squarish falloff
+		float mask = smoothstep(1.0, 1.0 - fadeDistance, dot(cs2, cs2));
+
+		return mix(1.0, esm, mask);
 	}
 #endif

+ 6 - 0
src/Shaders/default.vertex.fx

@@ -3,6 +3,9 @@ attribute vec3 position;
 #ifdef NORMAL
 attribute vec3 normal;
 #endif
+#ifdef TANGENT
+attribute vec4 tangent;
+#endif
 #ifdef UV1
 attribute vec2 uv;
 #endif
@@ -75,6 +78,8 @@ varying vec3 vNormalW;
 varying vec4 vColor;
 #endif
 
+#include<bumpVertexDeclaration>
+
 #include<clipPlaneVertexDeclaration>
 
 #include<fogVertexDeclaration>
@@ -196,6 +201,7 @@ void main(void) {
 	}
 #endif
 
+#include<bumpVertex>
 #include<clipPlaneVertex>
 #include<fogVertex>
 #include<shadowsVertex>[0..maxSimultaneousLights]

+ 230 - 44
src/Shaders/fxaa.fragment.fx

@@ -1,50 +1,236 @@
-#define FXAA_REDUCE_MIN   (1.0/128.0)
-#define FXAA_REDUCE_MUL   (1.0/8.0)
-#define FXAA_SPAN_MAX     8.0
-
-varying vec2 vUV;
+varying vec2 vUV;
 uniform sampler2D textureSampler;
 uniform vec2 texelSize;
 
+const float fxaaQualitySubpix = 1.0;
+const float fxaaQualityEdgeThreshold = 0.166;
+const float fxaaQualityEdgeThresholdMin = 0.0833;
+const vec3 kLumaCoefficients = vec3(0.2126, 0.7152, 0.0722);
+
+#define FxaaLuma(rgba) dot(rgba.rgb, kLumaCoefficients)
+
 void main(){
-	vec2 localTexelSize = texelSize;
-	vec4 rgbNW = texture2D(textureSampler, (vUV + vec2(-1.0, -1.0) * localTexelSize));
-	vec4 rgbNE = texture2D(textureSampler, (vUV + vec2(1.0, -1.0) * localTexelSize));
-	vec4 rgbSW = texture2D(textureSampler, (vUV + vec2(-1.0, 1.0) * localTexelSize));
-	vec4 rgbSE = texture2D(textureSampler, (vUV + vec2(1.0, 1.0) * localTexelSize));
-	vec4 rgbM = texture2D(textureSampler, vUV);
-	vec4 luma = vec4(0.299, 0.587, 0.114, 1.0);
-	float lumaNW = dot(rgbNW, luma);
-	float lumaNE = dot(rgbNE, luma);
-	float lumaSW = dot(rgbSW, luma);
-	float lumaSE = dot(rgbSE, luma);
-	float lumaM = dot(rgbM, luma);
-	float lumaMin = min(lumaM, min(min(lumaNW, lumaNE), min(lumaSW, lumaSE)));
-	float lumaMax = max(lumaM, max(max(lumaNW, lumaNE), max(lumaSW, lumaSE)));
-
-	vec2 dir = vec2(-((lumaNW + lumaNE) - (lumaSW + lumaSE)), ((lumaNW + lumaSW) - (lumaNE + lumaSE)));
-
-	float dirReduce = max(
-		(lumaNW + lumaNE + lumaSW + lumaSE) * (0.25 * FXAA_REDUCE_MUL),
-		FXAA_REDUCE_MIN);
-
-	float rcpDirMin = 1.0 / (min(abs(dir.x), abs(dir.y)) + dirReduce);
-	dir = min(vec2(FXAA_SPAN_MAX, FXAA_SPAN_MAX),
-		max(vec2(-FXAA_SPAN_MAX, -FXAA_SPAN_MAX),
-		dir * rcpDirMin)) * localTexelSize;
-
-	vec4 rgbA = 0.5 * (
-		texture2D(textureSampler, vUV + dir * (1.0 / 3.0 - 0.5)) +
-		texture2D(textureSampler, vUV + dir * (2.0 / 3.0 - 0.5)));
-
-	vec4 rgbB = rgbA * 0.5 + 0.25 * (
-		texture2D(textureSampler, vUV + dir *  -0.5) +
-		texture2D(textureSampler, vUV + dir * 0.5));
-	float lumaB = dot(rgbB, luma);
-	if ((lumaB < lumaMin) || (lumaB > lumaMax)) {
-		gl_FragColor = rgbA;
-	}
-	else {
-		gl_FragColor = rgbB;
+	vec2 sampleCoordS = vUV + vec2( 0.0, 1.0) * texelSize;
+	vec2 sampleCoordE = vUV + vec2( 1.0, 0.0) * texelSize;
+	vec2 sampleCoordN = vUV + vec2( 0.0,-1.0) * texelSize;
+	vec2 sampleCoordW = vUV + vec2(-1.0, 0.0) * texelSize;
+
+	vec2 sampleCoordNW = vUV + vec2(-1.0,-1.0) * texelSize;
+	vec2 sampleCoordSE = vUV + vec2( 1.0, 1.0) * texelSize;
+	vec2 sampleCoordNE = vUV + vec2( 1.0,-1.0) * texelSize;
+	vec2 sampleCoordSW = vUV + vec2(-1.0, 1.0) * texelSize;
+
+	vec2 posM;
+
+	posM.x = vUV.x;
+	posM.y = vUV.y;
+
+	vec4 rgbyM = texture2D(textureSampler, vUV, 0.0);
+	float lumaM = FxaaLuma(rgbyM);
+	float lumaS = FxaaLuma(texture2D(textureSampler, sampleCoordS, 0.0));
+	float lumaE = FxaaLuma(texture2D(textureSampler, sampleCoordE, 0.0));
+	float lumaN = FxaaLuma(texture2D(textureSampler, sampleCoordN, 0.0));
+	float lumaW = FxaaLuma(texture2D(textureSampler, sampleCoordW, 0.0));
+	float maxSM = max(lumaS, lumaM);
+	float minSM = min(lumaS, lumaM);
+	float maxESM = max(lumaE, maxSM);
+	float minESM = min(lumaE, minSM);
+	float maxWN = max(lumaN, lumaW);
+	float minWN = min(lumaN, lumaW);
+	float rangeMax = max(maxWN, maxESM);
+	float rangeMin = min(minWN, minESM);
+	float rangeMaxScaled = rangeMax * fxaaQualityEdgeThreshold;
+	float range = rangeMax - rangeMin;
+	float rangeMaxClamped = max(fxaaQualityEdgeThresholdMin, rangeMaxScaled);
+
+	if(range < rangeMaxClamped) 
+	{
+		gl_FragColor = rgbyM;
+		return;
+	}
+
+	float lumaNW = FxaaLuma(texture2D(textureSampler, sampleCoordNW, 0.0));
+	float lumaSE = FxaaLuma(texture2D(textureSampler, sampleCoordSE, 0.0));
+	float lumaNE = FxaaLuma(texture2D(textureSampler, sampleCoordNE, 0.0));
+	float lumaSW = FxaaLuma(texture2D(textureSampler, sampleCoordSW, 0.0));
+	float lumaNS = lumaN + lumaS;
+	float lumaWE = lumaW + lumaE;
+	float subpixRcpRange = 1.0 / range;
+	float subpixNSWE = lumaNS + lumaWE;
+	float edgeHorz1 = (-2.0 * lumaM) + lumaNS;
+	float edgeVert1 = (-2.0 * lumaM) + lumaWE;
+	float lumaNESE = lumaNE + lumaSE;
+	float lumaNWNE = lumaNW + lumaNE;
+	float edgeHorz2 = (-2.0 * lumaE) + lumaNESE;
+	float edgeVert2 = (-2.0 * lumaN) + lumaNWNE;
+	float lumaNWSW = lumaNW + lumaSW;
+	float lumaSWSE = lumaSW + lumaSE;
+	float edgeHorz4 = (abs(edgeHorz1) * 2.0) + abs(edgeHorz2);
+	float edgeVert4 = (abs(edgeVert1) * 2.0) + abs(edgeVert2);
+	float edgeHorz3 = (-2.0 * lumaW) + lumaNWSW;
+	float edgeVert3 = (-2.0 * lumaS) + lumaSWSE;
+	float edgeHorz = abs(edgeHorz3) + edgeHorz4;
+	float edgeVert = abs(edgeVert3) + edgeVert4;
+	float subpixNWSWNESE = lumaNWSW + lumaNESE;
+	float lengthSign = texelSize.x;
+	bool horzSpan = edgeHorz >= edgeVert;
+	float subpixA = subpixNSWE * 2.0 + subpixNWSWNESE;
+
+	if (!horzSpan)
+	{
+		lumaN = lumaW;
+	}
+
+	if (!horzSpan) 
+	{
+		lumaS = lumaE;
+	}
+
+	if (horzSpan) 
+	{
+		lengthSign = texelSize.y;
 	}
+
+	float subpixB = (subpixA * (1.0 / 12.0)) - lumaM;
+	float gradientN = lumaN - lumaM;
+	float gradientS = lumaS - lumaM;
+	float lumaNN = lumaN + lumaM;
+	float lumaSS = lumaS + lumaM;
+	bool pairN = abs(gradientN) >= abs(gradientS);
+	float gradient = max(abs(gradientN), abs(gradientS));
+
+	if (pairN)
+	{
+		lengthSign = -lengthSign;
+	}
+
+	float subpixC = clamp(abs(subpixB) * subpixRcpRange, 0.0, 1.0);
+	vec2 posB;
+
+	posB.x = posM.x;
+	posB.y = posM.y;
+
+	vec2 offNP;
+
+	offNP.x = (!horzSpan) ? 0.0 : texelSize.x;
+	offNP.y = (horzSpan) ? 0.0 : texelSize.y;
+
+	if (!horzSpan) 
+	{
+		posB.x += lengthSign * 0.5;
+	}
+
+	if (horzSpan)
+	{
+		posB.y += lengthSign * 0.5;
+	}
+
+	vec2 posN;
+
+	posN.x = posB.x - offNP.x * 1.5;
+	posN.y = posB.y - offNP.y * 1.5;
+
+	vec2 posP;
+
+	posP.x = posB.x + offNP.x * 1.5;
+	posP.y = posB.y + offNP.y * 1.5;
+
+	float subpixD = ((-2.0) * subpixC) + 3.0;
+	float lumaEndN = FxaaLuma(texture2D(textureSampler, posN, 0.0));
+	float subpixE = subpixC * subpixC;
+	float lumaEndP = FxaaLuma(texture2D(textureSampler, posP, 0.0));
+
+	if (!pairN) 
+	{
+		lumaNN = lumaSS;
+	}
+
+	float gradientScaled = gradient * 1.0 / 4.0;
+	float lumaMM = lumaM - lumaNN * 0.5;
+	float subpixF = subpixD * subpixE;
+	bool lumaMLTZero = lumaMM < 0.0;
+
+	lumaEndN -= lumaNN * 0.5;
+	lumaEndP -= lumaNN * 0.5;
+
+	bool doneN = abs(lumaEndN) >= gradientScaled;
+	bool doneP = abs(lumaEndP) >= gradientScaled;
+
+	if (!doneN) 
+	{
+		posN.x -= offNP.x * 3.0;
+	}
+
+	if (!doneN) 
+	{
+		posN.y -= offNP.y * 3.0;
+	}
+
+	bool doneNP = (!doneN) || (!doneP);
+
+	if (!doneP) 
+	{
+		posP.x += offNP.x * 3.0;
+	}
+
+	if (!doneP)
+	{
+		posP.y += offNP.y * 3.0;
+	}
+
+	if (doneNP)
+	{
+		if (!doneN) lumaEndN = FxaaLuma(texture2D(textureSampler, posN.xy, 0.0));
+		if (!doneP) lumaEndP = FxaaLuma(texture2D(textureSampler, posP.xy, 0.0));
+		if (!doneN) lumaEndN = lumaEndN - lumaNN * 0.5;
+		if (!doneP) lumaEndP = lumaEndP - lumaNN * 0.5;
+	
+		doneN = abs(lumaEndN) >= gradientScaled;
+		doneP = abs(lumaEndP) >= gradientScaled;
+	
+		if (!doneN) posN.x -= offNP.x * 12.0;
+		if (!doneN) posN.y -= offNP.y * 12.0;
+	
+		doneNP = (!doneN) || (!doneP);
+	
+		if (!doneP) posP.x += offNP.x * 12.0;
+		if (!doneP) posP.y += offNP.y * 12.0;
+	}
+
+	float dstN = posM.x - posN.x;
+	float dstP = posP.x - posM.x;
+
+	if (!horzSpan)
+	{
+		dstN = posM.y - posN.y;
+	}
+	if (!horzSpan) 
+	{
+		dstP = posP.y - posM.y;
+	}
+
+	bool goodSpanN = (lumaEndN < 0.0) != lumaMLTZero;
+	float spanLength = (dstP + dstN);
+	bool goodSpanP = (lumaEndP < 0.0) != lumaMLTZero;
+	float spanLengthRcp = 1.0 / spanLength;
+	bool directionN = dstN < dstP;
+	float dst = min(dstN, dstP);
+	bool goodSpan = directionN ? goodSpanN : goodSpanP;
+	float subpixG = subpixF * subpixF;
+	float pixelOffset = (dst * (-spanLengthRcp)) + 0.5;
+	float subpixH = subpixG * fxaaQualitySubpix;
+	float pixelOffsetGood = goodSpan ? pixelOffset : 0.0;
+	float pixelOffsetSubpix = max(pixelOffsetGood, subpixH);
+
+	if (!horzSpan)
+	{
+		posM.x += pixelOffsetSubpix * lengthSign;
+	}
+
+	if (horzSpan)
+	{
+		posM.y += pixelOffsetSubpix * lengthSign;
+	}
+
+	gl_FragColor = texture2D(textureSampler, posM, 0.0);
 }

+ 7 - 0
src/Shaders/pbr.vertex.fx

@@ -5,6 +5,9 @@ attribute vec3 position;
 #ifdef NORMAL
 attribute vec3 normal;
 #endif
+#ifdef TANGENT
+attribute vec4 tangent;
+#endif
 #ifdef UV1
 attribute vec2 uv;
 #endif
@@ -80,6 +83,7 @@ varying vec4 vColor;
 #endif
 
 
+#include<bumpVertexDeclaration>
 #include<clipPlaneVertexDeclaration>
 #include<fogVertexDeclaration>
 #include<shadowsVertexDeclaration>[0..maxSimultaneousLights]
@@ -200,6 +204,9 @@ void main(void) {
     }
 #endif
 
+    // TBN
+#include<bumpVertex>
+
     // Clip plane
 #include<clipPlaneVertex>
 

+ 10 - 1
src/Shaders/shadowMap.fragment.fx

@@ -32,6 +32,8 @@ uniform vec3 lightPosition;
 uniform vec2 depthValues;
 #endif
 
+uniform float bias;
+
 void main(void)
 {
 #ifdef ALPHATEST
@@ -47,7 +49,14 @@ void main(void)
 	depth = clamp(depth, 0., 1.0);
 #else
 	float depth = vPosition.z / vPosition.w;
-	depth = depth * 0.5 + 0.5;
+	depth = depth * 0.5 + 0.5;	
+#endif
+
+	depth += bias;
+
+#ifdef ESM
+	const float shadowStrength = 50.0;
+	depth = exp(-shadowStrength * depth);
 #endif
 
 #ifdef VSM

+ 99 - 3
src/Tools/babylon.extendedGamepad.ts

@@ -38,7 +38,7 @@ module BABYLON {
 
         public rawPose: DevicePose; //GamepadPose;
 
-        private _mesh: AbstractMesh; // a node that will be attached to this Gamepad
+        public _mesh: AbstractMesh; // a node that will be attached to this Gamepad
         private _poseControlledCamera: TargetCamera;
 
         private _leftHandSystemQuaternion: Quaternion = new Quaternion();
@@ -166,7 +166,6 @@ module BABYLON {
 
         public onTriggerStateChangedObservable = new Observable<ExtendedGamepadButton>();
 
-
         public onMainButtonStateChangedObservable = new Observable<ExtendedGamepadButton>();
 
         public onSecondaryButtonStateChangedObservable = new Observable<ExtendedGamepadButton>();
@@ -206,6 +205,8 @@ module BABYLON {
 
         protected abstract handleButtonChange(buttonIdx: number, value: ExtendedGamepadButton, changes: GamepadButtonChanges);
 
+        public abstract initControllerMesh(scene: Scene)
+
         private _setButtonValue(newState: ExtendedGamepadButton, currentState: ExtendedGamepadButton, buttonIndex: number) {
             if (!currentState) {
                 this._buttons[buttonIndex] = {
@@ -245,6 +246,9 @@ module BABYLON {
     }
 
     export class OculusTouchController extends WebVRController {
+        private _defaultModel: BABYLON.AbstractMesh;
+        private _hlButtonA: BABYLON.HighlightLayer;
+        private _hlButtonB: BABYLON.HighlightLayer;
 
         public onSecondaryTriggerStateChangedObservable = new Observable<ExtendedGamepadButton>();
 
@@ -255,6 +259,28 @@ module BABYLON {
             this.controllerType = PoseEnabledControllerType.OCULUS;
         }
 
+        public initControllerMesh(scene: Scene) {
+            let meshName = this.hand === 'right' ? 'RightTouch.babylon' : 'LeftTouch.babylon';
+            SceneLoader.ImportMesh("", "http://yoda.blob.core.windows.net/models/", meshName, scene, (newMeshes) => {
+                /*
+                Parent Mesh name: oculus_touch_left
+                - body
+                - trigger
+                - thumbstick
+                - grip
+                - button_y 
+                - button_x
+                - button_enter
+                */
+
+                this._defaultModel = newMeshes[1];
+                this._hlButtonA = new BABYLON.HighlightLayer("hlButtonA", scene);
+                this._hlButtonB = new BABYLON.HighlightLayer("hlButtonB", scene);
+                this.attachToMesh(this._defaultModel);
+            });
+        }
+
+
         // helper getters for left and right hand.
         public get onAButtonStateChangedObservable() {
             if (this.hand === 'right') {
@@ -303,15 +329,51 @@ module BABYLON {
                     this.onPadStateChangedObservable.notifyObservers(notifyObject);
                     return;
                 case 1: // index trigger
+                    if (this._defaultModel) {
+                        (<AbstractMesh>(this._defaultModel.getChildren()[3])).rotation.x = -notifyObject.value * 0.20;
+                        (<AbstractMesh>(this._defaultModel.getChildren()[3])).position.y = -notifyObject.value * 0.005;
+                        (<AbstractMesh>(this._defaultModel.getChildren()[3])).position.z = -notifyObject.value * 0.005;
+                    }
                     this.onTriggerStateChangedObservable.notifyObservers(notifyObject);
                     return;
                 case 2:  // secondary trigger
+                    if (this._defaultModel) {
+                        (<AbstractMesh>(this._defaultModel.getChildren()[4])).position.x = notifyObject.value * 0.0035;
+                    }
                     this.onSecondaryTriggerStateChangedObservable.notifyObservers(notifyObject);
                     return;
                 case 3:
+                    if (this._defaultModel) {
+                        if (notifyObject.pressed) {
+                            (<AbstractMesh>(this._defaultModel.getChildren()[1])).position.y = -0.001;
+                        }
+                        else {
+                            (<AbstractMesh>(this._defaultModel.getChildren()[1])).position.y = 0;
+                        }
+                        if (notifyObject.touched) {
+                            this._hlButtonA.addMesh((<Mesh>this._defaultModel.getChildren()[1]), BABYLON.Color3.White());
+                        }
+                        else {
+                            this._hlButtonA.removeMesh((<Mesh>this._defaultModel.getChildren()[1]));
+                        }
+                    }
                     this.onMainButtonStateChangedObservable.notifyObservers(notifyObject);
                     return;
                 case 4:
+                    if (this._defaultModel) {
+                        if (notifyObject.pressed) {
+                            (<AbstractMesh>(this._defaultModel.getChildren()[2])).position.y = -0.001;
+                        }
+                        else {
+                            (<AbstractMesh>(this._defaultModel.getChildren()[2])).position.y = 0;
+                        }
+                        if (notifyObject.touched) {
+                            this._hlButtonB.addMesh((<Mesh>this._defaultModel.getChildren()[2]), BABYLON.Color3.White());
+                        }
+                        else {
+                            this._hlButtonB.removeMesh((<Mesh>this._defaultModel.getChildren()[2]));
+                        }
+                    }
                     this.onSecondaryButtonStateChangedObservable.notifyObservers(notifyObject);
                     return;
                 case 5:
@@ -323,13 +385,34 @@ module BABYLON {
     }
 
     export class ViveController extends WebVRController {
-
+        private _defaultModel: BABYLON.AbstractMesh;
+        private _hlButtonMenu: BABYLON.HighlightLayer;
 
         constructor(vrGamepad) {
             super(vrGamepad);
             this.controllerType = PoseEnabledControllerType.VIVE;
         }
 
+        public initControllerMesh(scene: Scene) {
+            SceneLoader.ImportMesh("", "http://yoda.blob.core.windows.net/models/", "ViveWand.babylon", scene, (newMeshes) => {
+                /*
+                Parent Mesh name: ViveWand
+                - body
+                - r_gripper
+                - l_gripper
+                - menu_button
+                - system_button
+                - trackpad
+                - trigger
+                - LED
+                */
+                this._defaultModel = newMeshes[1];
+                this._hlButtonMenu = new BABYLON.HighlightLayer("hlButtonMenu", scene);
+                this.attachToMesh(this._defaultModel);
+            });
+        }
+
+
         public get onLeftButtonStateChangedObservable() {
             return this.onMainButtonStateChangedObservable;
         }
@@ -356,12 +439,25 @@ module BABYLON {
                     this.onPadStateChangedObservable.notifyObservers(notifyObject);
                     return;
                 case 1: // index trigger
+                    if (this._defaultModel) {
+                        (<AbstractMesh>(this._defaultModel.getChildren()[6])).rotation.x = -notifyObject.value * 0.15;
+                    }
                     this.onTriggerStateChangedObservable.notifyObservers(notifyObject);
                     return;
                 case 2:  // left AND right button
                     this.onMainButtonStateChangedObservable.notifyObservers(notifyObject);
                     return;
                 case 3:
+                    if (this._defaultModel) {
+                        if (notifyObject.pressed) {
+                            (<AbstractMesh>(this._defaultModel.getChildren()[2])).position.y = -0.001;
+                             this._hlButtonMenu.addMesh((<Mesh>this._defaultModel.getChildren()[2]), BABYLON.Color3.White());
+                        }
+                        else {
+                            (<AbstractMesh>(this._defaultModel.getChildren()[2])).position.y = 0;
+                            this._hlButtonMenu.removeMesh((<Mesh>this._defaultModel.getChildren()[2]));
+                        }
+                    }
                     this.onSecondaryButtonStateChangedObservable.notifyObservers(notifyObject);
                     return;
             }

+ 65 - 24
src/Tools/babylon.rectPackingMap.ts

@@ -1,11 +1,11 @@
 module BABYLON {
 
     /**
-  * This class describe a rectangle that were added to the map.
-  * You have access to its coordinates either in pixel or normalized (UV)
-  */
+     * This class describe a rectangle that were added to the map.
+     * You have access to its coordinates either in pixel or normalized (UV)
+     */
     export class PackedRect {
-        constructor(root: PackedRect, parent: PackedRect, pos: Vector2, size: Size) {
+        constructor(root: RectPackingMap, parent: PackedRect, pos: Vector2, size: Size) {
             this._pos         = pos;
             this._size        = size;
             this._root        = root;
@@ -20,7 +20,7 @@
         /**
          * @returns the position of this node into the map
          */
-        public get pos() {
+        public get pos(): Vector2 {
             return this._pos;
         }
 
@@ -32,25 +32,49 @@
         }
 
         /**
+         * Retrieve the inner position (considering the margin) and stores it into the res object
+         * @param res must be a valid Vector2 that will contain the inner position after this call
+         */
+        public getInnerPosToRef(res: Vector2) {
+            let m = this._root._margin;
+            res.x = this._pos.x + m;
+            res.y = this._pos.y + m;
+        }
+
+        /**
+         * Retrieve the inner size (considering the margin) and stores it into the res object
+         * @param res must be a valid Size that will contain the inner size after this call
+         */
+        public getInnerSizeToRef(res: Size) {
+            let m = this._root._margin;
+            res.width = this._contentSize.width - (m*2);
+            res.height = this._contentSize.height - (m*2);
+        }
+
+        /**
          * Compute the UV of the top/left, top/right, bottom/right, bottom/left points of the rectangle this node handles into the map
          * @returns And array of 4 Vector2, containing UV coordinates for the four corners of the Rectangle into the map
          */
         public get UVs(): Vector2[] {
-            return this.getUVsForCustomSize(this._root._size);
+            if (!this._contentSize) {
+                throw new Error("Can't compute UVs for this object because it's nor allocated");
+            }
+            return this.getUVsForCustomSize(this._contentSize);
         }
 
-
         /**
-         * You may have allocated the PackedRect using over-provisioning (you allocated more than you need in order to prevent frequent deallocations/reallocations) and then using only a part of the PackRect.
+         * You may have allocated the PackedRect using over-provisioning (you allocated more than you need in order to prevent frequent deallocations/reallocations) 
+         * and then using only a part of the PackRect.
          * This method will return the UVs for this part by given the custom size of what you really use
          * @param customSize must be less/equal to the allocated size, UV will be compute from this 
          */
         public getUVsForCustomSize(customSize: Size): Vector2[] {
             var mainWidth = this._root._size.width;
             var mainHeight = this._root._size.height;
+            let margin = this._root._margin;
 
-            var topLeft = new Vector2(this._pos.x / mainWidth, this._pos.y / mainHeight);
-            var rightBottom = new Vector2((this._pos.x + customSize.width - 1) / mainWidth, (this._pos.y + customSize.height - 1) / mainHeight);
+            var topLeft = new Vector2((this._pos.x+margin) / mainWidth, (this._pos.y+margin) / mainHeight);
+            var rightBottom = new Vector2((this._pos.x + customSize.width + margin - 1) / mainWidth, (this._pos.y + customSize.height + margin - 1) / mainHeight);
             var uvs = new Array<Vector2>();
             uvs.push(topLeft);
             uvs.push(new Vector2(rightBottom.x, topLeft.y));
@@ -94,6 +118,7 @@
 
         private findNode(size: Size): PackedRect {
             var resNode: PackedRect = null;
+            let margin = this._root._margin * 2;
 
             // If this node is used, recurse to each of his subNodes to find an available one in its branch
             if (this.isUsed) {
@@ -110,7 +135,7 @@
 
             // The node is free, but was previously allocated (_initialSize is set), rely on initialSize to make the test as it's the space we have
             else if (this._initialSize) {
-                if ((size.width <= this._initialSize.width) && (size.height <= this._initialSize.height))
+                if (((size.width+margin) <= this._initialSize.width) && ((size.height+margin) <= this._initialSize.height))
                 {
                     resNode = this;
                 } else {
@@ -119,28 +144,35 @@
             }
 
             // The node is free and empty, rely on its size for the test
-            else if ((size.width <= this._size.width) && (size.height <= this._size.height)) {
+            else if (((size.width+margin) <= this._size.width) && ((size.height+margin) <= this._size.height)) {
                 resNode = this;
             }
             return resNode;
         }
 
+        private static  TpsSize = Size.Zero();
         private splitNode(contentSize: Size): PackedRect {
+            let cs = PackedRect.TpsSize;
+            let margin = this._root._margin*2;
+            cs.copyFrom(contentSize);
+            cs.width += margin;
+            cs.height += margin;
+
             // If there's no contentSize but an initialSize it means this node were previously allocated, but freed, we need to create a _leftNode as subNode and use to allocate the space we need (and this node will have a right/bottom subNode for the space left as this._initialSize may be greater than contentSize)
             if (!this._contentSize && this._initialSize) {
-                this._contentSize = contentSize.clone();
+                this._contentSize = cs.clone();
                 this._leftNode = new PackedRect(this._root, this, new Vector2(this._pos.x, this._pos.y), new Size(this._initialSize.width, this._initialSize.height));
                 return this._leftNode.splitNode(contentSize);
             } else {
-                this._contentSize = contentSize.clone();
-                this._initialSize = contentSize.clone();
+                this._contentSize = cs.clone();
+                this._initialSize = cs.clone();
 
-                if (contentSize.width !== this._size.width) {
-                    this._rightNode = new PackedRect(this._root, this, new Vector2(this._pos.x + contentSize.width, this._pos.y), new Size(this._size.width - contentSize.width, contentSize.height));
+                if (cs.width !== this._size.width) {
+                    this._rightNode = new PackedRect(this._root, this, new Vector2(this._pos.x + cs.width, this._pos.y), new Size(this._size.width - cs.width, cs.height));
                 }
 
-                if (contentSize.height !== this._size.height) {
-                    this._bottomNode = new PackedRect(this._root, this, new Vector2(this._pos.x, this._pos.y + contentSize.height), new Size(this._size.width, this._size.height - contentSize.height));
+                if (cs.height !== this._size.height) {
+                    this._bottomNode = new PackedRect(this._root, this, new Vector2(this._pos.x, this._pos.y + cs.height), new Size(this._size.width, this._size.height - cs.height));
                 }
                 return this;
             }
@@ -170,10 +202,13 @@
             var levelSize = 0;
 
             if (!this.isUsed) {
-                if (this._initialSize) {
-                    levelSize = this._initialSize.surface;
+                let margin = this._root._margin;
+                let is = this._initialSize;
+                if (is) {
+                    levelSize = is.surface - (is.width*margin) - (is.height*margin);
                 } else {
-                    levelSize = this._size.surface;
+                    let size = this._size;
+                    levelSize = size.surface - (size.width*margin) - (size.height*margin);
                 }
             }
 
@@ -188,7 +223,7 @@
             return levelSize + size;
         }
 
-        protected _root: PackedRect;
+        protected _root: RectPackingMap;
         protected _parent: PackedRect;
         private _contentSize: Size;
         private _initialSize: Size;
@@ -204,15 +239,19 @@
      * The purpose of this class is to pack several Rectangles into a big map, while trying to fit everything as optimally as possible.
      * This class is typically used to build lightmaps, sprite map or to pack several little textures into a big one.
      * Note that this class allows allocated Rectangles to be freed: that is the map is dynamically maintained so you can add/remove rectangle based on their life-cycle.
+     * In case you need a margin around the allocated rect, specify the amount in the margin argument during construction.
+     * In such case you will have to rely on innerPositionToRef and innerSizeToRef calls to get the proper size
      */
     export class RectPackingMap extends PackedRect {
         /**
          * Create an instance of the object with a dimension using the given size
          * @param size The dimension of the rectangle that will contain all the sub ones.
+         * @param margin The margin (empty space) created (in pixels) around the allocated Rectangles
          */
-        constructor(size: Size) {
+        constructor(size: Size, margin=0) {
             super(null, null, Vector2.Zero(), size);
 
+            this._margin = margin;
             this._root = this;
         }
 
@@ -236,5 +275,7 @@
 
             return freeSize / (this._size.width * this._size.height);
         }
+
+        public _margin: number;
     }
 }

+ 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.
      */
     export class PerfCounter {
+        public static Enabled = true;
+
         /**
          * 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.
          */
         public addCount(newCount: number, fetchResult: boolean) {
+            if (!PerfCounter.Enabled) {
+                return;
+            }
             this._current += newCount;
             if (fetchResult) {
                 this._fetchResult();
@@ -1263,6 +1268,9 @@
          * Start monitoring this performance counter
          */
         public beginMonitoring() {
+            if (!PerfCounter.Enabled) {
+                return;
+            }
             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
          */
         public endMonitoring(newFrame: boolean = true) {
+            if (!PerfCounter.Enabled) {
+                return;
+            }
+                        
             if (newFrame) {
                 this.fetchNewFrame();
             }

+ 11 - 0
src/babylon.engine.ts

@@ -46,6 +46,9 @@
     var prepareWebGLTexture = (texture: WebGLTexture, gl: WebGLRenderingContext, scene: Scene, width: number, height: number, invertY: boolean, noMipmap: boolean, isCompressed: boolean,
         processFunction: (width: number, height: number) => void, samplingMode: number = Texture.TRILINEAR_SAMPLINGMODE) => {
         var engine = scene.getEngine();
+        if (!engine) {
+            return;
+        }
         var potWidth = Tools.GetExponentOfTwo(width, engine.getCaps().maxTextureSize);
         var potHeight = Tools.GetExponentOfTwo(height, engine.getCaps().maxTextureSize);
 
@@ -422,6 +425,7 @@
         public isPointerLock = false;
         public cullBackFaces = true;
         public renderEvenInBackground = true;
+        public preventCacheWipeBetweenFrames = false;
         // To enable/disable IDB support and avoid XHR on .manifest
         public enableOfflineSupport = true;
         public scenes = new Array<Scene>();
@@ -555,6 +559,10 @@
                 options.audioEngine = true;
             }
 
+            if (options.stencil === undefined) {
+                options.stencil = true;
+            }
+
             // GL
             if (!options.disableWebGL2Support) {
                 try {
@@ -2065,6 +2073,9 @@
 
         // Textures
         public wipeCaches(): void {
+            if (this.preventCacheWipeBetweenFrames) {
+                return;
+            }
             this.resetTextureCache();
             this._currentEffect = null;
 

+ 0 - 0
src/babylon.scene.ts


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