Explorar o código

Merge remote-tracking branch 'BabylonJS/master'

MackeyK24 %!s(int64=8) %!d(string=hai) anos
pai
achega
4a0b781777
Modificáronse 79 ficheiros con 15550 adicións e 12599 borrados
  1. 1 1
      .travis.yml
  2. 1734 579
      Exporters/3ds Max/ActionsBuilder/Sources/babylon.max.js
  3. 3 0
      Exporters/3ds Max/BabylonExport.Entities/BabylonAbstractMesh.cs
  4. 0 3
      Exporters/3ds Max/BabylonExport.Entities/BabylonMesh.cs
  5. BIN=BIN
      Exporters/3ds Max/Max2Babylon-0.6.0.zip
  6. BIN=BIN
      Exporters/3ds Max/Max2Babylon-0.7.0.zip
  7. 1 0
      Exporters/3ds Max/Max2Babylon/Exporter/BabylonExporter.Mesh.cs
  8. 0 0
      Exporters/Unity 5/EditorToolkit/Redist/readme.md
  9. 10 0
      Playground/index.html
  10. 27 0
      Playground/index.js
  11. 140 0
      Playground/index2_5.html
  12. 621 568
      Tools/Gulp/config.json
  13. 101 97
      canvas2D/readme.md
  14. 10 6
      canvas2D/src/Engine/babylon.bounding2d.ts
  15. 104 74
      canvas2D/src/Engine/babylon.canvas2d.ts
  16. 2 0
      canvas2D/src/Engine/babylon.canvas2dLayoutEngine.ts
  17. 7 2
      canvas2D/src/Engine/babylon.ellipse2d.ts
  18. 19 8
      canvas2D/src/Engine/babylon.fontTexture.ts
  19. 7 5
      canvas2D/src/Engine/babylon.group2d.ts
  20. 17 12
      canvas2D/src/Engine/babylon.lines2d.ts
  21. 5 1
      canvas2D/src/Engine/babylon.modelRenderCache.ts
  22. 544 391
      canvas2D/src/Engine/babylon.prim2dBase.ts
  23. 1 1
      canvas2D/src/Engine/babylon.primitiveCollisionManager.ts
  24. 7 2
      canvas2D/src/Engine/babylon.rectangle2d.ts
  25. 56 48
      canvas2D/src/Engine/babylon.renderablePrim2d.ts
  26. 4 4
      canvas2D/src/Engine/babylon.shape2d.ts
  27. 38 2
      canvas2D/src/Engine/babylon.smartPropertyPrim.ts
  28. 3 15
      canvas2D/src/Engine/babylon.sprite2d.ts
  29. 38 14
      canvas2D/src/Engine/babylon.text2d.ts
  30. 0 13
      canvas2D/src/Engine/babylon.wireFrame2d.ts
  31. 249 0
      canvas2D/src/Tools/babylon.c2dlogging.ts
  32. 160 432
      canvas2D/src/Tools/babylon.math2D.ts
  33. 14 1
      canvas2D/src/shaders/ellipse2d.vertex.fx
  34. 14 1
      canvas2D/src/shaders/lines2d.vertex.fx
  35. 14 1
      canvas2D/src/shaders/rect2d.vertex.fx
  36. 17 3
      canvas2D/src/shaders/sprite2d.vertex.fx
  37. 15 1
      canvas2D/src/shaders/text2d.vertex.fx
  38. 13 6
      canvas2D/src/shaders/wireframe2d.vertex.fx
  39. 22 22
      dist/preview release/babylon.core.js
  40. 4121 4036
      dist/preview release/babylon.d.ts
  41. 34 34
      dist/preview release/babylon.js
  42. 768 333
      dist/preview release/babylon.max.js
  43. 4121 4036
      dist/preview release/babylon.module.d.ts
  44. 36 36
      dist/preview release/babylon.noworker.js
  45. 140 252
      dist/preview release/canvas2D/babylon.canvas2d.d.ts
  46. 1274 1001
      dist/preview release/canvas2D/babylon.canvas2d.js
  47. 12 12
      dist/preview release/canvas2D/babylon.canvas2d.min.js
  48. 2 2
      dist/preview release/inspector/babylon.inspector.bundle.js
  49. 1 1
      dist/preview release/what's new.md
  50. 70 36
      src/Bones/babylon.boneLookController.ts
  51. 8 6
      src/Cameras/Inputs/babylon.arcrotatecamera.input.gamepad.ts
  52. 38 22
      src/Cameras/Inputs/babylon.freecamera.input.gamepad.ts
  53. 159 52
      src/Cameras/VR/babylon.webVRCamera.ts
  54. 1 1
      src/Cameras/babylon.arcRotateCamera.ts
  55. 43 26
      src/Cameras/babylon.camera.ts
  56. 0 1
      src/Cameras/babylon.gamepadCamera.ts
  57. 2 2
      src/Cameras/babylon.targetCamera.ts
  58. 0 28
      src/Culling/babylon.ray.ts
  59. 1 1
      src/Layer/babylon.highlightlayer.ts
  60. 7 3
      src/Materials/Textures/babylon.dynamicTexture.ts
  61. 5 3
      src/Materials/Textures/babylon.renderTargetTexture.ts
  62. 21 10
      src/Materials/babylon.effect.ts
  63. 67 61
      src/Math/babylon.math.ts
  64. 0 55
      src/Mesh/babylon.abstractMesh.ts
  65. 5 22
      src/Mesh/babylon.mesh.ts
  66. 35 12
      src/Mesh/babylon.mesh.vertexData.ts
  67. 24 1
      src/Mesh/babylon.meshBuilder.ts
  68. 3 3
      src/Physics/Plugins/babylon.cannonJSPlugin.ts
  69. 2 17
      src/Physics/babylon.physicsEngine.ts
  70. 8 0
      src/PostProcess/babylon.postProcess.ts
  71. 0 17
      src/PostProcess/babylon.ssaoRenderingPipeline.ts
  72. 348 0
      src/Tools/babylon.extendedGamepad.ts
  73. 39 19
      src/Tools/babylon.gamepads.ts
  74. 6 0
      src/Tools/babylon.smartArray.ts
  75. 3 2
      src/Tools/babylon.tools.ts
  76. 89 77
      src/babylon.engine.ts
  77. 16 4
      src/babylon.mixins.ts
  78. 8 10
      src/babylon.node.ts
  79. 15 52
      src/babylon.scene.ts

+ 1 - 1
.travis.yml

@@ -1,6 +1,6 @@
 language: node_js
 language: node_js
 node_js:
 node_js:
-  - "4.1"
+  - "6"
 before_script:
 before_script:
   - npm install -g gulp
   - npm install -g gulp
   - cd ./Tools/Gulp
   - cd ./Tools/Gulp

A diferenza do arquivo foi suprimida porque é demasiado grande
+ 1734 - 579
Exporters/3ds Max/ActionsBuilder/Sources/babylon.max.js


+ 3 - 0
Exporters/3ds Max/BabylonExport.Entities/BabylonAbstractMesh.cs

@@ -6,6 +6,9 @@ namespace BabylonExport.Entities
     public class BabylonAbstractMesh: BabylonIAnimatable
     public class BabylonAbstractMesh: BabylonIAnimatable
     {
     {
         [DataMember]
         [DataMember]
+        public string id { get; set; }
+
+        [DataMember]
         public string name { get; set; }
         public string name { get; set; }
         
         
         [DataMember]
         [DataMember]

+ 0 - 3
Exporters/3ds Max/BabylonExport.Entities/BabylonMesh.cs

@@ -6,9 +6,6 @@ namespace BabylonExport.Entities
     public class BabylonMesh : BabylonAbstractMesh
     public class BabylonMesh : BabylonAbstractMesh
     {
     {
         [DataMember]
         [DataMember]
-        public string id { get; set; }
-
-        [DataMember]
         public string materialId { get; set; }
         public string materialId { get; set; }
 
 
         [DataMember]
         [DataMember]

BIN=BIN
Exporters/3ds Max/Max2Babylon-0.6.0.zip


BIN=BIN
Exporters/3ds Max/Max2Babylon-0.7.0.zip


+ 1 - 0
Exporters/3ds Max/Max2Babylon/Exporter/BabylonExporter.Mesh.cs

@@ -478,6 +478,7 @@ namespace Max2Babylon
                     var instanceRotation = instanceLocalTM.Rotation;
                     var instanceRotation = instanceLocalTM.Rotation;
                     var instanceScale = instanceLocalTM.Scaling;
                     var instanceScale = instanceLocalTM.Scaling;
 
 
+                    instance.id = instanceGameNode.MaxNode.GetGuid().ToString();
                     instance.position = new[] { instanceTrans.X, instanceTrans.Y, instanceTrans.Z };
                     instance.position = new[] { instanceTrans.X, instanceTrans.Y, instanceTrans.Z };
 
 
                     if (exportQuaternions)
                     if (exportQuaternions)

Exporters/Unity 5/EditorToolkit/Redist/readme.me → Exporters/Unity 5/EditorToolkit/Redist/readme.md


+ 10 - 0
Playground/index.html

@@ -76,6 +76,16 @@
                     <li><a href="#" onclick="setFontSize(22);">22</a></li>
                     <li><a href="#" onclick="setFontSize(22);">22</a></li>
                 </ul>
                 </ul>
             </div>
             </div>
+            <div class="btn-group desktopOnly">
+                <a class="btn dropdown-toggle" data-toggle="dropdown" href="#">
+                    <span id="currentVersion">Version: Latest</span>
+                    <span class="caret"></span>
+                </a>
+                <ul class="dropdown-menu" id="versionList">
+                    <li><a href="#" onclick="setVersion('latest');">Latest</a></li>
+                    <li><a href="#" onclick="setVersion('2.5');">2.5</a></li>
+                </ul>
+            </div>            
             <div class="btn-group">
             <div class="btn-group">
                 <label class="btn btn-sm active">
                 <label class="btn btn-sm active">
                     <input type="checkbox" autocomplete="off" id='safemodeToggle' style="margin-top:-0.1em;margin-right:4px">Safe Mode
                     <input type="checkbox" autocomplete="off" id='safemodeToggle' style="margin-top:-0.1em;margin-right:4px">Safe Mode

+ 27 - 0
Playground/index.js

@@ -23,6 +23,21 @@
         var scripts;
         var scripts;
         var zipCode;
         var zipCode;
         BABYLON.Engine.ShadersRepository = "/src/Shaders/";
         BABYLON.Engine.ShadersRepository = "/src/Shaders/";
+
+        var currentVersionElement = document.getElementById("currentVersion");
+
+        if (currentVersionElement) {
+            switch (BABYLON.Engine.Version) {
+                case "2.5":
+                    currentVersionElement.innerHTML = "Version: " + BABYLON.Engine.Version;
+                    break;
+                default:
+                    currentVersionElement.innerHTML = "Version: Latest";
+                    break;
+            }
+        }
+
+
         var loadScript = function (scriptURL, title) {
         var loadScript = function (scriptURL, title) {
             var xhr = new XMLHttpRequest();
             var xhr = new XMLHttpRequest();
 
 
@@ -400,6 +415,18 @@
                 });
                 });
         }
         }
 
 
+        // Versions
+        setVersion = function (version) {
+            switch (version) {
+                case "2.5":
+                    location.href = "index2_5.html" + location.hash;
+                    break;
+                default:
+                    location.href = "index.html" + location.hash;
+                    break;
+            }
+        }
+
         // Fonts
         // Fonts
         setFontSize = function (size) {
         setFontSize = function (size) {
             document.querySelector(".monaco-editor").style.fontSize = size + "px";
             document.querySelector(".monaco-editor").style.fontSize = size + "px";

+ 140 - 0
Playground/index2_5.html

@@ -0,0 +1,140 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <title>Babylon.js Playground</title>
+    <script src="https://code.jquery.com/pep/0.4.2/pep.min.js"></script>
+    <script src="https://babylonjs.azurewebsites.net/poly2tri.js"></script>
+    <script src="https://cdnjs.cloudflare.com/ajax/libs/dat-gui/0.6.2/dat.gui.min.js"></script>
+    <!--x-tag-->
+    <script src="xtag.min.js"></script>
+    <script src="splitbox.js"></script>
+    <link href="splitbox.css" rel="stylesheet" />
+    <!-- jszip -->
+    <script src="jszip.min.js"></script>
+    <script src="fileSaver.js"></script>
+    <!-- Bootstrap -->
+    <link href="bootstrap/css/bootstrap.min.css" rel="stylesheet">
+    <script src="node_modules/monaco-editor/min/vs/loader.js"></script>
+    <!-- Babylon.js -->
+    <script src="https://babylonjs.azurewebsites.net/cannon.js"></script>
+    <script src="https://babylonjs.azurewebsites.net/Oimo.js"></script>
+    <!--<script src="../babylon.js"></script>-->
+    <script src="https://babylonjs.azurewebsites.net/versions/babylon.2.5.js"></script>
+    <script src="https://babylonjs.azurewebsites.net/versions/babylon.2.5.canvas2d.js"></script>
+    <script src="https://babylonjs.azurewebsites.net/babylon.inspector.bundle.js"></script>
+    
+    <script src="https://babylonjs.azurewebsites.net/lib/babylon.fireMaterial.min.js"></script>
+    <script src="https://babylonjs.azurewebsites.net/lib/babylon.waterMaterial.min.js"></script>
+    <script src="https://babylonjs.azurewebsites.net/lib/babylon.lavaMaterial.min.js"></script>
+    <script src="https://babylonjs.azurewebsites.net/lib/babylon.normalMaterial.min.js"></script>
+    <script src="https://babylonjs.azurewebsites.net/lib/babylon.skyMaterial.min.js"></script>
+    <script src="https://babylonjs.azurewebsites.net/lib/babylon.triPlanarMaterial.min.js"></script>
+    <script src="https://babylonjs.azurewebsites.net/lib/babylon.terrainMaterial.min.js"></script>
+    <script src="https://babylonjs.azurewebsites.net/lib/babylon.gradientMaterial.min.js"></script>
+    <script src="https://babylonjs.azurewebsites.net/lib/babylon.furMaterial.min.js"></script>
+    <script src="https://babylonjs.azurewebsites.net/lib/babylon.gridMaterial.min.js"></script>
+
+    <script src="https://babylonjs.azurewebsites.net/lib/babylon.brickProceduralTexture.min.js"></script>
+    <script src="https://babylonjs.azurewebsites.net/lib/babylon.cloudProceduralTexture.min.js"></script>
+    <script src="https://babylonjs.azurewebsites.net/lib/babylon.fireProceduralTexture.min.js"></script>
+    <script src="https://babylonjs.azurewebsites.net/lib/babylon.grassProceduralTexture.min.js"></script>
+    <script src="https://babylonjs.azurewebsites.net/lib/babylon.marbleProceduralTexture.min.js"></script>
+    <script src="https://babylonjs.azurewebsites.net/lib/babylon.roadProceduralTexture.min.js"></script>
+    <script src="https://babylonjs.azurewebsites.net/lib/babylon.starfieldProceduralTexture.min.js"></script>
+    <script src="https://babylonjs.azurewebsites.net/lib/babylon.woodProceduralTexture.min.js"></script>
+
+    <script src="https://babylonjs.azurewebsites.net/lib/babylon.asciiArtPostProcess.min.js"></script>
+    <script src="https://babylonjs.azurewebsites.net/lib/babylon.digitalRainPostProcess.min.js"></script>
+
+    <script src="https://babylonjs.azurewebsites.net/lib/babylon.glTFFileLoader.js"></script>
+    <script src="https://babylonjs.azurewebsites.net/lib/babylon.objFileLoader.js"></script>
+    <script src="https://babylonjs.azurewebsites.net/lib/babylon.stlFileLoader.js"></script>
+    <link href="index.css" rel="stylesheet" />
+</head>
+<body>
+    <div class="navbar navbar-inverse navbar-fixed-top">
+        <div class="navbar-inner" id="topbar">
+            <a class="brand largeOnly" href="#" id="mainTitle">Babylon.js Playground</a>
+            <div class="btn-group">
+                <button class="btn" id="runButton">Run</button>
+                <button class="btn" id="saveButton">Save</button>
+                <button class="btn desktopOnly" id="zipButton">Get .zip</button>
+                <button class="btn desktopOnly" id="newButton">New</button>
+                <button class="btn desktopOnly" id="clearButton">Clear</button>
+            </div>
+            <div class="btn-group desktopOnly">
+                <a class="btn dropdown-toggle" data-toggle="dropdown" href="#">
+                    <span id="currentFontSize">Font: 12</span>
+                    <span class="caret"></span>
+                </a>
+                <ul class="dropdown-menu" id="sizeList">
+                    <li><a href="#" onclick="setFontSize(12);">12</a></li>
+                    <li><a href="#" onclick="setFontSize(14);">14</a></li>
+                    <li><a href="#" onclick="setFontSize(16);">16</a></li>
+                    <li><a href="#" onclick="setFontSize(18);">18</a></li>
+                    <li><a href="#" onclick="setFontSize(20);">20</a></li>
+                    <li><a href="#" onclick="setFontSize(22);">22</a></li>
+                </ul>
+            </div>
+            <div class="btn-group desktopOnly">
+                <a class="btn dropdown-toggle" data-toggle="dropdown" href="#">
+                    <span id="currentVersion">Version: Latest</span>
+                    <span class="caret"></span>
+                </a>
+                <ul class="dropdown-menu" id="versionList">
+                    <li><a href="#" onclick="setVersion('latest');">Latest</a></li>
+                    <li><a href="#" onclick="setVersion('2.5');">2.5</a></li>
+                </ul>
+            </div>            
+            <div class="btn-group">
+                <label class="btn btn-sm active">
+                    <input type="checkbox" autocomplete="off" id='safemodeToggle' style="margin-top:-0.1em;margin-right:4px">Safe Mode
+                </label>
+                <button class="btn btn-sm" id="editorButton">-Editor</button>
+                <button class="btn btn-sm" id="debugButton">+Debug layer</button>
+            </div>
+            <div class="btn-group pull-right">
+                <button class="btn" id="fullscreenButton">Fullscreen</button>
+            </div>
+            <div class="btn-group pull-right">
+                <a class="btn dropdown-toggle" data-toggle="dropdown" href="#">
+                    <span id="currentScript">Predefined scripts</span>
+                    <span class="caret"></span>
+                </a>
+                <ul class="dropdown-menu" id="scriptsList"></ul>
+            </div>
+        </div>
+    </div>
+
+    <x-splitbox>
+        <div id="jsEditor"></div>
+        <div splitter></div>
+        <div id="canvasZone">
+            <canvas touch-action="none" id="renderCanvas"></canvas>
+        </div>
+    </x-splitbox>
+
+    <span class="label" id="fpsLabel">FPS</span>
+
+    <div id="errorZone">
+    </div>
+
+    <div class="navbar navbar-inverse navbar-fixed-bottom">
+        <div class="navbar-inner">
+            <ul class="nav pull-left">
+                <li id="statusBar"></li>
+            </ul>
+            <ul class="nav pull-right">
+                <li><a href="http://www.html5gamedevs.com/forum/16-babylonjs/">Forum</a></li>
+                <li><a href="https://babylonjs.azurewebsites.net/sandbox">Sandbox</a></li>
+                <li><a href="https://github.com/BabylonJS/Babylon.js/wiki">Wiki</a></li>
+                <li><a href="https://doc.babylonjs.com">Documentation</a></li>
+            </ul>
+        </div>
+    </div>
+
+    <script src="https://code.jquery.com/jquery.js"></script>
+    <script src="bootstrap/js/bootstrap.min.js"></script>
+    <script src="index.js"></script>
+</body>
+</html>

A diferenza do arquivo foi suprimida porque é demasiado grande
+ 621 - 568
Tools/Gulp/config.json


+ 101 - 97
canvas2D/readme.md

@@ -1,103 +1,107 @@
-Canvas2D, a 100% WebGL based 2D Engine
-====================
-
-## Table of Content
-
-- [Introduction](#introduction)
-- [Documentation, want to give feedback, report a bug or need help?](#documentation)
+Canvas2D, a 100% WebGL based 2D Engine
+====================
+
+## Table of Content
+
+- [Introduction](#introduction)
+- [Documentation, want to give feedback, report a bug or need help?](#documentation)
 - [Releases](#releases)
 - [Releases](#releases)
 - [Features list](features.md) (separated page)
 - [Features list](features.md) (separated page)
-- [How to build it](#how-to-build-babyloncanvas2djs-with-gulp)
-
-## Introduction
-
-Canvas2D is a separated distributed set of .js/.d.ts files laying on the top of the [babylon.js library](../readme.md).
-
-Its purpose is to provide a general featured 2D Engine that will serve as the foundations for:
-
- - Any 2D Graphics related work
- - A WebGL based GUI Library also present in the library (but under development right now.)
-
- **Canvas2D provides two types of Canvas**
-
-  - [ScreenSpace](http://babylonjs-playground.com/#272WI1#6) Canvas, lying on the top (or [below](http://babylonjs-playground.com/#RXVJD#2)/between) the 3D content. Typically used for 3D Game/App on screen UI
-  - [WorldSpace](http://babylonjs-playground.com/#1BKDEO#22) Canvas, to display the content of a Canvas right in the 3D Scene. You can even make it [track a scene node and using billboard](http://babylonjs-playground.com/#1KYG17#1) mode to make it always face the screen.
-
-## Documentation
-
-#### Overview
-There's a full overview [documentation](http://doc.babylonjs.com/overviews/Canvas2D_Home) that we **greatly encourage you to read at least a bit before you start !**
-
-This overview page has many links to other documentation pages (organized like a wiki) you can learn a lot about the basic usage, the different features, how rendering works and the overall architecture of the 2D Engine.
-
-#### Reference
-The reference documentation is available [here](http://doc.babylonjs.com/classes/), most of the Canvas2D classes are suffixed by `2D` so you can use it in the filter box like this:![2D classes](http://i.imgur.com/hx4Llmi.png)
-
-#### Using the Forum
-
-If you need help, want to give feedback, report a bug or be aware of the latest development: you have to use the **[Babylon.js forum](http://www.html5gamedevs.com/forum/16-babylonjs/)**.
-
- - Questions are to be posted [here](http://www.html5gamedevs.com/forum/28-questions-answers/)
+- [How to build it](#how-to-build-babyloncanvas2djs-with-gulp)
+
+## Introduction
+
+Canvas2D is a separated distributed set of .js/.d.ts files laying on the top of the [babylon.js library](../readme.md).
+
+Its purpose is to provide a general featured 2D Engine that will serve as the foundations for:
+
+ - Any 2D Graphics related work
+ - A WebGL based GUI Library also present in the library (but under development right now.)
+
+ **Canvas2D provides two types of Canvas**
+
+  - [ScreenSpace](http://babylonjs-playground.com/#272WI1#6) Canvas, lying on the top (or [below](http://babylonjs-playground.com/#RXVJD#2)/between) the 3D content. Typically used for 3D Game/App on screen UI
+  - [WorldSpace](http://babylonjs-playground.com/#1BKDEO#22) Canvas, to display the content of a Canvas right in the 3D Scene. You can even make it [track a scene node and using billboard](http://babylonjs-playground.com/#1KYG17#1) mode to make it always face the screen.
+
+## Documentation
+
+#### Overview
+There's a full overview [documentation](http://doc.babylonjs.com/overviews/Canvas2D_Home) that we **greatly encourage you to read at least a bit before you start !**
+
+This overview page has many links to other documentation pages (organized like a wiki) you can learn a lot about the basic usage, the different features, how rendering works and the overall architecture of the 2D Engine.
+
+#### Reference
+The reference documentation is available [here](http://doc.babylonjs.com/classes/), most of the Canvas2D classes are suffixed by `2D` so you can use it in the filter box like this:![2D classes](http://i.imgur.com/hx4Llmi.png)
+
+#### Using the Forum
+
+If you need help, want to give feedback, report a bug or be aware of the latest development: you have to use the **[Babylon.js forum](http://www.html5gamedevs.com/forum/16-babylonjs/)**.
+
+ - Questions are to be posted [here](http://www.html5gamedevs.com/forum/28-questions-answers/)
  - Bugs reports must be made [there](http://www.html5gamedevs.com/forum/30-bugs/)
  - Bugs reports must be made [there](http://www.html5gamedevs.com/forum/30-bugs/)
  - Check [this post](http://www.html5gamedevs.com/topic/22552-canvas2d-main-post/) to be aware of all the improvements/fixes made during the alpha/beta development of the library. You can check the first post as I update it each time there's new stuff or I simply encourage you to follow the thread to get notified. **Please** don't ask question or report bugs in this thread, create a dedicated one, thanks!
  - Check [this post](http://www.html5gamedevs.com/topic/22552-canvas2d-main-post/) to be aware of all the improvements/fixes made during the alpha/beta development of the library. You can check the first post as I update it each time there's new stuff or I simply encourage you to follow the thread to get notified. **Please** don't ask question or report bugs in this thread, create a dedicated one, thanks!
  - [Another post](http://www.html5gamedevs.com/topic/25275-the-gui-lib-of-babylonjs/) was created to track the progress on the GUI Library, same rules and observations as above.
  - [Another post](http://www.html5gamedevs.com/topic/25275-the-gui-lib-of-babylonjs/) was created to track the progress on the GUI Library, same rules and observations as above.
 
 
-**Important** when you post something you better mentioned me using `@nockawa`, I'm **not** checking the forum everyday but some other users does and ping me if needed, but still: mentioning me is the best way to get my attention.
-
-## Releases
-
-You want to use an existing build, that's simple, you can grab either the latest official release or the latest build of the current developing version.
-
-- The latest official release can be found [here](https://github.com/BabylonJS/Babylon.js/tree/master/dist)
-- The latest preview release (which is the current developing version, stable most of the time) can be found [there](https://github.com/BabylonJS/Babylon.js/tree/master/dist/preview%20release/canvas2D)
-
-
-## How to build babylon.canvas2d.js with Gulp
-
-If you want to locally build the canvas2D library, you can follow the steps below. But sure you've read [this page](http://doc.babylonjs.com/generals/how_to_start) before to learn how to setup your local repository and the general build concepts.
-
-### Gulp
-Build Babylon.canvas2d.js with [gulp](http://gulpjs.com/ "gulp") and npm ([nodejs](http://nodejs.org/ "nodejs")), easy and cross-platform
-
-(Paths in this file are relative to this file location.)
-
-### How to use it
-
-From the /Tools/Gulp folder:
-
-#### First install gulp :
-```
-npm install -g gulp
-```
-
-#### Install some dependencies :
-```
-npm install
-```
-
-#### Update dependencies if necessary :
-```
-npm update
-```
-
-### From the javascript source
-#### Build Babylon.canvas2d.js:
-
-```
-gulp canvas2D
-```
-Will be generated in dist/preview release/canvas2D:
-- babylon.canvas2d.min.js
-- babylon.canvas2d.js (unminified)
-- babylon.canvas2d.d.ts
-
-#### Build the changed files for debug when you save a typescript or shader file:
-```
-gulp watch
-```
-
-#### Watch and run a web server for debug purpose:
-```
-gulp run
-```
-
+**Important** when you post something you better mentioned me using `@nockawa`, I'm **not** checking the forum everyday but some other users does and ping me if needed, but still: mentioning me is the best way to get my attention.
+
+#### We now use GitHub Issues and Projects
+
+You can take a look at the current GitHub Project for the [V3 here](https://github.com/BabylonJS/Babylon.js/projects/2)
+
+## Releases
+
+You want to use an existing build, that's simple, you can grab either the latest official release or the latest build of the current developing version.
+
+- The latest official release can be found [here](https://github.com/BabylonJS/Babylon.js/tree/master/dist)
+- The latest preview release (which is the current developing version, stable most of the time) can be found [there](https://github.com/BabylonJS/Babylon.js/tree/master/dist/preview%20release/canvas2D)
+
+
+## How to build babylon.canvas2d.js with Gulp
+
+If you want to locally build the canvas2D library, you can follow the steps below. But sure you've read [this page](http://doc.babylonjs.com/generals/how_to_start) before to learn how to setup your local repository and the general build concepts.
+
+### Gulp
+Build Babylon.canvas2d.js with [gulp](http://gulpjs.com/ "gulp") and npm ([nodejs](http://nodejs.org/ "nodejs")), easy and cross-platform
+
+(Paths in this file are relative to this file location.)
+
+### How to use it
+
+From the /Tools/Gulp folder:
+
+#### First install gulp :
+```
+npm install -g gulp
+```
+
+#### Install some dependencies :
+```
+npm install
+```
+
+#### Update dependencies if necessary :
+```
+npm update
+```
+
+### From the javascript source
+#### Build Babylon.canvas2d.js:
+
+```
+gulp canvas2D
+```
+Will be generated in dist/preview release/canvas2D:
+- babylon.canvas2d.min.js
+- babylon.canvas2d.js (unminified)
+- babylon.canvas2d.d.ts
+
+#### Build the changed files for debug when you save a typescript or shader file:
+```
+gulp watch
+```
+
+#### Watch and run a web server for debug purpose:
+```
+gulp run
+```
+

+ 10 - 6
canvas2D/src/Engine/babylon.bounding2d.ts

@@ -127,6 +127,10 @@
             b._worldAABBDirty = true;
             b._worldAABBDirty = true;
         }
         }
 
 
+        public toString(): string {
+            return `Center: ${this.center}, Extent: ${this.extent}, Radius: ${this.radius}`;
+        }
+
         /**
         /**
          * Duplicate this instance and return a new one
          * Duplicate this instance and return a new one
          * @return the duplicated instance
          * @return the duplicated instance
@@ -232,7 +236,7 @@
          * @param matrix the transformation matrix to apply
          * @param matrix the transformation matrix to apply
          * @return the new instance containing the result of the transformation applied on this BoundingInfo2D
          * @return the new instance containing the result of the transformation applied on this BoundingInfo2D
          */
          */
-        public transform(matrix: Matrix): BoundingInfo2D {
+        public transform(matrix: Matrix2D): BoundingInfo2D {
             var r = new BoundingInfo2D();
             var r = new BoundingInfo2D();
             this.transformToRef(matrix, r);
             this.transformToRef(matrix, r);
             return r;
             return r;
@@ -264,7 +268,7 @@
          * @param matrix The matrix to use to compute the transformation
          * @param matrix The matrix to use to compute the transformation
          * @param result A VALID (i.e. allocated) BoundingInfo2D object where the result will be stored
          * @param result A VALID (i.e. allocated) BoundingInfo2D object where the result will be stored
          */
          */
-        public transformToRef(matrix: Matrix, result: BoundingInfo2D) {
+        public transformToRef(matrix: Matrix2D, result: BoundingInfo2D) {
             // Construct a bounding box based on the extent values
             // Construct a bounding box based on the extent values
             let p = BoundingInfo2D._transform;
             let p = BoundingInfo2D._transform;
             p[0].x = this.center.x + this.extent.x;
             p[0].x = this.center.x + this.extent.x;
@@ -278,12 +282,12 @@
 
 
             // Transform the four points of the bounding box with the matrix
             // Transform the four points of the bounding box with the matrix
             for (let i = 0; i < 4; i++) {
             for (let i = 0; i < 4; i++) {
-                Vector2.TransformToRef(p[i], matrix, p[i]);
+                matrix.transformPointToRef(p[i], p[i]);
             }
             }
             BoundingInfo2D.CreateFromPointsToRef(p, result);
             BoundingInfo2D.CreateFromPointsToRef(p, result);
         }
         }
 
 
-        private _updateWorldAABB(worldMatrix: Matrix) {
+        private _updateWorldAABB(worldMatrix: Matrix2D) {
             // Construct a bounding box based on the extent values
             // Construct a bounding box based on the extent values
             let p = BoundingInfo2D._transform;
             let p = BoundingInfo2D._transform;
             p[0].x = this.center.x + this.extent.x;
             p[0].x = this.center.x + this.extent.x;
@@ -297,7 +301,7 @@
 
 
             // Transform the four points of the bounding box with the matrix
             // Transform the four points of the bounding box with the matrix
             for (let i = 0; i < 4; i++) {
             for (let i = 0; i < 4; i++) {
-                Vector2.TransformToRef(p[i], worldMatrix, p[i]);
+                worldMatrix.transformPointToRef(p[i], p[i]);
             }
             }
 
 
             this._worldAABB.x = Math.min(Math.min(p[0].x, p[1].x), Math.min(p[2].x, p[3].x));
             this._worldAABB.x = Math.min(Math.min(p[0].x, p[1].x), Math.min(p[2].x, p[3].x));
@@ -306,7 +310,7 @@
             this._worldAABB.w = Math.max(Math.max(p[0].y, p[1].y), Math.max(p[2].y, p[3].y));
             this._worldAABB.w = Math.max(Math.max(p[0].y, p[1].y), Math.max(p[2].y, p[3].y));
         }
         }
 
 
-        public worldMatrixAccess: () => Matrix;
+        public worldMatrixAccess: () => Matrix2D;
 
 
         public get worldAABBDirtyObservable(): Observable<BoundingInfo2D> {
         public get worldAABBDirtyObservable(): Observable<BoundingInfo2D> {
             if (!this._worldAABBDirtyObservable) {
             if (!this._worldAABBDirtyObservable) {

+ 104 - 74
canvas2D/src/Engine/babylon.canvas2d.ts

@@ -87,20 +87,6 @@
         }) {
         }) {
             super(settings);
             super(settings);
 
 
-            this._drawCallsOpaqueCounter          = new PerfCounter();
-            this._drawCallsAlphaTestCounter       = new PerfCounter();
-            this._drawCallsTransparentCounter     = new PerfCounter();
-            this._groupRenderCounter              = new PerfCounter();
-            this._updateTransparentDataCounter    = new PerfCounter();
-            this._cachedGroupRenderCounter        = new PerfCounter();
-            this._updateCachedStateCounter        = new PerfCounter();
-            this._updateLayoutCounter             = new PerfCounter();
-            this._updatePositioningCounter        = new PerfCounter();
-            this._updateLocalTransformCounter     = new PerfCounter();
-            this._updateGlobalTransformCounter    = new PerfCounter();
-            this._boundingInfoRecomputeCounter    = new PerfCounter();
-            this._layoutBoundingInfoUpdateCounter = new PerfCounter();
-
             this._cachedCanvasGroup = null;
             this._cachedCanvasGroup = null;
 
 
             this._renderingGroupObserver = null;
             this._renderingGroupObserver = null;
@@ -200,18 +186,24 @@
                     this._renderingGroupObserver = this._scene.onRenderingGroupObservable.add((e, s) => {
                     this._renderingGroupObserver = this._scene.onRenderingGroupObservable.add((e, s) => {
                         if ((this._scene.activeCamera === settings.renderingPhase.camera) && (e.renderStage===RenderingGroupInfo.STAGE_POSTTRANSPARENT)) {
                         if ((this._scene.activeCamera === settings.renderingPhase.camera) && (e.renderStage===RenderingGroupInfo.STAGE_POSTTRANSPARENT)) {
                             this._engine.clear(null, false, true, true);
                             this._engine.clear(null, false, true, true);
+                            C2DLogging._startFrameRender();
                             this._render();
                             this._render();
+                            C2DLogging._endFrameRender();
                         }
                         }
                     }, Math.pow(2, settings.renderingPhase.renderingGroupID));
                     }, Math.pow(2, settings.renderingPhase.renderingGroupID));
                 } else {
                 } else {
                     this._afterRenderObserver = this._scene.onAfterRenderObservable.add((d, s) => {
                     this._afterRenderObserver = this._scene.onAfterRenderObservable.add((d, s) => {
                         this._engine.clear(null, false, true, true);
                         this._engine.clear(null, false, true, true);
+                        C2DLogging._startFrameRender();
                         this._render();
                         this._render();
+                        C2DLogging._endFrameRender();
                     });
                     });
                 }
                 }
             } else {
             } else {
                 this._beforeRenderObserver = this._scene.onBeforeRenderObservable.add((d, s) => {
                 this._beforeRenderObserver = this._scene.onBeforeRenderObservable.add((d, s) => {
+                    C2DLogging._startFrameRender();
                     this._render();
                     this._render();
+                    C2DLogging._endFrameRender();
                 });
                 });
             }
             }
 
 
@@ -232,57 +224,96 @@
         }
         }
 
 
         public get drawCallsOpaqueCounter(): PerfCounter {
         public get drawCallsOpaqueCounter(): PerfCounter {
+            if (!this._drawCallsOpaqueCounter) {
+                this._drawCallsOpaqueCounter = new PerfCounter();
+            }
             return this._drawCallsOpaqueCounter;
             return this._drawCallsOpaqueCounter;
         }
         }
 
 
         public get drawCallsAlphaTestCounter(): PerfCounter {
         public get drawCallsAlphaTestCounter(): PerfCounter {
+            if (!this._drawCallsAlphaTestCounter) {
+                this._drawCallsAlphaTestCounter = new PerfCounter();
+            }
             return this._drawCallsAlphaTestCounter;
             return this._drawCallsAlphaTestCounter;
         }
         }
 
 
         public get drawCallsTransparentCounter(): PerfCounter {
         public get drawCallsTransparentCounter(): PerfCounter {
+            if (!this._drawCallsTransparentCounter) {
+                this._drawCallsTransparentCounter = new PerfCounter();
+            }
             return this._drawCallsTransparentCounter;
             return this._drawCallsTransparentCounter;
         }
         }
 
 
         public get groupRenderCounter(): PerfCounter {
         public get groupRenderCounter(): PerfCounter {
+            if (!this._groupRenderCounter) {
+                this._groupRenderCounter = new PerfCounter();
+            }
             return this._groupRenderCounter;
             return this._groupRenderCounter;
         }
         }
 
 
         public get updateTransparentDataCounter(): PerfCounter {
         public get updateTransparentDataCounter(): PerfCounter {
+            if (!this._updateTransparentDataCounter) {
+                this._updateTransparentDataCounter = new PerfCounter();
+            }
             return this._updateTransparentDataCounter;
             return this._updateTransparentDataCounter;
         }
         }
 
 
-        public get cachedGroupRenderCounter(): PerfCounter {
-            return this._cachedGroupRenderCounter;
-        }
-
         public get updateCachedStateCounter(): PerfCounter {
         public get updateCachedStateCounter(): PerfCounter {
+            if (!this._updateCachedStateCounter) {
+                this._updateCachedStateCounter = new PerfCounter();
+            }
             return this._updateCachedStateCounter;
             return this._updateCachedStateCounter;
         }
         }
 
 
         public get updateLayoutCounter(): PerfCounter {
         public get updateLayoutCounter(): PerfCounter {
+            if (!this._updateLayoutCounter) {
+                this._updateLayoutCounter = new PerfCounter();
+            }
             return this._updateLayoutCounter;
             return this._updateLayoutCounter;
         }
         }
 
 
         public get updatePositioningCounter(): PerfCounter {
         public get updatePositioningCounter(): PerfCounter {
+            if (!this._updatePositioningCounter) {
+                this._updatePositioningCounter = new PerfCounter();
+            }
             return this._updatePositioningCounter;
             return this._updatePositioningCounter;
         }
         }
 
 
         public get updateLocalTransformCounter(): PerfCounter {
         public get updateLocalTransformCounter(): PerfCounter {
+            if (!this._updateLocalTransformCounter) {
+                this._updateLocalTransformCounter = new PerfCounter();
+            }
             return this._updateLocalTransformCounter;
             return this._updateLocalTransformCounter;
         }
         }
 
 
         public get updateGlobalTransformCounter(): PerfCounter {
         public get updateGlobalTransformCounter(): PerfCounter {
+            if (!this._updateGlobalTransformCounter) {
+                this._updateGlobalTransformCounter = new PerfCounter();
+            }
             return this._updateGlobalTransformCounter;
             return this._updateGlobalTransformCounter;
         }
         }
 
 
         public get boundingInfoRecomputeCounter(): PerfCounter {
         public get boundingInfoRecomputeCounter(): PerfCounter {
+            if (!this._boundingInfoRecomputeCounter) {
+                this._boundingInfoRecomputeCounter = new PerfCounter();
+            }
             return this._boundingInfoRecomputeCounter;
             return this._boundingInfoRecomputeCounter;
         }
         }
 
 
         public get layoutBoundingInfoUpdateCounter(): PerfCounter {
         public get layoutBoundingInfoUpdateCounter(): PerfCounter {
+            if (!this._layoutBoundingInfoUpdateCounter) {
+                this._layoutBoundingInfoUpdateCounter = new PerfCounter();
+            }
             return this._layoutBoundingInfoUpdateCounter;
             return this._layoutBoundingInfoUpdateCounter;
         }
         }
 
 
+        public get canvasRenderTimeCounter(): PerfCounter {
+            if (!this._canvasRenderTimeCounter) {
+                this._canvasRenderTimeCounter = new PerfCounter();
+            }
+            return this._canvasRenderTimeCounter;
+        }
+
         public static get instances() : Array<Canvas2D> {
         public static get instances() : Array<Canvas2D> {
             return Canvas2D._INSTANCES;
             return Canvas2D._INSTANCES;
         }
         }
@@ -295,6 +326,7 @@
             let cachingStrategy = (settings.cachingStrategy == null) ? Canvas2D.CACHESTRATEGY_DONTCACHE : settings.cachingStrategy;
             let cachingStrategy = (settings.cachingStrategy == null) ? Canvas2D.CACHESTRATEGY_DONTCACHE : settings.cachingStrategy;
             this._cachingStrategy = cachingStrategy;
             this._cachingStrategy = cachingStrategy;
             this._isScreenSpace = (settings.isScreenSpace == null) ? true : settings.isScreenSpace;
             this._isScreenSpace = (settings.isScreenSpace == null) ? true : settings.isScreenSpace;
+            this._hierarchyDepth = 0;
         }
         }
 
 
         public static _zMinDelta: number = 1 / (Math.pow(2, 24) - 1);
         public static _zMinDelta: number = 1 / (Math.pow(2, 24) - 1);
@@ -502,7 +534,7 @@
             // Update the relatedTarget info with the over primitive or the captured one (if any)
             // Update the relatedTarget info with the over primitive or the captured one (if any)
             let targetPrim = capturedPrim || this._actualOverPrimitive.prim;
             let targetPrim = capturedPrim || this._actualOverPrimitive.prim;
 
 
-            let targetPointerPos = capturedPrim ? this._primPointerInfo.canvasPointerPos.subtract(new Vector2(targetPrim.globalTransform.m[12], targetPrim.globalTransform.m[13])) : this._actualOverPrimitive.intersectionLocation;
+            let targetPointerPos = capturedPrim ? this._primPointerInfo.canvasPointerPos.subtract(new Vector2(targetPrim.globalTransform.m[4], targetPrim.globalTransform.m[5])) : this._actualOverPrimitive.intersectionLocation;
 
 
             this._primPointerInfo.updateRelatedTarget(targetPrim, targetPointerPos);
             this._primPointerInfo.updateRelatedTarget(targetPrim, targetPointerPos);
 
 
@@ -1129,35 +1161,35 @@
         }
         }
 
 
         private _initPerfMetrics() {
         private _initPerfMetrics() {
-            this._drawCallsOpaqueCounter.fetchNewFrame();
-            this._drawCallsAlphaTestCounter.fetchNewFrame();
-            this._drawCallsTransparentCounter.fetchNewFrame();
-            this._groupRenderCounter.fetchNewFrame();
-            this._updateTransparentDataCounter.fetchNewFrame();
-            this._cachedGroupRenderCounter.fetchNewFrame();
-            this._updateCachedStateCounter.fetchNewFrame();
-            this._updateLayoutCounter.fetchNewFrame();
-            this._updatePositioningCounter.fetchNewFrame();
-            this._updateLocalTransformCounter.fetchNewFrame();
-            this._updateGlobalTransformCounter.fetchNewFrame();
-            this._boundingInfoRecomputeCounter.fetchNewFrame();
-            this._layoutBoundingInfoUpdateCounter.fetchNewFrame();
+            this.drawCallsOpaqueCounter.fetchNewFrame();
+            this.drawCallsAlphaTestCounter.fetchNewFrame();
+            this.drawCallsTransparentCounter.fetchNewFrame();
+            this.groupRenderCounter.fetchNewFrame();
+            this.updateTransparentDataCounter.fetchNewFrame();
+            this.updateCachedStateCounter.fetchNewFrame();
+            this.updateLayoutCounter.fetchNewFrame();
+            this.updatePositioningCounter.fetchNewFrame();
+            this.updateLocalTransformCounter.fetchNewFrame();
+            this.updateGlobalTransformCounter.fetchNewFrame();
+            this.boundingInfoRecomputeCounter.fetchNewFrame();
+            this.layoutBoundingInfoUpdateCounter.fetchNewFrame();
+            this.canvasRenderTimeCounter.beginMonitoring();
         }
         }
 
 
         private _fetchPerfMetrics() {
         private _fetchPerfMetrics() {
-            this._drawCallsOpaqueCounter.addCount(0, true);
-            this._drawCallsAlphaTestCounter.addCount(0, true);
-            this._drawCallsTransparentCounter.addCount(0, true);
-            this._groupRenderCounter.addCount(0, true);
-            this._updateTransparentDataCounter.addCount(0, true);
-            this._cachedGroupRenderCounter.addCount(0, true);
-            this._updateCachedStateCounter.addCount(0, true);
-            this._updateLayoutCounter.addCount(0, true);
-            this._updatePositioningCounter.addCount(0, true);
-            this._updateLocalTransformCounter.addCount(0, true);
-            this._updateGlobalTransformCounter.addCount(0, true);
-            this._boundingInfoRecomputeCounter.addCount(0, true);
-            this._layoutBoundingInfoUpdateCounter.addCount(0, true);
+            this.drawCallsOpaqueCounter.addCount(0, true);
+            this.drawCallsAlphaTestCounter.addCount(0, true);
+            this.drawCallsTransparentCounter.addCount(0, true);
+            this.groupRenderCounter.addCount(0, true);
+            this.updateTransparentDataCounter.addCount(0, true);
+            this.updateCachedStateCounter.addCount(0, true);
+            this.updateLayoutCounter.addCount(0, true);
+            this.updatePositioningCounter.addCount(0, true);
+            this.updateLocalTransformCounter.addCount(0, true);
+            this.updateGlobalTransformCounter.addCount(0, true);
+            this.boundingInfoRecomputeCounter.addCount(0, true);
+            this.layoutBoundingInfoUpdateCounter.addCount(0, true);
+            this.canvasRenderTimeCounter.endMonitoring(true);
         }
         }
 
 
         private _updateProfileCanvas() {
         private _updateProfileCanvas() {
@@ -1167,13 +1199,13 @@
 
 
             let format = (v: number) => (Math.round(v*100)/100).toString();
             let format = (v: number) => (Math.round(v*100)/100).toString();
 
 
-            let p = `Draw Calls:\n` +
+            let p = `Render Time: avg:${format(this.canvasRenderTimeCounter.lastSecAverage)}ms ${format(this.canvasRenderTimeCounter.current)}ms\n` +
+                    `Draw Calls:\n` +
                     ` - Opaque:      ${format(this.drawCallsOpaqueCounter.current)}, (avg:${format(this.drawCallsOpaqueCounter.lastSecAverage)}, t:${format(this.drawCallsOpaqueCounter.total)})\n` +
                     ` - Opaque:      ${format(this.drawCallsOpaqueCounter.current)}, (avg:${format(this.drawCallsOpaqueCounter.lastSecAverage)}, t:${format(this.drawCallsOpaqueCounter.total)})\n` +
                     ` - AlphaTest:   ${format(this.drawCallsAlphaTestCounter.current)}, (avg:${format(this.drawCallsAlphaTestCounter.lastSecAverage)}, t:${format(this.drawCallsAlphaTestCounter.total)})\n` +
                     ` - AlphaTest:   ${format(this.drawCallsAlphaTestCounter.current)}, (avg:${format(this.drawCallsAlphaTestCounter.lastSecAverage)}, t:${format(this.drawCallsAlphaTestCounter.total)})\n` +
                     ` - Transparent: ${format(this.drawCallsTransparentCounter.current)}, (avg:${format(this.drawCallsTransparentCounter.lastSecAverage)}, t:${format(this.drawCallsTransparentCounter.total)})\n` +
                     ` - Transparent: ${format(this.drawCallsTransparentCounter.current)}, (avg:${format(this.drawCallsTransparentCounter.lastSecAverage)}, t:${format(this.drawCallsTransparentCounter.total)})\n` +
                     `Group Render: ${this.groupRenderCounter.current}, (avg:${format(this.groupRenderCounter.lastSecAverage)}, t:${format(this.groupRenderCounter.total)})\n` + 
                     `Group Render: ${this.groupRenderCounter.current}, (avg:${format(this.groupRenderCounter.lastSecAverage)}, t:${format(this.groupRenderCounter.total)})\n` + 
                     `Update Transparent Data: ${this.updateTransparentDataCounter.current}, (avg:${format(this.updateTransparentDataCounter.lastSecAverage)}, t:${format(this.updateTransparentDataCounter.total)})\n` + 
                     `Update Transparent Data: ${this.updateTransparentDataCounter.current}, (avg:${format(this.updateTransparentDataCounter.lastSecAverage)}, t:${format(this.updateTransparentDataCounter.total)})\n` + 
-                    `Cached Group Render: ${this.cachedGroupRenderCounter.current}, (avg:${format(this.cachedGroupRenderCounter.lastSecAverage)}, t:${format(this.cachedGroupRenderCounter.total)})\n` + 
                     `Update Cached States: ${this.updateCachedStateCounter.current}, (avg:${format(this.updateCachedStateCounter.lastSecAverage)}, t:${format(this.updateCachedStateCounter.total)})\n` + 
                     `Update Cached States: ${this.updateCachedStateCounter.current}, (avg:${format(this.updateCachedStateCounter.lastSecAverage)}, t:${format(this.updateCachedStateCounter.total)})\n` + 
                     ` - Update Layout: ${this.updateLayoutCounter.current}, (avg:${format(this.updateLayoutCounter.lastSecAverage)}, t:${format(this.updateLayoutCounter.total)})\n` + 
                     ` - Update Layout: ${this.updateLayoutCounter.current}, (avg:${format(this.updateLayoutCounter.lastSecAverage)}, t:${format(this.updateLayoutCounter.total)})\n` + 
                     ` - Update Positioning: ${this.updatePositioningCounter.current}, (avg:${format(this.updatePositioningCounter.lastSecAverage)}, t:${format(this.updatePositioningCounter.total)})\n` + 
                     ` - Update Positioning: ${this.updatePositioningCounter.current}, (avg:${format(this.updatePositioningCounter.lastSecAverage)}, t:${format(this.updatePositioningCounter.total)})\n` + 
@@ -1210,12 +1242,6 @@
             }
             }
         }
         }
 
 
-        public addCachedGroupRenderCounter(count: number) {
-            if (this._cachedGroupRenderCounter) {
-                this._cachedGroupRenderCounter.addCount(count, false);
-            }
-        }
-
         public addUpdateCachedStateCounter(count: number) {
         public addUpdateCachedStateCounter(count: number) {
             if (this._updateCachedStateCounter) {
             if (this._updateCachedStateCounter) {
                 this._updateCachedStateCounter.addCount(count, false);
                 this._updateCachedStateCounter.addCount(count, false);
@@ -1303,7 +1329,6 @@
         private _drawCallsTransparentCounter     : PerfCounter;
         private _drawCallsTransparentCounter     : PerfCounter;
         private _groupRenderCounter              : PerfCounter;
         private _groupRenderCounter              : PerfCounter;
         private _updateTransparentDataCounter    : PerfCounter;
         private _updateTransparentDataCounter    : PerfCounter;
-        private _cachedGroupRenderCounter        : PerfCounter;
         private _updateCachedStateCounter        : PerfCounter;
         private _updateCachedStateCounter        : PerfCounter;
         private _updateLayoutCounter             : PerfCounter;
         private _updateLayoutCounter             : PerfCounter;
         private _updatePositioningCounter        : PerfCounter;
         private _updatePositioningCounter        : PerfCounter;
@@ -1311,6 +1336,7 @@
         private _updateLocalTransformCounter     : PerfCounter;
         private _updateLocalTransformCounter     : PerfCounter;
         private _boundingInfoRecomputeCounter    : PerfCounter;
         private _boundingInfoRecomputeCounter    : PerfCounter;
         private _layoutBoundingInfoUpdateCounter : PerfCounter;
         private _layoutBoundingInfoUpdateCounter : PerfCounter;
+        private _canvasRenderTimeCounter         : PerfCounter;
 
 
         private _profilingCanvas: Canvas2D;
         private _profilingCanvas: Canvas2D;
         private _profileInfoText: Text2D;
         private _profileInfoText: Text2D;
@@ -1455,6 +1481,7 @@
                 this._setRenderingScale(scale);
                 this._setRenderingScale(scale);
             }
             }
         }
         }
+        private static _pCLS = Vector3.Zero();
 
 
         private _updateCanvasState(forceRecompute: boolean) {
         private _updateCanvasState(forceRecompute: boolean) {
             // Check if the update has already been made for this render Frame
             // Check if the update has already been made for this render Frame
@@ -1464,14 +1491,7 @@
 
 
             // Detect a change of HWRendering scale
             // Detect a change of HWRendering scale
             let hwsl = this.engine.getHardwareScalingLevel();
             let hwsl = this.engine.getHardwareScalingLevel();
-            let hwslChanged = this._curHWScale !== hwsl;
-            if (hwslChanged) {
-                this._curHWScale = hwsl;
-                for (let child of this.children) {
-                    child._setFlags(SmartPropertyPrim.flagLocalTransformDirty|SmartPropertyPrim.flagGlobalTransformDirty);
-                }
-                this._setLayoutDirty();
-            }
+            this._curHWScale = hwsl;
 
 
             // Detect a change of rendering size
             // Detect a change of rendering size
             let renderingSizeChanged = false;
             let renderingSizeChanged = false;
@@ -1487,16 +1507,8 @@
             }
             }
             this._renderingSize.height = newHeight;
             this._renderingSize.height = newHeight;
 
 
-            // If the canvas fit the rendering size and it changed, update
-            if (renderingSizeChanged && this._fitRenderingDevice) {
-                this.size = this._renderingSize.clone();
-                if (this._background) {
-                    this._background.size = this.size;
-                }
-
-                // Dirty the Layout at the Canvas level to recompute as the size changed
-                this._setLayoutDirty();
-            }
+            let prevCLS = Canvas2D._pCLS;
+            prevCLS.copyFrom(this._canvasLevelScale);
 
 
             // If there's a design size, update the scale according to the renderingSize
             // If there's a design size, update the scale according to the renderingSize
             if (this._designSize) {
             if (this._designSize) {
@@ -1508,11 +1520,29 @@
                 }
                 }
                 this.size = this._designSize.clone();
                 this.size = this._designSize.clone();
                 this._canvasLevelScale.copyFromFloats(scale, scale, 1);
                 this._canvasLevelScale.copyFromFloats(scale, scale, 1);
-            } else if (this._curHWScale !== 1) {
+            } else {
                 let ratio = 1 / this._curHWScale;
                 let ratio = 1 / this._curHWScale;
                 this._canvasLevelScale.copyFromFloats(ratio, ratio, 1);
                 this._canvasLevelScale.copyFromFloats(ratio, ratio, 1);
             }
             }
 
 
+            if (!prevCLS.equals(this._canvasLevelScale)) {
+                for (let child of this.children) {
+                    child._setFlags(SmartPropertyPrim.flagLocalTransformDirty|SmartPropertyPrim.flagGlobalTransformDirty);
+                }
+                this._setLayoutDirty();
+            }
+
+            // If the canvas fit the rendering size and it changed, update
+            if (renderingSizeChanged && this._fitRenderingDevice) {
+                this.size = this._renderingSize.clone();
+                if (this._background) {
+                    this._background.size = this.size;
+                }
+
+                // Dirty the Layout at the Canvas level to recompute as the size changed
+                this._setLayoutDirty();
+            }
+
             var context = new PrepareRender2DContext();
             var context = new PrepareRender2DContext();
 
 
             ++this._globalTransformProcessStep;
             ++this._globalTransformProcessStep;
@@ -1527,8 +1557,8 @@
         /**
         /**
          * Method that renders the Canvas, you should not invoke
          * Method that renders the Canvas, you should not invoke
          */
          */
+        @logMethod("==========CANVAS RENDER===============")
         private _render() {
         private _render() {
-
             this._initPerfMetrics();
             this._initPerfMetrics();
 
 
             if (this._renderObservable && this._renderObservable.hasObservers()) {
             if (this._renderObservable && this._renderObservable.hasObservers()) {

+ 2 - 0
canvas2D/src/Engine/babylon.canvas2dLayoutEngine.ts

@@ -61,6 +61,7 @@
         // A very simple (no) layout computing...
         // A very simple (no) layout computing...
         // The Canvas and its direct children gets the Canvas' size as Layout Area
         // The Canvas and its direct children gets the Canvas' size as Layout Area
         // Indirect children have their Layout Area to the actualSize (margin area) of their parent
         // Indirect children have their Layout Area to the actualSize (margin area) of their parent
+        @logMethod()
         public updateLayout(prim: Prim2DBase) {
         public updateLayout(prim: Prim2DBase) {
 
 
             // If this prim is layoutDiry we update  its layoutArea and also the one of its direct children
             // If this prim is layoutDiry we update  its layoutArea and also the one of its direct children
@@ -73,6 +74,7 @@
 
 
         }
         }
 
 
+        @logMethod()
         private _doUpdate(prim: Prim2DBase) {
         private _doUpdate(prim: Prim2DBase) {
             // Canvas ?
             // Canvas ?
             if (prim instanceof Canvas2D) {
             if (prim instanceof Canvas2D) {

+ 7 - 2
canvas2D/src/Engine/babylon.ellipse2d.ts

@@ -203,6 +203,7 @@
          * - rotation: the initial rotation (in radian) of the primitive. default is 0
          * - rotation: the initial rotation (in radian) of the primitive. default is 0
          * - scale: the initial scale of the primitive. default is 1. You can alternatively use scaleX &| scaleY to apply non uniform scale
          * - scale: the initial scale of the primitive. default is 1. You can alternatively use scaleX &| scaleY to apply non uniform scale
          * - dontInheritParentScale: if set the parent's scale won't be taken into consideration to compute the actualScale property
          * - dontInheritParentScale: if set the parent's scale won't be taken into consideration to compute the actualScale property
+         * - alignToPixel: if true the primitive will be aligned to the target rendering device's pixel
          * - opacity: set the overall opacity of the primitive, 1 to be opaque (default), less than 1 to be transparent.
          * - opacity: set the overall opacity of the primitive, 1 to be opaque (default), less than 1 to be transparent.
          * - zOrder: override the zOrder with the specified value
          * - zOrder: override the zOrder with the specified value
          * - origin: define the normalized origin point location, default [0.5;0.5]
          * - origin: define the normalized origin point location, default [0.5;0.5]
@@ -245,6 +246,7 @@
             scaleX                ?: number,
             scaleX                ?: number,
             scaleY                ?: number,
             scaleY                ?: number,
             dontInheritParentScale?: boolean,
             dontInheritParentScale?: boolean,
+            alignToPixel          ?: boolean,
             opacity               ?: number,
             opacity               ?: number,
             zOrder                ?: number, 
             zOrder                ?: number, 
             origin                ?: Vector2,
             origin                ?: Vector2,
@@ -419,20 +421,23 @@
             return res;
             return res;
         }
         }
 
 
+        private static _riv0 = new Vector2(0,0);
         protected refreshInstanceDataPart(part: InstanceDataBase): boolean {
         protected refreshInstanceDataPart(part: InstanceDataBase): boolean {
             if (!super.refreshInstanceDataPart(part)) {
             if (!super.refreshInstanceDataPart(part)) {
                 return false;
                 return false;
             }
             }
+
+            let s = Ellipse2D._riv0;
+            this.getActualGlobalScaleToRef(s);
+
             if (part.id === Shape2D.SHAPE2D_BORDERPARTID) {
             if (part.id === Shape2D.SHAPE2D_BORDERPARTID) {
                 let d = <Ellipse2DInstanceData>part;
                 let d = <Ellipse2DInstanceData>part;
                 let size = this.actualSize;
                 let size = this.actualSize;
-                let s = this.actualScale;
                 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) {
             else if (part.id === Shape2D.SHAPE2D_FILLPARTID) {
                 let d = <Ellipse2DInstanceData>part;
                 let d = <Ellipse2DInstanceData>part;
                 let size = this.actualSize;
                 let size = this.actualSize;
-                let s = this.actualScale;
                 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;
             return true;

+ 19 - 8
canvas2D/src/Engine/babylon.fontTexture.ts

@@ -26,12 +26,13 @@
      */
      */
     export abstract class BaseFontTexture extends Texture {
     export abstract class BaseFontTexture extends Texture {
 
 
-        constructor(url: string, scene: Scene, noMipmap: boolean = false, invertY: boolean = true, samplingMode: number = Texture.TRILINEAR_SAMPLINGMODE) {
+        constructor(url: string, scene: Scene, noMipmap: boolean = false, invertY: boolean = true, samplingMode: number = Texture.TRILINEAR_SAMPLINGMODE, premultipliedAlpha: boolean = false) {
 
 
             super(url, scene, noMipmap, invertY, samplingMode);
             super(url, scene, noMipmap, invertY, samplingMode);
 
 
             this._cachedFontId = null;
             this._cachedFontId = null;
             this._charInfos = new StringDictionary<CharInfo>();
             this._charInfos = new StringDictionary<CharInfo>();
+            this._isPremultipliedAlpha = premultipliedAlpha;
         }
         }
 
 
         /**
         /**
@@ -50,6 +51,13 @@
         }
         }
 
 
         /**
         /**
+         * True if the font was drawn using multiplied alpha
+         */
+        public get isPremultipliedAlpha(): boolean {
+            return this._isPremultipliedAlpha;
+        }
+
+        /**
          * Get the Width (in pixel) of the Space character
          * Get the Width (in pixel) of the Space character
          */
          */
         public get spaceWidth(): number {
         public get spaceWidth(): number {
@@ -148,6 +156,7 @@
         protected _spaceWidth;
         protected _spaceWidth;
         protected _superSample: boolean;
         protected _superSample: boolean;
         protected _signedDistanceField: boolean;
         protected _signedDistanceField: boolean;
+        protected _isPremultipliedAlpha: boolean;
         protected _cachedFontId: string;
         protected _cachedFontId: string;
     }
     }
 
 
@@ -174,11 +183,12 @@
                             textureUrl: string = null,
                             textureUrl: string = null,
                             noMipmap: boolean = false,
                             noMipmap: boolean = false,
                             invertY: boolean = true,
                             invertY: boolean = true,
-                            samplingMode: number = Texture.TRILINEAR_SAMPLINGMODE, 
+                            samplingMode: number = Texture.TRILINEAR_SAMPLINGMODE,
+                            premultipliedAlpha: boolean = false,
                             onLoad: () => void = null,
                             onLoad: () => void = null,
                             onError: (msg: string, code: number) => void = null)
                             onError: (msg: string, code: number) => void = null)
         {
         {
-            super(null, scene, noMipmap, invertY, samplingMode);
+            super(null, scene, noMipmap, invertY, samplingMode, premultipliedAlpha);
 
 
             var xhr = new XMLHttpRequest();
             var xhr = new XMLHttpRequest();
             xhr.onreadystatechange = () => {
             xhr.onreadystatechange = () => {
@@ -351,30 +361,30 @@
             return true;
             return true;
         }
         }
 
 
-        public static GetCachedFontTexture(scene: Scene, fontName: string, supersample: boolean = false, signedDistanceField: boolean = false): FontTexture {
+        public static GetCachedFontTexture(scene: Scene, fontName: string, supersample: boolean = false, signedDistanceField: boolean = false, bilinearFiltering: boolean=false): FontTexture {
             let dic = scene.getOrAddExternalDataWithFactory("FontTextureCache", () => new StringDictionary<FontTexture>());
             let dic = scene.getOrAddExternalDataWithFactory("FontTextureCache", () => new StringDictionary<FontTexture>());
 
 
-            let lfn = fontName.toLocaleLowerCase() + (supersample ? "_+SS" : "_-SS") + (signedDistanceField ? "_+SDF" : "_-SDF");
+            let lfn = fontName.toLocaleLowerCase() + (supersample ? "_+SS" : "_-SS") + (signedDistanceField ? "_+SDF" : "_-SDF") + (bilinearFiltering ? "_+BF" : "_-BF");
             let ft = dic.get(lfn);
             let ft = dic.get(lfn);
             if (ft) {
             if (ft) {
                 ++ft._usedCounter;
                 ++ft._usedCounter;
                 return ft;
                 return ft;
             }
             }
 
 
-            ft = new FontTexture(null, fontName, scene, supersample ? 100 : 200, Texture.BILINEAR_SAMPLINGMODE, supersample, signedDistanceField);
+            ft = new FontTexture(null, fontName, scene, supersample ? 100 : 200, (signedDistanceField || bilinearFiltering) ? Texture.BILINEAR_SAMPLINGMODE : Texture.NEAREST_SAMPLINGMODE, supersample, signedDistanceField);
             ft._cachedFontId = lfn;
             ft._cachedFontId = lfn;
             dic.add(lfn, ft);
             dic.add(lfn, ft);
 
 
             return ft;
             return ft;
         }
         }
 
 
-        public static ReleaseCachedFontTexture(scene: Scene, fontName: string, supersample: boolean = false, signedDistanceField: boolean = false) {
+        public static ReleaseCachedFontTexture(scene: Scene, fontName: string, supersample: boolean = false, signedDistanceField: boolean = false, bilinearFiltering: boolean=false) {
             let dic = scene.getExternalData<StringDictionary<FontTexture>>("FontTextureCache");
             let dic = scene.getExternalData<StringDictionary<FontTexture>>("FontTextureCache");
             if (!dic) {
             if (!dic) {
                 return;
                 return;
             }
             }
 
 
-            let lfn = fontName.toLocaleLowerCase() + (supersample ? "_+SS" : "_-SS") + (signedDistanceField ? "_+SDF" : "_-SDF");
+            let lfn = fontName.toLocaleLowerCase() + (supersample ? "_+SS" : "_-SS") + (signedDistanceField ? "_+SDF" : "_-SDF") + (bilinearFiltering ? "_+BF" : "_-BF");
             var font = dic.get(lfn);
             var font = dic.get(lfn);
             if (--font._usedCounter === 0) {
             if (--font._usedCounter === 0) {
                 dic.remove(lfn);
                 dic.remove(lfn);
@@ -404,6 +414,7 @@
             this._sdfScale = 8;
             this._sdfScale = 8;
             this._signedDistanceField = signedDistanceField;
             this._signedDistanceField = signedDistanceField;
             this._superSample = false;
             this._superSample = false;
+            this._isPremultipliedAlpha = !signedDistanceField;
 
 
             // SDF will use super sample no matter what, the resolution is otherwise too poor to produce correct result
             // SDF will use super sample no matter what, the resolution is otherwise too poor to produce correct result
             if (superSample || signedDistanceField) {
             if (superSample || signedDistanceField) {

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

@@ -87,7 +87,7 @@
             trackNode               ?: Node,
             trackNode               ?: Node,
             trackNodeOffset         ?: Vector3,
             trackNodeOffset         ?: Vector3,
             opacity                 ?: number,
             opacity                 ?: number,
-            zOrder                  ?: number, 
+            zOrder                  ?: number,
             origin                  ?: Vector2,
             origin                  ?: Vector2,
             size                    ?: Size,
             size                    ?: Size,
             width                   ?: number,
             width                   ?: number,
@@ -135,7 +135,7 @@
             this._cacheBehavior = (settings.cacheBehavior == null) ? Group2D.GROUPCACHEBEHAVIOR_FOLLOWCACHESTRATEGY : settings.cacheBehavior;
             this._cacheBehavior = (settings.cacheBehavior == null) ? Group2D.GROUPCACHEBEHAVIOR_FOLLOWCACHESTRATEGY : settings.cacheBehavior;
             let rd = this._renderableData;
             let rd = this._renderableData;
             if (rd) {
             if (rd) {
-                rd._noResizeOnScale = (this.cacheBehavior & Group2D.GROUPCACHEBEHAVIOR_NORESIZEONSCALE) !== 0;                
+                rd._noResizeOnScale = (this.cacheBehavior & Group2D.GROUPCACHEBEHAVIOR_NORESIZEONSCALE) !== 0;
             }
             }
             this.size = size;
             this.size = size;
             this._viewportPosition = Vector2.Zero();
             this._viewportPosition = Vector2.Zero();
@@ -398,7 +398,9 @@
                 // If it's a force refresh, prepare all the children
                 // If it's a force refresh, prepare all the children
                 if (context.forceRefreshPrimitive) {
                 if (context.forceRefreshPrimitive) {
                     for (let p of this._children) {
                     for (let p of this._children) {
-                        p._prepareRender(context);
+                        if (!p.isDisposed) {
+                            p._prepareRender(context);
+                        }
                     }
                     }
                 } else {
                 } else {
                     // Each primitive that changed at least once was added into the primDirtyList, we have to sort this level using
                     // Each primitive that changed at least once was added into the primDirtyList, we have to sort this level using
@@ -836,8 +838,8 @@
                 if ((size.width < Group2D._s.width) || (size.height < Group2D._s.height)) {
                 if ((size.width < Group2D._s.width) || (size.height < Group2D._s.height)) {
                     // For Screen space: over-provisioning of 7% more to avoid frequent resizing for few pixels...
                     // For Screen space: over-provisioning of 7% more to avoid frequent resizing for few pixels...
                     // For World space: no over-provisioning
                     // For World space: no over-provisioning
-                    let overprovisioning = this.owner.isScreenSpace ? 1.07 : 1; 
-                    curWidth  = Math.floor(Group2D._s.width  * overprovisioning);    
+                    let overprovisioning = this.owner.isScreenSpace ? 1.07 : 1;
+                    curWidth  = Math.floor(Group2D._s.width  * overprovisioning);
                     curHeight = Math.floor(Group2D._s.height * overprovisioning);
                     curHeight = Math.floor(Group2D._s.height * overprovisioning);
                     //console.log(`[${this._globalTransformProcessStep}] Resize group ${this.id}, width: ${curWidth}, height: ${curHeight}`);
                     //console.log(`[${this._globalTransformProcessStep}] Resize group ${this.id}, width: ${curWidth}, height: ${curHeight}`);
                     rd._cacheTexture.freeRect(rd._cacheNode);
                     rd._cacheTexture.freeRect(rd._cacheNode);

+ 17 - 12
canvas2D/src/Engine/babylon.lines2d.ts

@@ -315,9 +315,6 @@
         }
         }
 
 
         protected updateLevelBoundingInfo(): boolean {
         protected updateLevelBoundingInfo(): boolean {
-            if (!this._size) {
-                return false;
-            }
             if (!this._boundingMin) {
             if (!this._boundingMin) {
                 this._computeLines2D();
                 this._computeLines2D();
             }
             }
@@ -336,6 +333,7 @@
          * - rotation: the initial rotation (in radian) of the primitive. default is 0
          * - rotation: the initial rotation (in radian) of the primitive. default is 0
          * - scale: the initial scale of the primitive. default is 1. You can alternatively use scaleX &| scaleY to apply non uniform scale
          * - scale: the initial scale of the primitive. default is 1. You can alternatively use scaleX &| scaleY to apply non uniform scale
          * - dontInheritParentScale: if set the parent's scale won't be taken into consideration to compute the actualScale property
          * - dontInheritParentScale: if set the parent's scale won't be taken into consideration to compute the actualScale property
+         * - alignToPixel: if true the primitive will be aligned to the target rendering device's pixel
          * - opacity: set the overall opacity of the primitive, 1 to be opaque (default), less than 1 to be transparent.
          * - opacity: set the overall opacity of the primitive, 1 to be opaque (default), less than 1 to be transparent.
          * - zOrder: override the zOrder with the specified value
          * - zOrder: override the zOrder with the specified value
          * - origin: define the normalized origin point location, default [0.5;0.5]
          * - origin: define the normalized origin point location, default [0.5;0.5]
@@ -380,6 +378,7 @@
             scaleX                ?: number,
             scaleX                ?: number,
             scaleY                ?: number,
             scaleY                ?: number,
             dontInheritParentScale?: boolean,
             dontInheritParentScale?: boolean,
+            alignToPixel          ?: boolean,
             opacity               ?: number,
             opacity               ?: number,
             zOrder                ?: number, 
             zOrder                ?: number, 
             origin                ?: Vector2,
             origin                ?: Vector2,
@@ -423,8 +422,6 @@
             this._borderVB = null;
             this._borderVB = null;
             this._borderIB = null;
             this._borderIB = null;
 
 
-            this._size = Size.Zero();
-
             this._boundingMin = null;
             this._boundingMin = null;
             this._boundingMax = null;
             this._boundingMax = null;
 
 
@@ -1152,12 +1149,12 @@
                 let pta = this._primTriArray;
                 let pta = this._primTriArray;
                 let l = this.closed ? pl + 1 : pl;
                 let l = this.closed ? pl + 1 : pl;
 
 
-                this.transformPointWithOriginToRef(contour[0], null, Lines2D._prevA);
-                this.transformPointWithOriginToRef(contour[1], null, Lines2D._prevB);
+                Lines2D._prevA.copyFrom(contour[0]);
+                Lines2D._prevB.copyFrom(contour[1]);
                 let si = 0;
                 let si = 0;
                 for (let i = 1; i < l; i++) {
                 for (let i = 1; i < l; i++) {
-                    this.transformPointWithOriginToRef(contour[(i % pl) * 2 + 0], null, Lines2D._curA);
-                    this.transformPointWithOriginToRef(contour[(i % pl) * 2 + 1], null, Lines2D._curB);
+                    Lines2D._curA.copyFrom(contour[(i % pl) * 2 + 0]);
+                    Lines2D._curB.copyFrom(contour[(i % pl) * 2 + 1]);
 
 
                     pta.storeTriangle(si++, Lines2D._prevA, Lines2D._prevB, Lines2D._curA);
                     pta.storeTriangle(si++, Lines2D._prevA, Lines2D._prevB, Lines2D._curA);
                     pta.storeTriangle(si++, Lines2D._curA,  Lines2D._prevB, Lines2D._curB);
                     pta.storeTriangle(si++, Lines2D._curA,  Lines2D._prevB, Lines2D._curB);
@@ -1173,15 +1170,15 @@
                     for (let i = 0; i < l; i += 3) {
                     for (let i = 0; i < l; i += 3) {
                         Lines2D._curA.x = points[tri[i + 0] * 2 + 0];
                         Lines2D._curA.x = points[tri[i + 0] * 2 + 0];
                         Lines2D._curA.y = points[tri[i + 0] * 2 + 1];
                         Lines2D._curA.y = points[tri[i + 0] * 2 + 1];
-                        this.transformPointWithOriginToRef(Lines2D._curA, null, Lines2D._curB);
+                        Lines2D._curB.copyFrom(Lines2D._curA);
 
 
                         Lines2D._curA.x = points[tri[i + 1] * 2 + 0];
                         Lines2D._curA.x = points[tri[i + 1] * 2 + 0];
                         Lines2D._curA.y = points[tri[i + 1] * 2 + 1];
                         Lines2D._curA.y = points[tri[i + 1] * 2 + 1];
-                        this.transformPointWithOriginToRef(Lines2D._curA, null, Lines2D._prevA);
+                        Lines2D._prevA.copyFrom(Lines2D._curA);
 
 
                         Lines2D._curA.x = points[tri[i + 2] * 2 + 0];
                         Lines2D._curA.x = points[tri[i + 2] * 2 + 0];
                         Lines2D._curA.y = points[tri[i + 2] * 2 + 1];
                         Lines2D._curA.y = points[tri[i + 2] * 2 + 1];
-                        this.transformPointWithOriginToRef(Lines2D._curA, null, Lines2D._prevB);
+                        Lines2D._prevB.copyFrom(Lines2D._curA);
 
 
                         pta.storeTriangle(si++, Lines2D._prevA, Lines2D._prevB, Lines2D._curB);
                         pta.storeTriangle(si++, Lines2D._prevA, Lines2D._prevB, Lines2D._curB);
                     }
                     }
@@ -1200,8 +1197,16 @@
             }
             }
 
 
             let bs = this._boundingMax.subtract(this._boundingMin);
             let bs = this._boundingMax.subtract(this._boundingMin);
+
+            // If the size is not size we were computing the first pass to determine the size took by the primitive
+            if (!this._size) {
+                // Set the size and compute a second time to consider the size while computing the points using the origin
+                this._size = new Size(bs.x, bs.y);
+                this._updatePositioningState();
+            }
             this._size.width = bs.x;
             this._size.width = bs.x;
             this._size.height = bs.y;
             this._size.height = bs.y;
+            this._actualSize = null;
         }
         }
 
 
         public get size(): Size {
         public get size(): Size {

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

@@ -1,6 +1,6 @@
 module BABYLON {
 module BABYLON {
     export const enum ShaderDataType {
     export const enum ShaderDataType {
-        Vector2, Vector3, Vector4, Matrix, float, Color3, Color4, Size
+        Vector2, Vector3, Vector4, float, Color3, Color4, Size
     }
     }
 
 
     export class GroupInstanceInfo {
     export class GroupInstanceInfo {
@@ -50,6 +50,10 @@
             return true;
             return true;
         }
         }
 
 
+        public get isDisposed(): boolean {
+            return this._isDisposed;
+        }
+
         private _isDisposed: boolean;
         private _isDisposed: boolean;
         owner: Group2D;
         owner: Group2D;
 
 

A diferenza do arquivo foi suprimida porque é demasiado grande
+ 544 - 391
canvas2D/src/Engine/babylon.prim2dBase.ts


+ 1 - 1
canvas2D/src/Engine/babylon.primitiveCollisionManager.ts

@@ -640,7 +640,7 @@
             });
             });
 
 
             if (!this._AABBRenderPrim) {
             if (!this._AABBRenderPrim) {
-                this._AABBRenderPrim = new WireFrame2D([g], { parent: this._owner, alignToPixel: false, id: "###DEBUG PCM AABB###" });
+                this._AABBRenderPrim = new WireFrame2D([g], { parent: this._owner, alignToPixel: true, id: "###DEBUG PCM AABB###" });
             } else {
             } else {
                 this._AABBRenderPrim.wireFrameGroups.set("main", g);
                 this._AABBRenderPrim.wireFrameGroups.set("main", g);
                 this._AABBRenderPrim.wireFrameGroupsDirty();
                 this._AABBRenderPrim.wireFrameGroupsDirty();

+ 7 - 2
canvas2D/src/Engine/babylon.rectangle2d.ts

@@ -288,6 +288,7 @@
          * - rotation: the initial rotation (in radian) of the primitive. default is 0
          * - rotation: the initial rotation (in radian) of the primitive. default is 0
          * - scale: the initial scale of the primitive. default is 1. You can alternatively use scaleX &| scaleY to apply non uniform scale
          * - scale: the initial scale of the primitive. default is 1. You can alternatively use scaleX &| scaleY to apply non uniform scale
          * - dontInheritParentScale: if set the parent's scale won't be taken into consideration to compute the actualScale property
          * - dontInheritParentScale: if set the parent's scale won't be taken into consideration to compute the actualScale property
+         * - alignToPixel: if true the primitive will be aligned to the target rendering device's pixel
          * - opacity: set the overall opacity of the primitive, 1 to be opaque (default), less than 1 to be transparent.
          * - opacity: set the overall opacity of the primitive, 1 to be opaque (default), less than 1 to be transparent.
          * - zOrder: override the zOrder with the specified value
          * - zOrder: override the zOrder with the specified value
          * - origin: define the normalized origin point location, default [0.5;0.5]
          * - origin: define the normalized origin point location, default [0.5;0.5]
@@ -329,6 +330,7 @@
             scaleX                ?: number,
             scaleX                ?: number,
             scaleY                ?: number,
             scaleY                ?: number,
             dontInheritParentScale?: boolean,
             dontInheritParentScale?: boolean,
+            alignToPixel          ?: boolean,
             opacity               ?: number,
             opacity               ?: number,
             zOrder                ?: number, 
             zOrder                ?: number, 
             origin                ?: Vector2,
             origin                ?: Vector2,
@@ -585,20 +587,23 @@
             return res;
             return res;
         }
         }
 
 
+        private static _riv0 = new Vector2(0,0);
         protected refreshInstanceDataPart(part: InstanceDataBase): boolean {
         protected refreshInstanceDataPart(part: InstanceDataBase): boolean {
             if (!super.refreshInstanceDataPart(part)) {
             if (!super.refreshInstanceDataPart(part)) {
                 return false;
                 return false;
             }
             }
+
+            let s = Rectangle2D._riv0;
+            this.getActualGlobalScaleToRef(s);
+
             if (part.id === Shape2D.SHAPE2D_BORDERPARTID) {
             if (part.id === Shape2D.SHAPE2D_BORDERPARTID) {
                 let d = <Rectangle2DInstanceData>part;
                 let d = <Rectangle2DInstanceData>part;
                 let size = this.actualSize;
                 let size = this.actualSize;
-                let s = this.actualScale;
                 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) {
             else if (part.id === Shape2D.SHAPE2D_FILLPARTID) {
                 let d = <Rectangle2DInstanceData>part;
                 let d = <Rectangle2DInstanceData>part;
                 let size = this.actualSize;
                 let size = this.actualSize;
-                let s = this.actualScale;
                 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;
             return true;

+ 56 - 48
canvas2D/src/Engine/babylon.renderablePrim2d.ts

@@ -80,15 +80,24 @@
         attributeName: string;
         attributeName: string;
         category: string;
         category: string;
         size: number;
         size: number;
-        shaderOffset: number;
         instanceOffset: StringDictionary<number>;
         instanceOffset: StringDictionary<number>;
         dataType: ShaderDataType;
         dataType: ShaderDataType;
+
+        curCategory: string;
+        curCategoryOffset: number;
+
         //uniformLocation: WebGLUniformLocation;
         //uniformLocation: WebGLUniformLocation;
 
 
         delimitedCategory: string;
         delimitedCategory: string;
 
 
         constructor() {
         constructor() {
+            this.attributeName = null;
+            this.category = null;
+            this.size = null;
             this.instanceOffset = new StringDictionary<number>();
             this.instanceOffset = new StringDictionary<number>();
+            this.dataType = 0;
+            this.curCategory = "";
+            this.curCategoryOffset = 0;
         }
         }
 
 
         setSize(val) {
         setSize(val) {
@@ -107,8 +116,8 @@
                 this.dataType = ShaderDataType.Vector4;
                 this.dataType = ShaderDataType.Vector4;
                 return;
                 return;
             }
             }
-            if (val instanceof Matrix) {
-                throw new Error("Matrix type is not supported by WebGL Instance Buffer, you have to use four Vector4 properties instead");
+            if (val instanceof Matrix2D) {
+                throw new Error("Matrix2D type is not supported by WebGL Instance Buffer, you have to use four Vector4 properties instead");
             }
             }
             if (typeof (val) === "number") {
             if (typeof (val) === "number") {
                 this.size = 4;
                 this.size = 4;
@@ -181,14 +190,6 @@
                         array[offset] = v;
                         array[offset] = v;
                         break;
                         break;
                     }
                     }
-                case ShaderDataType.Matrix:
-                    {
-                        let v = <Matrix>val;
-                        for (let i = 0; i < 16; i++) {
-                            array[offset + i] = v.m[i];
-                        }
-                        break;
-                    }
                 case ShaderDataType.Size:
                 case ShaderDataType.Size:
                     {
                     {
                         let s = <Size>val;
                         let s = <Size>val;
@@ -233,16 +234,25 @@
                 if (info.category && InstanceClassInfo._CurCategories.indexOf(info.delimitedCategory) === -1) {
                 if (info.category && InstanceClassInfo._CurCategories.indexOf(info.delimitedCategory) === -1) {
                     return;
                     return;
                 }
                 }
-                if (!info.size) {
-                    info.setSize(val);
-                    node.classContent.mapProperty(info, true);
-                } else if (!info.instanceOffset.contains(InstanceClassInfo._CurCategories)) {
-                    node.classContent.mapProperty(info, false);
+
+                let catOffset: number;
+                if (info.curCategory === InstanceClassInfo._CurCategories) {
+                    catOffset = info.curCategoryOffset;
+                } else {
+                    if (!info.size) {
+                        info.setSize(val);
+                        node.classContent.mapProperty(info, true);
+                    } else if (!info.instanceOffset.contains(InstanceClassInfo._CurCategories)) {
+                        node.classContent.mapProperty(info, false);
+                    }
+                    catOffset = info.instanceOffset.get(InstanceClassInfo._CurCategories);
+                    info.curCategory = InstanceClassInfo._CurCategories;
+                    info.curCategoryOffset = catOffset;
                 }
                 }
 
 
                 let obj: InstanceDataBase = this;
                 let obj: InstanceDataBase = this;
                 if (obj.dataBuffer && obj.dataElements) {
                 if (obj.dataBuffer && obj.dataElements) {
-                    let offset = obj.dataElements[obj.curElement].offset + info.instanceOffset.get(InstanceClassInfo._CurCategories);
+                    let offset = obj.dataElements[obj.curElement].offset + catOffset;
                     info.writeData(obj.dataBuffer.buffer, offset, val);
                     info.writeData(obj.dataBuffer.buffer, offset, val);
                 }
                 }
             }
             }
@@ -284,6 +294,15 @@
         set transformY(value: Vector4) {
         set transformY(value: Vector4) {
         }
         }
 
 
+        // The vector3 is: rendering width, height and 1 if the primitive must be aligned to pixel or 0 otherwise
+        @instanceData()
+        get renderingInfo(): Vector3 {
+            return null;
+        }
+
+        set renderingInfo(val: Vector3) {
+        }
+
         @instanceData()
         @instanceData()
         get opacity(): number {
         get opacity(): number {
             return null;
             return null;
@@ -430,8 +449,9 @@
             for (let part of this._instanceDataParts) {
             for (let part of this._instanceDataParts) {
                 part.freeElements();
                 part.freeElements();
                 gii = part.groupInstanceInfo;
                 gii = part.groupInstanceInfo;
+                part.groupInstanceInfo = null;
             }
             }
-            if (gii) {
+            if (gii && !gii.isDisposed) {
                 let usedCount = 0;
                 let usedCount = 0;
                 if (gii.hasOpaqueData) {
                 if (gii.hasOpaqueData) {
                     let od = gii.opaqueData[0];
                     let od = gii.opaqueData[0];
@@ -660,6 +680,9 @@
             if (!gii) {
             if (!gii) {
                 gii = rd._renderGroupInstancesInfo.get(this.modelKey);
                 gii = rd._renderGroupInstancesInfo.get(this.modelKey);
             }
             }
+            if (gii.isDisposed) {
+                return;
+            }
 
 
             let isTransparent = this.isTransparent;
             let isTransparent = this.isTransparent;
             let isAlphaTest = this.isAlphaTest;
             let isAlphaTest = this.isAlphaTest;
@@ -824,23 +847,7 @@
             return null;
             return null;
         }
         }
 
 
-        /**
-         * Transform a given point using the Primitive's origin setting.
-         * This method requires the Primitive's actualSize to be accurate
-         * @param p the point to transform
-         * @param originOffset an offset applied on the current origin before performing the transformation. Depending on which frame of reference your data is expressed you may have to apply a offset. (if you data is expressed from the bottom/left, no offset is required. If it's expressed from the center the a [-0.5;-0.5] offset has to be applied.
-         * @param res an allocated Vector2 that will receive the transformed content
-         */
-        protected transformPointWithOriginByRef(p: Vector2, originOffset:Vector2, res: Vector2) {
-            let actualSize = this.actualSize;
-            res.x = p.x - ((this.origin.x + (originOffset ? originOffset.x : 0)) * actualSize.width);
-            res.y = p.y - ((this.origin.y + (originOffset ? originOffset.y : 0)) * actualSize.height);
-        }
-
-        protected transformPointWithOriginToRef(p: Vector2, originOffset: Vector2, res: Vector2) {
-            this.transformPointWithOriginByRef(p, originOffset, res);
-            return res;
-        }
+        private static _toz = Size.Zero();
 
 
         /**
         /**
          * Get the info for a given effect based on the dataPart metadata
          * Get the info for a given effect based on the dataPart metadata
@@ -928,10 +935,11 @@
         }
         }
 
 
         private static _uV = new Vector2(1, 1);
         private static _uV = new Vector2(1, 1);
-        private static _s = Vector3.Zero();
+        private static _s = Vector2.Zero();
         private static _r = Quaternion.Identity();
         private static _r = Quaternion.Identity();
-        private static _t = Vector3.Zero();
-        private static _iV3 = new Vector3(1, 1, 1); // Must stay identity vector3
+        private static _t = Vector2.Zero();
+        private static _iV2 = new Vector2(1, 1); // Must stay identity vector3
+
         /**
         /**
          * Update the instanceDataBase level properties of a part
          * Update the instanceDataBase level properties of a part
          * @param part the part to update
          * @param part the part to update
@@ -940,14 +948,13 @@
         protected updateInstanceDataPart(part: InstanceDataBase, positionOffset: Vector2 = null) {
         protected updateInstanceDataPart(part: InstanceDataBase, positionOffset: Vector2 = null) {
             let t = this._globalTransform.multiply(this.renderGroup.invGlobalTransform);    // Compute the transformation into the renderGroup's space
             let t = this._globalTransform.multiply(this.renderGroup.invGlobalTransform);    // Compute the transformation into the renderGroup's space
             let scl = RenderablePrim2D._s;
             let scl = RenderablePrim2D._s;
-            let rot = RenderablePrim2D._r;
             let trn = RenderablePrim2D._t;
             let trn = RenderablePrim2D._t;
-            t.decompose(scl, rot, trn);
+            let rot = t.decompose(scl, trn);
             let pas = this.actualScale;
             let pas = this.actualScale;
-            scl.x = pas.x;
-            scl.y = pas.y;
-            scl.z = 1;
-            t = Matrix.Compose(this.applyActualScaleOnTransform() ? scl : RenderablePrim2D._iV3, rot, trn);
+            let canvasScale = this.owner._canvasLevelScale;
+            scl.x = pas.x * canvasScale.x * this._postScale.x;
+            scl.y = pas.y * canvasScale.y * this._postScale.y;
+            t = Matrix2D.Compose(this.applyActualScaleOnTransform() ? scl : RenderablePrim2D._iV2, rot, trn);
 
 
             let size = (<Size>this.renderGroup.viewportSize);
             let size = (<Size>this.renderGroup.viewportSize);
             let zBias = this.actualZOffset;
             let zBias = this.actualZOffset;
@@ -957,8 +964,8 @@
 
 
             // If there's an offset, apply the global transformation matrix on it to get a global offset
             // If there's an offset, apply the global transformation matrix on it to get a global offset
             if (positionOffset) {
             if (positionOffset) {
-                offX = positionOffset.x * t.m[0] + positionOffset.y * t.m[4];
-                offY = positionOffset.x * t.m[1] + positionOffset.y * t.m[5];
+                offX = positionOffset.x * t.m[0] + positionOffset.y * t.m[2];
+                offY = positionOffset.x * t.m[1] + positionOffset.y * t.m[3];
             }
             }
 
 
             // Have to convert the coordinates to clip space which is ranged between [-1;1] on X and Y axis, with 0,0 being the left/bottom corner
             // Have to convert the coordinates to clip space which is ranged between [-1;1] on X and Y axis, with 0,0 being the left/bottom corner
@@ -970,10 +977,11 @@
             let w = size.width;
             let w = size.width;
             let h = size.height;
             let h = size.height;
             let invZBias = 1 / zBias;
             let invZBias = 1 / zBias;
-            let tx = new Vector4(t.m[0] * 2 / w, t.m[4] * 2 / w, 0, ((t.m[12] + offX) * 2 / w) - 1);
-            let ty = new Vector4(t.m[1] * 2 / h, t.m[5] * 2 / h, 0, ((t.m[13] + offY) * 2 / h) - 1);
 
 
+            let tx = new Vector4(t.m[0] * 2 / w, t.m[2] * 2 / w, 0, ((t.m[4] + offX) * 2 / w) - 1);
+            let ty = new Vector4(t.m[1] * 2 / h, t.m[3] * 2 / h, 0, ((t.m[5] + offY) * 2 / h) - 1);
 
 
+            part.renderingInfo = new Vector3(w, h, this.alignToPixel ? 1 : 0);
             part.transformX = tx;
             part.transformX = tx;
             part.transformY = ty;
             part.transformY = ty;
             part.opacity = this.actualOpacity;
             part.opacity = this.actualOpacity;

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

@@ -146,9 +146,9 @@
                     } else if (fill instanceof GradientColorBrush2D) {
                     } else if (fill instanceof GradientColorBrush2D) {
                         d.fillGradientColor1 = fill.color1;
                         d.fillGradientColor1 = fill.color1;
                         d.fillGradientColor2 = fill.color2;
                         d.fillGradientColor2 = fill.color2;
-                        var t = Matrix.Compose(new Vector3(fill.scale, fill.scale, fill.scale), Quaternion.RotationAxis(new Vector3(0, 0, 1), fill.rotation), new Vector3(fill.translation.x, fill.translation.y, 0));
+                        var t = Matrix2D.Compose(new Vector2(fill.scale, fill.scale), fill.rotation, new Vector2(fill.translation.x, fill.translation.y));
 
 
-                        let ty = new Vector4(t.m[1], t.m[5], t.m[9], t.m[13]);
+                        let ty = new Vector4(t.m[1], t.m[3], 0, t.m[5]);
                         d.fillGradientTY = ty;
                         d.fillGradientTY = ty;
                     }
                     }
                 }
                 }
@@ -166,9 +166,9 @@
                     } else if (border instanceof GradientColorBrush2D) {
                     } else if (border instanceof GradientColorBrush2D) {
                         d.borderGradientColor1 = border.color1;
                         d.borderGradientColor1 = border.color1;
                         d.borderGradientColor2 = border.color2;
                         d.borderGradientColor2 = border.color2;
-                        var t = Matrix.Compose(new Vector3(border.scale, border.scale, border.scale), Quaternion.RotationAxis(new Vector3(0, 0, 1), border.rotation), new Vector3(border.translation.x, border.translation.y, 0));
+                        var t = Matrix2D.Compose(new Vector2(border.scale, border.scale), border.rotation, new Vector2(border.translation.x, border.translation.y));
 
 
-                        let ty = new Vector4(t.m[1], t.m[5], t.m[9], t.m[13]);
+                        let ty = new Vector4(t.m[1], t.m[3], 0, t.m[5]);
                         d.borderGradientTY = ty;
                         d.borderGradientTY = ty;
                     }
                     }
                 }
                 }

+ 38 - 2
canvas2D/src/Engine/babylon.smartPropertyPrim.ts

@@ -675,6 +675,7 @@
             } 
             } 
         }
         }
 
 
+        @logProp()
         protected _triggerPropertyChanged(propInfo: Prim2DPropInfo, newValue: any) {
         protected _triggerPropertyChanged(propInfo: Prim2DPropInfo, newValue: any) {
             if (this.isDisposed) {
             if (this.isDisposed) {
                 return;
                 return;
@@ -1103,13 +1104,13 @@
         }
         }
 
 
         protected _boundingBoxDirty() {
         protected _boundingBoxDirty() {
-            this._setFlags(SmartPropertyPrim.flagLevelBoundingInfoDirty);
+            this._setFlags(SmartPropertyPrim.flagLevelBoundingInfoDirty|SmartPropertyPrim.flagLayoutBoundingInfoDirty);
 
 
             // Escalate the dirty flag in the instance hierarchy, stop when a renderable group is found or at the end
             // Escalate the dirty flag in the instance hierarchy, stop when a renderable group is found or at the end
             if (this instanceof Prim2DBase) {
             if (this instanceof Prim2DBase) {
                 let curprim: Prim2DBase = (<any>this);
                 let curprim: Prim2DBase = (<any>this);
                 while (curprim) {
                 while (curprim) {
-                    curprim._setFlags(SmartPropertyPrim.flagBoundingInfoDirty);
+                    curprim._setFlags(SmartPropertyPrim.flagBoundingInfoDirty|SmartPropertyPrim.flagLayoutBoundingInfoDirty);
                     if (curprim.isSizeAuto) {
                     if (curprim.isSizeAuto) {
                         curprim.onPrimitivePropertyDirty(Prim2DBase.sizeProperty.flagId);
                         curprim.onPrimitivePropertyDirty(Prim2DBase.sizeProperty.flagId);
                         if (curprim._isFlagSet(SmartPropertyPrim.flagUsePositioning)) {
                         if (curprim._isFlagSet(SmartPropertyPrim.flagUsePositioning)) {
@@ -1198,6 +1199,7 @@
         /**
         /**
          * Retrieve the boundingInfo for this Primitive, computed based on the primitive itself and NOT its children
          * Retrieve the boundingInfo for this Primitive, computed based on the primitive itself and NOT its children
          */
          */
+        @logProp()
         public get levelBoundingInfo(): BoundingInfo2D {
         public get levelBoundingInfo(): BoundingInfo2D {
             if (this._isFlagSet(SmartPropertyPrim.flagLevelBoundingInfoDirty)) {
             if (this._isFlagSet(SmartPropertyPrim.flagLevelBoundingInfoDirty)) {
                 if (this.updateLevelBoundingInfo()) {
                 if (this.updateLevelBoundingInfo()) {
@@ -1283,6 +1285,39 @@
             }
             }
         }
         }
 
 
+        public _getFlagsDebug(flags: number): string {
+            let res = "";
+            if (flags & SmartPropertyPrim.flagNoPartOfLayout)          res += "NoPartOfLayout, ";
+            if (flags & SmartPropertyPrim.flagLevelBoundingInfoDirty)  res += "LevelBoundingInfoDirty, ";
+            if (flags & SmartPropertyPrim.flagModelDirty)              res += "ModelDirty, ";
+            if (flags & SmartPropertyPrim.flagLayoutDirty)             res += "LayoutDirty, ";
+            if (flags & SmartPropertyPrim.flagLevelVisible)            res += "LevelVisible, ";
+            if (flags & SmartPropertyPrim.flagBoundingInfoDirty)       res += "BoundingInfoDirty, ";
+            if (flags & SmartPropertyPrim.flagIsPickable)              res += "IsPickable, ";
+            if (flags & SmartPropertyPrim.flagIsVisible)               res += "IsVisible, ";
+            if (flags & SmartPropertyPrim.flagVisibilityChanged)       res += "VisibilityChanged, ";
+            if (flags & SmartPropertyPrim.flagPositioningDirty)        res += "PositioningDirty, ";
+            if (flags & SmartPropertyPrim.flagTrackedGroup)            res += "TrackedGroup, ";
+            if (flags & SmartPropertyPrim.flagWorldCacheChanged)       res += "WorldCacheChanged, ";
+            if (flags & SmartPropertyPrim.flagChildrenFlatZOrder)      res += "ChildrenFlatZOrder, ";
+            if (flags & SmartPropertyPrim.flagZOrderDirty)             res += "ZOrderDirty, ";
+            if (flags & SmartPropertyPrim.flagActualOpacityDirty)      res += "ActualOpacityDirty, ";
+            if (flags & SmartPropertyPrim.flagPrimInDirtyList)         res += "PrimInDirtyList, ";
+            if (flags & SmartPropertyPrim.flagIsContainer)             res += "IsContainer, ";
+            if (flags & SmartPropertyPrim.flagNeedRefresh)             res += "NeedRefresh, ";
+            if (flags & SmartPropertyPrim.flagActualScaleDirty)        res += "ActualScaleDirty, ";
+            if (flags & SmartPropertyPrim.flagDontInheritParentScale)  res += "DontInheritParentScale, ";
+            if (flags & SmartPropertyPrim.flagGlobalTransformDirty)    res += "GlobalTransformDirty, ";
+            if (flags & SmartPropertyPrim.flagLayoutBoundingInfoDirty) res += "LayoutBoundingInfoDirty, ";
+            if (flags & SmartPropertyPrim.flagCollisionActor)          res += "CollisionActor, ";
+            if (flags & SmartPropertyPrim.flagModelUpdate)             res += "ModelUpdate, ";
+            if (flags & SmartPropertyPrim.flagLocalTransformDirty)     res += "LocalTransformDirty, ";
+            if (flags & SmartPropertyPrim.flagUsePositioning)          res += "UsePositioning, ";
+            if (flags & SmartPropertyPrim.flagComputingPositioning)    res += "ComputingPositioning, ";
+
+            return res.slice(0, res.length - 2);
+        }
+
         public static flagNoPartOfLayout          = 0x0000001;    // set if the primitive's position/size must not be computed by Layout Engine
         public static flagNoPartOfLayout          = 0x0000001;    // set if the primitive's position/size must not be computed by Layout Engine
         public static flagLevelBoundingInfoDirty  = 0x0000002;    // set if the primitive's level bounding box (not including children) is dirty
         public static flagLevelBoundingInfoDirty  = 0x0000002;    // set if the primitive's level bounding box (not including children) is dirty
         public static flagModelDirty              = 0x0000004;    // set if the model must be changed
         public static flagModelDirty              = 0x0000004;    // set if the model must be changed
@@ -1310,6 +1345,7 @@
         public static flagLocalTransformDirty     = 0x1000000;    // set if the local transformation matrix must be recomputed
         public static flagLocalTransformDirty     = 0x1000000;    // set if the local transformation matrix must be recomputed
         public static flagUsePositioning          = 0x2000000;    // set if the primitive rely on the positioning engine (padding or margin is used)
         public static flagUsePositioning          = 0x2000000;    // set if the primitive rely on the positioning engine (padding or margin is used)
         public static flagComputingPositioning    = 0x4000000;    // set if the positioning engine is computing the primitive, used to avoid re entrance
         public static flagComputingPositioning    = 0x4000000;    // set if the positioning engine is computing the primitive, used to avoid re entrance
+        public static flagAlignPrimitive          = 0x8000000;    // set if the primitive should be pixel aligned to the render target
 
 
         private   _uid                : string;
         private   _uid                : string;
         private   _flags              : number;
         private   _flags              : number;

+ 3 - 15
canvas2D/src/Engine/babylon.sprite2d.ts

@@ -224,17 +224,6 @@
         //    this._spriteScaleFactor = value;
         //    this._spriteScaleFactor = value;
         //}
         //}
 
 
-        /**
-         * Get/set if the sprite rendering should be aligned to the target rendering device pixel or not
-         */
-        public get alignToPixel(): boolean {
-            return this._alignToPixel;
-        }
-
-        public set alignToPixel(value: boolean) {
-            this._alignToPixel = value;
-        }
-
         protected updateLevelBoundingInfo(): boolean {
         protected updateLevelBoundingInfo(): boolean {
             BoundingInfo2D.CreateFromSizeToRef(this.size, this._levelBoundingInfo);
             BoundingInfo2D.CreateFromSizeToRef(this.size, this._levelBoundingInfo);
             return true;
             return true;
@@ -273,15 +262,14 @@
          * - scale: the initial scale of the primitive. default is 1. You can alternatively use scaleX &| scaleY to apply non uniform scale
          * - scale: the initial scale of the primitive. default is 1. You can alternatively use scaleX &| scaleY to apply non uniform scale
          * - size: the size of the sprite displayed in the canvas, if not specified the spriteSize will be used
          * - size: the size of the sprite displayed in the canvas, if not specified the spriteSize will be used
          * - dontInheritParentScale: if set the parent's scale won't be taken into consideration to compute the actualScale property
          * - dontInheritParentScale: if set the parent's scale won't be taken into consideration to compute the actualScale property
+         * - alignToPixel: if true the sprite's texels will be aligned to the rendering viewport pixels, ensuring the best rendering quality but slow animations won't be done as smooth as if you set false. If false a texel could lies between two pixels, being blended by the texture sampling mode you choose, the rendering result won't be as good, but very slow animation will be overall better looking. Default is true: content will be aligned.
          * - opacity: set the overall opacity of the primitive, 1 to be opaque (default), less than 1 to be transparent.
          * - opacity: set the overall opacity of the primitive, 1 to be opaque (default), less than 1 to be transparent.
          * - zOrder: override the zOrder with the specified value
          * - zOrder: override the zOrder with the specified value
          * - origin: define the normalized origin point location, default [0.5;0.5]
          * - origin: define the normalized origin point location, default [0.5;0.5]
          * - spriteSize: the size of the sprite (in pixels) as it is stored in the texture, if null the size of the given texture will be used, default is null.
          * - spriteSize: the size of the sprite (in pixels) as it is stored in the texture, if null the size of the given texture will be used, default is null.
          * - spriteLocation: the location (in pixels) in the texture of the top/left corner of the Sprite to display, default is null (0,0)
          * - spriteLocation: the location (in pixels) in the texture of the top/left corner of the Sprite to display, default is null (0,0)
-         * - spriteScaleFactor: DEPRECATED. Old behavior: say you want to display a sprite twice as big as its bitmap which is 64,64, you set the spriteSize to 128,128 and have to set the spriteScaleFactory to 0.5,0.5 in order to address only the 64,64 pixels of the bitmaps. Default is 1,1.
          * - scale9: draw the sprite as a Scale9 sprite, see http://yannickloriot.com/2013/03/9-patch-technique-in-cocos2d/ for more info. x, y, w, z are left, bottom, right, top coordinate of the resizable box
          * - scale9: draw the sprite as a Scale9 sprite, see http://yannickloriot.com/2013/03/9-patch-technique-in-cocos2d/ for more info. x, y, w, z are left, bottom, right, top coordinate of the resizable box
          * - invertY: if true the texture Y will be inverted, default is false.
          * - invertY: if true the texture Y will be inverted, default is false.
-         * - alignToPixel: if true the sprite's texels will be aligned to the rendering viewport pixels, ensuring the best rendering quality but slow animations won't be done as smooth as if you set false. If false a texel could lies between two pixels, being blended by the texture sampling mode you choose, the rendering result won't be as good, but very slow animation will be overall better looking. Default is true: content will be aligned.
          * - isVisible: true if the sprite must be visible, false for hidden. Default is true.
          * - isVisible: true if the sprite must be visible, false for hidden. Default is true.
          * - isPickable: if true the Primitive can be used with interaction mode and will issue Pointer Event. If false it will be ignored for interaction/intersection test. Default value is true.
          * - isPickable: if true the Primitive can be used with interaction mode and will issue Pointer Event. If false it will be ignored for interaction/intersection test. Default value is true.
          * - isContainer: if true the Primitive acts as a container for interaction, if the primitive is not pickable or doesn't intersection, no further test will be perform on its children. If set to false, children will always be considered for intersection/interaction. Default value is true.
          * - isContainer: if true the Primitive acts as a container for interaction, if the primitive is not pickable or doesn't intersection, no further test will be perform on its children. If set to false, children will always be considered for intersection/interaction. Default value is true.
@@ -317,6 +305,7 @@
             scaleX                ?: number,
             scaleX                ?: number,
             scaleY                ?: number,
             scaleY                ?: number,
             dontInheritParentScale?: boolean,
             dontInheritParentScale?: boolean,
+            alignToPixel          ?: boolean,
             opacity               ?: number,
             opacity               ?: number,
             zOrder                ?: number, 
             zOrder                ?: number, 
             origin                ?: Vector2,
             origin                ?: Vector2,
@@ -325,7 +314,6 @@
             spriteScaleFactor     ?: Vector2,
             spriteScaleFactor     ?: Vector2,
             scale9                ?: Vector4,
             scale9                ?: Vector4,
             invertY               ?: boolean,
             invertY               ?: boolean,
-            alignToPixel          ?: boolean,
             isVisible             ?: boolean,
             isVisible             ?: boolean,
             isPickable            ?: boolean,
             isPickable            ?: boolean,
             isContainer           ?: boolean,
             isContainer           ?: boolean,
@@ -364,6 +352,7 @@
             if (settings.size != null) {
             if (settings.size != null) {
                 this.size = settings.size;
                 this.size = settings.size;
             }
             }
+            this._updatePositioningState();
             this.spriteFrame = 0;
             this.spriteFrame = 0;
             this.invertY = (settings.invertY == null) ? false : settings.invertY;
             this.invertY = (settings.invertY == null) ? false : settings.invertY;
             this.alignToPixel = (settings.alignToPixel == null) ? true : settings.alignToPixel;
             this.alignToPixel = (settings.alignToPixel == null) ? true : settings.alignToPixel;
@@ -552,7 +541,6 @@
         private _spriteFrame: number;
         private _spriteFrame: number;
         private _scale9: Vector4;
         private _scale9: Vector4;
         private _invertY: boolean;
         private _invertY: boolean;
-        private _alignToPixel: boolean;
     }
     }
 
 
     export class Sprite2DInstanceData extends InstanceDataBase {
     export class Sprite2DInstanceData extends InstanceDataBase {

A diferenza do arquivo foi suprimida porque é demasiado grande
+ 38 - 14
canvas2D/src/Engine/babylon.text2d.ts


+ 0 - 13
canvas2D/src/Engine/babylon.wireFrame2d.ts

@@ -406,11 +406,6 @@
             if (!super.refreshInstanceDataPart(part)) {
             if (!super.refreshInstanceDataPart(part)) {
                 return false;
                 return false;
             }
             }
-
-            if (part.id === WireFrame2D.WIREFRAME2D_MAINPARTID) {
-                let d = <WireFrame2DInstanceData>this._instanceDataParts[0];
-                d.properties = new Vector3(this.alignToPixel ? 1 : 0, 2/this.renderGroup.actualWidth, 2/this.renderGroup.actualHeight);
-            }
             return true;
             return true;
         }
         }
 
 
@@ -452,13 +447,5 @@
         constructor(partId: number) {
         constructor(partId: number) {
             super(partId, 1);
             super(partId, 1);
         }
         }
-
-        // the properties is for now the alignedToPixel value
-        @instanceData()
-        get properties(): Vector3 {
-            return null;
-        }
-        set properties(value: Vector3) {
-        }
     }
     }
 }
 }

+ 249 - 0
canvas2D/src/Tools/babylon.c2dlogging.ts

@@ -0,0 +1,249 @@
+module BABYLON {
+    // logging stuffs
+    export class C2DLogging {
+        // Set to true to temporary disable logging.
+        public static snooze = true;
+        public static logFrameRender(frameCount: number) {
+            C2DLogging.snooze = true;
+            C2DLogging._logFramesCount = frameCount;
+        }
+        public static setPostMessage(message: () => string) {
+            if (C2DLoggingInternals.enableLog) {
+                C2DLoggingInternals.postMessages[C2DLoggingInternals.callDepth-1] = message();
+            }
+        }
+
+        public static _startFrameRender() {
+            if (C2DLogging._logFramesCount === 0) {
+                return;
+            }
+            C2DLogging.snooze = false;
+        }
+
+        public static _endFrameRender() {
+            if (C2DLogging._logFramesCount === 0) {
+                return;
+            }
+            C2DLogging.snooze = true;
+            --C2DLogging._logFramesCount;
+        }
+
+        private static _logFramesCount = 0;
+    }
+
+    class C2DLoggingInternals {
+        //-------------FLAG TO CHANGE TO ENABLE/DISABLE LOGGING ACTIVATION--------------
+        // This flag can't be changed at runtime you must manually change it in the code
+        public static enableLog = false;
+
+        public static callDepth = 0;
+
+        public static depths = [
+            "|-", "|--", "|---", "|----", "|-----", "|------", "|-------", "|--------", "|---------", "|----------",
+            "|-----------", "|------------", "|-------------", "|--------------", "|---------------", "|----------------", "|-----------------", "|------------------", "|-------------------", "|--------------------"
+        ];
+        public static postMessages = [];
+
+        public static computeIndent(): string {
+            // Compute the indent
+            let indent: string = null;
+            if (C2DLoggingInternals.callDepth < 20) {
+                indent = C2DLoggingInternals.depths[C2DLoggingInternals.callDepth];
+            } else {
+                indent = "|";
+                for (let i = 0; i <= C2DLoggingInternals.callDepth; i++) {
+                    indent = indent + "-";
+                }
+            }
+            return indent;
+        }
+
+        public static getFormattedValue(a): string {
+            if (a instanceof Prim2DBase) {
+                return a.id;
+            }
+            if (a == null) {
+                return "[null]";
+            }
+            return a.toString();
+        }
+    }
+
+    export function logProp<T>(message: string = "", alsoGet = false, setNoProlog=false, getNoProlog=false): (target: Object, propName: string | symbol, descriptor: TypedPropertyDescriptor<T>) => void {
+        return (target: Object, propName: string | symbol, descriptor: TypedPropertyDescriptor<T>) => {
+            if (!C2DLoggingInternals.enableLog) {
+                return descriptor;
+            }
+
+            let getter = descriptor.get, setter = descriptor.set;
+
+            if (getter && alsoGet) {
+                descriptor.get = function (): T {
+                    if (C2DLogging.snooze) {
+                        return getter.call(this);
+                    } else {
+                        let indent = C2DLoggingInternals.computeIndent();
+                        let id = this.id || "";
+
+                        if (message !== null && message !== "") {
+                            console.log(message);
+                        }
+
+                        let isSPP = this instanceof SmartPropertyPrim;
+                        let flags = isSPP ? this._flags : 0;
+                        let depth = C2DLoggingInternals.callDepth;
+                        if (!getNoProlog) {
+                            console.log(`${indent} [${id}] (${depth}) ==> get ${propName} property`);
+                        }
+                        ++C2DLoggingInternals.callDepth;
+                        C2DLogging.setPostMessage(() => "[no msg]");
+
+                        // Call the initial getter
+                        let r = getter.call(this);
+
+                        --C2DLoggingInternals.callDepth;
+                        let flagsStr = "";
+                        if (isSPP) {
+                            let nflags = this._flags;
+                            let newFlags = this._getFlagsDebug((nflags & flags) ^ nflags);
+                            let removedFlags = this._getFlagsDebug((nflags & flags) ^ flags);
+                            flagsStr = "";
+                            if (newFlags !== "") {
+                                flagsStr = ` +++[${newFlags}]`;
+                            }
+                            if (removedFlags !== "") {
+                                if (flagsStr !== "") {
+                                    flagsStr += ",";
+                                }
+                                flagsStr += ` ---[${removedFlags}]`;
+                            }
+                        }
+                        console.log(`${indent} [${id}] (${depth})${getNoProlog ? "" : " <=="} get ${propName} property => ${C2DLoggingInternals.getFormattedValue(r)}${flagsStr}, ${C2DLoggingInternals.postMessages[C2DLoggingInternals.callDepth]}`);
+
+                        return r;
+                    }
+                }
+            }
+
+            // Overload the property setter implementation to add our own logic
+            if (setter) {
+                descriptor.set = function (val) {
+                    if (C2DLogging.snooze) {
+                        setter.call(this, val);
+                    } else {
+                        let indent = C2DLoggingInternals.computeIndent();
+                        let id = this.id || "";
+
+                        if (message !== null && message !== "") {
+                            console.log(message);
+                        }
+                        let isSPP = this instanceof SmartPropertyPrim;
+                        let flags = isSPP ? this._flags : 0;
+                        let depth = C2DLoggingInternals.callDepth;
+                        if (!setNoProlog) {
+                            console.log(`${indent} [${id}] (${depth}) ==> set ${propName} property with ${C2DLoggingInternals.getFormattedValue(val)}`);
+                        }
+                        ++C2DLoggingInternals.callDepth;
+                        C2DLogging.setPostMessage(() => "[no msg]");
+
+                        // Change the value
+                        setter.call(this, val);
+
+                        --C2DLoggingInternals.callDepth;
+                        let flagsStr = "";
+                        if (isSPP) {
+                            let nflags = this._flags;
+                            let newFlags = this._getFlagsDebug((nflags & flags) ^ nflags);
+                            let removedFlags = this._getFlagsDebug((nflags & flags) ^ flags);
+                            flagsStr = "";
+                            if (newFlags !== "") {
+                                flagsStr = ` +++[${newFlags}]`;
+                            }
+                            if (removedFlags !== "") {
+                                if (flagsStr !== "") {
+                                    flagsStr += ",";
+                                }
+                                flagsStr += ` ---[${removedFlags}]`;
+                            }
+                        }
+                        console.log(`${indent} [${id}] (${depth})${setNoProlog ? "" : " <=="} set ${propName} property, ${C2DLoggingInternals.postMessages[C2DLoggingInternals.callDepth]}${flagsStr}`);
+                    }
+                }
+            }
+
+            return descriptor;
+        }
+    }
+
+    export function logMethod(message: string = "", noProlog = false) {
+        return (target, key, descriptor) => {
+            if (!C2DLoggingInternals.enableLog) {
+                return descriptor;
+            }
+
+            if (descriptor === undefined) {
+                descriptor = Object.getOwnPropertyDescriptor(target, key);
+            }
+            var originalMethod = descriptor.value;
+
+            //editing the descriptor/value parameter
+            descriptor.value = function () {
+                var args = [];
+                for (var _i = 0; _i < arguments.length; _i++) {
+                    args[_i - 0] = arguments[_i];
+                }
+                if (C2DLogging.snooze) {
+                    return originalMethod.apply(this, args);
+                } else {
+                    var a = args.map(a => C2DLoggingInternals.getFormattedValue(a) + ", ").join();
+                    a = a.slice(0, a.length - 2);
+
+                    let indent = C2DLoggingInternals.computeIndent();
+                    let id = this.id || "";
+
+                    if (message !== null && message !== "") {
+                        console.log(message);
+                    }
+
+                    let isSPP = this instanceof SmartPropertyPrim;
+                    let flags = isSPP ? this._flags : 0;
+                    let depth = C2DLoggingInternals.callDepth;
+                    if (!noProlog) {
+                        console.log(`${indent} [${id}] (${depth}) ==> call: ${key} (${a})`);
+                    }
+                    ++C2DLoggingInternals.callDepth;
+                    C2DLogging.setPostMessage(() => "[no msg]");
+
+                    // Call the method!
+                    var result = originalMethod.apply(this, args);
+
+                    --C2DLoggingInternals.callDepth;
+                    let flagsStr = "";
+                    if (isSPP) {
+                        let nflags = this._flags;
+                        let newFlags = this._getFlagsDebug((nflags & flags) ^ nflags);
+                        let removedFlags = this._getFlagsDebug((nflags & flags) ^ flags);
+                        flagsStr = "";
+                        if (newFlags !== "") {
+                            flagsStr = ` +++[${newFlags}]`;
+                        }
+                        if (removedFlags !== "") {
+                            if (flagsStr !== "") {
+                                flagsStr += ",";
+                            }
+                            flagsStr += ` ---[${removedFlags}]`;
+                        }
+                    }
+                    console.log(`${indent} [${id}] (${depth})${noProlog ? "" : " <=="} call: ${key} (${a}) Res: ${C2DLoggingInternals.getFormattedValue(result)}, ${C2DLoggingInternals.postMessages[C2DLoggingInternals.callDepth]}${flagsStr}`);
+
+                    return result;
+                }
+            };
+
+            // return edited descriptor as opposed to overwriting the descriptor
+            return descriptor;
+        }
+        
+    }
+
+}

+ 160 - 432
canvas2D/src/Tools/babylon.math2D.ts

@@ -1,407 +1,152 @@
 module BABYLON {
 module BABYLON {
 
 
     /**
     /**
-     * This class stores the data to make 2D transformation using a Translation (tX, tY), a Scale (sX, sY) and a rotation around the Z axis (rZ).
-     * You can multiply two Transform2D object to produce the result of their concatenation.
-     * You can transform a given Point (a Vector2D instance) with a Transform2D object or with the Invert of the Transform2D object.
-     * There no need to compute/store the Invert of a Transform2D as the invertTranform methods are almost as fast as the transform ones.
-     * This class is as light as it could be and the transformation operations are pretty optimal.
-     */
-    export class Transform2D {
-        /**
-         * A 2D Vector representing the translation to the origin
-         */
-        public translation: Vector2;
-
-        /**
-         * A number (in radian) representing the rotation around the Z axis at the origin
-         */
-        public rotation: number;
-
-        /**
-         * A 2D Vector representing the scale to apply at the origin
-         */
-        public scale: Vector2;
+       * A class storing a Matrix2D for 2D transformations
+       * The stored matrix is a 3*3 Matrix2D
+       * I   [0,1]   [mX, mY]   R   [ CosZ, SinZ]  T    [ 0,  0]  S   [Sx,  0]
+       * D = [2,3] = [nX, nY]   O = [-SinZ, CosZ]  R =  [ 0,  0]  C = [ 0, Sy]
+       * X   [4,5]   [tX, tY]   T   [  0  ,  0  ]  N    [Tx, Ty]  L   [ 0,  0]
+       *
+       * IDX = index, zero based. ROT = Z axis Rotation. TRN = Translation. SCL = Scale.
+       */
+    export class Matrix2D {
 
 
-        constructor() {
-            this.translation = Vector2.Zero();
-            this.rotation = 0;
-            this.scale = new Vector2(1, 1);
+        public static Zero(): Matrix2D {
+            return new Matrix2D();
         }
         }
-
-        /**
-         * Set the Transform2D object with the given values
-         * @param translation The translation to set
-         * @param rotation The rotation (in radian) to set
-         * @param scale The scale to set
-         */
-        public set(translation: Vector2, rotation: number, scale: Vector2) {
-            this.translation.copyFrom(translation);
-            this.rotation = rotation;
-            this.scale.copyFrom(scale);
+        
+        public static FromValuesToRef(m0: number, m1: number, m2: number, m3: number, m4: number, m5: number, result: Matrix2D) {
+            result.m[0] = m0;   result.m[1] = m1;
+            result.m[2] = m2;   result.m[3] = m3;
+            result.m[4] = m4;   result.m[5] = m5;
         }
         }
 
 
-        /**
-         * Set the Transform2D object from float values
-         * @param transX The translation on X axis, nothing is set if not specified
-         * @param transY The translation on Y axis, nothing is set if not specified
-         * @param rotation The rotation in radian, nothing is set if not specified
-         * @param scaleX The scale along the X axis, nothing is set if not specified
-         * @param scaleY The scale along the Y axis, nothing is set if not specified
-         */
-        public setFromFloats(transX?: number, transY?: number, rotation?: number, scaleX?: number, scaleY?: number) {
-            if (transX) {
-                this.translation.x = transX;
-            }
-
-            if (transY) {
-                this.translation.y = transY;
-            }
-
-            if (rotation) {
-                this.rotation = rotation;
-            }
-
-            if (scaleX) {
-                this.scale.x = scaleX;
-            }
-
-            if (scaleY) {
-                this.scale.y = scaleY;
-            }
-        }
-
-        /**
-         * Return a copy of the object
-         */
-        public clone(): Transform2D {
-            let res = new Transform2D();
-            res.translation.copyFrom(this.translation);
-            res.rotation = this.rotation;
-            res.scale.copyFrom(this.scale);
-
-            return res;
+        public static FromMatrix(source: Matrix): Matrix2D {
+            let result = new Matrix2D();
+            Matrix2D.FromMatrixToRef(source, result);
+            return result;
         }
         }
 
 
-        /**
-         * Convert a given degree angle into its radian equivalent
-         * @param angleDegree the number to convert
-         */
-        public static ToRadian(angleDegree: number): number {
-            return angleDegree * Math.PI * 2 / 360;
+        public static FromMatrixToRef(source: Matrix, result: Matrix2D) {
+            result.m[0] = source.m[0];    result.m[1] = source.m[1];
+            result.m[2] = source.m[4];    result.m[3] = source.m[5];
+            result.m[4] = source.m[8];    result.m[5] = source.m[9];
         }
         }
 
 
-        /**
-         * Create a new instance and returns it
-         * @param translation The translation to store, default is (0,0)
-         * @param rotation The rotation to store, default is 0
-         * @param scale The scale to store, default is (1,1)
-         */
-        public static Make(translation?: Vector2, rotation?: number, scale?: Vector2): Transform2D {
-            let res = new Transform2D();
-            if (translation) {
-                res.translation.copyFrom(translation);
-            }
-            if (rotation) {
-                res.rotation = rotation;
-            }
-            if (scale) {
-                res.scale.copyFrom(scale);
-            }
+        public static Rotation(angle: number): Matrix2D {
+            var result = new Matrix2D();
 
 
-            return res;
-        }
+            Matrix2D.RotationToRef(angle, result);
 
 
-        /**
-         * Set the given Transform2D object with the given values
-         * @param translation The translation to store, default is (0,0)
-         * @param rotation The rotation to store, default is 0
-         * @param scale The scale to store, default is (1,1)
-         */
-        public static MakeToRef(res: Transform2D, translation?: Vector2, rotation?: number, scale?: Vector2) {
-            if (translation) {
-                res.translation.copyFrom(translation);
-            } else {
-                res.translation.copyFromFloats(0, 0);
-            }
-            if (rotation) {
-                res.rotation = rotation;
-            } else {
-                res.rotation = 0;
-            }
-            if (scale) {
-                res.scale.copyFrom(scale);
-            } else {
-                res.scale.copyFromFloats(1, 1);
-            }
+            return result;
         }
         }
 
 
-        /**
-         * Create a Transform2D object from float values
-         * @param transX The translation on X axis, 0 per default
-         * @param transY The translation on Y axis, 0 per default
-         * @param rotation The rotation in radian, 0 per default
-         * @param scaleX The scale along the X axis, 1 per default
-         * @param scaleY The scale along the Y axis, 1 per default
-         */
-        public static MakeFromFloats(transX?: number, transY?: number, rotation?: number, scaleX?: number, scaleY?: number): Transform2D {
-            let res = new Transform2D();
-
-            if (transX) {
-                res.translation.x = transX;
-            }
-
-            if (transY) {
-                res.translation.y = transY;
-            }
-
-            if (rotation) {
-                res.rotation = rotation;
-            }
-
-            if (scaleX) {
-                res.scale.x = scaleX;
-            }
-
-            if (scaleY) {
-                res.scale.y = scaleY;
-            }
+        public static RotationToRef(angle: number, result: Matrix2D): void {
+            var s = Math.sin(angle);
+            var c = Math.cos(angle);
 
 
-            return res;
+            result.m[0] = c;    result.m[1] = s;
+            result.m[2] = -s;   result.m[3] = c;
+            result.m[4] = 0;    result.m[5] = 0;
         }
         }
 
 
-        /**
-         * Set the given Transform2D object with the given float values
-         * @param transX The translation on X axis, 0 per default
-         * @param transY The translation on Y axis, 0 per default
-         * @param rotation The rotation in radian, 0 per default
-         * @param scaleX The scale along the X axis, 1 per default
-         * @param scaleY The scale along the Y axis, 1 per default
-         */
-        public static MakeFromFloatsToRef(res: Transform2D, transX?: number, transY?: number, rotation?: number, scaleX?: number, scaleY?: number) {
-            res.translation.x = (transX!=null)   ? transX   : 0;
-            res.translation.y = (transY!=null)   ? transY   : 0;
-            res.rotation      = (rotation!=null) ? rotation : 0;
-            res.scale.x       = (scaleX!=null)   ? scaleX   : 1;
-            res.scale.y       = (scaleY!=null)   ? scaleY   : 1;
-        }
+        public static Translation(x: number, y: number): Matrix2D {
+            var result = new Matrix2D();
 
 
-        /**
-         * Create a Transform2D containing only Zeroed values
-         */
-        public static Zero(): Transform2D {
-            let res = new Transform2D();
-            res.scale.copyFromFloats(0, 0);
-            return res;
-        }
+            Matrix2D.TranslationToRef(x, y, result);
 
 
-        /**
-         * Copy the value of the other object into 'this'
-         * @param other The other object to copy values from
-         */
-        public copyFrom(other: Transform2D) {
-            this.translation.copyFrom(other.translation);
-            this.rotation = other.rotation;
-            this.scale.copyFrom(other.scale);
+            return result;
         }
         }
 
 
-        public toMatrix2D(): Matrix2D {
-            let res = new Matrix2D();
-            this.toMatrix2DToRef(res);
-            return res;
+        public static TranslationToRef(x: number, y: number, result: Matrix2D): void {
+            result.m[0] = 1;    result.m[1] = 0;
+            result.m[2] = 0;    result.m[3] = 1;
+            result.m[4] = x;    result.m[5] = y;
         }
         }
 
 
-        public toMatrix2DToRef(res: Matrix2D) {
-            let tx = this.translation.x;
-            let ty = this.translation.y;
-            let r = this.rotation;
-            let cosr = Math.cos(r);
-            let sinr = Math.sin(r);
-            let sx = this.scale.x;
-            let sy = this.scale.y;
+        public static Scaling(x: number, y: number): Matrix2D {
+            var result = new Matrix2D();
 
 
-            res.m[0] = cosr * sx;   res.m[1] = sinr * sy;
-            res.m[2] = -sinr* sx;   res.m[3] = cosr * sy;
-            res.m[4] = tx;          res.m[5] = ty;
-        }
+            Matrix2D.ScalingToRef(x, y, result);
 
 
-        /**
-         * In place transformation from a parent matrix.
-         * @param parent transform object. "this" will be the result of parent * this
-         */
-        public multiplyToThis(parent: Transform2D) {
-            this.multiplyToRef(parent, this);
-        }
-
-        /**
-         * Transform this object with a parent and return the result. Result = parent * this
-         * @param parent The parent transformation
-         */
-        public multiply(parent: Transform2D): Transform2D {
-            let res = new Transform2D();
-            this.multiplyToRef(parent, res);
-            return res;
+            return result;
         }
         }
 
 
-        /**
-         * Transform a point and store the result in the very same object
-         * @param p Transform this point and change the values with the transformed ones
-         */
-        public transformPointInPlace(p: Vector2) {
-            this.transformPointToRef(p, p);
+        public static ScalingToRef(x: number, y: number, result: Matrix2D): void {
+            result.m[0] = x;    result.m[1] = 0;
+            result.m[2] = 0;    result.m[3] = y;
+            result.m[4] = 0;    result.m[5] = 0;
         }
         }
 
 
-        /**
-         * Transform a point and store the result into a reference object
-         * @param p The point to transform
-         * @param res Will contain the new transformed coordinates. Can be the object of 'p'.
-         */
-        public transformPointToRef(p: Vector2, res: Vector2) {
-            this.transformFloatsToRef(p.x, p.y, res);
-        }
+        public m = new Float32Array(6);
 
 
-        /**
-         * Transform this object with a parent and store the result in reference object
-         * @param parent The parent transformation
-         * @param result Will contain parent * this. Can be the object of either parent or 'this'
-         */
-        public multiplyToRef(parent: Transform2D, result: Transform2D) {
-            if (!parent || !result) {
-                throw new Error("Valid parent and result objects must be specified");
-            }
-            let tx = this.translation.x;
-            let ty = this.translation.y;
-            let ptx = parent.translation.x;
-            let pty = parent.translation.y;
-            let pr = parent.rotation;
-            let psx = parent.scale.x;
-            let psy = parent.scale.y;
-            let cosr = Math.cos(pr);
-            let sinr = Math.sin(pr);
-            result.translation.x = (((tx * cosr) - (ty * sinr)) * psx) + ptx;
-            result.translation.y = (((tx * sinr) + (ty * cosr)) * psy) + pty;
-            this.scale.multiplyToRef(parent.scale, result.scale);
-            result.rotation = this.rotation;
+        public static Identity(): Matrix2D {
+            let res = new Matrix2D();
+            Matrix2D.IdentityToRef(res);
+            return res;
         }
         }
 
 
-        /**
-         * Transform the given coordinates and store the result in a Vector2 object
-         * @param x The X coordinate to transform
-         * @param y The Y coordinate to transform
-         * @param res The Vector2 object that will contain the result of the transformation
-         */
-        public transformFloatsToRef(x: number, y: number, res: Vector2) {
-            let tx = this.translation.x;
-            let ty = this.translation.y;
-            let pr = this.rotation;
-            let sx = this.scale.x;
-            let sy = this.scale.y;
-            let cosr = Math.cos(pr);
-            let sinr = Math.sin(pr);
-            res.x = (((x * cosr) - (y * sinr)) * sx) + tx;
-            res.y = (((x * sinr) + (y * cosr)) * sy) + ty;
+        public static IdentityToRef(res: Matrix2D) {
+            res.m[1] = res.m[2] = res.m[4] = res[5] = 0;
+            res.m[0] = res.m[3] = 1;
         }
         }
 
 
-        /**
-         * Invert transform the given coordinates and store the result in a reference object. res = invert(this) * (x,y)
-         * @param p Transform this point and change the values with the transformed ones
-         * @param res Will contain the result of the invert transformation.
-         */
-        public invertTransformFloatsToRef(x: number, y: number, res: Vector2) {
-            let px = x - this.translation.x;
-            let py = y - this.translation.y;
-
-            let pr = -this.rotation;
-            let sx = this.scale.x;
-            let sy = this.scale.y;
-            let psx = (sx===1) ? 1 : (1/sx);
-            let psy = (sy===1) ? 1 : (1/sy);
-            let cosr = Math.cos(pr);
-            let sinr = Math.sin(pr);
-            res.x = (((px * cosr) - (py * sinr)) * psx);
-            res.y = (((px * sinr) + (py * cosr)) * psy);
+        public static FromQuaternion(quaternion: Quaternion): Matrix2D {
+            let result = new Matrix2D();
+            Matrix2D.FromQuaternionToRef(quaternion, result);
+            return result;
         }
         }
 
 
-        /**
-         * Transform a point and return the result
-         * @param p the point to transform
-         */
-        public transformPoint(p: Vector2): Vector2 {
-            let res = Vector2.Zero();
-            this.transformPointToRef(p, res);
-            return res;
-        }
+        public static FromQuaternionToRef(quaternion: Quaternion, result: Matrix2D) {
+            var xx = quaternion.x * quaternion.x;
+            var yy = quaternion.y * quaternion.y;
+            var zz = quaternion.z * quaternion.z;
+            var xy = quaternion.x * quaternion.y;
+            var zw = quaternion.z * quaternion.w;
+            //var zx = quaternion.z * quaternion.x;
+            //var yw = quaternion.y * quaternion.w;
+            //var yz = quaternion.y * quaternion.z;
+            //var xw = quaternion.x * quaternion.w;
 
 
-        /**
-         * Transform the given coordinates and return the result in a Vector2 object
-         * @param x The X coordinate to transform
-         * @param y The Y coordinate to transform
-         */
-        public transformFloats(x: number, y: number): Vector2 {
-            let res = Vector2.Zero();
-            this.transformFloatsToRef(x, y, res);
-            return res;
+            result.m[0] = 1.0 - (2.0 * (yy + zz));
+            result.m[1] = 2.0 * (xy + zw);
+            //result.m[2] = 2.0 * (zx - yw);
+            //result.m[3] = 0;
+            result.m[2] = 2.0 * (xy - zw);
+            result.m[3] = 1.0 - (2.0 * (zz + xx));
+            //result.m[6] = 2.0 * (yz + xw);
+            //result.m[7] = 0;
+            //result.m[8] = 2.0 * (zx + yw);
+            //result.m[9] = 2.0 * (yz - xw);
+            //result.m[10] = 1.0 - (2.0 * (yy + xx));
+            //result.m[11] = 0;
+            //result.m[12] = 0;
+            //result.m[13] = 0;
+            //result.m[14] = 0;
+            //result.m[15] = 1.0;
         }
         }
 
 
-        /**
-         * Invert transform a given point and store the result in the very same object. p = invert(this) * p
-         * @param p Transform this point and change the values with the transformed ones
-         */
-        public invertTransformPointInPlace(p: Vector2) {
-            this.invertTransformPointToRef(p, p);
-        }
+        public static Compose(scale: Vector2, rotation: number, translation: Vector2): Matrix2D {
+            var result = Matrix2D.Scaling(scale.x, scale.y);
 
 
-        /**
-         * Invert transform a given point and store the result in a reference object. res = invert(this) * p
-         * @param p Transform this point and change the values with the transformed ones
-         * @param res Will contain the result of the invert transformation. 'res' can be the same object as 'p'
-         */
-        public invertTransformPointToRef(p: Vector2, res: Vector2) {
-            this.invertTransformFloatsToRef(p.x, p.y, res);
-        }
+            var rotationMatrix = Matrix2D.Rotation(rotation);
+            result = result.multiply(rotationMatrix);
 
 
-        /**
-         * Invert transform a given point and return the result. return = invert(this) * p
-         * @param p The Point to transform
-         */
-        public invertTransformPoint(p: Vector2): Vector2 {
-            let res = Vector2.Zero();
-            this.invertTransformPointToRef(p, res);
-            return res;
-        }
+            result.setTranslation(translation);
 
 
-        /**
-         * Invert transform the given coordinates and return the result. return = invert(this) * (x,y)
-         * @param x The X coordinate to transform
-         * @param y The Y coordinate to transform
-         */
-        public invertTransformFloats(x: number, y: number): Vector2 {
-            let res = Vector2.Zero();
-            this.invertTransformFloatsToRef(x, y, res);
-            return res;
+            return result;
         }
         }
-    }
 
 
-    /**
-     * A class storing a Matrix for 2D transformations
-     * The stored matrix is a 2*3 Matrix
-     * I   [0,1]   [mX, mY]   R   [ CosZ, SinZ]  T    [ 0,  0]  S   [Sx,  0]
-     * D = [2,3] = [nX, nY]   O = [-SinZ, CosZ]  R =  [ 0,  0]  C = [ 0, Sy]
-     * X   [4,5]   [tX, tY]   T   [  0  ,  0  ]  N    [Tx, Ty]  L   [ 0,  0]
-     *
-     * IDX = index, zero based. ROT = Z axis Rotation. TRN = Translation. SCL = Scale.
-     */
-    export class Matrix2D {
-
-        public static Identity(): Matrix2D {
-            let res = new Matrix2D();
-            Matrix2D.IdentityToRef(res);
-            return res;
+        public static Invert(source: Matrix2D): Matrix2D {
+            let result = new Matrix2D();
+            source.invertToRef(result);
+            return result;
         }
         }
 
 
-        public static IdentityToRef(res: Matrix2D) {
-            res.m[1] = res.m[2] = res.m[4] = res.m[5] = 0;
-            res.m[0] = res.m[3] = 1;           
+        public clone(): Matrix2D {
+            let result = new Matrix2D();
+            result.copyFrom(this);
+            return result;
         }
         }
 
 
         public copyFrom(other: Matrix2D) {
         public copyFrom(other: Matrix2D) {
@@ -410,8 +155,17 @@
             }
             }
         }
         }
 
 
+        public getTranslation(): Vector2 {
+            return new Vector2(this.m[4], this.m[5]);
+        }
+
+        public setTranslation(translation: Vector2) {
+            this.m[4] = translation.x;
+            this.m[5] = translation.y;
+        }
+
         public determinant(): number {
         public determinant(): number {
-            return (this.m[0] * this.m[3]) - (this.m[1] * this.m[2]);
+            return this.m[0] * this.m[3] - this.m[1] * this.m[2];
         }
         }
 
 
         public invertToThis() {
         public invertToThis() {
@@ -424,26 +178,25 @@
             return res;
             return res;
         }
         }
 
 
+        // http://mathworld.wolfram.com/MatrixInverse.html
         public invertToRef(res: Matrix2D) {
         public invertToRef(res: Matrix2D) {
-            let a00 = this.m[0], a01 = this.m[1],
-                a10 = this.m[2], a11 = this.m[3],
-                a20 = this.m[4], a21 = this.m[5];
+            let l0 = this.m[0]; let l1 = this.m[1];
+            let l2 = this.m[2]; let l3 = this.m[3];
+            let l4 = this.m[4]; let l5 = this.m[5];
 
 
-            let det21 = a21 * a10 - a11 * a20;
-
-            let det = (a00 * a11) - (a01 * a10);
-            if (det < (Epsilon*Epsilon)) {
+            let det = this.determinant();
+            if (det < (Epsilon * Epsilon)) {
                 throw new Error("Can't invert matrix, near null determinant");
                 throw new Error("Can't invert matrix, near null determinant");
             }
             }
 
 
-            det = 1 / det;
+            let detDiv = 1 / det;
+
+            let det4 = l2 * l5 - l3 * l4;
+            let det5 = l1 * l4 - l0 * l5;
 
 
-            res.m[0] = a11 * det;
-            res.m[1] = -a01 * det;
-            res.m[2] = -a10 * det;
-            res.m[3] = a00 * det;
-            res.m[4] = det21 * det;
-            res.m[5] = (-a21 * a00 + a01 * a20) * det;
+            res.m[0] = l3 * detDiv;     res.m[1] = -l1 * detDiv;
+            res.m[2] = -l2 * detDiv;    res.m[3] = l0 * detDiv;
+            res.m[4] = det4 * detDiv;   res.m[5] = det5 * detDiv;
         }
         }
 
 
         public multiplyToThis(other: Matrix2D) {
         public multiplyToThis(other: Matrix2D) {
@@ -457,59 +210,17 @@
         }
         }
 
 
         public multiplyToRef(other: Matrix2D, result: Matrix2D) {
         public multiplyToRef(other: Matrix2D, result: Matrix2D) {
-            var tm0 = this.m[0];
-            var tm1 = this.m[1];
-            //var tm2 = this.m[2];
-            //var tm3 = this.m[3];
-            var tm4 = this.m[2];
-            var tm5 = this.m[3];
-            //var tm6 = this.m[6];
-            //var tm7 = this.m[7];
-            var tm8 = this.m[4];
-            var tm9 = this.m[5];
-            //var tm10 = this.m[10];
-            //var tm11 = this.m[11];
-            //var tm12 = this.m[12];
-            //var tm13 = this.m[13];
-            //var tm14 = this.m[14];
-            //var tm15 = this.m[15];
-
-            var om0 = other.m[0];
-            var om1 = other.m[1];
-            //var om2 = other.m[2];
-            //var om3 = other.m[3];
-            var om4 = other.m[2];
-            var om5 = other.m[3];
-            //var om6 = other.m[6];
-            //var om7 = other.m[7];
-            var om8 = other.m[4];
-            var om9 = other.m[5];
-            //var om10 = other.m[10];
-            //var om11 = other.m[11];
-            //var om12 = other.m[12];
-            //var om13 = other.m[13];
-            //var om14 = other.m[14];
-            //var om15 = other.m[15];
-
-            result.m[0] = tm0 * om0 + tm1 * om4;
-            result.m[1] = tm0 * om1 + tm1 * om5;
-            //result.m[2] = tm0 * om2 + tm1 * om6 + tm2 * om10 + tm3 * om14;
-            //result.m[3] = tm0 * om3 + tm1 * om7 + tm2 * om11 + tm3 * om15;
-
-            result.m[2] = tm4 * om0 + tm5 * om4;
-            result.m[3] = tm4 * om1 + tm5 * om5;
-            //result.m[6] = tm4 * om2 + tm5 * om6 + tm6 * om10 + tm7 * om14;
-            //result.m[7] = tm4 * om3 + tm5 * om7 + tm6 * om11 + tm7 * om15;
-
-            result.m[4] = tm8 * om0 + tm9 * om4 + om8;
-            result.m[5] = tm8 * om1 + tm9 * om5 + om9;
-            //result.m[10] = tm8 * om2 + tm9 * om6 + tm10 * om10 + tm11 * om14;
-            //result.m[11] = tm8 * om3 + tm9 * om7 + tm10 * om11 + tm11 * om15;
-
-            //result.m[12] = tm12 * om0 + tm13 * om4 + tm14 * om8 + tm15 * om12;
-            //result.m[13] = tm12 * om1 + tm13 * om5 + tm14 * om9 + tm15 * om13;
-            //result.m[14] = tm12 * om2 + tm13 * om6 + tm14 * om10 + tm15 * om14;
-            //result.m[15] = tm12 * om3 + tm13 * om7 + tm14 * om11 + tm15 * om15;
+            let l0 = this.m[0];     let l1 = this.m[1];
+            let l2 = this.m[2];     let l3 = this.m[3];
+            let l4 = this.m[4];     let l5 = this.m[5];
+
+            let r0 = other.m[0];    let r1 = other.m[1];
+            let r2 = other.m[2];    let r3 = other.m[3];
+            let r4 = other.m[4];    let r5 = other.m[5];
+
+            result.m[0] = l0 * r0 + l1 * r2;        result.m[1] = l0 * r1 + l1 * r3;
+            result.m[2] = l2 * r0 + l3 * r2;        result.m[3] = l2 * r1 + l3 * r3;
+            result.m[4] = l4 * r0 + l5 * r2 + r4;   result.m[5] = l4 * r1 + l5 * r3 + r5;
         }
         }
 
 
         public transformFloats(x: number, y: number): Vector2 {
         public transformFloats(x: number, y: number): Vector2 {
@@ -533,7 +244,21 @@
             this.transformFloatsToRef(p.x, p.y, r);
             this.transformFloatsToRef(p.x, p.y, r);
         }
         }
 
 
-        public m = new Float32Array(6);
+        private static _decomp: Matrix2D = new Matrix2D();
+
+        public decompose(scale: Vector2, translation: Vector2): number {
+            translation.x = this.m[4];
+            translation.y = this.m[5];
+
+            scale.x = Math.sqrt(this.m[0] * this.m[0] + this.m[1] * this.m[1]);
+            scale.y = Math.sqrt(this.m[2] * this.m[2] + this.m[3] * this.m[3]);
+
+            if (scale.x === 0 || scale.y === 0) {
+                return null;
+            }
+
+            return Math.atan2(-this.m[2] / scale.y, this.m[0] / scale.x);
+        }
     }
     }
 
 
     /**
     /**
@@ -579,10 +304,13 @@
             this._updateCenterRadius();
             this._updateCenterRadius();
         }
         }
 
 
-        public transformInPlace(transform: Matrix) {
-            Vector2.TransformToRef(this.a, transform, this.a);
-            Vector2.TransformToRef(this.b, transform, this.b);
-            Vector2.TransformToRef(this.c, transform, this.c);
+        public transformInPlace(transform: Matrix2D) {
+            transform.transformPointToRef(this.a, this.a);
+            transform.transformPointToRef(this.b, this.b);
+            transform.transformPointToRef(this.c, this.c);
+            //Vector2.TransformToRef(this.a, transform, this.a);
+            //Vector2.TransformToRef(this.b, transform, this.b);
+            //Vector2.TransformToRef(this.c, transform, this.c);
 
 
             this._updateCenterRadius();
             this._updateCenterRadius();
         }
         }
@@ -686,7 +414,7 @@
          * @param tri2dInfo The triangle to transform
          * @param tri2dInfo The triangle to transform
          * @param transform The transformation matrix
          * @param transform The transformation matrix
          */
          */
-        public transformAndStoreToTri2DInfo(index: number, tri2dInfo: Tri2DInfo, transform: Matrix) {
+        public transformAndStoreToTri2DInfo(index: number, tri2dInfo: Tri2DInfo, transform: Matrix2D) {
             if (index >= this._count) {
             if (index >= this._count) {
                 throw new Error(`Can't fetch the triangle at index ${index}, max index is ${this._count - 1}`);
                 throw new Error(`Can't fetch the triangle at index ${index}, max index is ${this._count - 1}`);
             }
             }
@@ -735,7 +463,7 @@
          * @param setB The second set of triangles
          * @param setB The second set of triangles
          * @param bToATransform The transformation matrix to transform the setB triangles into the frame of reference of the setA
          * @param bToATransform The transformation matrix to transform the setB triangles into the frame of reference of the setA
          */
          */
-        public static doesIntersect(setA: Tri2DArray, setB: Tri2DArray, bToATransform: Matrix): boolean {
+        public static doesIntersect(setA: Tri2DArray, setB: Tri2DArray, bToATransform: Matrix2D): boolean {
             Tri2DArray._checkInitStatics();
             Tri2DArray._checkInitStatics();
 
 
             let a = Tri2DArray.tempT[0];
             let a = Tri2DArray.tempT[0];

+ 14 - 1
canvas2D/src/shaders/ellipse2d.vertex.fx

@@ -9,6 +9,7 @@ attribute float index;
 att vec2 zBias;
 att vec2 zBias;
 att vec4 transformX;
 att vec4 transformX;
 att vec4 transformY;
 att vec4 transformY;
+att vec3 renderingInfo;
 att float opacity;
 att float opacity;
 
 
 #ifdef Border
 #ifdef Border
@@ -104,6 +105,18 @@ void main(void) {
 	pos.xy = pos2.xy * properties.xy;
 	pos.xy = pos2.xy * properties.xy;
 	pos.z = 1.0;
 	pos.z = 1.0;
 	pos.w = 1.0;
 	pos.w = 1.0;
-	gl_Position = vec4(dot(pos, transformX), dot(pos, transformY), zBias.x, 1);
 
 
+	float x = dot(pos, transformX);
+	float y = dot(pos, transformY);
+	if (renderingInfo.z == 1.0) {
+		float rw = renderingInfo.x;
+		float rh = renderingInfo.y;
+		float irw = 2.0 / rw;
+		float irh = 2.0 / rh;
+
+		x = (floor((x / irw) + 0.5) * irw) + irw / 2.0;
+		y = (floor((y / irh) + 0.5) * irh) + irh / 2.0;
+	}
+
+	gl_Position = vec4(x, y, zBias.x, 1);
 }
 }

+ 14 - 1
canvas2D/src/shaders/lines2d.vertex.fx

@@ -9,6 +9,7 @@ attribute vec2 position;
 att vec2 zBias;
 att vec2 zBias;
 att vec4 transformX;
 att vec4 transformX;
 att vec4 transformY;
 att vec4 transformY;
+att vec3 renderingInfo;
 att float opacity;
 att float opacity;
 
 
 #ifdef FillSolid
 #ifdef FillSolid
@@ -64,6 +65,18 @@ void main(void) {
 	pos.xy = position.xy;
 	pos.xy = position.xy;
 	pos.z = 1.0;
 	pos.z = 1.0;
 	pos.w = 1.0;
 	pos.w = 1.0;
-	gl_Position = vec4(dot(pos, transformX), dot(pos, transformY), zBias.x, 1);
+	
+	float x = dot(pos, transformX);
+	float y = dot(pos, transformY);
+	if (renderingInfo.z == 1.0) {
+		float rw = renderingInfo.x;
+		float rh = renderingInfo.y;
+		float irw = 2.0 / rw;
+		float irh = 2.0 / rh;
 
 
+		x = (floor((x / irw) + 0.5) * irw) + irw / 2.0;
+		y = (floor((y / irh) + 0.5) * irh) + irh / 2.0;
+	}
+
+	gl_Position = vec4(x, y, zBias.x, 1);
 }
 }

+ 14 - 1
canvas2D/src/shaders/rect2d.vertex.fx

@@ -9,6 +9,7 @@ attribute float index;
 att vec2 zBias;
 att vec2 zBias;
 att vec4 transformX;
 att vec4 transformX;
 att vec4 transformY;
 att vec4 transformY;
+att vec3 renderingInfo;
 att float opacity;
 att float opacity;
 
 
 #ifdef Border
 #ifdef Border
@@ -202,6 +203,18 @@ void main(void) {
 	pos.xy = pos2.xy * properties.xy;
 	pos.xy = pos2.xy * properties.xy;
 	pos.z = 1.0;
 	pos.z = 1.0;
 	pos.w = 1.0;
 	pos.w = 1.0;
-	gl_Position = vec4(dot(pos, transformX), dot(pos, transformY), zBias.x, 1);
 
 
+	float x = dot(pos, transformX);
+	float y = dot(pos, transformY);
+	if (renderingInfo.z == 1.0) {
+		float rw = renderingInfo.x;
+		float rh = renderingInfo.y;
+		float irw = 2.0 / rw;
+		float irh = 2.0 / rh;
+
+		x = (floor((x / irw) + 0.5) * irw) + irw / 2.0;
+		y = (floor((y / irh) + 0.5) * irh) + irh / 2.0;
+	}
+
+	gl_Position = vec4(x, y, zBias.x, 1);
 }
 }

+ 17 - 3
canvas2D/src/shaders/sprite2d.vertex.fx

@@ -1,4 +1,4 @@
-// based on if Instanced Array are supported or not, declare the field either as attribute or uniform
+//based on if Instanced Array are supported or not, declare the field either as attribute or uniform
 #ifdef Instanced
 #ifdef Instanced
 #define att attribute
 #define att attribute
 #else
 #else
@@ -25,6 +25,7 @@ att vec4 scale9;
 att vec2 zBias;
 att vec2 zBias;
 att vec4 transformX;
 att vec4 transformX;
 att vec4 transformY;
 att vec4 transformY;
+att vec3 renderingInfo;
 att float opacity;
 att float opacity;
 
 
 // Uniforms
 // Uniforms
@@ -92,7 +93,7 @@ void main(void) {
 	}
 	}
 	else {
 	else {
 		vTopLeftUV = topLeftUV;
 		vTopLeftUV = topLeftUV;
-		vBottomRightUV = vec2(topLeftUV.x, topLeftUV.y + sizeUV.y);
+		vBottomRightUV = vec2(topLeftUV.x + sizeUV.x, topLeftUV.y + sizeUV.y);
 		vScale9 = scale9;
 		vScale9 = scale9;
 	}
 	}
 	vScaleFactor = scaleFactor;
 	vScaleFactor = scaleFactor;
@@ -101,5 +102,18 @@ void main(void) {
 	vOpacity = opacity;
 	vOpacity = opacity;
 	pos.z = 1.0;
 	pos.z = 1.0;
 	pos.w = 1.0;
 	pos.w = 1.0;
-	gl_Position = vec4(dot(pos, transformX), dot(pos, transformY), zBias.x, 1);
+
+	float x = dot(pos, transformX);
+	float y = dot(pos, transformY);
+	if (renderingInfo.z == 1.0) {
+		float rw = renderingInfo.x;
+		float rh = renderingInfo.y;
+		float irw = 2.0 / rw;
+		float irh = 2.0 / rh;
+
+		x = floor((x / irw) + 0.5) * irw;
+		y = floor((y / irh) + 0.5) * irh;
+	}
+
+	gl_Position = vec4(x, y, zBias.x, 1);
 }	
 }	

+ 15 - 1
canvas2D/src/shaders/text2d.vertex.fx

@@ -11,6 +11,7 @@ att vec2 zBias;
 
 
 att vec4 transformX;
 att vec4 transformX;
 att vec4 transformY;
 att vec4 transformY;
+att vec3 renderingInfo;
 att float opacity;
 att float opacity;
 
 
 att vec2 topLeftUV;
 att vec2 topLeftUV;
@@ -60,5 +61,18 @@ void main(void) {
 	pos.xy = floor(pos2.xy * superSampleFactor * sizeUV * textureSize);	// Align on target pixel to avoid bad interpolation
 	pos.xy = floor(pos2.xy * superSampleFactor * sizeUV * textureSize);	// Align on target pixel to avoid bad interpolation
 	pos.z = 1.0;
 	pos.z = 1.0;
 	pos.w = 1.0;
 	pos.w = 1.0;
-	gl_Position = vec4(dot(pos, transformX), dot(pos, transformY), zBias.x, 1);
+
+	float x = dot(pos, transformX);
+	float y = dot(pos, transformY);
+	if (renderingInfo.z == 1.0) {
+		float rw = renderingInfo.x;
+		float rh = renderingInfo.y;
+		float irw = 2.0 / rw;
+		float irh = 2.0 / rh;
+
+		x = floor((x / irw) + 0.5) * irw;
+		y = floor((y / irh) + 0.5) * irh;
+	}
+
+	gl_Position = vec4(x, y, zBias.x, 1);
 }
 }

+ 13 - 6
canvas2D/src/shaders/wireframe2d.vertex.fx

@@ -18,6 +18,7 @@ att vec3 properties;
 att vec2 zBias;
 att vec2 zBias;
 att vec4 transformX;
 att vec4 transformX;
 att vec4 transformY;
 att vec4 transformY;
+att vec3 renderingInfo;
 att float opacity;
 att float opacity;
 
 
 // Uniforms
 // Uniforms
@@ -30,11 +31,17 @@ void main(void) {
 	vec4 p = vec4(pos.xy, 1.0, 1.0);
 	vec4 p = vec4(pos.xy, 1.0, 1.0);
 	vColor = vec4(col.xyz, col.w*opacity);
 	vColor = vec4(col.xyz, col.w*opacity);
 
 
-	vec4 pp = vec4(dot(p, transformX), dot(p, transformY), zBias.x, 1);
-	
-	if (properties.x == 1.0) {
-		pp.xy = pp.xy - mod(pp.xy, properties.yz) + (properties.yz*0.5);
+	float x = dot(p, transformX);
+	float y = dot(p, transformY);
+	if (renderingInfo.z == 1.0) {
+		float rw = renderingInfo.x;
+		float rh = renderingInfo.y;
+		float irw = 2.0 / rw;
+		float irh = 2.0 / rh;
+
+		x = (floor((x / irw) + 0.5) * irw) + irw/2.0;
+		y = (floor((y / irh) + 0.5) * irh) + irh/2.0;
 	}
 	}
 
 
-	gl_Position = pp;
-}	
+	gl_Position = vec4(x, y, zBias.x, 1);
+}

A diferenza do arquivo foi suprimida porque é demasiado grande
+ 22 - 22
dist/preview release/babylon.core.js


A diferenza do arquivo foi suprimida porque é demasiado grande
+ 4121 - 4036
dist/preview release/babylon.d.ts


A diferenza do arquivo foi suprimida porque é demasiado grande
+ 34 - 34
dist/preview release/babylon.js


A diferenza do arquivo foi suprimida porque é demasiado grande
+ 768 - 333
dist/preview release/babylon.max.js


A diferenza do arquivo foi suprimida porque é demasiado grande
+ 4121 - 4036
dist/preview release/babylon.module.d.ts


A diferenza do arquivo foi suprimida porque é demasiado grande
+ 36 - 36
dist/preview release/babylon.noworker.js


A diferenza do arquivo foi suprimida porque é demasiado grande
+ 140 - 252
dist/preview release/canvas2D/babylon.canvas2d.d.ts


A diferenza do arquivo foi suprimida porque é demasiado grande
+ 1274 - 1001
dist/preview release/canvas2D/babylon.canvas2d.js


A diferenza do arquivo foi suprimida porque é demasiado grande
+ 12 - 12
dist/preview release/canvas2D/babylon.canvas2d.min.js


+ 2 - 2
dist/preview release/inspector/babylon.inspector.bundle.js

@@ -65,8 +65,8 @@ var INSPECTOR =
 	if(false) {
 	if(false) {
 		// When the styles change, update the <style> tags
 		// When the styles change, update the <style> tags
 		if(!content.locals) {
 		if(!content.locals) {
-			module.hot.accept("!!./../../../Tools/Gulp/node_modules/css-loader/index.js!./babylon.inspector.css", function() {
-				var newContent = require("!!./../../../Tools/Gulp/node_modules/css-loader/index.js!./babylon.inspector.css");
+			module.hot.accept("!!../../../Tools/Gulp/node_modules/css-loader/index.js!./babylon.inspector.css", function() {
+				var newContent = require("!!../../../Tools/Gulp/node_modules/css-loader/index.js!./babylon.inspector.css");
 				if(typeof newContent === 'string') newContent = [[module.id, newContent, '']];
 				if(typeof newContent === 'string') newContent = [[module.id, newContent, '']];
 				update(newContent);
 				update(newContent);
 			});
 			});

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

@@ -13,6 +13,7 @@
  - New Facet Data feature ([jerome](https://github.com/jbousquie))
  - New Facet Data feature ([jerome](https://github.com/jbousquie))
  - babylon.fontTexture.ts was moved from babylon.js to canvas2D ([nockawa](https://github.com/nockawa))
  - babylon.fontTexture.ts was moved from babylon.js to canvas2D ([nockawa](https://github.com/nockawa))
  - Multi-platform Compressed Textures for Desktops & Mobile Devices with fall back.  Batch (dos) scripts to convert entire directories of .jpg's & .png's ([jcpalmer](https://github.com/Palmer-JC))
  - Multi-platform Compressed Textures for Desktops & Mobile Devices with fall back.  Batch (dos) scripts to convert entire directories of .jpg's & .png's ([jcpalmer](https://github.com/Palmer-JC))
+ - All deprecated functions and properties were removed ([deltakosh](https://github.com/deltakosh))
 
 
 ### Updates
 ### Updates
 - Added `Light.customProjectionMatrixBuilder` to allow developers to define their own projection matrix for shadows ([deltakosh](https://github.com/deltakosh))
 - Added `Light.customProjectionMatrixBuilder` to allow developers to define their own projection matrix for shadows ([deltakosh](https://github.com/deltakosh))
@@ -60,7 +61,6 @@
 - File `spotLight.ts` documented ([jerome](https://github.com/jbousquie))  
 - File `spotLight.ts` documented ([jerome](https://github.com/jbousquie))  
 - File `shadowGenerator.ts` documented ([jerome](https://github.com/jbousquie))  
 - File `shadowGenerator.ts` documented ([jerome](https://github.com/jbousquie))  
 
 
-
 ## Canvas2D
 ## Canvas2D
 
 
 ### Major Updates
 ### Major Updates

+ 70 - 36
src/Bones/babylon.boneLookController.ts

@@ -151,19 +151,18 @@ module BABYLON {
                     bone: Bone, 
                     bone: Bone, 
                     target: Vector3, 
                     target: Vector3, 
                     options?: {
                     options?: {
-                        adjustYaw?: number, 
-                        adjustPitch?: number, 
-                        adjustRoll?: number, 
-                        slerpAmount?: number, 
                         maxYaw?:number, 
                         maxYaw?:number, 
                         minYaw?:number, 
                         minYaw?:number, 
                         maxPitch?:number, 
                         maxPitch?:number, 
                         minPitch?:number,
                         minPitch?:number,
+                        slerpAmount?: number, 
                         upAxis?:Vector3,
                         upAxis?:Vector3,
                         upAxisSpace?:Space,
                         upAxisSpace?:Space,
                         yawAxis?:Vector3,
                         yawAxis?:Vector3,
                         pitchAxis?:Vector3,
                         pitchAxis?:Vector3,
-                        showSpaceAxes?:boolean
+                        adjustYaw?: number, 
+                        adjustPitch?: number, 
+                        adjustRoll?: number, 
                     }){
                     }){
 
 
             this.mesh = mesh;
             this.mesh = mesh;
@@ -302,16 +301,16 @@ module BABYLON {
 
 
             if(checkYaw || checkPitch){
             if(checkYaw || checkPitch){
 
 
-                var _tmpMat3 = BoneLookController._tmpMats[2];
-                var _tmpMat3Inv = BoneLookController._tmpMats[3];
+                var spaceMat = BoneLookController._tmpMats[2];
+                var spaceMatInv = BoneLookController._tmpMats[3];
 
 
                 if(this.upAxisSpace == Space.BONE && upAxis.y == 1){
                 if(this.upAxisSpace == Space.BONE && upAxis.y == 1){
 
 
-                    parentBone.getRotationMatrixToRef(Space.WORLD, this.mesh, _tmpMat3);
+                    parentBone.getRotationMatrixToRef(Space.WORLD, this.mesh, spaceMat);
                     
                     
                 }else if(this.upAxisSpace == Space.LOCAL && upAxis.y == 1 && !parentBone){
                 }else if(this.upAxisSpace == Space.LOCAL && upAxis.y == 1 && !parentBone){
 
 
-                    _tmpMat3.copyFrom(mesh.getWorldMatrix());
+                    spaceMat.copyFrom(mesh.getWorldMatrix());
 
 
                 }else{
                 }else{
 
 
@@ -332,17 +331,18 @@ module BABYLON {
                     rightAxis.normalize();
                     rightAxis.normalize();
                     var forwardAxis = Vector3.Cross(rightAxis, upAxis);
                     var forwardAxis = Vector3.Cross(rightAxis, upAxis);
 
 
-                    Matrix.FromXYZAxesToRef(rightAxis, upAxis, forwardAxis, _tmpMat3);
+                    Matrix.FromXYZAxesToRef(rightAxis, upAxis, forwardAxis, spaceMat);
                     
                     
                 }
                 }
 
 
-                _tmpMat3.invertToRef(_tmpMat3Inv);
+                spaceMat.invertToRef(spaceMatInv);
                 
                 
                 var xzlen:number;
                 var xzlen:number;
 
 
                 if(checkPitch){
                 if(checkPitch){
                     var localTarget = BoneLookController._tmpVecs[3];
                     var localTarget = BoneLookController._tmpVecs[3];
-                    Vector3.TransformCoordinatesToRef(target.subtract(bonePos), _tmpMat3Inv, localTarget);
+                    target.subtractToRef(bonePos, localTarget);
+                    Vector3.TransformCoordinatesToRef(localTarget, spaceMatInv, localTarget);
 
 
                     var xzlen = Math.sqrt(localTarget.x * localTarget.x + localTarget.z * localTarget.z);
                     var xzlen = Math.sqrt(localTarget.x * localTarget.x + localTarget.z * localTarget.z);
                     var pitch = Math.atan2(localTarget.y, xzlen);
                     var pitch = Math.atan2(localTarget.y, xzlen);
@@ -357,7 +357,7 @@ module BABYLON {
                     }
                     }
                     
                     
                     if(pitch != newPitch){
                     if(pitch != newPitch){
-                        Vector3.TransformCoordinatesToRef(localTarget, _tmpMat3, localTarget);
+                        Vector3.TransformCoordinatesToRef(localTarget, spaceMat, localTarget);
                         localTarget.addInPlace(bonePos);
                         localTarget.addInPlace(bonePos);
                         target = localTarget;
                         target = localTarget;
                     }
                     }
@@ -365,7 +365,8 @@ module BABYLON {
 
 
                 if(checkYaw){
                 if(checkYaw){
                     var localTarget = BoneLookController._tmpVecs[4];
                     var localTarget = BoneLookController._tmpVecs[4];
-                    Vector3.TransformCoordinatesToRef(target.subtract(bonePos), _tmpMat3Inv, localTarget);
+                    target.subtractToRef(bonePos, localTarget);
+                    Vector3.TransformCoordinatesToRef(localTarget, spaceMatInv, localTarget);
 
 
                     var yaw = Math.atan2(localTarget.x, localTarget.z);
                     var yaw = Math.atan2(localTarget.x, localTarget.z);
                     var newYaw = yaw;
                     var newYaw = yaw;
@@ -376,45 +377,57 @@ module BABYLON {
                             xzlen = Math.sqrt(localTarget.x * localTarget.x + localTarget.z * localTarget.z);
                             xzlen = Math.sqrt(localTarget.x * localTarget.x + localTarget.z * localTarget.z);
                         }
                         }
 
 
-                        if(yaw > this._maxYaw){
-                            localTarget.z = this._maxYawCos*xzlen;
-                            localTarget.x = this._maxYawSin*xzlen;
-                            newYaw = this._maxYaw;
-                        }else if(yaw < this._minYaw){
-                            localTarget.z = this._minYawCos*xzlen;
-                            localTarget.x = this._minYawSin*xzlen;
-                            newYaw = this._minYaw;
+                        if(this._yawRange > Math.PI){
+                            if (this._isAngleBetween(yaw, this._maxYaw, this._midYawConstraint)) {
+                                localTarget.z = this._maxYawCos * xzlen;
+                                localTarget.x = this._maxYawSin * xzlen;
+                                newYaw = this._maxYaw;
+                            }else if (this._isAngleBetween(yaw, this._midYawConstraint, this._minYaw)) {
+                                localTarget.z = this._minYawCos * xzlen;
+                                localTarget.x = this._minYawSin * xzlen;
+                                newYaw = this._minYaw;
+                            }
+                        }else{
+                            if (yaw > this._maxYaw) {
+                                localTarget.z = this._maxYawCos * xzlen;
+                                localTarget.x = this._maxYawSin * xzlen;
+                                newYaw = this._maxYaw;
+                            }else if (yaw < this._minYaw) {
+                                localTarget.z = this._minYawCos * xzlen;
+                                localTarget.x = this._minYawSin * xzlen;
+                                newYaw = this._minYaw;
+                            }
                         }
                         }
                     }
                     }
 
 
                     if(this._slerping && this._yawRange > Math.PI){
                     if(this._slerping && this._yawRange > Math.PI){
-                        //are we going to be crossing into the min/max region
-                        var _tmpVec8 = BoneLookController._tmpVecs[8];
-                        _tmpVec8.copyFrom(Axis.Z);
+                        //are we going to be crossing into the min/max region?
+                        var boneFwd = BoneLookController._tmpVecs[8];
+                        boneFwd.copyFrom(Axis.Z);
                         if (this._transformYawPitch) {
                         if (this._transformYawPitch) {
-                            Vector3.TransformCoordinatesToRef(_tmpVec8, this._transformYawPitchInv, _tmpVec8);
+                            Vector3.TransformCoordinatesToRef(boneFwd, this._transformYawPitchInv, boneFwd);
                         }
                         }
 
 
                         var boneRotMat = BABYLON.BoneLookController._tmpMats[4];
                         var boneRotMat = BABYLON.BoneLookController._tmpMats[4];
                         this._boneQuat.toRotationMatrix(boneRotMat);
                         this._boneQuat.toRotationMatrix(boneRotMat);
                         this.mesh.getWorldMatrix().multiplyToRef(boneRotMat, boneRotMat);
                         this.mesh.getWorldMatrix().multiplyToRef(boneRotMat, boneRotMat);
-                        BABYLON.Vector3.TransformCoordinatesToRef(_tmpVec8, boneRotMat, _tmpVec8);
-                        BABYLON.Vector3.TransformCoordinatesToRef(_tmpVec8, _tmpMat3Inv, _tmpVec8);
+                        BABYLON.Vector3.TransformCoordinatesToRef(boneFwd, boneRotMat, boneFwd);
+                        BABYLON.Vector3.TransformCoordinatesToRef(boneFwd, spaceMatInv, boneFwd);
 
 
-                        var boneYaw = Math.atan2(_tmpVec8.x, _tmpVec8.z);
-                        var ang1 = this._getAngleBetween(boneYaw, yaw);
-                        var ang2 = this._getAngleBetween(boneYaw, this._midYawConstraint);
+                        var boneYaw = Math.atan2(boneFwd.x, boneFwd.z);
+                        var angBtwTar = this._getAngleBetween(boneYaw, yaw);
+                        var angBtwMidYaw = this._getAngleBetween(boneYaw, this._midYawConstraint);
 
 
-                        if(ang1 > ang2){
+                        if(angBtwTar > angBtwMidYaw){
 
 
                             if (xzlen == null) {
                             if (xzlen == null) {
                                 xzlen = Math.sqrt(localTarget.x * localTarget.x + localTarget.z * localTarget.z);
                                 xzlen = Math.sqrt(localTarget.x * localTarget.x + localTarget.z * localTarget.z);
                             }
                             }
 
 
-                            var ang3 = this._getAngleBetween(boneYaw, this._maxYaw);
-                            var ang4 = this._getAngleBetween(boneYaw, this._minYaw);
+                            var angBtwMax = this._getAngleBetween(boneYaw, this._maxYaw);
+                            var angBtwMin = this._getAngleBetween(boneYaw, this._minYaw);
 
 
-                            if(ang4 < ang3){
+                            if(angBtwMin < angBtwMax){
                                 newYaw = boneYaw+Math.PI*.75;
                                 newYaw = boneYaw+Math.PI*.75;
                                 localTarget.z = Math.cos(newYaw) * xzlen;
                                 localTarget.z = Math.cos(newYaw) * xzlen;
                                 localTarget.x = Math.sin(newYaw) * xzlen;
                                 localTarget.x = Math.sin(newYaw) * xzlen;
@@ -427,7 +440,7 @@ module BABYLON {
                     }
                     }
 
 
                     if(yaw != newYaw){
                     if(yaw != newYaw){
-                        Vector3.TransformCoordinatesToRef(localTarget, _tmpMat3, localTarget);
+                        Vector3.TransformCoordinatesToRef(localTarget, spaceMat, localTarget);
                         localTarget.addInPlace(bonePos);
                         localTarget.addInPlace(bonePos);
                         target = localTarget;
                         target = localTarget;
                     }
                     }
@@ -524,5 +537,26 @@ module BABYLON {
             return ab;
             return ab;
         }
         }
 
 
+        private _isAngleBetween(ang, ang1, ang2):boolean {
+
+            ang %= (2 * Math.PI);
+            ang = (ang < 0) ? ang + (2 * Math.PI) : ang;
+            ang1 %= (2 * Math.PI);
+            ang1 = (ang1 < 0) ? ang1 + (2 * Math.PI) : ang1;
+            ang2 %= (2 * Math.PI);
+            ang2 = (ang2 < 0) ? ang2 + (2 * Math.PI) : ang2;
+
+            if(ang1 < ang2){
+                if(ang > ang1 && ang < ang2){
+                    return true;
+                }
+            }else{
+                if(ang > ang2 && ang < ang1){
+                    return true;
+                }
+            }
+            return false;
+        }
+
     }
     }
 }
 }

+ 8 - 6
src/Cameras/Inputs/babylon.arcrotatecamera.input.gamepad.ts

@@ -3,7 +3,7 @@ module BABYLON {
         camera: ArcRotateCamera;
         camera: ArcRotateCamera;
 
 
         public gamepad: Gamepad;
         public gamepad: Gamepad;
-        private _gamepads: Gamepads;
+        private _gamepads: Gamepads<Gamepad>;
 
 
         @serialize()
         @serialize()
         public gamepadRotationSensibility = 80;
         public gamepadRotationSensibility = 80;
@@ -11,10 +11,10 @@ module BABYLON {
         @serialize()
         @serialize()
         public gamepadMoveSensibility = 40;
         public gamepadMoveSensibility = 40;
 
 
-        attachControl(element : HTMLElement, noPreventDefault?: boolean) {
+        attachControl(element: HTMLElement, noPreventDefault?: boolean) {
             this._gamepads = new Gamepads((gamepad: Gamepad) => { this._onNewGameConnected(gamepad); });
             this._gamepads = new Gamepads((gamepad: Gamepad) => { this._onNewGameConnected(gamepad); });
         }
         }
-        
+
         detachControl(element: HTMLElement) {
         detachControl(element: HTMLElement) {
             if (this._gamepads) {
             if (this._gamepads) {
                 this._gamepads.dispose();
                 this._gamepads.dispose();
@@ -53,9 +53,11 @@ module BABYLON {
         }
         }
 
 
         private _onNewGameConnected(gamepad: Gamepad) {
         private _onNewGameConnected(gamepad: Gamepad) {
-            // Only the first gamepad can control the camera
-            if (gamepad.index === 0) {
-                this.gamepad = gamepad;
+            if (gamepad.type !== Gamepad.POSE_ENABLED) {
+                // prioritize XBOX gamepads.
+                if (!this.gamepad || gamepad.type === Gamepad.XBOX) {
+                    this.gamepad = gamepad;
+                }
             }
             }
         }
         }
 
 

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

@@ -1,28 +1,34 @@
-module BABYLON {       
+module BABYLON {
     export class FreeCameraGamepadInput implements ICameraInput<FreeCamera> {
     export class FreeCameraGamepadInput implements ICameraInput<FreeCamera> {
-        camera : FreeCamera;
-        
+        camera: FreeCamera;
+
         public gamepad: Gamepad;
         public gamepad: Gamepad;
-        private _gamepads: Gamepads;
+        private _gamepads: Gamepads<Gamepad>;
 
 
         @serialize()
         @serialize()
         public gamepadAngularSensibility = 200;
         public gamepadAngularSensibility = 200;
 
 
         @serialize()
         @serialize()
         public gamepadMoveSensibility = 40;
         public gamepadMoveSensibility = 40;
-        
-        attachControl(element : HTMLElement, noPreventDefault?: boolean){
+
+        // private members
+        private _cameraTransform: Matrix = Matrix.Identity();
+        private _deltaTransform: Vector3 = Vector3.Zero();
+        private _vector3: Vector3 = Vector3.Zero();
+        private _vector2: Vector2 = Vector2.Zero();
+
+        attachControl(element: HTMLElement, noPreventDefault?: boolean) {
             this._gamepads = new Gamepads((gamepad: Gamepad) => { this._onNewGameConnected(gamepad); });
             this._gamepads = new Gamepads((gamepad: Gamepad) => { this._onNewGameConnected(gamepad); });
         }
         }
-        
+
         detachControl(element: HTMLElement) {
         detachControl(element: HTMLElement) {
             if (this._gamepads) {
             if (this._gamepads) {
                 this._gamepads.dispose();
                 this._gamepads.dispose();
             }
             }
             this.gamepad = null;
             this.gamepad = null;
         }
         }
-        
-        checkInputs(){
+
+        checkInputs() {
             if (this.gamepad) {
             if (this.gamepad) {
                 var camera = this.camera;
                 var camera = this.camera;
                 var LSValues = this.gamepad.leftStick;
                 var LSValues = this.gamepad.leftStick;
@@ -37,30 +43,40 @@ module BABYLON {
                 RSValues.x = Math.abs(normalizedRX) > 0.001 ? 0 + normalizedRX : 0;
                 RSValues.x = Math.abs(normalizedRX) > 0.001 ? 0 + normalizedRX : 0;
                 RSValues.y = Math.abs(normalizedRY) > 0.001 ? 0 + normalizedRY : 0;
                 RSValues.y = Math.abs(normalizedRY) > 0.001 ? 0 + normalizedRY : 0;
 
 
-                var cameraTransform = Matrix.RotationYawPitchRoll(camera.rotation.y, camera.rotation.x, 0);
+                if (!camera.rotationQuaternion) {
+                    Matrix.RotationYawPitchRollToRef(camera.rotation.y, camera.rotation.x, 0, this._cameraTransform);
+                } else {
+                    camera.rotationQuaternion.toRotationMatrix(this._cameraTransform);
+                }
 
 
                 var speed = camera._computeLocalCameraSpeed() * 50.0;
                 var speed = camera._computeLocalCameraSpeed() * 50.0;
-                var deltaTransform = Vector3.TransformCoordinates(new Vector3(LSValues.x * speed, 0, -LSValues.y * speed), cameraTransform);
-                camera.cameraDirection = camera.cameraDirection.add(deltaTransform);
-                camera.cameraRotation = camera.cameraRotation.add(new Vector2(RSValues.y, RSValues.x));
+                this._vector3.copyFromFloats(LSValues.x * speed, 0, -LSValues.y * speed);
+
+                Vector3.TransformCoordinatesToRef(this._vector3, this._cameraTransform, this._deltaTransform);
+                camera.cameraDirection.addInPlace(this._deltaTransform);
+                this._vector2.copyFromFloats(RSValues.y, RSValues.x)
+                camera.cameraRotation.addInPlace(this._vector2);
             }
             }
         }
         }
-        
+
         private _onNewGameConnected(gamepad: Gamepad) {
         private _onNewGameConnected(gamepad: Gamepad) {
-            // Only the first gamepad can control the camera
-            if (gamepad.index === 0) {
-                this.gamepad = gamepad;
+            // Only the first gamepad found can control the camera
+            if (gamepad.type !== Gamepad.POSE_ENABLED) {
+                // prioritize XBOX gamepads.
+                if (!this.gamepad || gamepad.type === Gamepad.XBOX) {
+                    this.gamepad = gamepad;
+                }
             }
             }
         }
         }
-        
-        getTypeName(): string{
+
+        getTypeName(): string {
             return "FreeCameraGamepadInput";
             return "FreeCameraGamepadInput";
         }
         }
-        
-        getSimpleName(){
+
+        getSimpleName() {
             return "gamepad";
             return "gamepad";
         }
         }
     }
     }
-    
+
     CameraInputTypes["FreeCameraGamepadInput"] = FreeCameraGamepadInput;
     CameraInputTypes["FreeCameraGamepadInput"] = FreeCameraGamepadInput;
 }
 }

+ 159 - 52
src/Cameras/VR/babylon.webVRCamera.ts

@@ -4,15 +4,41 @@ declare var VRFrameData;
 
 
 module BABYLON {
 module BABYLON {
 
 
+    /**
+     * This is a copy of VRPose.
+     * IMPORTANT!! The data is right-hand data.
+     * @export
+     * @interface DevicePose
+     */
+    export interface DevicePose {
+        readonly position?: Float32Array;
+        readonly linearVelocity?: Float32Array;
+        readonly linearAcceleration?: Float32Array;
+
+        readonly orientation?: Float32Array;
+        readonly angularVelocity?: Float32Array;
+        readonly angularAcceleration?: Float32Array;
+    }
+
+    export interface PoseControlled {
+        position: Vector3;
+        rotationQuaternion: Quaternion;
+        devicePosition?: Vector3;
+        deviceRotationQuaternion: Quaternion;
+        rawPose: DevicePose;
+        deviceScaleFactor: number;
+        updateFromDevice(poseData: DevicePose);
+    }
+
     export interface WebVROptions {
     export interface WebVROptions {
         trackPosition?: boolean; //update the camera's position
         trackPosition?: boolean; //update the camera's position
         positionScale?: number;
         positionScale?: number;
         displayName?: string; //if there are more than one VRDisplays.
         displayName?: string; //if there are more than one VRDisplays.
     }
     }
 
 
-    export class WebVRFreeCamera extends FreeCamera {
+    export class WebVRFreeCamera extends FreeCamera implements PoseControlled {
         public _vrDevice = null;
         public _vrDevice = null;
-        private _cacheState = null;
+        public rawPose: DevicePose = null;
         private _vrEnabled = false;
         private _vrEnabled = false;
         private _attached: boolean = false;
         private _attached: boolean = false;
 
 
@@ -23,13 +49,24 @@ module BABYLON {
 
 
         private _quaternionCache: Quaternion;
         private _quaternionCache: Quaternion;
 
 
-        private _positionOffset: Vector3;
+        private _positionOffset: Vector3 = Vector3.Zero();
+
+        public devicePosition = Vector3.Zero();
+        public deviceRotationQuaternion;
+        public deviceScaleFactor: number = 1;
+
+        public controllers: Array<WebVRController> = [];
+        public onControllersAttached: (controllers: Array<WebVRController>) => void;
 
 
         constructor(name: string, position: Vector3, scene: Scene, compensateDistortion = false, private webVROptions: WebVROptions = {}) {
         constructor(name: string, position: Vector3, scene: Scene, compensateDistortion = false, private webVROptions: WebVROptions = {}) {
             super(name, position, scene);
             super(name, position, scene);
 
 
-            //using the position provided as the current position offset
-            this._positionOffset = position;
+            this.rotationQuaternion = new Quaternion();
+            this.deviceRotationQuaternion = new Quaternion();
+
+            if (this.webVROptions && this.webVROptions.positionScale) {
+                this.deviceScaleFactor = this.webVROptions.positionScale;
+            }
 
 
             //enable VR
             //enable VR
             this.getEngine().initWebVR();
             this.getEngine().initWebVR();
@@ -37,8 +74,6 @@ module BABYLON {
             if (!this.getEngine().vrDisplaysPromise) {
             if (!this.getEngine().vrDisplaysPromise) {
                 Tools.Error("WebVR is not enabled on your browser");
                 Tools.Error("WebVR is not enabled on your browser");
             } else {
             } else {
-                //TODO get the metrics updated using the device's eye parameters!
-                //TODO also check that the device has the right capabilities!
                 this._frameData = new VRFrameData();
                 this._frameData = new VRFrameData();
                 this.getEngine().vrDisplaysPromise.then((devices) => {
                 this.getEngine().vrDisplaysPromise.then((devices) => {
                     if (devices.length > 0) {
                     if (devices.length > 0) {
@@ -62,7 +97,7 @@ module BABYLON {
                         }
                         }
 
 
                         //reset the rig parameters.
                         //reset the rig parameters.
-                        this.setCameraRigMode(Camera.RIG_MODE_WEBVR, { vrDisplay: this._vrDevice, frameData: this._frameData });
+                        this.setCameraRigMode(Camera.RIG_MODE_WEBVR, { parentCamera: this, vrDisplay: this._vrDevice, frameData: this._frameData });
 
 
                         if (this._attached) {
                         if (this._attached) {
                             this.getEngine().enableVR(this._vrDevice)
                             this.getEngine().enableVR(this._vrDevice)
@@ -70,33 +105,52 @@ module BABYLON {
                     } else {
                     } else {
                         Tools.Error("No WebVR devices found!");
                         Tools.Error("No WebVR devices found!");
                     }
                     }
-                })
+                });
             }
             }
 
 
-            this.rotationQuaternion = new Quaternion();
-            this._quaternionCache = new Quaternion();
+            // try to attach the controllers, if found.
+            this.initControllers();
         }
         }
 
 
         public _checkInputs(): void {
         public _checkInputs(): void {
             if (this._vrEnabled && this._vrDevice.getFrameData(this._frameData)) {
             if (this._vrEnabled && this._vrDevice.getFrameData(this._frameData)) {
-                var currentPost = this._frameData.pose;
-                //make sure we have data
-                if (currentPost && currentPost.orientation) {
-                    this._cacheState = currentPost;
-                    this.rotationQuaternion.copyFromFloats(this._cacheState.orientation[0], this._cacheState.orientation[1], -this._cacheState.orientation[2], -this._cacheState.orientation[3]);
-                    if (this.webVROptions.trackPosition && this._cacheState.position) {
-                        this.position.copyFromFloats(this._cacheState.position[0], this._cacheState.position[1], -this._cacheState.position[2]);
-                        //scale the position accordingly
-                        this.webVROptions.positionScale && this.position.scaleInPlace(this.webVROptions.positionScale);
-                        //add the position offset
-                        this.position.addInPlace(this._positionOffset);
-                    }
-                }
+                var currentPose = this._frameData.pose;
+                this.updateFromDevice(currentPose);
             }
             }
 
 
             super._checkInputs();
             super._checkInputs();
         }
         }
 
 
+        updateFromDevice(poseData: DevicePose) {
+            if (poseData && poseData.orientation) {
+                this.rawPose = poseData;
+                this.deviceRotationQuaternion.copyFromFloats(this.rawPose.orientation[0], this.rawPose.orientation[1], -this.rawPose.orientation[2], -this.rawPose.orientation[3]);
+
+                if (this.getScene().useRightHandedSystem) {
+                    this.deviceRotationQuaternion.z *= -1;
+                    this.deviceRotationQuaternion.w *= -1;
+                }
+                if (this.webVROptions.trackPosition && this.rawPose.position) {
+                    this.devicePosition.copyFromFloats(this.rawPose.position[0], this.rawPose.position[1], -this.rawPose.position[2]);
+                    if (this.getScene().useRightHandedSystem) {
+                        this.devicePosition.z *= -1;
+                    }
+                }
+            }
+        }
+
+
+        /**
+         * WebVR's attach control will start broadcasting frames to the device.
+         * Note that in certain browsers (chrome for example) this function must be called
+         * within a user-interaction callback. Example:
+         * <pre> scene.onPointerDown = function() { camera.attachControl(canvas); }</pre>
+         * 
+         * @param {HTMLElement} element 
+         * @param {boolean} [noPreventDefault] 
+         * 
+         * @memberOf WebVRFreeCamera
+         */
         public attachControl(element: HTMLElement, noPreventDefault?: boolean): void {
         public attachControl(element: HTMLElement, noPreventDefault?: boolean): void {
             super.attachControl(element, noPreventDefault);
             super.attachControl(element, noPreventDefault);
             this._attached = true;
             this._attached = true;
@@ -115,12 +169,6 @@ module BABYLON {
             this.getEngine().disableVR();
             this.getEngine().disableVR();
         }
         }
 
 
-        public requestVRFullscreen(requestPointerlock: boolean) {
-            //Backwards comp.
-            Tools.Warn("requestVRFullscreen is deprecated. call attachControl() to start sending frames to the VR display.")
-            //this.getEngine().switchFullscreen(requestPointerlock);
-        }
-
         public getClassName(): string {
         public getClassName(): string {
             return "WebVRFreeCamera";
             return "WebVRFreeCamera";
         }
         }
@@ -132,34 +180,93 @@ module BABYLON {
         }
         }
 
 
         /**
         /**
-         * 
-         * Set the position offset of the VR camera
-         * The offset will be added to the WebVR pose, after scaling it (if set).
-         * 
-         * @param {Vector3} [newPosition] an optional new position. if not provided, the current camera position will be used.
-         * 
-         * @memberOf WebVRFreeCamera
+         * This function is called by the two RIG cameras.
+         * 'this' is the left or right camera (and NOT (!!!) the WebVRFreeCamera instance)
          */
          */
-        public setPositionOffset(newPosition?: Vector3) {
-            if(newPosition) {
-                this._positionOffset = newPosition;
-            } else {
-                this._positionOffset.copyFrom(this.position);
+        protected _getWebVRViewMatrix(): Matrix {
+            var viewArray = this._cameraRigParams["left"] ? this._cameraRigParams["frameData"].leftViewMatrix : this._cameraRigParams["frameData"].rightViewMatrix;
+
+            if (!this.getScene().useRightHandedSystem) {
+                [2, 6, 8, 9, 14].forEach(function (num) {
+                    viewArray[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) {
+                this._webvrViewMatrix.invert();
+                // scale the position, if set
+                if (parentCamera.deviceScaleFactor) {
+                    this._webvrViewMatrix.m[12] *= parentCamera.deviceScaleFactor;
+                    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;
+                this._webvrViewMatrix.invert();
+            }
+            // is rotation offset set? 
+            if (!Quaternion.IsIdentity(this.rotationQuaternion)) {
+                this.rotationQuaternion.toRotationMatrix(this._tempMatrix);
+                this._tempMatrix.multiplyToRef(this._webvrViewMatrix, this._webvrViewMatrix);
             }
             }
+
+            this._updateCameraRotationMatrix();
+            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);
+
+            return this._webvrViewMatrix;
         }
         }
-    }
-    
-    export class WebVRGamepadCamera extends WebVRFreeCamera {
 
 
-        constructor(name: string, position: Vector3, scene: Scene, compensateDistortion:boolean = false, webVROptions: WebVROptions = {}) {
-            super(name, position, scene, compensateDistortion, webVROptions);
-            
-            this.inputs.addGamepad();
+        protected _updateCameraRotationMatrix() {
+            this._webvrViewMatrix.getRotationMatrixToRef(this._cameraRotationMatrix);
         }
         }
 
 
-        public getClassName(): string {
-            return "WebVRGamepadCamera";
+        public _isSynchronizedViewMatrix() {
+            return false;
         }
         }
-    }    
+
+        protected _getWebVRProjectionMatrix(): Matrix {
+            var projectionArray = this._cameraRigParams["left"] ? this._cameraRigParams["frameData"].leftProjectionMatrix : this._cameraRigParams["frameData"].rightProjectionMatrix;
+            //babylon compatible matrix
+            if (!this.getScene().useRightHandedSystem) {
+                [8, 9, 10, 11].forEach(function (num) {
+                    projectionArray[num] *= -1;
+                });
+            }
+            Matrix.FromArrayToRef(projectionArray, 0, this._projectionMatrix);
+            return this._projectionMatrix;
+        }
+
+        public initControllers() {
+            this.controllers = [];
+            new BABYLON.Gamepads((gp) => {
+                if (gp.type === BABYLON.Gamepad.POSE_ENABLED) {
+                    let webVrController: WebVRController = <WebVRController>gp;
+                    webVrController.attachToPoseControlledCamera(this);
+
+                    // since this is async - sanity check. Is the controller already stored?
+                    if (this.controllers.indexOf(webVrController) === -1) {
+                        //add to the controllers array
+                        this.controllers.push(webVrController);
+
+                        //did we find enough controllers? Great! let the developer know.
+                        if (this.onControllersAttached && this.controllers.length === 2) {
+                            this.onControllersAttached(this.controllers);
+                        }
+                    }
+                }
+            });
+        }
+    }
 }
 }
 
 

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

@@ -445,7 +445,7 @@ module BABYLON {
                 this.position.copyFrom(this._newPosition);
                 this.position.copyFrom(this._newPosition);
 
 
                 var up = this.upVector;
                 var up = this.upVector;
-                if (this.allowUpsideDown && this.beta < 0) {
+                if (this.allowUpsideDown && sinb < 0) {
                     up = up.clone();
                     up = up.clone();
                     up = up.negate();
                     up = up.negate();
                 }
                 }

+ 43 - 26
src/Cameras/babylon.camera.ts

@@ -119,6 +119,8 @@
         public _cameraRigParams: any;
         public _cameraRigParams: any;
         public _rigCameras = new Array<Camera>();
         public _rigCameras = new Array<Camera>();
         public _rigPostProcess: PostProcess;
         public _rigPostProcess: PostProcess;
+        protected _webvrViewMatrix = Matrix.Identity();
+
 
 
         // Cache
         // Cache
         private _computedViewMatrix = Matrix.Identity();
         private _computedViewMatrix = Matrix.Identity();
@@ -127,7 +129,6 @@
         private _worldMatrix: Matrix;
         private _worldMatrix: Matrix;
         public _postProcesses = new Array<PostProcess>();
         public _postProcesses = new Array<PostProcess>();
         private _transformMatrix = Matrix.Zero();
         private _transformMatrix = Matrix.Zero();
-        private _webvrViewMatrix = Matrix.Identity();
 
 
         public _activeMeshes = new SmartArray<Mesh>(256);
         public _activeMeshes = new SmartArray<Mesh>(256);
 
 
@@ -149,7 +150,7 @@
 
 
         public getClassName(): string {
         public getClassName(): string {
             return "Camera";
             return "Camera";
-        }          
+        }
 
 
         /**
         /**
          * @param {boolean} fullDetails - support for multiple levels of logging within scene loading
          * @param {boolean} fullDetails - support for multiple levels of logging within scene loading
@@ -292,6 +293,14 @@
         public _checkInputs(): void {
         public _checkInputs(): void {
         }
         }
 
 
+        public get rigCameras(): Camera[] {
+            return this._rigCameras;
+        }
+
+        public get rigPostProcess(): PostProcess {
+            return this._rigPostProcess;
+        }
+
         private _cascadePostProcessesToRigCams(): void {
         private _cascadePostProcessesToRigCams(): void {
             // invalidate framebuffer
             // invalidate framebuffer
             if (this._postProcesses.length > 0) {
             if (this._postProcesses.length > 0) {
@@ -590,7 +599,8 @@
                     this._rigCameras[1]._cameraRigParams.vrPreViewMatrix = metrics.rightPreViewMatrix;
                     this._rigCameras[1]._cameraRigParams.vrPreViewMatrix = metrics.rightPreViewMatrix;
                     this._rigCameras[1].getProjectionMatrix = this._rigCameras[1]._getVRProjectionMatrix;
                     this._rigCameras[1].getProjectionMatrix = this._rigCameras[1]._getVRProjectionMatrix;
 
 
-                    if (metrics.compensateDistortion) {
+   
+                   if (metrics.compensateDistortion) {
                         this._rigCameras[0]._rigPostProcess = new VRDistortionCorrectionPostProcess("VR_Distort_Compensation_Left", this._rigCameras[0], false, metrics);
                         this._rigCameras[0]._rigPostProcess = new VRDistortionCorrectionPostProcess("VR_Distort_Compensation_Left", this._rigCameras[0], false, metrics);
                         this._rigCameras[1]._rigPostProcess = new VRDistortionCorrectionPostProcess("VR_Distort_Compensation_Right", this._rigCameras[1], true, metrics);
                         this._rigCameras[1]._rigPostProcess = new VRDistortionCorrectionPostProcess("VR_Distort_Compensation_Right", this._rigCameras[1], true, metrics);
                     }
                     }
@@ -599,19 +609,28 @@
                     if (rigParams.vrDisplay) {
                     if (rigParams.vrDisplay) {
                         //var leftEye = rigParams.vrDisplay.getEyeParameters('left');
                         //var leftEye = rigParams.vrDisplay.getEyeParameters('left');
                         //var rightEye = rigParams.vrDisplay.getEyeParameters('right');
                         //var rightEye = rigParams.vrDisplay.getEyeParameters('right');
+
+                        //Left eye
                         this._rigCameras[0].viewport = new Viewport(0, 0, 0.5, 1.0);
                         this._rigCameras[0].viewport = new Viewport(0, 0, 0.5, 1.0);
                         this._rigCameras[0].setCameraRigParameter("left", true);
                         this._rigCameras[0].setCameraRigParameter("left", true);
                         this._rigCameras[0].setCameraRigParameter("frameData", rigParams.frameData);
                         this._rigCameras[0].setCameraRigParameter("frameData", rigParams.frameData);
-                        //this._rigCameras[0].setCameraRigParameter("vrOffsetMatrix", Matrix.Translation(-leftEye.offset[0], leftEye.offset[1], -leftEye.offset[2]));
+                        this._rigCameras[0].setCameraRigParameter("parentCamera", rigParams.parentCamera);
+                        //this._rigCameras[0].setCameraRigParameter('eyeParameters', leftEye);
                         this._rigCameras[0]._cameraRigParams.vrWorkMatrix = new Matrix();
                         this._rigCameras[0]._cameraRigParams.vrWorkMatrix = new Matrix();
                         this._rigCameras[0].getProjectionMatrix = this._getWebVRProjectionMatrix;
                         this._rigCameras[0].getProjectionMatrix = this._getWebVRProjectionMatrix;
-                        //this._rigCameras[0]._getViewMatrix = this._getWebVRViewMatrix;
+                        this._rigCameras[0]._getViewMatrix = this._getWebVRViewMatrix;
+                        this._rigCameras[0]._isSynchronizedViewMatrix = this._isSynchronizedViewMatrix;
+                        this._rigCameras[0]._updateCameraRotationMatrix = this._updateCameraRotationMatrix;
+                        //Right eye
                         this._rigCameras[1].viewport = new Viewport(0.5, 0, 0.5, 1.0);
                         this._rigCameras[1].viewport = new Viewport(0.5, 0, 0.5, 1.0);
+                        //this._rigCameras[1].setCameraRigParameter('eyeParameters', rightEye);
                         this._rigCameras[1].setCameraRigParameter("frameData", rigParams.frameData);
                         this._rigCameras[1].setCameraRigParameter("frameData", rigParams.frameData);
-                        //this._rigCameras[1].setCameraRigParameter("vrOffsetMatrix", Matrix.Translation(-rightEye.offset[0], rightEye.offset[1], -rightEye.offset[2]));
+                        this._rigCameras[1].setCameraRigParameter("parentCamera", rigParams.parentCamera);
                         this._rigCameras[1]._cameraRigParams.vrWorkMatrix = new Matrix();
                         this._rigCameras[1]._cameraRigParams.vrWorkMatrix = new Matrix();
                         this._rigCameras[1].getProjectionMatrix = this._getWebVRProjectionMatrix;
                         this._rigCameras[1].getProjectionMatrix = this._getWebVRProjectionMatrix;
-                        //this._rigCameras[1]._getViewMatrix = this._getWebVRViewMatrix;
+                        this._rigCameras[1]._getViewMatrix = this._getWebVRViewMatrix;
+                        this._rigCameras[1]._isSynchronizedViewMatrix = this._isSynchronizedViewMatrix;
+                        this._rigCameras[1]._updateCameraRotationMatrix = this._updateCameraRotationMatrix;
                     }
                     }
                     break;
                     break;
 
 
@@ -627,26 +646,24 @@
             this._cameraRigParams.vrWorkMatrix.multiplyToRef(this._cameraRigParams.vrHMatrix, this._projectionMatrix);
             this._cameraRigParams.vrWorkMatrix.multiplyToRef(this._cameraRigParams.vrHMatrix, this._projectionMatrix);
             return this._projectionMatrix;
             return this._projectionMatrix;
         }
         }
-
-        private _getWebVRProjectionMatrix(): Matrix {
-            var projectionArray = this._cameraRigParams["left"] ? this._cameraRigParams["frameData"].leftProjectionMatrix : this._cameraRigParams["frameData"].rightProjectionMatrix;
-            //babylon compatible matrix
-            [8, 9, 10, 11].forEach(function (num) {
-                projectionArray[num] *= -1;
-            });
-            Matrix.FromArrayToRef(projectionArray, 0, this._projectionMatrix);
-            return this._projectionMatrix;
+        
+        protected _updateCameraRotationMatrix() {
+           // only here for webvr
+        }
+        /**
+         * This function MUST be overwritten by the different WebVR cameras available.
+         * The context in which it is running is the RIG camera. So 'this' is the TargetCamera, left or right.
+         */
+        protected _getWebVRProjectionMatrix(): Matrix {
+            return Matrix.Identity();
         }
         }
 
 
-        //Can be used, but we'll use the free camera's view matrix calculation
-        private _getWebVRViewMatrix(): Matrix {
-            var projectionArray = this._cameraRigParams["left"] ? this._cameraRigParams["frameData"].leftViewMatrix : this._cameraRigParams["frameData"].rightViewMatrix;
-            //babylon compatible matrix
-            [8, 9, 10, 11].forEach(function (num) {
-                projectionArray[num] *= -1;
-            });
-            Matrix.FromArrayToRef(projectionArray, 0, this._webvrViewMatrix);
-            return this._webvrViewMatrix;
+        /**
+         * This function MUST be overwritten by the different WebVR cameras available.
+         * The context in which it is running is the RIG camera. So 'this' is the TargetCamera, left or right.
+         */
+        protected _getWebVRViewMatrix(): Matrix {
+            return Matrix.Identity();
         }
         }
 
 
         public setCameraRigParameter(name: string, value: any) {
         public setCameraRigParameter(name: string, value: any) {
@@ -742,7 +759,7 @@
                 case "WebVRFreeCamera":
                 case "WebVRFreeCamera":
                     return () => new WebVRFreeCamera(name, Vector3.Zero(), scene);
                     return () => new WebVRFreeCamera(name, Vector3.Zero(), scene);
                 case "WebVRGamepadCamera":
                 case "WebVRGamepadCamera":
-                    return () => new WebVRGamepadCamera(name, Vector3.Zero(), scene);
+                    return () => new WebVRFreeCamera(name, Vector3.Zero(), scene);
                 case "VRDeviceOrientationFreeCamera":
                 case "VRDeviceOrientationFreeCamera":
                     return () => new VRDeviceOrientationFreeCamera(name, Vector3.Zero(), scene);
                     return () => new VRDeviceOrientationFreeCamera(name, Vector3.Zero(), scene);
                 case "VRDeviceOrientationGamepadCamera":
                 case "VRDeviceOrientationGamepadCamera":

+ 0 - 1
src/Cameras/babylon.gamepadCamera.ts

@@ -31,7 +31,6 @@ module BABYLON {
         
         
         
         
         constructor(name: string, position: Vector3, scene: Scene) {
         constructor(name: string, position: Vector3, scene: Scene) {
-            Tools.Warn("Deprecated. Please use Universal Camera instead.");
             super(name, position, scene);
             super(name, position, scene);
         }
         }
 
 

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

@@ -219,7 +219,7 @@ module BABYLON {
             super._checkInputs();
             super._checkInputs();
         }
         }
 
 
-        private _updateCameraRotationMatrix() {
+        protected _updateCameraRotationMatrix() {
             if (this.rotationQuaternion) {
             if (this.rotationQuaternion) {
                 this.rotationQuaternion.toRotationMatrix(this._cameraRotationMatrix);
                 this.rotationQuaternion.toRotationMatrix(this._cameraRotationMatrix);
                 //update the up vector!
                 //update the up vector!
@@ -247,7 +247,7 @@ module BABYLON {
             } else {
             } else {
                 Matrix.LookAtLHToRef(this.position, this._currentTarget, this.upVector, this._viewMatrix);
                 Matrix.LookAtLHToRef(this.position, this._currentTarget, this.upVector, this._viewMatrix);
             }
             }
-            
+
             return this._viewMatrix;
             return this._viewMatrix;
         }
         }
 
 

+ 0 - 28
src/Culling/babylon.ray.ts

@@ -246,34 +246,6 @@
 
 
         }
         }
 
 
-        /**
-         *  @Deprecated. Use new RayHelper.show() instead.
-         * */
-        public show(scene:Scene, color:Color3): void{
-
-            console.warn('Ray.show() has been deprecated.  Use new RayHelper.show() instead.');
-
-            if(!this._rayHelper){
-                this._rayHelper = new RayHelper(this);
-            }
-            
-            this._rayHelper.show(scene, color);
-
-        }
-
-        /**
-         *  @Deprecated. Use new RayHelper.hide() instead.
-         * */
-        public hide(): void{
-
-            console.warn('Ray.hide() has been deprecated.  Use new RayHelper.hide() instead.');
-
-            if(this._rayHelper){
-                this._rayHelper.hide();
-                this._rayHelper = null;
-            }
-
-        }
 
 
         private static smallnum = 0.00000001;
         private static smallnum = 0.00000001;
         private static rayl = 10e8;
         private static rayl = 10e8;

+ 1 - 1
src/Layer/babylon.highlightlayer.ts

@@ -248,7 +248,7 @@ module BABYLON {
          * @param scene The scene to use the layer in
          * @param scene The scene to use the layer in
          * @param options Sets of none mandatory options to use with the layer (see IHighlightLayerOptions for more information)
          * @param options Sets of none mandatory options to use with the layer (see IHighlightLayerOptions for more information)
          */
          */
-        constructor(name: string, scene: Scene, options?: IHighlightLayerOptions) {
+        constructor(public name: string, scene: Scene, options?: IHighlightLayerOptions) {
             this._scene = scene || Engine.LastCreatedScene;
             this._scene = scene || Engine.LastCreatedScene;
             var engine = scene.getEngine();
             var engine = scene.getEngine();
             this._engine = engine;
             this._engine = engine;

+ 7 - 3
src/Materials/Textures/babylon.dynamicTexture.ts

@@ -75,11 +75,15 @@ module BABYLON {
             }
             }
 
 
             this._context.font = font;
             this._context.font = font;
-            if (x === null) {
+            if (x === null  || x === undefined) {
                 var textSize = this._context.measureText(text);
                 var textSize = this._context.measureText(text);
                 x = (size.width - textSize.width) / 2;
                 x = (size.width - textSize.width) / 2;
             }
             }
-
+            if (y === null || y === undefined) {
+                var fontSize = parseInt((font.replace(/\D/g,'')));;
+                y = (size.height /2) + (fontSize/3.65);
+            }
+            
             this._context.fillStyle = color;
             this._context.fillStyle = color;
             this._context.fillText(text, x, y);
             this._context.fillText(text, x, y);
 
 
@@ -103,4 +107,4 @@ module BABYLON {
             return newTexture;
             return newTexture;
         }
         }
     }
     }
-} 
+} 

+ 5 - 3
src/Materials/Textures/babylon.renderTargetTexture.ts

@@ -370,8 +370,6 @@
                 scene.updateTransformMatrix(true);
                 scene.updateTransformMatrix(true);
             }
             }
 
 
-            this.onAfterRenderObservable.notifyObservers(faceIndex);
-
             // Dump ?
             // Dump ?
             if (dumpForDebug) {
             if (dumpForDebug) {
                 Tools.DumpFramebuffer(this._size, this._size, engine);
                 Tools.DumpFramebuffer(this._size, this._size, engine);
@@ -386,7 +384,11 @@
                     }
                     }
                 }
                 }
 
 
-                engine.unBindFramebuffer(this._texture, this.isCube);
+                engine.unBindFramebuffer(this._texture, this.isCube, () => {
+                    this.onAfterRenderObservable.notifyObservers(faceIndex);    
+                });
+            } else {
+                this.onAfterRenderObservable.notifyObservers(faceIndex);
             }
             }
         }
         }
 
 

+ 21 - 10
src/Materials/babylon.effect.ts

@@ -41,21 +41,31 @@
         }
         }
 
 
         public reduce(currentDefines: string): string {
         public reduce(currentDefines: string): string {
-
-            var currentFallbacks = this._defines[this._currentRank];
-            if (currentFallbacks) {
-                for (var index = 0; index < currentFallbacks.length; index++) {
-                    currentDefines = currentDefines.replace("#define " + currentFallbacks[index], "");
-                }
-            }
-
-            if (this._mesh && this._currentRank === this._meshRank) {
+            // First we try to switch to CPU skinning
+            if (this._mesh && this._mesh.computeBonesUsingShaders && this._mesh.numBoneInfluencers > 0) {
                 this._mesh.computeBonesUsingShaders = false;
                 this._mesh.computeBonesUsingShaders = false;
                 currentDefines = currentDefines.replace("#define NUM_BONE_INFLUENCERS " + this._mesh.numBoneInfluencers, "#define NUM_BONE_INFLUENCERS 0");
                 currentDefines = currentDefines.replace("#define NUM_BONE_INFLUENCERS " + this._mesh.numBoneInfluencers, "#define NUM_BONE_INFLUENCERS 0");
                 Tools.Log("Falling back to CPU skinning for " + this._mesh.name);
                 Tools.Log("Falling back to CPU skinning for " + this._mesh.name);
+
+                var scene = this._mesh.getScene();
+                for (var index = 0; index < scene.meshes.length; index++) {
+                    var otherMesh = scene.meshes[index];
+
+                    if (otherMesh.material === this._mesh.material && otherMesh.computeBonesUsingShaders && otherMesh.numBoneInfluencers > 0) {
+                        otherMesh.computeBonesUsingShaders = false;
+                    }
+                }
             }
             }
+            else {
+                var currentFallbacks = this._defines[this._currentRank];
+                if (currentFallbacks) {
+                    for (var index = 0; index < currentFallbacks.length; index++) {
+                        currentDefines = currentDefines.replace("#define " + currentFallbacks[index], "");
+                    }
+                }
 
 
-            this._currentRank++;
+                this._currentRank++;
+            }
 
 
             return currentDefines;
             return currentDefines;
         }
         }
@@ -304,6 +314,7 @@
             result = result.replace(/[ \t]attribute/g, " in");
             result = result.replace(/[ \t]attribute/g, " in");
             
             
             if (isFragment) {
             if (isFragment) {
+                result = result.replace(/texture2DLodEXT\(/g, "textureLod(");
                 result = result.replace(/textureCubeLodEXT\(/g, "textureLod(");
                 result = result.replace(/textureCubeLodEXT\(/g, "textureLod(");
                 result = result.replace(/texture2D\(/g, "texture(");
                 result = result.replace(/texture2D\(/g, "texture(");
                 result = result.replace(/textureCube\(/g, "texture(");
                 result = result.replace(/textureCube\(/g, "texture(");

+ 67 - 61
src/Math/babylon.math.ts

@@ -1275,7 +1275,7 @@
 
 
         /**
         /**
          * Returns a new Vector3 set witth the result of the division of the current Vector3 coordinates by the passed ones.  
          * Returns a new Vector3 set witth the result of the division of the current Vector3 coordinates by the passed ones.  
-         */        
+         */
         public divide(otherVector: Vector3): Vector3 {
         public divide(otherVector: Vector3): Vector3 {
             return new Vector3(this.x / otherVector.x, this.y / otherVector.y, this.z / otherVector.z);
             return new Vector3(this.x / otherVector.x, this.y / otherVector.y, this.z / otherVector.z);
         }
         }
@@ -2485,7 +2485,7 @@
         public conjugateToRef(ref: Quaternion): Quaternion {
         public conjugateToRef(ref: Quaternion): Quaternion {
             ref.copyFromFloats(-this.x, -this.y, -this.z, this.w);
             ref.copyFromFloats(-this.x, -this.y, -this.z, this.w);
             return this;
             return this;
-        }   
+        }
         /** 
         /** 
          * Conjugates in place the current Quaternion.
          * Conjugates in place the current Quaternion.
          * Returns the updated Quaternion.  
          * Returns the updated Quaternion.  
@@ -2535,7 +2535,7 @@
          * Returns the current Quaternion.  
          * Returns the current Quaternion.  
          */
          */
         public toEulerAnglesToRef(result: Vector3, order = "YZX"): Quaternion {
         public toEulerAnglesToRef(result: Vector3, order = "YZX"): Quaternion {
-            
+
             var qz = this.z;
             var qz = this.z;
             var qx = this.x;
             var qx = this.x;
             var qy = this.y;
             var qy = this.y;
@@ -2546,25 +2546,25 @@
             var sqx = qx * qx;
             var sqx = qx * qx;
             var sqy = qy * qy;
             var sqy = qy * qy;
 
 
-            var zAxisY = qy*qz - qx*qw;
+            var zAxisY = qy * qz - qx * qw;
             var limit = .4999999;
             var limit = .4999999;
 
 
-            if(zAxisY < -limit){
-                result.y = 2 * Math.atan2(qy,qw);
-                result.x = Math.PI/2;
+            if (zAxisY < -limit) {
+                result.y = 2 * Math.atan2(qy, qw);
+                result.x = Math.PI / 2;
                 result.z = 0;
                 result.z = 0;
-            }else if(zAxisY > limit){
-                result.y = 2 * Math.atan2(qy,qw);
-                result.x = -Math.PI/2;
+            } else if (zAxisY > limit) {
+                result.y = 2 * Math.atan2(qy, qw);
+                result.x = -Math.PI / 2;
                 result.z = 0;
                 result.z = 0;
-            }else{
+            } else {
                 result.z = Math.atan2(2.0 * (qx * qy + qz * qw), (-sqz - sqx + sqy + sqw));
                 result.z = Math.atan2(2.0 * (qx * qy + qz * qw), (-sqz - sqx + sqy + sqw));
                 result.x = Math.asin(-2.0 * (qz * qy - qx * qw));
                 result.x = Math.asin(-2.0 * (qz * qy - qx * qw));
                 result.y = Math.atan2(2.0 * (qz * qx + qy * qw), (sqz - sqx - sqy + sqw));
                 result.y = Math.atan2(2.0 * (qz * qx + qy * qw), (sqz - sqx - sqy + sqw));
             }
             }
 
 
             return this;
             return this;
-            
+
         }
         }
         /**
         /**
          * Updates the passed rotation matrix with the current Quaternion values.  
          * Updates the passed rotation matrix with the current Quaternion values.  
@@ -2680,6 +2680,10 @@
         public static Identity(): Quaternion {
         public static Identity(): Quaternion {
             return new Quaternion(0.0, 0.0, 0.0, 1.0);
             return new Quaternion(0.0, 0.0, 0.0, 1.0);
         }
         }
+
+        public static IsIdentity(quaternion: Quaternion) {
+            return quaternion && quaternion.x === 0 && quaternion.y === 0 && quaternion.z === 0 && quaternion.w === 1;
+        }
         /**
         /**
          * Returns a new Quaternion set from the passed axis (Vector3) and angle in radians (float). 
          * Returns a new Quaternion set from the passed axis (Vector3) and angle in radians (float). 
          */
          */
@@ -2764,7 +2768,7 @@
          * cf to Vector3.RotationFromAxis() documentation.  
          * cf to Vector3.RotationFromAxis() documentation.  
          * Note : axis1, axis2 and axis3 are normalized during this operation.   
          * Note : axis1, axis2 and axis3 are normalized during this operation.   
          */
          */
-         public static RotationQuaternionFromAxis(axis1: Vector3, axis2: Vector3, axis3: Vector3, ref: Quaternion): Quaternion {
+        public static RotationQuaternionFromAxis(axis1: Vector3, axis2: Vector3, axis3: Vector3, ref: Quaternion): Quaternion {
             var quat = new Quaternion(0.0, 0.0, 0.0, 0.0);
             var quat = new Quaternion(0.0, 0.0, 0.0, 0.0);
             Quaternion.RotationQuaternionFromAxisToRef(axis1, axis2, axis3, quat);
             Quaternion.RotationQuaternionFromAxisToRef(axis1, axis2, axis3, quat);
             return quat;
             return quat;
@@ -2781,7 +2785,7 @@
         }
         }
 
 
         public static Slerp(left: Quaternion, right: Quaternion, amount: number): Quaternion {
         public static Slerp(left: Quaternion, right: Quaternion, amount: number): Quaternion {
-            
+
             var result = Quaternion.Identity();
             var result = Quaternion.Identity();
 
 
             Quaternion.SlerpToRef(left, right, amount, result);
             Quaternion.SlerpToRef(left, right, amount, result);
@@ -2790,7 +2794,7 @@
 
 
         }
         }
 
 
-        public static SlerpToRef(left: Quaternion, right: Quaternion, amount: number, result:Quaternion): void {
+        public static SlerpToRef(left: Quaternion, right: Quaternion, amount: number, result: Quaternion): void {
             var num2;
             var num2;
             var num3;
             var num3;
             var num = amount;
             var num = amount;
@@ -2868,9 +2872,9 @@
         public toArray(): Float32Array {
         public toArray(): Float32Array {
             return this.m;
             return this.m;
         }
         }
-         /**
-         * Returns the matrix underlying array.  
-         */       
+        /**
+        * Returns the matrix underlying array.  
+        */
         public asArray(): Float32Array {
         public asArray(): Float32Array {
             return this.toArray();
             return this.toArray();
         }
         }
@@ -2995,10 +2999,10 @@
             this.m[14] = z;
             this.m[14] = z;
             return this;
             return this;
         }
         }
-                /**
-         * Inserts the translation vector in the current Matrix.  
-         * Returns the updated Matrix.  
-         */
+        /**
+ * Inserts the translation vector in the current Matrix.  
+ * Returns the updated Matrix.  
+ */
         public setTranslation(vector3: Vector3): Matrix {
         public setTranslation(vector3: Vector3): Matrix {
             this.m[12] = vector3.x;
             this.m[12] = vector3.x;
             this.m[13] = vector3.y;
             this.m[13] = vector3.y;
@@ -3014,7 +3018,7 @@
         /**
         /**
          * Fill a Vector3 with the extracted translation from the Matrix.  
          * Fill a Vector3 with the extracted translation from the Matrix.  
          */
          */
-        public getTranslationToRef(result:Vector3): Matrix {
+        public getTranslationToRef(result: Vector3): Matrix {
             result.x = this.m[12];
             result.x = this.m[12];
             result.y = this.m[13];
             result.y = this.m[13];
             result.z = this.m[14];
             result.z = this.m[14];
@@ -3030,7 +3034,7 @@
             this.setRowFromFloats(1, 0, 1, 0, 0);
             this.setRowFromFloats(1, 0, 1, 0, 0);
             this.setRowFromFloats(2, 0, 0, 1, 0);
             this.setRowFromFloats(2, 0, 0, 1, 0);
             return this;
             return this;
-        }        
+        }
         /**
         /**
          * Returns a new Matrix set with the multiplication result of the current Matrix and the passed one.  
          * Returns a new Matrix set with the multiplication result of the current Matrix and the passed one.  
          */
          */
@@ -3202,7 +3206,7 @@
         /**
         /**
          * Returns a new Matrix as the extracted rotation matrix from the current one.  
          * Returns a new Matrix as the extracted rotation matrix from the current one.  
          */
          */
-        public getRotationMatrix(): Matrix{
+        public getRotationMatrix(): Matrix {
             var result = Matrix.Identity();
             var result = Matrix.Identity();
             this.getRotationMatrixToRef(result);
             this.getRotationMatrixToRef(result);
             return result;
             return result;
@@ -3211,7 +3215,7 @@
          * Extracts the rotation matrix from the current one and sets it as the passed "result".  
          * Extracts the rotation matrix from the current one and sets it as the passed "result".  
          * Returns the current Matrix.  
          * Returns the current Matrix.  
          */
          */
-        public getRotationMatrixToRef(result:Matrix): Matrix {
+        public getRotationMatrixToRef(result: Matrix): Matrix {
             var m = this.m;
             var m = this.m;
 
 
             var xs = m[0] * m[1] * m[2] * m[3] < 0 ? -1 : 1;
             var xs = m[0] * m[1] * m[2] * m[3] < 0 ? -1 : 1;
@@ -3309,7 +3313,7 @@
             this.m[i + 3] = row.w;
             this.m[i + 3] = row.w;
             return this;
             return this;
         }
         }
-        
+
         /**
         /**
          * Sets the index-th row of the current matrix with the passed 4 x float values.
          * Sets the index-th row of the current matrix with the passed 4 x float values.
          * Returns the updated Matrix.    
          * Returns the updated Matrix.    
@@ -3364,9 +3368,9 @@
             return result;
             return result;
         }
         }
 
 
-          /**
-         * Update a Matrix with values composed by the passed scale (vector3), rotation (quaternion) and translation (vector3).  
-         */
+        /**
+       * Update a Matrix with values composed by the passed scale (vector3), rotation (quaternion) and translation (vector3).  
+       */
         public static ComposeToRef(scale: Vector3, rotation: Quaternion, translation: Vector3, result: Matrix): void {
         public static ComposeToRef(scale: Vector3, rotation: Quaternion, translation: Vector3, result: Matrix): void {
             Matrix.FromValuesToRef(scale.x, 0, 0, 0,
             Matrix.FromValuesToRef(scale.x, 0, 0, 0,
                 0, scale.y, 0, 0,
                 0, scale.y, 0, 0,
@@ -3377,7 +3381,7 @@
             MathTmp.Matrix[1].multiplyToRef(MathTmp.Matrix[0], result);
             MathTmp.Matrix[1].multiplyToRef(MathTmp.Matrix[0], result);
 
 
             result.setTranslation(translation);
             result.setTranslation(translation);
-        }      
+        }
         /**
         /**
          * Returns a new indentity Matrix.  
          * Returns a new indentity Matrix.  
          */
          */
@@ -3750,7 +3754,7 @@
             let a = 2.0 / width;
             let a = 2.0 / width;
             let b = 2.0 / height;
             let b = 2.0 / height;
             let c = 2.0 / (f - n);
             let c = 2.0 / (f - n);
-            let d = -(f + n)/(f - n);
+            let d = -(f + n) / (f - n);
 
 
             BABYLON.Matrix.FromValuesToRef(
             BABYLON.Matrix.FromValuesToRef(
                 a, 0.0, 0.0, 0.0,
                 a, 0.0, 0.0, 0.0,
@@ -3780,7 +3784,7 @@
             let a = 2.0 / (right - left);
             let a = 2.0 / (right - left);
             let b = 2.0 / (top - bottom);
             let b = 2.0 / (top - bottom);
             let c = 2.0 / (f - n);
             let c = 2.0 / (f - n);
-            let d = -(f + n)/(f - n);
+            let d = -(f + n) / (f - n);
             let i0 = (left + right) / (left - right);
             let i0 = (left + right) / (left - right);
             let i1 = (top + bottom) / (bottom - top);
             let i1 = (top + bottom) / (bottom - top);
 
 
@@ -3818,8 +3822,8 @@
 
 
             let a = 2.0 * n / width;
             let a = 2.0 * n / width;
             let b = 2.0 * n / height;
             let b = 2.0 * n / height;
-            let c = (f + n)/(f - n);
-            let d = -2.0 * f * n/(f - n);
+            let c = (f + n) / (f - n);
+            let d = -2.0 * f * n / (f - n);
 
 
             BABYLON.Matrix.FromValuesToRef(
             BABYLON.Matrix.FromValuesToRef(
                 a, 0.0, 0.0, 0.0,
                 a, 0.0, 0.0, 0.0,
@@ -3849,8 +3853,8 @@
             let t = 1.0 / (Math.tan(fov * 0.5));
             let t = 1.0 / (Math.tan(fov * 0.5));
             let a = isVerticalFovFixed ? (t / aspect) : t;
             let a = isVerticalFovFixed ? (t / aspect) : t;
             let b = isVerticalFovFixed ? t : (t * aspect);
             let b = isVerticalFovFixed ? t : (t * aspect);
-            let c = (f + n)/(f - n);
-            let d = -2.0 * f * n/(f - n);
+            let c = (f + n) / (f - n);
+            let d = -2.0 * f * n / (f - n);
 
 
             BABYLON.Matrix.FromValuesToRef(
             BABYLON.Matrix.FromValuesToRef(
                 a, 0.0, 0.0, 0.0,
                 a, 0.0, 0.0, 0.0,
@@ -3883,13 +3887,13 @@
             let t = 1.0 / (Math.tan(fov * 0.5));
             let t = 1.0 / (Math.tan(fov * 0.5));
             let a = isVerticalFovFixed ? (t / aspect) : t;
             let a = isVerticalFovFixed ? (t / aspect) : t;
             let b = isVerticalFovFixed ? t : (t * aspect);
             let b = isVerticalFovFixed ? t : (t * aspect);
-            let c = -(f + n)/(f - n);
-            let d = -2*f*n/(f - n);
+            let c = -(f + n) / (f - n);
+            let d = -2 * f * n / (f - n);
 
 
             BABYLON.Matrix.FromValuesToRef(
             BABYLON.Matrix.FromValuesToRef(
                 a, 0.0, 0.0, 0.0,
                 a, 0.0, 0.0, 0.0,
                 0.0, b, 0.0, 0.0,
                 0.0, b, 0.0, 0.0,
-                0.0, 0.0, c,-1.0,
+                0.0, 0.0, c, -1.0,
                 0.0, 0.0, d, 0.0,
                 0.0, 0.0, d, 0.0,
                 result
                 result
             );
             );
@@ -3897,8 +3901,10 @@
         /**
         /**
          * Sets the passed matrix "result" as a left-handed perspective projection matrix  for WebVR computed from the passed floats : vertical angle of view (fov), width/height ratio (aspect), z near and far limits.  
          * Sets the passed matrix "result" as a left-handed perspective projection matrix  for WebVR computed from the passed floats : vertical angle of view (fov), width/height ratio (aspect), z near and far limits.  
          */
          */
-        public static PerspectiveFovWebVRToRef(fov, znear: number, zfar: number, result: Matrix, isVerticalFovFixed = true): void {
-            //left handed
+        public static PerspectiveFovWebVRToRef(fov, znear: number, zfar: number, result: Matrix, rightHanded = false): void {
+
+            var rightHandedFactor = rightHanded ? -1 : 1;
+
             var upTan = Math.tan(fov.upDegrees * Math.PI / 180.0);
             var upTan = Math.tan(fov.upDegrees * Math.PI / 180.0);
             var downTan = Math.tan(fov.downDegrees * Math.PI / 180.0);
             var downTan = Math.tan(fov.downDegrees * Math.PI / 180.0);
             var leftTan = Math.tan(fov.leftDegrees * Math.PI / 180.0);
             var leftTan = Math.tan(fov.leftDegrees * Math.PI / 180.0);
@@ -3908,12 +3914,12 @@
             result.m[0] = xScale;
             result.m[0] = xScale;
             result.m[1] = result.m[2] = result.m[3] = result.m[4] = 0.0;
             result.m[1] = result.m[2] = result.m[3] = result.m[4] = 0.0;
             result.m[5] = yScale;
             result.m[5] = yScale;
-            result.m[6] = result.m[7] =  0.0;
-            result.m[8] = ((leftTan - rightTan) * xScale * 0.5);
-            result.m[9] = -((upTan - downTan) * yScale * 0.5);
-            result.m[10] = -(znear + zfar) / (zfar - znear);
+            result.m[6] = result.m[7] = 0.0;
+            result.m[8] = ((leftTan - rightTan) * xScale * 0.5) * rightHandedFactor;
+            result.m[9] = -((upTan - downTan) * yScale * 0.5) * rightHandedFactor;
+            result.m[10] = -(znear + zfar) / (zfar - znear) * rightHandedFactor;
             // result.m[10] = -zfar / (znear - zfar);
             // result.m[10] = -zfar / (znear - zfar);
-            result.m[11] = 1.0;
+            result.m[11] = 1.0 * rightHandedFactor;
             result.m[12] = result.m[13] = result.m[15] = 0.0;
             result.m[12] = result.m[13] = result.m[15] = 0.0;
             result.m[14] = -(2.0 * zfar * znear) / (zfar - znear);
             result.m[14] = -(2.0 * zfar * znear) / (zfar - znear);
             // result.m[14] = (znear * zfar) / (znear - zfar);
             // result.m[14] = (znear * zfar) / (znear - zfar);
@@ -4028,29 +4034,29 @@
          * Sets the passed matrix "mat" as a rotation matrix composed from the 3 passed  left handed axis.  
          * Sets the passed matrix "mat" as a rotation matrix composed from the 3 passed  left handed axis.  
          */
          */
         public static FromXYZAxesToRef(xaxis: Vector3, yaxis: Vector3, zaxis: Vector3, mat: Matrix) {
         public static FromXYZAxesToRef(xaxis: Vector3, yaxis: Vector3, zaxis: Vector3, mat: Matrix) {
-            
+
             mat.m[0] = xaxis.x;
             mat.m[0] = xaxis.x;
             mat.m[1] = xaxis.y;
             mat.m[1] = xaxis.y;
             mat.m[2] = xaxis.z;
             mat.m[2] = xaxis.z;
 
 
             mat.m[3] = 0.0;
             mat.m[3] = 0.0;
-            
+
             mat.m[4] = yaxis.x;
             mat.m[4] = yaxis.x;
             mat.m[5] = yaxis.y;
             mat.m[5] = yaxis.y;
             mat.m[6] = yaxis.z;
             mat.m[6] = yaxis.z;
-            
+
             mat.m[7] = 0.0;
             mat.m[7] = 0.0;
-            
+
             mat.m[8] = zaxis.x;
             mat.m[8] = zaxis.x;
             mat.m[9] = zaxis.y;
             mat.m[9] = zaxis.y;
             mat.m[10] = zaxis.z;
             mat.m[10] = zaxis.z;
-            
+
             mat.m[11] = 0.0;
             mat.m[11] = 0.0;
-            
+
             mat.m[12] = 0.0;
             mat.m[12] = 0.0;
             mat.m[13] = 0.0;
             mat.m[13] = 0.0;
             mat.m[14] = 0.0;
             mat.m[14] = 0.0;
-            
+
             mat.m[15] = 1.0;
             mat.m[15] = 1.0;
 
 
         }
         }
@@ -4058,7 +4064,7 @@
         /**
         /**
          * Sets the passed matrix "result" as a rotation matrix according to the passed quaternion.  
          * Sets the passed matrix "result" as a rotation matrix according to the passed quaternion.  
          */
          */
-        public static FromQuaternionToRef(quat:Quaternion, result:Matrix){
+        public static FromQuaternionToRef(quat: Quaternion, result: Matrix) {
 
 
             var xx = quat.x * quat.x;
             var xx = quat.x * quat.x;
             var yy = quat.y * quat.y;
             var yy = quat.y * quat.y;
@@ -4863,12 +4869,12 @@
             for (var i = 0; i < totalPoints.length - 3; i++) {
             for (var i = 0; i < totalPoints.length - 3; i++) {
                 var amount = 0.0;
                 var amount = 0.0;
                 for (var c = 0; c < nbPoints; c++) {
                 for (var c = 0; c < nbPoints; c++) {
-                    catmullRom.push( Vector3.CatmullRom(totalPoints[i], totalPoints[i + 1], totalPoints[i + 2], totalPoints[i + 3], amount) );
+                    catmullRom.push(Vector3.CatmullRom(totalPoints[i], totalPoints[i + 1], totalPoints[i + 2], totalPoints[i + 3], amount));
                     amount += step
                     amount += step
                 }
                 }
             }
             }
             i--;
             i--;
-            catmullRom.push( Vector3.CatmullRom(totalPoints[i], totalPoints[i + 1], totalPoints[i + 2], totalPoints[i + 3], amount) );
+            catmullRom.push(Vector3.CatmullRom(totalPoints[i], totalPoints[i + 1], totalPoints[i + 2], totalPoints[i + 3], amount));
             return new Curve3(catmullRom);
             return new Curve3(catmullRom);
         }
         }
 
 
@@ -5031,13 +5037,13 @@
         public static Color3: Color3[] = [Color3.Black(), Color3.Black(), Color3.Black()];
         public static Color3: Color3[] = [Color3.Black(), Color3.Black(), Color3.Black()];
         public static Vector2: Vector2[] = [Vector2.Zero(), Vector2.Zero(), Vector2.Zero()];  // 3 temp Vector2 at once should be enough
         public static Vector2: Vector2[] = [Vector2.Zero(), Vector2.Zero(), Vector2.Zero()];  // 3 temp Vector2 at once should be enough
         public static Vector3: Vector3[] = [Vector3.Zero(), Vector3.Zero(), Vector3.Zero(),
         public static Vector3: Vector3[] = [Vector3.Zero(), Vector3.Zero(), Vector3.Zero(),
-            Vector3.Zero(), Vector3.Zero(), Vector3.Zero(), Vector3.Zero(), Vector3.Zero(), Vector3.Zero()];    // 9 temp Vector3 at once should be enough
+        Vector3.Zero(), Vector3.Zero(), Vector3.Zero(), Vector3.Zero(), Vector3.Zero(), Vector3.Zero()];    // 9 temp Vector3 at once should be enough
         public static Vector4: Vector4[] = [Vector4.Zero(), Vector4.Zero(), Vector4.Zero()];  // 3 temp Vector4 at once should be enough
         public static Vector4: Vector4[] = [Vector4.Zero(), Vector4.Zero(), Vector4.Zero()];  // 3 temp Vector4 at once should be enough
         public static Quaternion: Quaternion[] = [Quaternion.Zero(), Quaternion.Zero()];                // 2 temp Quaternion at once should be enough
         public static Quaternion: Quaternion[] = [Quaternion.Zero(), Quaternion.Zero()];                // 2 temp Quaternion at once should be enough
         public static Matrix: Matrix[] = [Matrix.Zero(), Matrix.Zero(),
         public static Matrix: Matrix[] = [Matrix.Zero(), Matrix.Zero(),
-            Matrix.Zero(), Matrix.Zero(),
-            Matrix.Zero(), Matrix.Zero(),
-            Matrix.Zero(), Matrix.Zero()];                      // 6 temp Matrices at once should be enough
+        Matrix.Zero(), Matrix.Zero(),
+        Matrix.Zero(), Matrix.Zero(),
+        Matrix.Zero(), Matrix.Zero()];                      // 6 temp Matrices at once should be enough
     }
     }
     // Same as Tmp but not exported to keep it onyl for math functions to avoid conflicts
     // Same as Tmp but not exported to keep it onyl for math functions to avoid conflicts
     class MathTmp {
     class MathTmp {

+ 0 - 55
src/Mesh/babylon.abstractMesh.ts

@@ -161,8 +161,6 @@
 
 
         // Physics
         // Physics
         public physicsImpostor: BABYLON.PhysicsImpostor;
         public physicsImpostor: BABYLON.PhysicsImpostor;
-        //Deprecated, Legacy support
-        public onPhysicsCollide: (collidedMesh: AbstractMesh, contact: any) => void;
 
 
         // Collisions
         // Collisions
         private _checkCollisions = false;
         private _checkCollisions = false;
@@ -1100,45 +1098,10 @@
             return this._boundingInfo.intersectsPoint(point);
             return this._boundingInfo.intersectsPoint(point);
         }
         }
 
 
-        // Physics
-        /**
-         *  @Deprecated. Use new PhysicsImpostor instead.
-         * */
-        public setPhysicsState(impostor?: any, options?: PhysicsImpostorParameters): any {
-            //legacy support
-            if (impostor.impostor) {
-                options = impostor;
-                impostor = impostor.impostor;
-            }
-            this.physicsImpostor = new PhysicsImpostor(this, impostor, options, this.getScene());
-            return this.physicsImpostor.physicsBody;
-        }
-
         public getPhysicsImpostor(): PhysicsImpostor {
         public getPhysicsImpostor(): PhysicsImpostor {
             return this.physicsImpostor;
             return this.physicsImpostor;
         }
         }
 
 
-        /**
-         * @Deprecated. Use getPhysicsImpostor().getParam("mass");
-         */
-        public getPhysicsMass(): number {
-            return this.physicsImpostor.getParam("mass")
-        }
-
-        /**
-         * @Deprecated. Use getPhysicsImpostor().getParam("friction");
-         */
-        public getPhysicsFriction(): number {
-            return this.physicsImpostor.getParam("friction")
-        }
-
-        /**
-         * @Deprecated. Use getPhysicsImpostor().getParam("restitution");
-         */
-        public getPhysicsRestitution(): number {
-            return this.physicsImpostor.getParam("restitution")
-        }
-
         public getPositionInCameraSpace(camera?: Camera): Vector3 {
         public getPositionInCameraSpace(camera?: Camera): Vector3 {
             if (!camera) {
             if (!camera) {
                 camera = this.getScene().activeCamera;
                 camera = this.getScene().activeCamera;
@@ -1178,24 +1141,6 @@
             return this;
             return this;
         }
         }
 
 
-        /**
-         * @Deprecated
-         */
-        public updatePhysicsBodyPosition(): void {
-            Tools.Warn("updatePhysicsBodyPosition() is deprecated, please use updatePhysicsBody()");
-            this.updatePhysicsBody();
-        }
-
-        /**
-         * @Deprecated
-         * Calling this function is not needed anymore. 
-         * The physics engine takes care of transofmration automatically.
-         */
-        public updatePhysicsBody(): void {
-            //Unneeded
-        }
-
-
         // Collisions
         // Collisions
 
 
         /**
         /**

+ 5 - 22
src/Mesh/babylon.mesh.ts

@@ -769,24 +769,6 @@
         }
         }
 
 
         /**
         /**
-         * Deprecated since BabylonJS v2.3
-         */
-        public updateVerticesDataDirectly(kind: string, data: Float32Array, offset?: number, makeItUnique?: boolean): void {
-            Tools.Warn("Mesh.updateVerticesDataDirectly deprecated since 2.3.");
-
-            if (!this._geometry) {
-                return;
-            }
-            if (!makeItUnique) {
-                this._geometry.updateVerticesDataDirectly(kind, data, offset);
-            }
-            else {
-                this.makeGeometryUnique();
-                this.updateVerticesDataDirectly(kind, data, offset, false);
-            }
-        }
-
-        /**
          * This method updates the vertex positions of an updatable mesh according to the `positionFunction` returned values.
          * This method updates the vertex positions of an updatable mesh according to the `positionFunction` returned values.
          * tuto : http://doc.babylonjs.com/tutorials/How_to_dynamically_morph_a_mesh#other-shapes-updatemeshpositions  
          * tuto : http://doc.babylonjs.com/tutorials/How_to_dynamically_morph_a_mesh#other-shapes-updatemeshpositions  
          * The parameter `positionFunction` is a simple JS function what is passed the mesh `positions` array. It doesn't need to return anything.
          * The parameter `positionFunction` is a simple JS function what is passed the mesh `positions` array. It doesn't need to return anything.
@@ -1919,9 +1901,10 @@
             // Physics
             // Physics
             //TODO implement correct serialization for physics impostors.
             //TODO implement correct serialization for physics impostors.
             if (this.getPhysicsImpostor()) {
             if (this.getPhysicsImpostor()) {
-                serializationObject.physicsMass = this.getPhysicsMass();
-                serializationObject.physicsFriction = this.getPhysicsFriction();
-                serializationObject.physicsRestitution = this.getPhysicsRestitution();
+                var impostor = this.getPhysicsImpostor();
+                serializationObject.physicsMass = impostor.getParam("mass");
+                serializationObject.physicsFriction = impostor.getParam("friction");
+                serializationObject.physicsRestitution = impostor.getParam("mass");
                 serializationObject.physicsImpostor = this.getPhysicsImpostor().type;
                 serializationObject.physicsImpostor = this.getPhysicsImpostor().type;
             }
             }
 
 
@@ -2173,7 +2156,7 @@
             }
             }
 
 
 
 
-            //(Deprecated) physics
+            // Physics
             if (parsedMesh.physicsImpostor) {
             if (parsedMesh.physicsImpostor) {
                 mesh.physicsImpostor = new BABYLON.PhysicsImpostor(mesh, parsedMesh.physicsImpostor, {
                 mesh.physicsImpostor = new BABYLON.PhysicsImpostor(mesh, parsedMesh.physicsImpostor, {
                     mass: parsedMesh.physicsMass,
                     mass: parsedMesh.physicsMass,

+ 35 - 12
src/Mesh/babylon.mesh.vertexData.ts

@@ -468,7 +468,7 @@
         /**
         /**
          * Creates the vertexData of the Ribbon.  
          * Creates the vertexData of the Ribbon.  
          */
          */
-        public static CreateRibbon(options: { pathArray: Vector3[][], closeArray?: boolean, closePath?: boolean, offset?: number, sideOrientation?: number, invertUV?: boolean }): VertexData {
+        public static CreateRibbon(options: { pathArray: Vector3[][], closeArray?: boolean, closePath?: boolean, offset?: number, sideOrientation?: number, invertUV?: boolean, uvs?: Vector2[], colors?: Color4[] }): VertexData {
             var pathArray: Vector3[][] = options.pathArray;
             var pathArray: Vector3[][] = options.pathArray;
             var closeArray: boolean = options.closeArray || false;
             var closeArray: boolean = options.closeArray || false;
             var closePath: boolean = options.closePath || false;
             var closePath: boolean = options.closePath || false;
@@ -477,6 +477,8 @@
             var offset: number = options.offset || defaultOffset;
             var offset: number = options.offset || defaultOffset;
             offset = offset > defaultOffset ? defaultOffset : Math.floor(offset); // offset max allowed : defaultOffset
             offset = offset > defaultOffset ? defaultOffset : Math.floor(offset); // offset max allowed : defaultOffset
             var sideOrientation: number = (options.sideOrientation === 0) ? 0 : options.sideOrientation || Mesh.DEFAULTSIDE;
             var sideOrientation: number = (options.sideOrientation === 0) ? 0 : options.sideOrientation || Mesh.DEFAULTSIDE;
+            var customUV = options.uvs;
+            var customColors = options.colors;
 
 
             var positions: number[] = [];
             var positions: number[] = [];
             var indices: number[] = [];
             var indices: number[] = [];
@@ -507,7 +509,7 @@
 
 
             // positions and horizontal distances (u)
             // positions and horizontal distances (u)
             var idc: number = 0;
             var idc: number = 0;
-            var closePathCorr: number = (closePath) ? 1 : 0;
+            var closePathCorr: number = (closePath) ? 1 : 0;    // the final index will be +1 if closePath
             var path: Vector3[];
             var path: Vector3[];
             var l: number;
             var l: number;
             minlg = pathArray[0].length;
             minlg = pathArray[0].length;
@@ -532,7 +534,7 @@
                     j++;
                     j++;
                 }
                 }
 
 
-                if (closePath) {
+                if (closePath) {        // an extra hidden vertex is added in the "positions" array
                     j--;
                     j--;
                     positions.push(path[0].x, path[0].y, path[0].z);
                     positions.push(path[0].x, path[0].y, path[0].z);
                     vectlg = path[j].subtract(path[0]).length();
                     vectlg = path[j].subtract(path[0]).length();
@@ -586,14 +588,21 @@
             // uvs
             // uvs
             var u: number;
             var u: number;
             var v: number;
             var v: number;
-            for (p = 0; p < pathArray.length; p++) {
-                for (i = 0; i < minlg + closePathCorr; i++) {
-                    u = (uTotalDistance[p] != 0.0) ? us[p][i] / uTotalDistance[p] : 0.0;
-                    v = (vTotalDistance[i] != 0.0) ? vs[i][p] / vTotalDistance[i] : 0.0;
-                    if (invertUV) {
-                        uvs.push(v, u);
-                    } else {
-                        uvs.push(u, v);
+            if (customUV) {
+                for (p = 0; p < customUV.length; p++) {
+                    uvs.push(customUV[p].x, customUV[p].y);
+                }
+            }
+            else {
+                for (p = 0; p < pathArray.length; p++) {
+                    for (i = 0; i < minlg + closePathCorr; i++) {
+                        u = (uTotalDistance[p] != 0.0) ? us[p][i] / uTotalDistance[p] : 0.0;
+                        v = (vTotalDistance[i] != 0.0) ? vs[i][p] / vTotalDistance[i] : 0.0;
+                        if (invertUV) {
+                            uvs.push(v, u);
+                        } else {
+                            uvs.push(u, v);
+                        }
                     }
                     }
                 }
                 }
             }
             }
@@ -633,7 +642,7 @@
             // normals
             // normals
             VertexData.ComputeNormals(positions, indices, normals);
             VertexData.ComputeNormals(positions, indices, normals);
 
 
-            if (closePath) {
+            if (closePath) {        // update both the first and last vertex normals to their average value
                 var indexFirst: number = 0;
                 var indexFirst: number = 0;
                 var indexLast: number = 0;
                 var indexLast: number = 0;
                 for (p = 0; p < pathArray.length; p++) {
                 for (p = 0; p < pathArray.length; p++) {
@@ -656,6 +665,17 @@
             // sides
             // sides
             VertexData._ComputeSides(sideOrientation, positions, indices, normals, uvs);
             VertexData._ComputeSides(sideOrientation, positions, indices, normals, uvs);
 
 
+            // Colors
+            if (customColors) {
+                var colors = new Float32Array(customColors.length * 4);
+                for (var c = 0; c < customColors.length; c++) {
+                    colors[c * 4] = customColors[c].r;
+                    colors[c * 4 + 1] = customColors[c].g;
+                    colors[c * 4 + 2] = customColors[c].b;
+                    colors[c * 4 + 3] = customColors[c].a;
+                }
+            }
+
             // Result
             // Result
             var vertexData = new VertexData();
             var vertexData = new VertexData();
 
 
@@ -663,6 +683,9 @@
             vertexData.positions = positions;
             vertexData.positions = positions;
             vertexData.normals = normals;
             vertexData.normals = normals;
             vertexData.uvs = uvs;
             vertexData.uvs = uvs;
+            if (customColors) {
+                vertexData.set(colors, VertexBuffer.ColorKind);
+            }
 
 
             if (closePath) {
             if (closePath) {
                 (<any>vertexData)._idx = idx;
                 (<any>vertexData)._idx = idx;

+ 24 - 1
src/Mesh/babylon.meshBuilder.ts

@@ -122,9 +122,14 @@
          * You can also set the mesh side orientation with the values : BABYLON.Mesh.FRONTSIDE (default), BABYLON.Mesh.BACKSIDE or BABYLON.Mesh.DOUBLESIDE  
          * You can also set the mesh side orientation with the values : BABYLON.Mesh.FRONTSIDE (default), BABYLON.Mesh.BACKSIDE or BABYLON.Mesh.DOUBLESIDE  
          * Detail here : http://doc.babylonjs.com/tutorials/02._Discover_Basic_Elements#side-orientation    
          * Detail here : http://doc.babylonjs.com/tutorials/02._Discover_Basic_Elements#side-orientation    
          * The optional parameter `invertUV` (boolean, default false) swaps in the geometry the U and V coordinates to apply a texture.  
          * The optional parameter `invertUV` (boolean, default false) swaps in the geometry the U and V coordinates to apply a texture.  
+         * The parameter `uvs` is an optional flat array of `Vector4` to update/set each ribbon vertex with its own custom UV values instead of the computed ones.  
+         * The parameters `colors` is an optional flat array of `Color4` to set/update each ribbon vertex with its own custom color values.  
+         * Note that if you use the parameters `uvs` or `colors`, the passed arrays must be populated with the right number of elements, it is to say the number of ribbon vertices. Remember that 
+         * if you set `closePath` to `true`, there's one extra vertex per path in the geometry.  
+         * Moreover, you can use the parameter `color` with `instance` (to update the ribbon), only if you previously used it at creation time.  
          * The mesh can be set to updatable with the boolean parameter `updatable` (default false) if its internal geometry is supposed to change once created.  
          * The mesh can be set to updatable with the boolean parameter `updatable` (default false) if its internal geometry is supposed to change once created.  
          */
          */
-        public static CreateRibbon(name: string, options: { pathArray: Vector3[][], closeArray?: boolean, closePath?: boolean, offset?: number, updatable?: boolean, sideOrientation?: number, instance?: Mesh, invertUV?: boolean }, scene?: Scene): Mesh {
+        public static CreateRibbon(name: string, options: { pathArray: Vector3[][], closeArray?: boolean, closePath?: boolean, offset?: number, updatable?: boolean, sideOrientation?: number, instance?: Mesh, invertUV?: boolean, uvs?: Vector2[], colors?: Color4[] }, scene?: Scene): Mesh {
             var pathArray = options.pathArray;
             var pathArray = options.pathArray;
             var closeArray = options.closeArray;
             var closeArray = options.closeArray;
             var closePath = options.closePath;
             var closePath = options.closePath;
@@ -187,6 +192,24 @@
                 instance._boundingInfo = new BoundingInfo(Tmp.Vector3[0], Tmp.Vector3[1]);
                 instance._boundingInfo = new BoundingInfo(Tmp.Vector3[0], Tmp.Vector3[1]);
                 instance._boundingInfo.update(instance._worldMatrix);
                 instance._boundingInfo.update(instance._worldMatrix);
                 instance.updateVerticesData(VertexBuffer.PositionKind, positions, false, false);
                 instance.updateVerticesData(VertexBuffer.PositionKind, positions, false, false);
+                if (options.colors) {
+                    var colors = instance.getVerticesData(VertexBuffer.ColorKind);
+                    for (var c = 0; c < options.colors.length; c++) {
+                        colors[c * 4] = options.colors[c].r;
+                        colors[c * 4 + 1] = options.colors[c].g;
+                        colors[c * 4 + 2] = options.colors[c].b;
+                        colors[c * 4 + 3] = options.colors[c].a;
+                    }
+                    instance.updateVerticesData(VertexBuffer.ColorKind, colors, false, false);
+                }
+                if (options.uvs) {
+                    var uvs = instance.getVerticesData(VertexBuffer.UVKind);
+                    for (var i = 0; i < options.uvs.length; i++) {
+                        uvs[i * 2] = options.uvs[i].x;
+                        uvs[i * 2 + 1] = options.uvs[i].y;
+                    }
+                    instance.updateVerticesData(VertexBuffer.UVKind, uvs, false, false);
+                }
                 if (!instance.areNormalsFrozen || instance.isFacetDataEnabled) {
                 if (!instance.areNormalsFrozen || instance.isFacetDataEnabled) {
                     var indices = instance.getIndices();
                     var indices = instance.getIndices();
                     var normals = instance.getVerticesData(VertexBuffer.NormalKind);
                     var normals = instance.getVerticesData(VertexBuffer.NormalKind);

+ 3 - 3
src/Physics/Plugins/babylon.cannonJSPlugin.ts

@@ -227,7 +227,7 @@
             var returnValue;
             var returnValue;
             var extendSize = impostor.getObjectExtendSize();
             var extendSize = impostor.getObjectExtendSize();
             switch (impostor.type) {
             switch (impostor.type) {
-                case PhysicsEngine.SphereImpostor:
+                case PhysicsImpostor.SphereImpostor:
                     var radiusX = extendSize.x;
                     var radiusX = extendSize.x;
                     var radiusY = extendSize.y;
                     var radiusY = extendSize.y;
                     var radiusZ = extendSize.z;
                     var radiusZ = extendSize.z;
@@ -352,7 +352,7 @@
             }
             }
 
 
             //If it is a heightfield, if should be centered.
             //If it is a heightfield, if should be centered.
-            if (impostor.type === PhysicsEngine.HeightmapImpostor) {
+            if (impostor.type === PhysicsImpostor.HeightmapImpostor) {
                 var mesh = <AbstractMesh>(<any>object);
                 var mesh = <AbstractMesh>(<any>object);
                 //calculate the correct body position:
                 //calculate the correct body position:
                 var rotationQuaternion = mesh.rotationQuaternion;
                 var rotationQuaternion = mesh.rotationQuaternion;
@@ -382,7 +382,7 @@
 
 
                 mesh.setPivotMatrix(oldPivot);
                 mesh.setPivotMatrix(oldPivot);
                 mesh.computeWorldMatrix(true);
                 mesh.computeWorldMatrix(true);
-            } else if (impostor.type === PhysicsEngine.MeshImpostor) {
+            } else if (impostor.type === PhysicsImpostor.MeshImpostor) {
                 this._tmpDeltaPosition.copyFromFloats(0, 0, 0);
                 this._tmpDeltaPosition.copyFromFloats(0, 0, 0);
                 this._tmpPosition.copyFrom(object.position);
                 this._tmpPosition.copyFrom(object.position);
             }
             }

+ 2 - 17
src/Physics/babylon.physicsEngine.ts

@@ -47,24 +47,9 @@
             return this._physicsPlugin.name;
             return this._physicsPlugin.name;
         }
         }
 
 
-        // Statics, Legacy support.
-        /**
-         * @Deprecated
-         *  
-         */
-        public static NoImpostor = PhysicsImpostor.NoImpostor;
-        public static SphereImpostor = PhysicsImpostor.SphereImpostor;
-        public static BoxImpostor = PhysicsImpostor.BoxImpostor;
-        public static PlaneImpostor = PhysicsImpostor.PlaneImpostor;
-        public static MeshImpostor = PhysicsImpostor.MeshImpostor;
-        public static CylinderImpostor = PhysicsImpostor.CylinderImpostor;
-        public static HeightmapImpostor = PhysicsImpostor.HeightmapImpostor;
-        public static CapsuleImpostor = -1;
-        public static ConeImpostor = -1;
-        public static ConvexHullImpostor = -1;
-
+        // Statics
         public static Epsilon = 0.001;
         public static Epsilon = 0.001;
-        
+
         //new methods and parameters
         //new methods and parameters
         
         
         private _impostors: Array<PhysicsImpostor> = [];
         private _impostors: Array<PhysicsImpostor> = [];

+ 8 - 0
src/PostProcess/babylon.postProcess.ts

@@ -14,6 +14,8 @@
         */ 
         */ 
         public enablePixelPerfectMode = false;
         public enablePixelPerfectMode = false;
 
 
+        public samples = 1;
+
         private _camera: Camera;
         private _camera: Camera;
         private _scene: Scene;
         private _scene: Scene;
         private _engine: Engine;
         private _engine: Engine;
@@ -193,6 +195,12 @@
                 this.onSizeChangedObservable.notifyObservers(this);
                 this.onSizeChangedObservable.notifyObservers(this);
             }
             }
 
 
+            this._textures.forEach(texture => {
+                if (texture.samples !== this.samples) {
+                    this._engine.updateRenderTargetTextureSampleCount(texture, this.samples);
+                }
+            });
+
             if (this.enablePixelPerfectMode) {
             if (this.enablePixelPerfectMode) {
                 this._scaleRatio.copyFromFloats(requiredWidth / desiredWidth, requiredHeight / desiredHeight);
                 this._scaleRatio.copyFromFloats(requiredWidth / desiredWidth, requiredHeight / desiredHeight);
                 this._engine.bindFramebuffer(this._textures.data[this._currentRenderTextureInd], 0, requiredWidth, requiredHeight);
                 this._engine.bindFramebuffer(this._textures.data[this._currentRenderTextureInd], 0, requiredWidth, requiredHeight);

+ 0 - 17
src/PostProcess/babylon.ssaoRenderingPipeline.ts

@@ -126,23 +126,6 @@
         }
         }
 
 
         // Public Methods
         // Public Methods
-        /**
-         * Returns the horizontal blur PostProcess
-         * @return {BABYLON.BlurPostProcess} The horizontal blur post-process
-         */
-        public getBlurHPostProcess(): BlurPostProcess {
-            Tools.Error("SSAORenderinPipeline.getBlurHPostProcess() is deprecated, no more blur post-process exists");
-            return null;
-        }
-
-        /**
-         * Returns the vertical blur PostProcess
-         * @return {BABYLON.BlurPostProcess} The vertical blur post-process
-         */
-        public getBlurVPostProcess(): BlurPostProcess {
-            Tools.Error("SSAORenderinPipeline.getBlurVPostProcess() is deprecated, no more blur post-process exists");
-            return null;
-        }
 
 
         /**
         /**
          * Removes the internal pipeline assets and detatches the pipeline from the scene cameras
          * Removes the internal pipeline assets and detatches the pipeline from the scene cameras

+ 348 - 0
src/Tools/babylon.extendedGamepad.ts

@@ -0,0 +1,348 @@
+
+module BABYLON {
+
+    export enum PoseEnabledControllerType {
+        VIVE,
+        OCULUS,
+        GENERIC
+    }
+
+    export interface MutableGamepadButton {
+        value: number;
+        touched: boolean;
+        pressed: boolean;
+    }
+
+    export class PoseEnabledControllerHelper {
+        public static InitiateController(vrGamepad: any) {
+            // for now, only Oculus and Vive are supported
+            if (vrGamepad.id.indexOf('Oculus Touch') !== -1) {
+                return new OculusTouchController(vrGamepad);
+            } else {
+                return new ViveController(vrGamepad);
+            }
+        }
+    }
+
+    export class PoseEnabledController extends Gamepad implements PoseControlled {
+        devicePosition: Vector3;
+        deviceRotationQuaternion: Quaternion;
+        deviceScaleFactor: number = 1;
+
+        public position: Vector3;
+        public rotationQuaternion: Quaternion;
+        public controllerType: PoseEnabledControllerType;
+
+        private _calculatedPosition: Vector3;
+        private _calculatedRotation: Quaternion;
+
+        public rawPose: DevicePose; //GamepadPose;
+
+        private _mesh: AbstractMesh; // a node that will be attached to this Gamepad
+        private _poseControlledCamera: PoseControlled;
+
+        constructor(public vrGamepad) {
+            super(vrGamepad.id, vrGamepad.index, vrGamepad);
+            this.type = Gamepad.POSE_ENABLED;
+            this.controllerType = PoseEnabledControllerType.GENERIC;
+            this.position = Vector3.Zero();
+            this.rotationQuaternion = new Quaternion();
+            this.devicePosition = Vector3.Zero();
+            this.deviceRotationQuaternion = new Quaternion();
+
+            this._calculatedPosition = Vector3.Zero();
+            this._calculatedRotation = new Quaternion();
+        }
+
+        public update() {
+            super.update();
+            // update this device's offset position from the attached camera, if provided
+            if (this._poseControlledCamera && this._poseControlledCamera.deviceScaleFactor) {
+                //this.position.copyFrom(this._poseControlledCamera.position);
+                //this.rotationQuaternion.copyFrom(this._poseControlledCamera.rotationQuaternion);
+                this.deviceScaleFactor = this._poseControlledCamera.deviceScaleFactor;
+            }
+            var pose: GamepadPose = this.vrGamepad.pose;
+            this.updateFromDevice(pose);
+
+            if (this._mesh) {
+                this._mesh.position.copyFrom(this._calculatedPosition);
+                this._mesh.rotationQuaternion.copyFrom(this._calculatedRotation);
+            }
+        }
+
+        updateFromDevice(poseData: DevicePose) {
+            if (poseData) {
+                this.rawPose = poseData;
+                if (poseData.position) {
+                    this.devicePosition.copyFromFloats(poseData.position[0], poseData.position[1], -poseData.position[2]);
+                    if (this._mesh && this._mesh.getScene().useRightHandedSystem) {
+                        this.devicePosition.z *= -1;
+                    }
+
+                    this.devicePosition.scaleToRef(this.deviceScaleFactor, this._calculatedPosition);
+                    this._calculatedPosition.addInPlace(this.position);
+
+                    // scale the position using the scale factor, add the device's position
+                    if (this._poseControlledCamera) {
+                        // this allows total positioning freedom - the device, the camera and the mesh can be individually controlled.
+                        this._calculatedPosition.addInPlace(this._poseControlledCamera.position);
+                    }
+                }
+                if (poseData.orientation) {
+                    this.deviceRotationQuaternion.copyFromFloats(this.rawPose.orientation[0], this.rawPose.orientation[1], -this.rawPose.orientation[2], -this.rawPose.orientation[3]);
+                    if (this._mesh && this._mesh.getScene().useRightHandedSystem) {
+                        this.deviceRotationQuaternion.z *= -1;
+                        this.deviceRotationQuaternion.w *= -1;
+                    }
+
+                    // if the camera is set, rotate to the camera's rotation
+                    this.rotationQuaternion.multiplyToRef(this.deviceRotationQuaternion, this._calculatedRotation);
+                    if (this._poseControlledCamera) {
+                        this._calculatedRotation.multiplyToRef(this._poseControlledCamera.rotationQuaternion, this._calculatedRotation);
+                    }
+                }
+            }
+        }
+
+
+        public attachToMesh(mesh: AbstractMesh) {
+            this._mesh = mesh;
+            if (!this._mesh.rotationQuaternion) {
+                this._mesh.rotationQuaternion = new Quaternion();
+            }
+        }
+
+        public attachToPoseControlledCamera(camera: PoseControlled) {
+            this._poseControlledCamera = camera;
+            this.deviceScaleFactor = camera.deviceScaleFactor;
+        }
+
+        public detachMesh() {
+            this._mesh = undefined;
+        }
+    }
+
+    export interface GamepadButtonChanges {
+        changed: boolean;
+        pressChanged: boolean;
+        touchChanged: boolean;
+        valueChanged: boolean;
+    }
+
+    export abstract class WebVRController extends PoseEnabledController {
+
+        //public onTriggerStateChangedObservable = new Observable<{ state: ExtendedGamepadButton, changes: GamepadButtonChanges }>();
+
+        public onTriggerStateChangedObservable = new Observable<ExtendedGamepadButton>();
+
+
+        public onMainButtonStateChangedObservable = new Observable<ExtendedGamepadButton>();
+
+        public onSecondaryButtonStateChangedObservable = new Observable<ExtendedGamepadButton>();
+
+        public onPadStateChangedObservable = new Observable<ExtendedGamepadButton>();
+        public onPadValuesChangedObservable = new Observable<StickValues>();
+
+        protected _buttons: Array<MutableGamepadButton>;
+
+        private _onButtonStateChange: (controlledIndex: number, buttonIndex: number, state: ExtendedGamepadButton) => void;
+
+        public onButtonStateChange(callback: (controlledIndex: number, buttonIndex: number, state: ExtendedGamepadButton) => void) {
+            this._onButtonStateChange = callback;
+        }
+
+        public pad: StickValues = { x: 0, y: 0 };
+
+        public hand: string; // 'left' or 'right', see https://w3c.github.io/gamepad/extensions.html#gamepadhand-enum
+
+        constructor(vrGamepad) {
+            super(vrGamepad);
+            this._buttons = new Array<ExtendedGamepadButton>(vrGamepad.buttons.length);
+            this.hand = vrGamepad.hand;
+        }
+
+        public update() {
+            super.update();
+            for (var index = 0; index < this._buttons.length; index++) {
+                this._setButtonValue(this.vrGamepad.buttons[index], this._buttons[index], index);
+            };
+            if (this.leftStick.x !== this.pad.x || this.leftStick.y !== this.pad.y) {
+                this.pad.x = this.leftStick.x;
+                this.pad.y = this.leftStick.y;
+                this.onPadValuesChangedObservable.notifyObservers(this.pad);
+            }
+        }
+
+        protected abstract handleButtonChange(buttonIdx: number, value: ExtendedGamepadButton, changes: GamepadButtonChanges);
+
+        private _setButtonValue(newState: ExtendedGamepadButton, currentState: ExtendedGamepadButton, buttonIndex: number) {
+            if (!currentState) {
+                this._buttons[buttonIndex] = {
+                    pressed: newState.pressed,
+                    touched: newState.touched,
+                    value: newState.value
+                }
+                return;
+            }
+            this._checkChanges(newState, currentState);
+            if (this._changes.changed) {
+                this._onButtonStateChange && this._onButtonStateChange(this.index, buttonIndex, newState);
+
+                this.handleButtonChange(buttonIndex, newState, this._changes);
+            }
+            this._buttons[buttonIndex].pressed = newState.pressed;
+            this._buttons[buttonIndex].touched = newState.touched;
+            // oculus triggers are never 0, thou not touched.
+            this._buttons[buttonIndex].value = newState.value < 0.00000001 ? 0 : newState.value;
+        }
+
+        // avoid GC, store state in a tmp object
+        private _changes: GamepadButtonChanges = {
+            pressChanged: false,
+            touchChanged: false,
+            valueChanged: false,
+            changed: false
+        };
+
+        private _checkChanges(newState: ExtendedGamepadButton, currentState: ExtendedGamepadButton) {
+            this._changes.pressChanged = newState.pressed !== currentState.pressed;
+            this._changes.touchChanged = newState.touched !== currentState.touched;
+            this._changes.valueChanged = newState.value !== currentState.value;
+            this._changes.changed = this._changes.pressChanged || this._changes.touchChanged || this._changes.valueChanged;
+            return this._changes;
+        }
+    }
+
+    export class OculusTouchController extends WebVRController {
+
+        public onSecondaryTriggerStateChangedObservable = new Observable<ExtendedGamepadButton>();
+
+        public onThumbRestChangedObservable = new Observable<ExtendedGamepadButton>();
+
+        constructor(vrGamepad) {
+            super(vrGamepad);
+            this.controllerType = PoseEnabledControllerType.OCULUS;
+        }
+
+        // helper getters for left and right hand.
+        public get onAButtonStateChangedObservable() {
+            if (this.hand === 'right') {
+                return this.onMainButtonStateChangedObservable;
+            } else {
+                throw new Error('No A button on left hand');
+            }
+        }
+
+        public get onBButtonStateChangedObservable() {
+            if (this.hand === 'right') {
+                return this.onSecondaryButtonStateChangedObservable;
+            } else {
+                throw new Error('No B button on left hand');
+            }
+        }
+
+        public get onXButtonStateChangedObservable() {
+            if (this.hand === 'left') {
+                return this.onMainButtonStateChangedObservable;
+            } else {
+                throw new Error('No X button on right hand');
+            }
+        }
+
+        public get onYButtonStateChangedObservable() {
+            if (this.hand === 'left') {
+                return this.onSecondaryButtonStateChangedObservable;
+            } else {
+                throw new Error('No Y button on right hand');
+            }
+        }
+
+        /*
+         0) thumb stick (touch, press, value = pressed (0,1)). value is in this.leftStick
+         1) index trigger (touch (?), press (only when value > 0.1), value 0 to 1)
+         2) secondary trigger (same)
+         3) A (right) X (left), touch, pressed = value
+         4) B / Y 
+         5) thumb rest
+        */
+        protected handleButtonChange(buttonIdx: number, state: ExtendedGamepadButton, changes: GamepadButtonChanges) {
+            let notifyObject = state; //{ state: state, changes: changes };
+            switch (buttonIdx) {
+                case 0:
+                    this.onPadStateChangedObservable.notifyObservers(notifyObject);
+                    return;
+                case 1: // index trigger
+                    this.onTriggerStateChangedObservable.notifyObservers(notifyObject);
+                    return;
+                case 2:  // secondary trigger
+                    this.onSecondaryTriggerStateChangedObservable.notifyObservers(notifyObject);
+                    return;
+                case 3:
+                    this.onMainButtonStateChangedObservable.notifyObservers(notifyObject);
+                    return;
+                case 4:
+                    this.onSecondaryButtonStateChangedObservable.notifyObservers(notifyObject);
+                    return;
+                case 5:
+                    this.onThumbRestChangedObservable.notifyObservers(notifyObject);
+                    return;
+            }
+        }
+
+    }
+
+    export class ViveController extends WebVRController {
+
+
+        constructor(vrGamepad) {
+            super(vrGamepad);
+            this.controllerType = PoseEnabledControllerType.VIVE;
+        }
+
+        public get onLeftButtonStateChangedObservable() {
+            return this.onMainButtonStateChangedObservable;
+        }
+
+        public get onRightButtonStateChangedObservable() {
+            return this.onMainButtonStateChangedObservable;
+        }
+
+        public get onMenuButtonStateChangedObservable() {
+            return this.onSecondaryButtonStateChangedObservable;
+        }
+
+        /**
+         * Vive mapping:
+         * 0: touchpad
+         * 1: trigger
+         * 2: left AND right buttons
+         * 3: menu button
+         */
+        protected handleButtonChange(buttonIdx: number, state: ExtendedGamepadButton, changes: GamepadButtonChanges) {
+            let notifyObject = state; //{ state: state, changes: changes };
+            switch (buttonIdx) {
+                case 0:
+                    this.onPadStateChangedObservable.notifyObservers(notifyObject);
+                    return;
+                case 1: // index trigger
+                    this.onTriggerStateChangedObservable.notifyObservers(notifyObject);
+                    return;
+                case 2:  // left AND right button
+                    this.onMainButtonStateChangedObservable.notifyObservers(notifyObject);
+                    return;
+                case 3:
+                    this.onSecondaryButtonStateChangedObservable.notifyObservers(notifyObject);
+                    return;
+            }
+        }
+    }
+
+
+}
+
+interface ExtendedGamepadButton extends GamepadButton {
+    readonly pressed: boolean;
+    readonly touched: boolean;
+    readonly value: number;
+}

+ 39 - 19
src/Tools/babylon.gamepads.ts

@@ -1,29 +1,33 @@
 module BABYLON {
 module BABYLON {
-    export class Gamepads {
-        private babylonGamepads: Array<Gamepad> = [];
+    export class Gamepads<T extends Gamepad> {
+        private babylonGamepads: Array<T> = [];
         private oneGamepadConnected: boolean = false;
         private oneGamepadConnected: boolean = false;
 
 
         private isMonitoring: boolean = false;
         private isMonitoring: boolean = false;
         private gamepadEventSupported: boolean = 'GamepadEvent' in window;
         private gamepadEventSupported: boolean = 'GamepadEvent' in window;
-        private gamepadSupportAvailable: boolean = <boolean>(navigator.getGamepads ||
-            !!navigator.webkitGetGamepads || !!navigator.msGetGamepads || !!navigator.webkitGamepads);
+        private gamepadSupport: () => Array<any> = (navigator.getGamepads ||
+            navigator.webkitGetGamepads || navigator.msGetGamepads || navigator.webkitGamepads);
 
 
-        private _callbackGamepadConnected: (gamepad: Gamepad) => void;
+        private _callbackGamepadConnected: (gamepad: T) => void;
 
 
-        private _onGamepadConnectedEvent: (evt: Event) => void;
+        private _onGamepadConnectedEvent: (evt) => void;
         private _onGamepadDisonnectedEvent: (evt: Event) => void;
         private _onGamepadDisonnectedEvent: (evt: Event) => void;
 
 
         private static gamepadDOMInfo: HTMLElement;
         private static gamepadDOMInfo: HTMLElement;
 
 
 
 
-        constructor(ongamedpadconnected: (gamepad: Gamepad) => void) {
+        constructor(ongamedpadconnected: (gamepad: T) => void) {
             this._callbackGamepadConnected = ongamedpadconnected;
             this._callbackGamepadConnected = ongamedpadconnected;
-            if (this.gamepadSupportAvailable) {
-
+            if (this.gamepadSupport) {
+                //first add already-connected gamepads
+                this._updateGamepadObjects();
+                if (this.babylonGamepads.length) {
+                    this._startMonitoringGamepads();
+                }
                 // Checking if the gamepad connected event is supported (like in Firefox)
                 // Checking if the gamepad connected event is supported (like in Firefox)
                 if (this.gamepadEventSupported) {
                 if (this.gamepadEventSupported) {
                     this._onGamepadConnectedEvent = (evt) => {
                     this._onGamepadConnectedEvent = (evt) => {
-                        this._onGamepadConnected(evt);
+                        this._onGamepadConnected(evt.gamepad);
                     };
                     };
                     this._onGamepadDisonnectedEvent = (evt) => {
                     this._onGamepadDisonnectedEvent = (evt) => {
                         this._onGamepadDisconnected(evt);
                         this._onGamepadDisconnected(evt);
@@ -41,8 +45,8 @@
             if (Gamepads.gamepadDOMInfo) {
             if (Gamepads.gamepadDOMInfo) {
                 document.body.removeChild(Gamepads.gamepadDOMInfo);
                 document.body.removeChild(Gamepads.gamepadDOMInfo);
             }
             }
-            
-            if (this._onGamepadConnectedEvent){
+
+            if (this._onGamepadConnectedEvent) {
                 window.removeEventListener('gamepadconnected', this._onGamepadConnectedEvent, false);
                 window.removeEventListener('gamepadconnected', this._onGamepadConnectedEvent, false);
                 window.removeEventListener('gamepaddisconnected', this._onGamepadDisonnectedEvent, false);
                 window.removeEventListener('gamepaddisconnected', this._onGamepadDisonnectedEvent, false);
                 this._onGamepadConnectedEvent = null;
                 this._onGamepadConnectedEvent = null;
@@ -50,13 +54,13 @@
             }
             }
         }
         }
 
 
-        private _onGamepadConnected(evt) {
-            var newGamepad = this._addNewGamepad(evt.gamepad);
+        private _onGamepadConnected(gamepad) {
+            var newGamepad = this._addNewGamepad(gamepad);
             if (this._callbackGamepadConnected) this._callbackGamepadConnected(newGamepad);
             if (this._callbackGamepadConnected) this._callbackGamepadConnected(newGamepad);
             this._startMonitoringGamepads();
             this._startMonitoringGamepads();
         }
         }
 
 
-        private _addNewGamepad(gamepad): Gamepad {
+        private _addNewGamepad(gamepad): T {
             if (!this.oneGamepadConnected) {
             if (!this.oneGamepadConnected) {
                 this.oneGamepadConnected = true;
                 this.oneGamepadConnected = true;
                 if (Gamepads.gamepadDOMInfo) {
                 if (Gamepads.gamepadDOMInfo) {
@@ -70,6 +74,11 @@
             if (xboxOne || (<string>gamepad.id).search("Xbox 360") !== -1 || (<string>gamepad.id).search("xinput") !== -1) {
             if (xboxOne || (<string>gamepad.id).search("Xbox 360") !== -1 || (<string>gamepad.id).search("xinput") !== -1) {
                 newGamepad = new Xbox360Pad(gamepad.id, gamepad.index, gamepad, xboxOne);
                 newGamepad = new Xbox360Pad(gamepad.id, gamepad.index, gamepad, xboxOne);
             }
             }
+            // (<string>gamepad.id).search("Open VR") !== -1 || (<string>gamepad.id).search("Oculus Touch") !== -1
+            // if pose is supported, use the (WebVR) pose enabled controller
+            else if (gamepad.pose) {
+                newGamepad = PoseEnabledControllerHelper.InitiateController(gamepad);
+            }
             else {
             else {
                 newGamepad = new GenericPad(gamepad.id, gamepad.index, gamepad);
                 newGamepad = new GenericPad(gamepad.id, gamepad.index, gamepad);
             }
             }
@@ -147,6 +156,9 @@
         }
         }
     }
     }
     export class Gamepad {
     export class Gamepad {
+
+        public type: number;
+
         private _leftStick: StickValues;
         private _leftStick: StickValues;
         private _rightStick: StickValues;
         private _rightStick: StickValues;
 
 
@@ -158,7 +170,13 @@
         private _onleftstickchanged: (values: StickValues) => void;
         private _onleftstickchanged: (values: StickValues) => void;
         private _onrightstickchanged: (values: StickValues) => void;
         private _onrightstickchanged: (values: StickValues) => void;
 
 
-        constructor(public id: string, public index: number, public browserGamepad, leftStickX:number = 0, leftStickY:number = 1, rightStickX:number = 2, rightStickY:number = 3) {
+        public static GAMEPAD = 0;
+        public static GENERIC = 1;
+        public static XBOX = 2;
+        public static POSE_ENABLED = 3;
+
+        constructor(public id: string, public index: number, public browserGamepad, leftStickX: number = 0, leftStickY: number = 1, rightStickX: number = 2, rightStickY: number = 3) {
+            this.type = Gamepad.GAMEPAD;
             this._leftStickAxisX = leftStickX;
             this._leftStickAxisX = leftStickX;
             this._leftStickAxisY = leftStickY;
             this._leftStickAxisY = leftStickY;
             this._rightStickAxisX = rightStickX;
             this._rightStickAxisX = rightStickX;
@@ -222,6 +240,7 @@
 
 
         constructor(public id: string, public index: number, public gamepad) {
         constructor(public id: string, public index: number, public gamepad) {
             super(id, index, gamepad);
             super(id, index, gamepad);
+            this.type = Gamepad.GENERIC;
             this._buttons = new Array(gamepad.buttons.length);
             this._buttons = new Array(gamepad.buttons.length);
         }
         }
 
 
@@ -293,10 +312,11 @@
         private _dPadLeft: number = 0;
         private _dPadLeft: number = 0;
         private _dPadRight: number = 0;
         private _dPadRight: number = 0;
 
 
-        private _isXboxOnePad:boolean = false;
+        private _isXboxOnePad: boolean = false;
 
 
-        constructor(id: string, index: number, gamepad:any, xboxOne:boolean = false) {
+        constructor(id: string, index: number, gamepad: any, xboxOne: boolean = false) {
             super(id, index, gamepad, 0, 1, (xboxOne ? 3 : 2), (xboxOne ? 4 : 3));
             super(id, index, gamepad, 0, 1, (xboxOne ? 3 : 2), (xboxOne ? 4 : 3));
+            this.type = Gamepad.XBOX;
             this._isXboxOnePad = xboxOne;
             this._isXboxOnePad = xboxOne;
         }
         }
 
 
@@ -495,4 +515,4 @@ interface Navigator {
     webkitGetGamepads(func?: any): any
     webkitGetGamepads(func?: any): any
     msGetGamepads(func?: any): any;
     msGetGamepads(func?: any): any;
     webkitGamepads(func?: any): any;
     webkitGamepads(func?: any): any;
-}
+}

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

@@ -25,6 +25,12 @@
             value.__smartArrayFlags[this._id] = this._duplicateId;
             value.__smartArrayFlags[this._id] = this._duplicateId;
         }
         }
 
 
+        public forEach(func: (content: T) => void): void {
+            for (var index = 0; index < this.length; index++) {
+                func(this.data[index]);
+            }
+        }
+
         public pushNoDuplicate(value): boolean {
         public pushNoDuplicate(value): boolean {
             if (value.__smartArrayFlags && value.__smartArrayFlags[this._id] === this._duplicateId) {
             if (value.__smartArrayFlags && value.__smartArrayFlags[this._id] === this._duplicateId) {
                 return false;
                 return false;

+ 3 - 2
src/Tools/babylon.tools.ts

@@ -1,4 +1,4 @@
-module BABYLON {
+module BABYLON {
     export interface IAnimatable {
     export interface IAnimatable {
         animations: Array<Animation>;
         animations: Array<Animation>;
     }
     }
@@ -745,7 +745,7 @@
             Tools.EncodeScreenshotCanvasData(successCallback, mimeType);
             Tools.EncodeScreenshotCanvasData(successCallback, mimeType);
         }
         }
 
 
-        public static CreateScreenshotUsingRenderTarget(engine: Engine, camera: Camera, size: any, successCallback?: (data: string) => void, mimeType: string = "image/png"): void {
+        public static CreateScreenshotUsingRenderTarget(engine: Engine, camera: Camera, size: any, successCallback?: (data: string) => void, mimeType: string = "image/png", samples: number = 1): void {
             var width: number;
             var width: number;
             var height: number;
             var height: number;
 
 
@@ -792,6 +792,7 @@
             //At this point size can be a number, or an object (according to engine.prototype.createRenderTargetTexture method)
             //At this point size can be a number, or an object (according to engine.prototype.createRenderTargetTexture method)
             var texture = new RenderTargetTexture("screenShot", size, scene, false, false, Engine.TEXTURETYPE_UNSIGNED_INT, false, Texture.NEAREST_SAMPLINGMODE);
             var texture = new RenderTargetTexture("screenShot", size, scene, false, false, Engine.TEXTURETYPE_UNSIGNED_INT, false, Texture.NEAREST_SAMPLINGMODE);
             texture.renderList = scene.meshes;
             texture.renderList = scene.meshes;
+            texture.samples = samples;
 
 
             texture.onAfterRenderObservable.add(() => {
             texture.onAfterRenderObservable.add(() => {
                 Tools.DumpFramebuffer(width, height, engine, successCallback, mimeType);
                 Tools.DumpFramebuffer(width, height, engine, successCallback, mimeType);

+ 89 - 77
src/babylon.engine.ts

@@ -211,7 +211,7 @@
             if (!lastCreatedEngine) {
             if (!lastCreatedEngine) {
                 return null;
                 return null;
             }
             }
-            
+
             if (lastCreatedEngine.scenes.length === 0) {
             if (lastCreatedEngine.scenes.length === 0) {
                 return null;
                 return null;
             }
             }
@@ -514,19 +514,19 @@
 
 
         private _vaoRecordInProgress = false;
         private _vaoRecordInProgress = false;
         private _mustWipeVertexAttributes = false;
         private _mustWipeVertexAttributes = false;
-        
+
         // Hardware supported Compressed Textures
         // Hardware supported Compressed Textures
         private _texturesSupported = new Array<string>();
         private _texturesSupported = new Array<string>();
-        private _textureFormatInUse : string; 
-        
+        private _textureFormatInUse: string;
+
         public get texturesSupported(): Array<string> {
         public get texturesSupported(): Array<string> {
             return this._texturesSupported;
             return this._texturesSupported;
         }
         }
-        
+
         public get textureFormatInUse(): string {
         public get textureFormatInUse(): string {
             return this._textureFormatInUse;
             return this._textureFormatInUse;
         }
         }
-        
+
         /**
         /**
          * @constructor
          * @constructor
          * @param {HTMLCanvasElement} canvas - the canvas to be used for rendering
          * @param {HTMLCanvasElement} canvas - the canvas to be used for rendering
@@ -558,8 +558,8 @@
                         this._webGLVersion = 2.0;
                         this._webGLVersion = 2.0;
                     }
                     }
                 } catch (e) {
                 } catch (e) {
-                // Do nothing
-                }  
+                    // Do nothing
+                }
             }
             }
 
 
             if (!this._gl) {
             if (!this._gl) {
@@ -576,7 +576,7 @@
             if (!this._gl) {
             if (!this._gl) {
                 throw new Error("WebGL not supported");
                 throw new Error("WebGL not supported");
             }
             }
-            
+
             this._onBlur = () => {
             this._onBlur = () => {
                 this._windowIsBackground = true;
                 this._windowIsBackground = true;
             };
             };
@@ -624,15 +624,15 @@
 
 
             // Extensions
             // Extensions
             this._caps.standardDerivatives = this._webGLVersion > 1 || (this._gl.getExtension('OES_standard_derivatives') !== null);
             this._caps.standardDerivatives = this._webGLVersion > 1 || (this._gl.getExtension('OES_standard_derivatives') !== null);
-            
-            this._caps.astc  = this._gl.getExtension('WEBGL_compressed_texture_astc' ) || this._gl.getExtension('WEBKIT_WEBGL_compressed_texture_astc' );
-            this._caps.s3tc  = this._gl.getExtension('WEBGL_compressed_texture_s3tc' ) || this._gl.getExtension('WEBKIT_WEBGL_compressed_texture_s3tc' );
+
+            this._caps.astc = this._gl.getExtension('WEBGL_compressed_texture_astc') || this._gl.getExtension('WEBKIT_WEBGL_compressed_texture_astc');
+            this._caps.s3tc = this._gl.getExtension('WEBGL_compressed_texture_s3tc') || this._gl.getExtension('WEBKIT_WEBGL_compressed_texture_s3tc');
             this._caps.pvrtc = this._gl.getExtension('WEBGL_compressed_texture_pvrtc') || this._gl.getExtension('WEBKIT_WEBGL_compressed_texture_pvrtc');
             this._caps.pvrtc = this._gl.getExtension('WEBGL_compressed_texture_pvrtc') || this._gl.getExtension('WEBKIT_WEBGL_compressed_texture_pvrtc');
-            this._caps.etc1  = this._gl.getExtension('WEBGL_compressed_texture_etc1' ) || this._gl.getExtension('WEBKIT_WEBGL_compressed_texture_etc1' );
-            this._caps.etc2  = this._gl.getExtension('WEBGL_compressed_texture_etc'  ) || this._gl.getExtension('WEBKIT_WEBGL_compressed_texture_etc'  ) ||
-                               this._gl.getExtension('WEBGL_compressed_texture_es3_0'); // also a requirement of OpenGL ES 3
-            this._caps.atc   = this._gl.getExtension('WEBGL_compressed_texture_atc'  ) || this._gl.getExtension('WEBKIT_WEBGL_compressed_texture_atc'  );
-            
+            this._caps.etc1 = this._gl.getExtension('WEBGL_compressed_texture_etc1') || this._gl.getExtension('WEBKIT_WEBGL_compressed_texture_etc1');
+            this._caps.etc2 = this._gl.getExtension('WEBGL_compressed_texture_etc') || this._gl.getExtension('WEBKIT_WEBGL_compressed_texture_etc') ||
+                this._gl.getExtension('WEBGL_compressed_texture_es3_0'); // also a requirement of OpenGL ES 3
+            this._caps.atc = this._gl.getExtension('WEBGL_compressed_texture_atc') || this._gl.getExtension('WEBKIT_WEBGL_compressed_texture_atc');
+
             this._caps.textureAnisotropicFilterExtension = this._gl.getExtension('EXT_texture_filter_anisotropic') || this._gl.getExtension('WEBKIT_EXT_texture_filter_anisotropic') || this._gl.getExtension('MOZ_EXT_texture_filter_anisotropic');
             this._caps.textureAnisotropicFilterExtension = this._gl.getExtension('EXT_texture_filter_anisotropic') || this._gl.getExtension('WEBKIT_EXT_texture_filter_anisotropic') || this._gl.getExtension('MOZ_EXT_texture_filter_anisotropic');
             this._caps.maxAnisotropy = this._caps.textureAnisotropicFilterExtension ? this._gl.getParameter(this._caps.textureAnisotropicFilterExtension.MAX_TEXTURE_MAX_ANISOTROPY_EXT) : 0;
             this._caps.maxAnisotropy = this._caps.textureAnisotropicFilterExtension ? this._gl.getParameter(this._caps.textureAnisotropicFilterExtension.MAX_TEXTURE_MAX_ANISOTROPY_EXT) : 0;
             this._caps.uintIndices = this._webGLVersion > 1 || this._gl.getExtension('OES_element_index_uint') !== null;
             this._caps.uintIndices = this._webGLVersion > 1 || this._gl.getExtension('OES_element_index_uint') !== null;
@@ -645,58 +645,58 @@
 
 
             this._caps.textureFloat = this._webGLVersion > 1 || this._gl.getExtension('OES_texture_float');
             this._caps.textureFloat = this._webGLVersion > 1 || this._gl.getExtension('OES_texture_float');
             this._caps.textureFloatLinearFiltering = this._caps.textureFloat && this._gl.getExtension('OES_texture_float_linear');
             this._caps.textureFloatLinearFiltering = this._caps.textureFloat && this._gl.getExtension('OES_texture_float_linear');
-            this._caps.textureFloatRender = this._caps.textureFloat && this._canRenderToFloatFramebuffer();            
+            this._caps.textureFloatRender = this._caps.textureFloat && this._canRenderToFloatFramebuffer();
 
 
             this._caps.textureHalfFloat = this._webGLVersion > 1 || this._gl.getExtension('OES_texture_half_float');
             this._caps.textureHalfFloat = this._webGLVersion > 1 || this._gl.getExtension('OES_texture_half_float');
             this._caps.textureHalfFloatLinearFiltering = this._webGLVersion > 1 || (this._caps.textureHalfFloat && this._gl.getExtension('OES_texture_half_float_linear'));
             this._caps.textureHalfFloatLinearFiltering = this._webGLVersion > 1 || (this._caps.textureHalfFloat && this._gl.getExtension('OES_texture_half_float_linear'));
             this._caps.textureHalfFloatRender = this._caps.textureHalfFloat && this._canRenderToHalfFloatFramebuffer();
             this._caps.textureHalfFloatRender = this._caps.textureHalfFloat && this._canRenderToHalfFloatFramebuffer();
-            
+
             this._caps.textureLOD = this._webGLVersion > 1 || this._gl.getExtension('EXT_shader_texture_lod');
             this._caps.textureLOD = this._webGLVersion > 1 || this._gl.getExtension('EXT_shader_texture_lod');
 
 
             // Vertex array object 
             // Vertex array object 
-            if ( this._webGLVersion > 1) {
+            if (this._webGLVersion > 1) {
                 this._caps.vertexArrayObject = true;
                 this._caps.vertexArrayObject = true;
-            } else{
+            } else {
                 var vertexArrayObjectExtension = this._gl.getExtension('OES_vertex_array_object');
                 var vertexArrayObjectExtension = this._gl.getExtension('OES_vertex_array_object');
 
 
                 if (vertexArrayObjectExtension != null) {
                 if (vertexArrayObjectExtension != null) {
-                    this._caps.vertexArrayObject =  true;
+                    this._caps.vertexArrayObject = true;
                     this._gl.createVertexArray = vertexArrayObjectExtension.createVertexArrayOES.bind(vertexArrayObjectExtension);
                     this._gl.createVertexArray = vertexArrayObjectExtension.createVertexArrayOES.bind(vertexArrayObjectExtension);
                     this._gl.bindVertexArray = vertexArrayObjectExtension.bindVertexArrayOES.bind(vertexArrayObjectExtension);
                     this._gl.bindVertexArray = vertexArrayObjectExtension.bindVertexArrayOES.bind(vertexArrayObjectExtension);
                     this._gl.deleteVertexArray = vertexArrayObjectExtension.deleteVertexArrayOES.bind(vertexArrayObjectExtension);
                     this._gl.deleteVertexArray = vertexArrayObjectExtension.deleteVertexArrayOES.bind(vertexArrayObjectExtension);
-                } else{
+                } else {
                     this._caps.vertexArrayObject = false;
                     this._caps.vertexArrayObject = false;
                 }
                 }
             }
             }
             // Instances count            
             // Instances count            
-            if ( this._webGLVersion > 1) {
+            if (this._webGLVersion > 1) {
                 this._caps.instancedArrays = true;
                 this._caps.instancedArrays = true;
-            } else{
+            } else {
                 var instanceExtension = <ANGLE_instanced_arrays>this._gl.getExtension('ANGLE_instanced_arrays');
                 var instanceExtension = <ANGLE_instanced_arrays>this._gl.getExtension('ANGLE_instanced_arrays');
 
 
                 if (instanceExtension != null) {
                 if (instanceExtension != null) {
-                    this._caps.instancedArrays =  true;
+                    this._caps.instancedArrays = true;
                     this._gl.drawArraysInstanced = instanceExtension.drawArraysInstancedANGLE.bind(instanceExtension);
                     this._gl.drawArraysInstanced = instanceExtension.drawArraysInstancedANGLE.bind(instanceExtension);
                     this._gl.drawElementsInstanced = instanceExtension.drawElementsInstancedANGLE.bind(instanceExtension);
                     this._gl.drawElementsInstanced = instanceExtension.drawElementsInstancedANGLE.bind(instanceExtension);
                     this._gl.vertexAttribDivisor = instanceExtension.vertexAttribDivisorANGLE.bind(instanceExtension);
                     this._gl.vertexAttribDivisor = instanceExtension.vertexAttribDivisorANGLE.bind(instanceExtension);
-                } else{
+                } else {
                     this._caps.instancedArrays = false;
                     this._caps.instancedArrays = false;
                 }
                 }
             }
             }
-            
+
             // Intelligently add supported compressed formats in order to check for.
             // Intelligently add supported compressed formats in order to check for.
             // Check for ASTC support first as it is most powerful and to be very cross platform.
             // Check for ASTC support first as it is most powerful and to be very cross platform.
             // Next PVRTC & DXT, which are probably superior to ETC1/2.  
             // Next PVRTC & DXT, which are probably superior to ETC1/2.  
             // Likely no hardware which supports both PVR & DXT, so order matters little.
             // Likely no hardware which supports both PVR & DXT, so order matters little.
             // ETC2 is newer and handles ETC1 (no alpha capability), so check for first.
             // ETC2 is newer and handles ETC1 (no alpha capability), so check for first.
             // ATC before ETC1, since both old (widely supported), but ATC supports alpha, but ETC1 does not
             // ATC before ETC1, since both old (widely supported), but ATC supports alpha, but ETC1 does not
-            if (this._caps.astc ) this.texturesSupported.push('-astc.ktx');
-            if (this._caps.s3tc ) this.texturesSupported.push('-dxt.ktx');
+            if (this._caps.astc) this.texturesSupported.push('-astc.ktx');
+            if (this._caps.s3tc) this.texturesSupported.push('-dxt.ktx');
             if (this._caps.pvrtc) this.texturesSupported.push('-pvrtc.ktx');
             if (this._caps.pvrtc) this.texturesSupported.push('-pvrtc.ktx');
-            if (this._caps.etc2 ) this.texturesSupported.push('-etc2.ktx');
-            if (this._caps.atc  ) this.texturesSupported.push('-atc.ktx');
-            if (this._caps.etc1 ) this.texturesSupported.push('-etc1.ktx');
-            
+            if (this._caps.etc2) this.texturesSupported.push('-etc2.ktx');
+            if (this._caps.atc) this.texturesSupported.push('-atc.ktx');
+            if (this._caps.etc1) this.texturesSupported.push('-etc1.ktx');
+
             if (this._gl.getShaderPrecisionFormat) {
             if (this._gl.getShaderPrecisionFormat) {
                 var highp = this._gl.getShaderPrecisionFormat(this._gl.FRAGMENT_SHADER, this._gl.HIGH_FLOAT);
                 var highp = this._gl.getShaderPrecisionFormat(this._gl.FRAGMENT_SHADER, this._gl.HIGH_FLOAT);
                 this._caps.highPrecisionShaderSupported = highp.precision !== 0;
                 this._caps.highPrecisionShaderSupported = highp.precision !== 0;
@@ -1178,10 +1178,6 @@
                 this._oldSize = new BABYLON.Size(this.getRenderWidth(), this.getRenderHeight());
                 this._oldSize = new BABYLON.Size(this.getRenderWidth(), this.getRenderHeight());
                 this._oldHardwareScaleFactor = this.getHardwareScalingLevel();
                 this._oldHardwareScaleFactor = this.getHardwareScalingLevel();
 
 
-                //according to the WebVR specs, requestAnimationFrame should be triggered only once.
-                //But actually, no browser follow the specs...
-                //this._vrAnimationFrameHandler = this._vrDisplayEnabled.requestAnimationFrame(this._bindedRenderFunction);
-
                 //get the width and height, change the render size
                 //get the width and height, change the render size
                 var leftEye = this._vrDisplayEnabled.getEyeParameters('left');
                 var leftEye = this._vrDisplayEnabled.getEyeParameters('left');
                 var width, height;
                 var width, height;
@@ -1234,7 +1230,7 @@
             }
             }
         }
         }
 
 
-        public unBindFramebuffer(texture: WebGLTexture, disableGenerateMipMaps = false): void {
+        public unBindFramebuffer(texture: WebGLTexture, disableGenerateMipMaps = false, onBeforeUnbind?: () => void): void {
             this._currentRenderTarget = null;
             this._currentRenderTarget = null;
 
 
             // If MSAA, we need to bitblt back to main texture
             // If MSAA, we need to bitblt back to main texture
@@ -1243,9 +1239,9 @@
             if (texture._MSAAFramebuffer) {
             if (texture._MSAAFramebuffer) {
                 gl.bindFramebuffer(gl.READ_FRAMEBUFFER, texture._MSAAFramebuffer);
                 gl.bindFramebuffer(gl.READ_FRAMEBUFFER, texture._MSAAFramebuffer);
                 gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, texture._framebuffer);
                 gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, texture._framebuffer);
-                gl.blitFramebuffer( 0, 0, texture._width, texture._height, 
-                                    0, 0, texture._width, texture._height,
-                                    gl.COLOR_BUFFER_BIT, gl.NEAREST);
+                gl.blitFramebuffer(0, 0, texture._width, texture._height,
+                    0, 0, texture._width, texture._height,
+                    gl.COLOR_BUFFER_BIT, gl.NEAREST);
             }
             }
 
 
             if (texture.generateMipMaps && !disableGenerateMipMaps) {
             if (texture.generateMipMaps && !disableGenerateMipMaps) {
@@ -1254,6 +1250,14 @@
                 this._bindTextureDirectly(gl.TEXTURE_2D, null);
                 this._bindTextureDirectly(gl.TEXTURE_2D, null);
             }
             }
 
 
+            if (onBeforeUnbind) {
+                if (texture._MSAAFramebuffer) {
+                    // Bind the correct framebuffer
+                    this.bindUnboundFramebuffer(texture._framebuffer);
+                }
+                onBeforeUnbind();
+            }
+
             this.bindUnboundFramebuffer(null);
             this.bindUnboundFramebuffer(null);
         }
         }
 
 
@@ -1386,14 +1390,14 @@
         public bindArrayBuffer(buffer: WebGLBuffer): void {
         public bindArrayBuffer(buffer: WebGLBuffer): void {
             if (!this._vaoRecordInProgress) {
             if (!this._vaoRecordInProgress) {
                 this._unBindVertexArrayObject();
                 this._unBindVertexArrayObject();
-            }   
+            }
             this.bindBuffer(buffer, this._gl.ARRAY_BUFFER);
             this.bindBuffer(buffer, this._gl.ARRAY_BUFFER);
         }
         }
 
 
         private bindIndexBuffer(buffer: WebGLBuffer): void {
         private bindIndexBuffer(buffer: WebGLBuffer): void {
             if (!this._vaoRecordInProgress) {
             if (!this._vaoRecordInProgress) {
                 this._unBindVertexArrayObject();
                 this._unBindVertexArrayObject();
-            }            
+            }
             this.bindBuffer(buffer, this._gl.ELEMENT_ARRAY_BUFFER);
             this.bindBuffer(buffer, this._gl.ELEMENT_ARRAY_BUFFER);
         }
         }
 
 
@@ -1401,7 +1405,7 @@
             if (this._vaoRecordInProgress || this._currentBoundBuffer[target] !== buffer) {
             if (this._vaoRecordInProgress || this._currentBoundBuffer[target] !== buffer) {
                 this._gl.bindBuffer(target, buffer);
                 this._gl.bindBuffer(target, buffer);
                 this._currentBoundBuffer[target] = buffer;
                 this._currentBoundBuffer[target] = buffer;
-           }
+            }
         }
         }
 
 
         public updateArrayBuffer(data: Float32Array): void {
         public updateArrayBuffer(data: Float32Array): void {
@@ -1430,7 +1434,7 @@
             }
             }
         }
         }
 
 
-        private _bindIndexBufferWithCache(indexBuffer: WebGLBuffer): void {            
+        private _bindIndexBufferWithCache(indexBuffer: WebGLBuffer): void {
             if (indexBuffer == null) {
             if (indexBuffer == null) {
                 return;
                 return;
             }
             }
@@ -1482,10 +1486,10 @@
         public recordVertexArrayObject(vertexBuffers: { [key: string]: VertexBuffer; }, indexBuffer: WebGLBuffer, effect: Effect): WebGLVertexArrayObject {
         public recordVertexArrayObject(vertexBuffers: { [key: string]: VertexBuffer; }, indexBuffer: WebGLBuffer, effect: Effect): WebGLVertexArrayObject {
             var vao = this._gl.createVertexArray();
             var vao = this._gl.createVertexArray();
 
 
-            this._vaoRecordInProgress = true;                
-            
+            this._vaoRecordInProgress = true;
+
             this._gl.bindVertexArray(vao);
             this._gl.bindVertexArray(vao);
-            
+
             this._mustWipeVertexAttributes = true;
             this._mustWipeVertexAttributes = true;
             this._bindVertexBuffersAttributes(vertexBuffers, effect);
             this._bindVertexBuffersAttributes(vertexBuffers, effect);
 
 
@@ -1505,7 +1509,7 @@
                 this._cachedVertexBuffers = null;
                 this._cachedVertexBuffers = null;
                 this._cachedIndexBuffer = null;
                 this._cachedIndexBuffer = null;
 
 
-                this._uintIndicesCurrentlySet = indexBuffer != null && indexBuffer.is32Bits; 
+                this._uintIndicesCurrentlySet = indexBuffer != null && indexBuffer.is32Bits;
                 this._mustWipeVertexAttributes = true;
                 this._mustWipeVertexAttributes = true;
             }
             }
         }
         }
@@ -1554,7 +1558,7 @@
             if (this._cachedVertexBuffers !== vertexBuffers || this._cachedEffectForVertexBuffers !== effect) {
             if (this._cachedVertexBuffers !== vertexBuffers || this._cachedEffectForVertexBuffers !== effect) {
                 this._cachedVertexBuffers = vertexBuffers;
                 this._cachedVertexBuffers = vertexBuffers;
                 this._cachedEffectForVertexBuffers = effect;
                 this._cachedEffectForVertexBuffers = effect;
-                
+
                 this._bindVertexBuffersAttributes(vertexBuffers, effect);
                 this._bindVertexBuffersAttributes(vertexBuffers, effect);
             }
             }
 
 
@@ -1672,7 +1676,7 @@
         public drawPointClouds(verticesStart: number, verticesCount: number, instancesCount?: number): void {
         public drawPointClouds(verticesStart: number, verticesCount: number, instancesCount?: number): void {
             // Apply states
             // Apply states
             this.applyStates();
             this.applyStates();
-            this._drawCalls.addCount(1, false); 
+            this._drawCalls.addCount(1, false);
 
 
             if (instancesCount) {
             if (instancesCount) {
                 this._gl.drawArraysInstanced(this._gl.POINTS, verticesStart, verticesCount, instancesCount);
                 this._gl.drawArraysInstanced(this._gl.POINTS, verticesStart, verticesCount, instancesCount);
@@ -2089,7 +2093,7 @@
          * Current families are astc, dxt, pvrtc, etc2, atc, & etc1.
          * Current families are astc, dxt, pvrtc, etc2, atc, & etc1.
          * @returns The extension selected.
          * @returns The extension selected.
          */
          */
-        public setTextureFormatToUse(formatsAvailable : Array<string>) : string {
+        public setTextureFormatToUse(formatsAvailable: Array<string>): string {
             for (var i = 0, len1 = this.texturesSupported.length; i < len1; i++) {
             for (var i = 0, len1 = this.texturesSupported.length; i < len1; i++) {
                 for (var j = 0, len2 = formatsAvailable.length; j < len2; j++) {
                 for (var j = 0, len2 = formatsAvailable.length; j < len2; j++) {
                     if (this._texturesSupported[i] === formatsAvailable[j].toLowerCase()) {
                     if (this._texturesSupported[i] === formatsAvailable[j].toLowerCase()) {
@@ -2120,7 +2124,7 @@
                     extension = this._textureFormatInUse;
                     extension = this._textureFormatInUse;
                     url = url.substring(0, lastDot) + this._textureFormatInUse;
                     url = url.substring(0, lastDot) + this._textureFormatInUse;
                     isKTX = true;
                     isKTX = true;
-                    
+
                 }
                 }
             } else {
             } else {
                 var oldUrl = url;
                 var oldUrl = url;
@@ -2154,11 +2158,11 @@
                 }
                 }
             };
             };
             var callback: (arrayBuffer: any) => void;
             var callback: (arrayBuffer: any) => void;
-            if (isKTX || isTGA || isDDS){
+            if (isKTX || isTGA || isDDS) {
                 if (isKTX) {
                 if (isKTX) {
                     callback = (data) => {
                     callback = (data) => {
                         var ktx = new Internals.KhronosTextureContainer(data, 1);
                         var ktx = new Internals.KhronosTextureContainer(data, 1);
-    
+
                         prepareWebGLTexture(texture, this._gl, scene, ktx.pixelWidth, ktx.pixelHeight, invertY, false, true, () => {
                         prepareWebGLTexture(texture, this._gl, scene, ktx.pixelWidth, ktx.pixelHeight, invertY, false, true, () => {
                             ktx.uploadLevels(this._gl, !noMipmap);
                             ktx.uploadLevels(this._gl, !noMipmap);
                         }, samplingMode);
                         }, samplingMode);
@@ -2184,14 +2188,14 @@
                             Internals.DDSTools.UploadDDSLevels(this._gl, this.getCaps().s3tc, data, info, loadMipmap, 1);
                             Internals.DDSTools.UploadDDSLevels(this._gl, this.getCaps().s3tc, data, info, loadMipmap, 1);
                         }, samplingMode);
                         }, samplingMode);
                     };
                     };
-            }
+                }
 
 
-            if (!(fromData instanceof Array))
-                Tools.LoadFile(url, data => {
-                    callback(data);
-                }, null, scene.database, true, onerror);
-            else
-                callback(buffer);
+                if (!(fromData instanceof Array))
+                    Tools.LoadFile(url, data => {
+                        callback(data);
+                    }, null, scene.database, true, onerror);
+                else
+                    callback(buffer);
 
 
             } else {
             } else {
                 var onload = (img) => {
                 var onload = (img) => {
@@ -2339,7 +2343,7 @@
 
 
         public updateTextureSamplingMode(samplingMode: number, texture: WebGLTexture): void {
         public updateTextureSamplingMode(samplingMode: number, texture: WebGLTexture): void {
             var filters = getSamplingParameters(samplingMode, texture.generateMipMaps, this._gl);
             var filters = getSamplingParameters(samplingMode, texture.generateMipMaps, this._gl);
- 
+
             if (texture.isCube) {
             if (texture.isCube) {
                 this._bindTextureDirectly(this._gl.TEXTURE_CUBE_MAP, texture);
                 this._bindTextureDirectly(this._gl.TEXTURE_CUBE_MAP, texture);
 
 
@@ -2354,7 +2358,7 @@
                 this._bindTextureDirectly(this._gl.TEXTURE_2D, null);
                 this._bindTextureDirectly(this._gl.TEXTURE_2D, null);
             }
             }
 
 
-             texture.samplingMode = samplingMode;
+            texture.samplingMode = samplingMode;
         }
         }
 
 
         public updateDynamicTexture(texture: WebGLTexture, canvas: HTMLCanvasElement, invertY: boolean, premulAlpha: boolean = false, format?: number): void {
         public updateDynamicTexture(texture: WebGLTexture, canvas: HTMLCanvasElement, invertY: boolean, premulAlpha: boolean = false, format?: number): void {
@@ -2499,6 +2503,7 @@
             texture._width = width;
             texture._width = width;
             texture._height = height;
             texture._height = height;
             texture.isReady = true;
             texture.isReady = true;
+            texture.samples = 1;
             texture.generateMipMaps = generateMipMaps;
             texture.generateMipMaps = generateMipMaps;
             texture.references = 1;
             texture.references = 1;
             texture.samplingMode = samplingMode;
             texture.samplingMode = samplingMode;
@@ -2546,10 +2551,15 @@
             return depthStencilBuffer;
             return depthStencilBuffer;
         }
         }
 
 
-        public updateRenderTargetTextureSampleCount(texture: WebGLTexture, samples: number) : number {
+        public updateRenderTargetTextureSampleCount(texture: WebGLTexture, samples: number): number {
             if (this.webGLVersion < 2) {
             if (this.webGLVersion < 2) {
                 return 1;
                 return 1;
             }
             }
+
+            if (texture.samples === samples) {
+                return samples;
+            }
+
             var gl = this._gl;
             var gl = this._gl;
 
 
             samples = Math.min(samples, gl.getParameter(gl.MAX_SAMPLES));
             samples = Math.min(samples, gl.getParameter(gl.MAX_SAMPLES));
@@ -2582,6 +2592,7 @@
                 this.bindUnboundFramebuffer(texture._framebuffer);
                 this.bindUnboundFramebuffer(texture._framebuffer);
             }
             }
 
 
+            texture.samples = samples;
             texture._depthStencilBuffer = this._setupFramebufferDepthAttachments(texture._generateStencilBuffer, texture._generateDepthBuffer, texture._width, texture._height, samples);
             texture._depthStencilBuffer = this._setupFramebufferDepthAttachments(texture._generateStencilBuffer, texture._generateDepthBuffer, texture._width, texture._height, samples);
 
 
             gl.bindRenderbuffer(gl.RENDERBUFFER, null);
             gl.bindRenderbuffer(gl.RENDERBUFFER, null);
@@ -2614,6 +2625,7 @@
             texture.references = 1;
             texture.references = 1;
             texture.generateMipMaps = generateMipMaps;
             texture.generateMipMaps = generateMipMaps;
             texture.references = 1;
             texture.references = 1;
+            texture.samples = 1;
             texture.samplingMode = samplingMode;
             texture.samplingMode = samplingMode;
 
 
             var filters = getSamplingParameters(samplingMode, generateMipMaps, gl);
             var filters = getSamplingParameters(samplingMode, generateMipMaps, gl);
@@ -2685,7 +2697,7 @@
 
 
                     this._bindTextureDirectly(gl.TEXTURE_CUBE_MAP, texture);
                     this._bindTextureDirectly(gl.TEXTURE_CUBE_MAP, texture);
                     gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, 1);
                     gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, 1);
-    
+
                     ktx.uploadLevels(this._gl, !noMipmap);
                     ktx.uploadLevels(this._gl, !noMipmap);
 
 
                     gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
                     gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
@@ -2824,7 +2836,7 @@
 
 
             var onerror = () => {
             var onerror = () => {
                 scene._removePendingData(texture);
                 scene._removePendingData(texture);
-                if (onError){
+                if (onError) {
                     onError();
                     onError();
                 }
                 }
             };
             };
@@ -2871,7 +2883,7 @@
                         }
                         }
                     }
                     }
                 }
                 }
-                else {                    
+                else {
                     // Data are known to be in +X +Y +Z -X -Y -Z
                     // Data are known to be in +X +Y +Z -X -Y -Z
                     for (let index = 0; index < facesIndex.length; index++) {
                     for (let index = 0; index < facesIndex.length; index++) {
                         let faceData = rgbeDataArrays[index];
                         let faceData = rgbeDataArrays[index];
@@ -3380,10 +3392,10 @@
             return this._canRenderToFramebuffer(BABYLON.Engine.TEXTURETYPE_FLOAT);
             return this._canRenderToFramebuffer(BABYLON.Engine.TEXTURETYPE_FLOAT);
         }
         }
 
 
-        private _canRenderToHalfFloatFramebuffer(): boolean {       
+        private _canRenderToHalfFloatFramebuffer(): boolean {
             if (this._webGLVersion > 1) {
             if (this._webGLVersion > 1) {
                 return this._caps.colorBufferFloat;
                 return this._caps.colorBufferFloat;
-            }     
+            }
             return this._canRenderToFramebuffer(BABYLON.Engine.TEXTURETYPE_HALF_FLOAT);
             return this._canRenderToFramebuffer(BABYLON.Engine.TEXTURETYPE_HALF_FLOAT);
         }
         }
 
 
@@ -3392,7 +3404,7 @@
             let gl = this._gl;
             let gl = this._gl;
 
 
             //clear existing errors
             //clear existing errors
-            while(gl.getError() !== gl.NO_ERROR){}
+            while (gl.getError() !== gl.NO_ERROR) { }
 
 
             let successful = true;
             let successful = true;
 
 
@@ -3411,13 +3423,13 @@
             successful = successful && (gl.getError() === gl.NO_ERROR);
             successful = successful && (gl.getError() === gl.NO_ERROR);
 
 
             //try render by clearing frame buffer's color buffer
             //try render by clearing frame buffer's color buffer
-            if(successful){
+            if (successful) {
                 gl.clear(gl.COLOR_BUFFER_BIT);
                 gl.clear(gl.COLOR_BUFFER_BIT);
                 successful = successful && (gl.getError() === gl.NO_ERROR);
                 successful = successful && (gl.getError() === gl.NO_ERROR);
             }
             }
 
 
             //try reading from frame to ensure render occurs (just creating the FBO is not sufficient to determine if rendering is supported)
             //try reading from frame to ensure render occurs (just creating the FBO is not sufficient to determine if rendering is supported)
-            if(successful){
+            if (successful) {
                 //in practice it's sufficient to just read from the backbuffer rather than handle potentially issues reading from the texture
                 //in practice it's sufficient to just read from the backbuffer rather than handle potentially issues reading from the texture
                 gl.bindFramebuffer(gl.FRAMEBUFFER, null);
                 gl.bindFramebuffer(gl.FRAMEBUFFER, null);
                 let readFormat = gl.RGBA;
                 let readFormat = gl.RGBA;
@@ -3433,12 +3445,12 @@
             gl.bindFramebuffer(gl.FRAMEBUFFER, null);
             gl.bindFramebuffer(gl.FRAMEBUFFER, null);
 
 
             //clear accumulated errors
             //clear accumulated errors
-            while(!successful && (gl.getError() !== gl.NO_ERROR)) { }
+            while (!successful && (gl.getError() !== gl.NO_ERROR)) { }
 
 
             return successful;
             return successful;
         }
         }
 
 
-        private _getWebGLTextureType(type: number) : number {
+        private _getWebGLTextureType(type: number): number {
             if (type === Engine.TEXTURETYPE_FLOAT) {
             if (type === Engine.TEXTURETYPE_FLOAT) {
                 return this._gl.FLOAT;
                 return this._gl.FLOAT;
             }
             }
@@ -3450,7 +3462,7 @@
             return this._gl.UNSIGNED_BYTE;
             return this._gl.UNSIGNED_BYTE;
         };
         };
 
 
-        private _getRGBABufferInternalSizedFormat(type: number) : number {
+        private _getRGBABufferInternalSizedFormat(type: number): number {
             if (this._webGLVersion === 1) {
             if (this._webGLVersion === 1) {
                 return this._gl.RGBA;
                 return this._gl.RGBA;
             }
             }

+ 16 - 4
src/babylon.mixins.ts

@@ -40,13 +40,13 @@ interface WebGLRenderingContext {
     bindVertexArray(vao: WebGLVertexArrayObject): void;
     bindVertexArray(vao: WebGLVertexArrayObject): void;
     deleteVertexArray(vao: WebGLVertexArrayObject): void;
     deleteVertexArray(vao: WebGLVertexArrayObject): void;
 
 
-    blitFramebuffer(srcX0 : number, srcY0 : number, srcX1 : number, srcY1 : number, dstX0 : number, dstY0 : number, dstX1 : number, dstY1 : number, mask : number, filter : number) : void;
-    renderbufferStorageMultisample(target : number, samples : number, internalformat : number, width : number, height : number) : void;
+    blitFramebuffer(srcX0: number, srcY0: number, srcX1: number, srcY1: number, dstX0: number, dstY0: number, dstX1: number, dstY1: number, mask: number, filter: number): void;
+    renderbufferStorageMultisample(target: number, samples: number, internalformat: number, width: number, height: number): void;
 
 
     MAX_SAMPLES: number;
     MAX_SAMPLES: number;
     RGBA8: number;
     RGBA8: number;
-    READ_FRAMEBUFFER : number;
-    DRAW_FRAMEBUFFER : number;
+    READ_FRAMEBUFFER: number;
+    DRAW_FRAMEBUFFER: number;
 }
 }
 
 
 interface HTMLURL {
 interface HTMLURL {
@@ -89,6 +89,7 @@ interface WebGLTexture {
     samplingMode: number;
     samplingMode: number;
     references: number;
     references: number;
     generateMipMaps: boolean;
     generateMipMaps: boolean;
+    samples: number;
     type: number;
     type: number;
     onLoadedCallbacks: Array<Function>;
     onLoadedCallbacks: Array<Function>;
     _size: number;
     _size: number;
@@ -178,6 +179,17 @@ interface SIMD {
     Bool8x16: SIMD.Bool8x16Constructor;
     Bool8x16: SIMD.Bool8x16Constructor;
 }
 }
 
 
+interface GamepadPose {
+    hasOrientation: boolean;
+    hasPosition: boolean;
+    position?: Float32Array;
+    linearVelocity?: Float32Array;
+    linearAcceleration?: Float32Array;
+    orientation?: Float32Array;
+    angularVelocity?: Float32Array;
+    angularAcceleration?: Float32Array;
+}
+
 declare namespace SIMD {
 declare namespace SIMD {
     interface Float32x4 {
     interface Float32x4 {
         constructor: Float32x4Constructor;
         constructor: Float32x4Constructor;

+ 8 - 10
src/babylon.node.ts

@@ -264,16 +264,7 @@ module BABYLON {
             this._getDescendants(results, directDescendantsOnly, predicate);
             this._getDescendants(results, directDescendantsOnly, predicate);
 
 
             return results;
             return results;
-        }
-        
-        /**
-         * @param predicate: an optional predicate that will be called on every evaluated children, the predicate must return true for a given child to be part of the result, otherwise it will be ignored.
-         * @Deprecated, legacy support.
-         * use getDecendants instead.
-         */
-        public getChildren(predicate?: (node: Node) => boolean): Node[] {
-            return this.getDescendants(true, predicate);
-        }
+        }    
         
         
         /**
         /**
          * Get all child-meshes of this node.
          * Get all child-meshes of this node.
@@ -286,6 +277,13 @@ module BABYLON {
             return results;
             return results;
         }
         }
 
 
+        /**
+         * Get all direct children of this node.
+        */
+        public getChildren(predicate?: (node: Node) => boolean): Node[] {
+            return this.getDescendants(true, predicate);
+        }
+
         public _setReady(state: boolean): void {
         public _setReady(state: boolean): void {
             if (state === this._isReady) {
             if (state === this._isReady) {
                 return;
                 return;

+ 15 - 52
src/babylon.scene.ts

@@ -304,21 +304,9 @@
         private _onPointerDown: (evt: PointerEvent) => void;
         private _onPointerDown: (evt: PointerEvent) => void;
         private _onPointerUp: (evt: PointerEvent) => void;
         private _onPointerUp: (evt: PointerEvent) => void;
 
 
-        /**
-         * @deprecated Use onPointerObservable instead
-         */
         public onPointerMove: (evt: PointerEvent, pickInfo: PickingInfo) => void;
         public onPointerMove: (evt: PointerEvent, pickInfo: PickingInfo) => void;
-        /**
-         * @deprecated Use onPointerObservable instead
-         */
         public onPointerDown: (evt: PointerEvent, pickInfo: PickingInfo) => void;
         public onPointerDown: (evt: PointerEvent, pickInfo: PickingInfo) => void;
-        /**
-         * @deprecated Use onPointerObservable instead
-         */
         public onPointerUp: (evt: PointerEvent, pickInfo: PickingInfo) => void;
         public onPointerUp: (evt: PointerEvent, pickInfo: PickingInfo) => void;
-        /**
-         * @deprecated Use onPointerObservable instead
-         */
         public onPointerPick: (evt: PointerEvent, pickInfo: PickingInfo) => void;
         public onPointerPick: (evt: PointerEvent, pickInfo: PickingInfo) => void;
 
 
         /**
         /**
@@ -1897,6 +1885,21 @@
         }
         }
 
 
         /**
         /**
+         * Return a the first highlight layer of the scene with a given name.
+         * @param name The name of the highlight layer to look for.
+         * @return The highlight layer if found otherwise null. 
+         */
+        public getHighlightLayerByName(name: string): HighlightLayer {
+            for (var index = 0; index < this.highlightLayers.length; index++) {
+                if (this.highlightLayers[index].name === name) {
+                    return this.highlightLayers[index];
+                }
+            }
+
+            return null;
+        }
+
+        /**
          * Return a unique id as a string which can serve as an identifier for the scene
          * Return a unique id as a string which can serve as an identifier for the scene
          */
          */
         public get uid(): string {
         public get uid(): string {
@@ -3072,46 +3075,6 @@
             return this._physicsEngine !== undefined;
             return this._physicsEngine !== undefined;
         }
         }
 
 
-        /**
-         * 
-         * Sets the gravity of the physics engine (and NOT of the scene)
-         * @param {BABYLON.Vector3} [gravity] - the new gravity to be used
-         */
-        public setGravity(gravity: Vector3): void {
-            Tools.Warn("Deprecated, please use 'scene.getPhysicsEngine().setGravity()'")
-            if (!this._physicsEngine) {
-                return;
-            }
-
-            this._physicsEngine.setGravity(gravity);
-        }
-
-        /**
-         * Legacy support, using the new API
-         * @Deprecated
-         */
-        public createCompoundImpostor(parts: any, options: PhysicsImpostorParameters): any {
-            Tools.Warn("Scene.createCompoundImpostor is deprecated. Please use PhysicsImpostor parent/child")
-
-            if (parts.parts) { // Old API
-                options = parts;
-                parts = parts.parts;
-            }
-
-            var mainMesh: AbstractMesh = parts[0].mesh;
-            mainMesh.physicsImpostor = new PhysicsImpostor(mainMesh, parts[0].impostor, options, this)
-            for (var index = 1; index < parts.length; index++) {
-                var mesh: AbstractMesh = parts[index].mesh;
-                if (mesh.parent !== mainMesh) {
-                    mesh.position = mesh.position.subtract(mainMesh.position);
-                    mesh.parent = mainMesh;
-                }
-                mesh.physicsImpostor = new PhysicsImpostor(mesh, parts[index].impostor, options, this)
-
-            }
-            mainMesh.physicsImpostor.forceUpdate();
-        }
-
         public deleteCompoundImpostor(compound: any): void {
         public deleteCompoundImpostor(compound: any): void {
             var mesh: AbstractMesh = compound.parts[0].mesh;
             var mesh: AbstractMesh = compound.parts[0].mesh;
             mesh.physicsImpostor.dispose(/*true*/);
             mesh.physicsImpostor.dispose(/*true*/);