Forráskód Böngészése

Merge branch 'master'

Gary Hsu 8 éve
szülő
commit
8eae5629a6
100 módosított fájl, 28820 hozzáadás és 18804 törlés
  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. 16 0
      Exporters/3ds Max/BabylonExport.Entities/BabylonDirectionalLight.cs
  5. 0 3
      Exporters/3ds Max/BabylonExport.Entities/BabylonMesh.cs
  6. 9 0
      Exporters/3ds Max/BabylonExport.Entities/BabylonPBRMaterial.cs
  7. 11 0
      Exporters/3ds Max/BabylonExport.Entities/BabylonShadowGenerator.cs
  8. BIN
      Exporters/3ds Max/Max2Babylon-0.5.0.zip
  9. BIN
      Exporters/3ds Max/Max2Babylon-0.7.0.zip
  10. 1 0
      Exporters/3ds Max/Max2Babylon/Exporter/BabylonExporter.Mesh.cs
  11. 1 1
      Exporters/Maya/Tools/babylonReskinTool.mel
  12. 0 0
      Exporters/Unity 5/EditorToolkit/Redist/readme.md
  13. 1 0
      Playground/debug.html
  14. 1 0
      Playground/frame.html
  15. 3 0
      Playground/index-local.html
  16. 11 0
      Playground/index.html
  17. 27 0
      Playground/index.js
  18. 140 0
      Playground/index2_5.html
  19. 82 0
      Playground/scripts/pointer events handling.js
  20. 2 1
      Playground/scripts/scripts.txt
  21. 1 1
      Playground/scripts/shadows.js
  22. 644 561
      Tools/Gulp/config.json
  23. 3 3
      Tools/Gulp/package.json
  24. BIN
      assets/sounds/explosion.wav
  25. BIN
      assets/sounds/jump.wav
  26. BIN
      assets/textures/Ground.jpg
  27. 101 97
      canvas2D/readme.md
  28. 28 36
      canvas2D/src/Engine/babylon.atlasPicture.ts
  29. 17 6
      canvas2D/src/Engine/babylon.bounding2d.ts
  30. 204 115
      canvas2D/src/Engine/babylon.canvas2d.ts
  31. 100 31
      canvas2D/src/Engine/babylon.canvas2dLayoutEngine.ts
  32. 10 20
      canvas2D/src/Engine/babylon.ellipse2d.ts
  33. 161 41
      canvas2D/src/Engine/babylon.fontTexture.ts
  34. 46 66
      canvas2D/src/Engine/babylon.group2d.ts
  35. 18 13
      canvas2D/src/Engine/babylon.lines2d.ts
  36. 22 1
      canvas2D/src/Engine/babylon.modelRenderCache.ts
  37. 986 399
      canvas2D/src/Engine/babylon.prim2dBase.ts
  38. 1 1
      canvas2D/src/Engine/babylon.primitiveCollisionManager.ts
  39. 16 26
      canvas2D/src/Engine/babylon.rectangle2d.ts
  40. 70 69
      canvas2D/src/Engine/babylon.renderablePrim2d.ts
  41. 7 7
      canvas2D/src/Engine/babylon.shape2d.ts
  42. 44 3
      canvas2D/src/Engine/babylon.smartPropertyPrim.ts
  43. 9 38
      canvas2D/src/Engine/babylon.sprite2d.ts
  44. 120 32
      canvas2D/src/Engine/babylon.text2d.ts
  45. 1 33
      canvas2D/src/Engine/babylon.wireFrame2d.ts
  46. 249 0
      canvas2D/src/Tools/babylon.c2dlogging.ts
  47. 316 6
      canvas2D/src/Tools/babylon.math2D.ts
  48. 14 1
      canvas2D/src/shaders/ellipse2d.vertex.fx
  49. 14 1
      canvas2D/src/shaders/lines2d.vertex.fx
  50. 14 1
      canvas2D/src/shaders/rect2d.vertex.fx
  51. 24 8
      canvas2D/src/shaders/sprite2d.vertex.fx
  52. 7 0
      canvas2D/src/shaders/text2d.fragment.fx
  53. 18 3
      canvas2D/src/shaders/text2d.vertex.fx
  54. 13 6
      canvas2D/src/shaders/wireframe2d.vertex.fx
  55. 33 0
      contributing.md
  56. 29 28
      dist/preview release/babylon.core.js
  57. 7682 6996
      dist/preview release/babylon.d.ts
  58. 39 37
      dist/preview release/babylon.js
  59. 3291 1041
      dist/preview release/babylon.max.js
  60. 7682 6996
      dist/preview release/babylon.module.d.ts
  61. 39 37
      dist/preview release/babylon.noworker.js
  62. 278 100
      dist/preview release/canvas2D/babylon.canvas2d.d.ts
  63. 2281 916
      dist/preview release/canvas2D/babylon.canvas2d.js
  64. 12 12
      dist/preview release/canvas2D/babylon.canvas2d.min.js
  65. 4 4
      dist/preview release/inspector/babylon.inspector.bundle.js
  66. 3 0
      dist/preview release/inspector/babylon.inspector.css
  67. 148 3
      dist/preview release/inspector/babylon.inspector.d.ts
  68. 562 50
      dist/preview release/inspector/babylon.inspector.js
  69. 3 3
      dist/preview release/inspector/babylon.inspector.min.js
  70. 2 5
      dist/preview release/loaders/babylon.glTFFileLoader.js
  71. 2 2
      dist/preview release/loaders/babylon.glTFFileLoader.min.js
  72. 16 0
      dist/preview release/materialsLibrary/babylon.customMaterial.d.ts
  73. 398 0
      dist/preview release/materialsLibrary/babylon.customMaterial.js
  74. 1 0
      dist/preview release/materialsLibrary/babylon.customMaterial.min.js
  75. 1 1
      dist/preview release/materialsLibrary/babylon.furMaterial.js
  76. 1 1
      dist/preview release/materialsLibrary/babylon.furMaterial.min.js
  77. 21 0
      dist/preview release/materialsLibrary/babylon.shadowOnlyMaterial.d.ts
  78. 209 0
      dist/preview release/materialsLibrary/babylon.shadowOnlyMaterial.js
  79. 1 0
      dist/preview release/materialsLibrary/babylon.shadowOnlyMaterial.min.js
  80. 0 1
      dist/preview release/materialsLibrary/babylon.waterMaterial.d.ts
  81. 0 1
      dist/preview release/materialsLibrary/babylon.waterMaterial.js
  82. 1 1
      dist/preview release/materialsLibrary/babylon.waterMaterial.min.js
  83. 11 0
      dist/preview release/proceduralTexturesLibrary/babylon.normalMapProceduralTexture.d.ts
  84. 46 0
      dist/preview release/proceduralTexturesLibrary/babylon.normalMapProceduralTexture.js
  85. 1 0
      dist/preview release/proceduralTexturesLibrary/babylon.normalMapProceduralTexture.min.js
  86. 8 0
      dist/preview release/proceduralTexturesLibrary/babylon.waterProceduralTexture.d.ts
  87. 28 0
      dist/preview release/proceduralTexturesLibrary/babylon.waterProceduralTexture.js
  88. 1 0
      dist/preview release/proceduralTexturesLibrary/babylon.waterProceduralTexture.min.js
  89. 77 18
      dist/preview release/what's new.md
  90. 4 0
      inspector/sass/_tabPanel.scss
  91. 1 0
      inspector/sass/_tree.scss
  92. 139 107
      inspector/src/Inspector.ts
  93. 25 18
      inspector/src/adapters/Adapter.ts
  94. 55 0
      inspector/src/adapters/CameraAdapter.ts
  95. 59 0
      inspector/src/adapters/SoundAdapter.ts
  96. 37 0
      inspector/src/adapters/TextureAdapter.ts
  97. 197 131
      inspector/src/properties.ts
  98. 22 0
      inspector/src/tabs/CameraTab.ts
  99. 49 85
      inspector/src/tabs/ShaderTab.ts
  100. 0 0
      inspector/src/tabs/SoundTab.ts

+ 1 - 1
.travis.yml

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

A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 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
     {
         [DataMember]
+        public string id { get; set; }
+
+        [DataMember]
         public string name { get; set; }
         
         [DataMember]

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

@@ -0,0 +1,16 @@
+using System.Runtime.Serialization;
+
+namespace BabylonExport.Entities
+{
+    [DataContract]
+    public class BabylonDirectionalLight : BabylonLight
+    {
+        [DataMember]
+        public float shadowOrthoScale { get; set; }
+
+        public BabylonDirectionalLight()
+        {
+            shadowOrthoScale = 0.5f;
+        }
+    }
+}

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

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

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

@@ -152,6 +152,9 @@ namespace BabylonExport.Entities
         public bool useRadianceOverAlpha { get; set; }
 
         [DataMember]
+        public bool usePhysicalLightFalloff { get; set; }
+
+        [DataMember]
         public float indexOfRefraction { get; set; }
 
         [DataMember]
@@ -179,6 +182,7 @@ namespace BabylonExport.Entities
             indexOfRefraction = 0.66f;
             useRadianceOverAlpha = true;
             useSpecularOverAlpha = true;
+            usePhysicalLightFalloff = true;
             useEmissiveAsIllumination = false;
 
             // Default Null Metallic Workflow
@@ -205,5 +209,10 @@ namespace BabylonExport.Entities
             overloadedEmissive = new[] {1f, 1f, 1f };
             overloadedReflection = new[] { 1f, 1f, 1f };
         }
+
+        public void SetCustomType(string type)
+        {
+            this.customType = type;
+        }
     }
 }

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

@@ -24,6 +24,9 @@ namespace BabylonExport.Entities
         public bool useBlurVarianceShadowMap { get; set; }
 
         [DataMember]
+        public float darkness { get; set; }
+
+        [DataMember]
         public float blurScale { get; set; }
 
         [DataMember]
@@ -35,5 +38,13 @@ namespace BabylonExport.Entities
         [DataMember]
         public bool forceBackFacesOnly { get; set; }
 
+        public BabylonShadowGenerator()
+        {
+            darkness = 0;
+            blurScale = 2;
+            blurBoxOffset = 0;
+            bias = 0.00005f;
+            forceBackFacesOnly = false;
+        }
     }
 }

BIN
Exporters/3ds Max/Max2Babylon-0.5.0.zip


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 instanceScale = instanceLocalTM.Scaling;
 
+                    instance.id = instanceGameNode.MaxNode.GetGuid().ToString();
                     instance.position = new[] { instanceTrans.X, instanceTrans.Y, instanceTrans.Z };
 
                     if (exportQuaternions)

+ 1 - 1
Exporters/Maya/Tools/babylonReskinTool.mel

@@ -43,7 +43,7 @@ global proc babylonReskinTool() {
     string $window = `window -title "Reskin Geometry Tool"`;
     columnLayout -adjustableColumn true;
     textFieldGrp -label "New Skin Name" -text "" myReskinName;
-    intSliderGrp -label "Max Influencers" -field true -minValue 1 -maxValue 20 -fieldMinValue 1 -fieldMaxValue 20 -value 5 myReskinInfluencers;
+    intSliderGrp -label "Max Influencers" -field true -minValue 1 -maxValue 8 -fieldMinValue 1 -fieldMaxValue 8 -value 4 myReskinInfluencers;
     button -label "Reskin Selected Meshes" -command "reskinSelectedMeshes()" myReskinButton; 
     showWindow $window;
 }

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


+ 1 - 0
Playground/debug.html

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

+ 1 - 0
Playground/frame.html

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

+ 3 - 0
Playground/index-local.html

@@ -16,6 +16,9 @@
     <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="../tools/DevLoader/BabylonLoader.js"></script>
     <link href="index.css" rel="stylesheet" />
 </head>

+ 11 - 0
Playground/index.html

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

+ 27 - 0
Playground/index.js

@@ -23,6 +23,21 @@
         var scripts;
         var zipCode;
         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 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
         setFontSize = function (size) {
             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>

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

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

+ 2 - 1
Playground/scripts/scripts.txt

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

+ 1 - 1
Playground/scripts/shadows.js

@@ -45,7 +45,7 @@
 	// Shadows
 	var shadowGenerator = new BABYLON.ShadowGenerator(1024, light);
 	shadowGenerator.getShadowMap().renderList.push(torus);
-	shadowGenerator.useVarianceShadowMap = true;
+	shadowGenerator.useExponentialShadowMap = true;
 
 	var shadowGenerator2 = new BABYLON.ShadowGenerator(1024, light2);
 	shadowGenerator2.getShadowMap().renderList.push(torus);

A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 644 - 561
Tools/Gulp/config.json


+ 3 - 3
Tools/Gulp/package.json

@@ -8,10 +8,10 @@
   "license": "(Apache-2.0)",
   "devDependencies": {
     "gulp": "^3.8.11",
-    "gulp-uglify": "~1.5.3",
+    "gulp-uglify": "^2.0.1",
     "gulp-sourcemaps": "~1.9.1",
-    "typescript": "^2.1.4",
-    "gulp-typescript": "^3.1.3",
+    "typescript": "~2.1.4",
+    "gulp-typescript": "^3.1.5",
     "through2": "~0.6.5",
     "gulp-util": "~3.0.4",
     "gulp-concat": "~2.5.2",

BIN
assets/sounds/explosion.wav


BIN
assets/sounds/jump.wav


BIN
assets/textures/Ground.jpg


+ 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)
 - [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/)
  - 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.
 
-**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
+```
+

+ 28 - 36
canvas2D/src/Engine/babylon.atlasPicture.ts

@@ -208,46 +208,38 @@
          * @param onError a callback that will be called in case of error
          */
         public static loadFromUrl(texture: Texture, url: string, onLoad: (api: AtlasPictureInfo) => void, onError: (msg: string, code: number) => void = null) {
-            var xhr = new XMLHttpRequest();
-            xhr.onreadystatechange = () => {
-                if (xhr.readyState === XMLHttpRequest.DONE) {
-                    if (xhr.status === 200) {
-                        let ext = url.split('.').pop().split(/\#|\?/)[0];
-                        let plugins = AtlasPictureInfoFactory.plugins.get(ext.toLocaleLowerCase());
-                        if (!plugins) {
-                            if (onError) {
-                                onError("couldn't find a plugin for this file extension", -1);
-                            }
-                            return;
-                        }
-                        for (let p of plugins) {
-                            let ret = p.loadFile(xhr.response);
-                            if (ret) {
-                                if (ret.api) {
-                                    ret.api.texture = texture;
-                                    if (onLoad) {
-                                        onLoad(ret.api);
-                                    }
-                                } else if (onError) {
-                                    onError(ret.errorMsg, ret.errorCode);
-                                }
-                                return;
+            Tools.LoadFile(url, (data) => {
+                let ext = url.split('.').pop().split(/\#|\?/)[0];
+                let plugins = AtlasPictureInfoFactory.plugins.get(ext.toLocaleLowerCase());
+                if (!plugins) {
+                    if (onError) {
+                        onError("couldn't find a plugin for this file extension", -1);
+                    }
+                    return;
+                }
+                for (let p of plugins) {
+                    let ret = p.loadFile(data);
+                    if (ret) {
+                        if (ret.api) {
+                            ret.api.texture = texture;
+                            if (onLoad) {
+                                onLoad(ret.api);
                             }
+                        } else if (onError) {
+                            onError(ret.errorMsg, ret.errorCode);
                         }
-
-                        if (onError) {
-                            onError("No plugin to load this Atlas Data file format", -1);
-                        }
-
-                    } else {
-                        if (onError) {
-                            onError("Couldn't load file through HTTP Request, HTTP Status " + xhr.status, xhr.status);
-                        }
+                        return;
                     }
                 }
-            }
-            xhr.open("GET", url, true);
-            xhr.send();
+
+                if (onError) {
+                    onError("No plugin to load this Atlas Data file format", -1);
+                }
+            }, null, null, null, () => {
+                if (onError) {
+                    onError("Couldn't load file", -1);
+                }
+            });
             return null;
         }
 

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

@@ -127,6 +127,10 @@
             b._worldAABBDirty = true;
         }
 
+        public toString(): string {
+            return `Center: ${this.center}, Extent: ${this.extent}, Radius: ${this.radius}`;
+        }
+
         /**
          * Duplicate this instance and return a new one
          * @return the duplicated instance
@@ -153,6 +157,13 @@
             this._worldAABBDirty = true;
         }
 
+        public equals(other: BoundingInfo2D): boolean {
+            if (!other) {
+                return false;
+            }
+            return other.center.equals(this.center) && other.extent.equals(this.extent);
+        }
+
         /**
          * return the max extend of the bounding info
          */
@@ -225,7 +236,7 @@
          * @param matrix the transformation matrix to apply
          * @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();
             this.transformToRef(matrix, r);
             return r;
@@ -257,7 +268,7 @@
          * @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
          */
-        public transformToRef(matrix: Matrix, result: BoundingInfo2D) {
+        public transformToRef(matrix: Matrix2D, result: BoundingInfo2D) {
             // Construct a bounding box based on the extent values
             let p = BoundingInfo2D._transform;
             p[0].x = this.center.x + this.extent.x;
@@ -271,12 +282,12 @@
 
             // Transform the four points of the bounding box with the matrix
             for (let i = 0; i < 4; i++) {
-                Vector2.TransformToRef(p[i], matrix, p[i]);
+                matrix.transformPointToRef(p[i], p[i]);
             }
             BoundingInfo2D.CreateFromPointsToRef(p, result);
         }
 
-        private _updateWorldAABB(worldMatrix: Matrix) {
+        private _updateWorldAABB(worldMatrix: Matrix2D) {
             // Construct a bounding box based on the extent values
             let p = BoundingInfo2D._transform;
             p[0].x = this.center.x + this.extent.x;
@@ -290,7 +301,7 @@
 
             // Transform the four points of the bounding box with the matrix
             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));
@@ -299,7 +310,7 @@
             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> {
             if (!this._worldAABBDirtyObservable) {

+ 204 - 115
canvas2D/src/Engine/babylon.canvas2d.ts

@@ -87,19 +87,6 @@
         }) {
             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._cachedCanvasGroup = null;
 
             this._renderingGroupObserver = null;
@@ -168,6 +155,8 @@
             this._scene = scene;
             this._engine = engine;
             this._renderingSize = new Size(0, 0);
+            this._curHWScale = 0;
+            this._canvasLevelScale = new Vector2(1, 1);
             this._designSize = settings.designSize || null;
             this._designUseHorizAxis = settings.designUseHorizAxis === true;
             if (!this._trackedGroups) {
@@ -197,18 +186,24 @@
                     this._renderingGroupObserver = this._scene.onRenderingGroupObservable.add((e, s) => {
                         if ((this._scene.activeCamera === settings.renderingPhase.camera) && (e.renderStage===RenderingGroupInfo.STAGE_POSTTRANSPARENT)) {
                             this._engine.clear(null, false, true, true);
+                            C2DLogging._startFrameRender();
                             this._render();
+                            C2DLogging._endFrameRender();
                         }
                     }, Math.pow(2, settings.renderingPhase.renderingGroupID));
                 } else {
                     this._afterRenderObserver = this._scene.onAfterRenderObservable.add((d, s) => {
                         this._engine.clear(null, false, true, true);
+                        C2DLogging._startFrameRender();
                         this._render();
+                        C2DLogging._endFrameRender();
                     });
                 }
             } else {
                 this._beforeRenderObserver = this._scene.onBeforeRenderObservable.add((d, s) => {
+                    C2DLogging._startFrameRender();
                     this._render();
+                    C2DLogging._endFrameRender();
                 });
             }
 
@@ -229,53 +224,96 @@
         }
 
         public get drawCallsOpaqueCounter(): PerfCounter {
+            if (!this._drawCallsOpaqueCounter) {
+                this._drawCallsOpaqueCounter = new PerfCounter();
+            }
             return this._drawCallsOpaqueCounter;
         }
 
         public get drawCallsAlphaTestCounter(): PerfCounter {
+            if (!this._drawCallsAlphaTestCounter) {
+                this._drawCallsAlphaTestCounter = new PerfCounter();
+            }
             return this._drawCallsAlphaTestCounter;
         }
 
         public get drawCallsTransparentCounter(): PerfCounter {
+            if (!this._drawCallsTransparentCounter) {
+                this._drawCallsTransparentCounter = new PerfCounter();
+            }
             return this._drawCallsTransparentCounter;
         }
 
         public get groupRenderCounter(): PerfCounter {
+            if (!this._groupRenderCounter) {
+                this._groupRenderCounter = new PerfCounter();
+            }
             return this._groupRenderCounter;
         }
 
         public get updateTransparentDataCounter(): PerfCounter {
+            if (!this._updateTransparentDataCounter) {
+                this._updateTransparentDataCounter = new PerfCounter();
+            }
             return this._updateTransparentDataCounter;
         }
 
-        public get cachedGroupRenderCounter(): PerfCounter {
-            return this._cachedGroupRenderCounter;
-        }
-
         public get updateCachedStateCounter(): PerfCounter {
+            if (!this._updateCachedStateCounter) {
+                this._updateCachedStateCounter = new PerfCounter();
+            }
             return this._updateCachedStateCounter;
         }
 
         public get updateLayoutCounter(): PerfCounter {
+            if (!this._updateLayoutCounter) {
+                this._updateLayoutCounter = new PerfCounter();
+            }
             return this._updateLayoutCounter;
         }
 
         public get updatePositioningCounter(): PerfCounter {
+            if (!this._updatePositioningCounter) {
+                this._updatePositioningCounter = new PerfCounter();
+            }
             return this._updatePositioningCounter;
         }
 
         public get updateLocalTransformCounter(): PerfCounter {
+            if (!this._updateLocalTransformCounter) {
+                this._updateLocalTransformCounter = new PerfCounter();
+            }
             return this._updateLocalTransformCounter;
         }
 
         public get updateGlobalTransformCounter(): PerfCounter {
+            if (!this._updateGlobalTransformCounter) {
+                this._updateGlobalTransformCounter = new PerfCounter();
+            }
             return this._updateGlobalTransformCounter;
         }
 
         public get boundingInfoRecomputeCounter(): PerfCounter {
+            if (!this._boundingInfoRecomputeCounter) {
+                this._boundingInfoRecomputeCounter = new PerfCounter();
+            }
             return this._boundingInfoRecomputeCounter;
         }
 
+        public get layoutBoundingInfoUpdateCounter(): PerfCounter {
+            if (!this._layoutBoundingInfoUpdateCounter) {
+                this._layoutBoundingInfoUpdateCounter = new PerfCounter();
+            }
+            return this._layoutBoundingInfoUpdateCounter;
+        }
+
+        public get canvasRenderTimeCounter(): PerfCounter {
+            if (!this._canvasRenderTimeCounter) {
+                this._canvasRenderTimeCounter = new PerfCounter();
+            }
+            return this._canvasRenderTimeCounter;
+        }
+
         public static get instances() : Array<Canvas2D> {
             return Canvas2D._INSTANCES;
         }
@@ -288,6 +326,7 @@
             let cachingStrategy = (settings.cachingStrategy == null) ? Canvas2D.CACHESTRATEGY_DONTCACHE : settings.cachingStrategy;
             this._cachingStrategy = cachingStrategy;
             this._isScreenSpace = (settings.isScreenSpace == null) ? true : settings.isScreenSpace;
+            this._hierarchyDepth = 0;
         }
 
         public static _zMinDelta: number = 1 / (Math.pow(2, 24) - 1);
@@ -320,9 +359,7 @@
                     if (this.isVisible === false) {
                         return;
                     }
-                    let hs = 1 / this.engine.getHardwareScalingLevel();
-                    let localPos = e.localPosition.multiplyByFloats(hs, hs);
-                    this._handlePointerEventForInteraction(e, localPos, s);
+                    this._handlePointerEventForInteraction(e, e.localPosition, s);
                 });
             }
 
@@ -495,7 +532,7 @@
             // Update the relatedTarget info with the over primitive or the captured one (if any)
             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);
 
@@ -516,7 +553,7 @@
         }
 
         private _updatePointerInfo(eventData: PointerInfoBase, localPosition: Vector2): boolean {
-            let s = this.scale;
+            let s = this._canvasLevelScale.multiplyByFloats(this.scaleX, this.scaleY);
             let pii = this._primPointerInfo;
             pii.cancelBubble = false;
             if (!pii.canvasPointerPos) {
@@ -531,17 +568,20 @@
 
             if (this._isScreenSpace) {
                 var cameraViewport = camera.viewport;
-                var viewport = cameraViewport.toGlobal(engine.getRenderWidth(), engine.getRenderHeight());
+                let renderWidth = engine.getRenderWidth();
+                let renderHeight = engine.getRenderHeight();
+//                console.log(`Render Width: ${renderWidth} Height: ${renderHeight}, localX: ${localPosition.x}, localY: ${localPosition.y}`);
+                var viewport = cameraViewport.toGlobal(renderWidth, renderHeight);
 
                 // Moving coordinates to local viewport world
                 var x = localPosition.x - viewport.x;
                 var y = localPosition.y - viewport.y;
 
-                pii.canvasPointerPos.x = (x - this.actualPosition.x) / s;
-                pii.canvasPointerPos.y = (engine.getRenderHeight() - y - this.actualPosition.y) / s;
+                pii.canvasPointerPos.x = (x - this.actualPosition.x) / s.x;
+                pii.canvasPointerPos.y = (renderHeight - y - this.actualPosition.y) / s.y;
             } else {
-                pii.canvasPointerPos.x = localPosition.x / s;
-                pii.canvasPointerPos.y = localPosition.y / s;
+                pii.canvasPointerPos.x = localPosition.x / s.x;
+                pii.canvasPointerPos.y = localPosition.y / s.x;
             }
             //console.log(`UpdatePointerInfo for ${this.id}, X:${pii.canvasPointerPos.x}, Y:${pii.canvasPointerPos.y}`);
             pii.mouseWheelDelta = 0;
@@ -791,13 +831,13 @@
 
                             if (ii.isPrimIntersected(prim) !== null) {
                                 if (prim.actionManager) {
-                                    if (this._pickStartingTime !== 0 && ((new Date().getTime() - this._pickStartingTime) > ActionManager.LongPressDelay) && (Math.abs(this._pickStartingPosition.x - ii.pickPosition.x) < ActionManager.DragMovementThreshold && Math.abs(this._pickStartingPosition.y - ii.pickPosition.y) < ActionManager.DragMovementThreshold)) {
+                                    if (this._pickStartingTime !== 0 && ((new Date().getTime() - this._pickStartingTime) > Scene.LongPressDelay) && (Math.abs(this._pickStartingPosition.x - ii.pickPosition.x) < Scene.DragMovementThreshold && Math.abs(this._pickStartingPosition.y - ii.pickPosition.y) < Scene.DragMovementThreshold)) {
                                         this._pickStartingTime = 0;
                                         prim.actionManager.processTrigger(ActionManager.OnLongPressTrigger, ActionEvent.CreateNewFromPrimitive(prim, ppi.primitivePointerPos, eventData));
                                     }
                                 }
                             }
-                        }, ActionManager.LongPressDelay);
+                        }, Scene.LongPressDelay);
                     }
                 }
             }
@@ -812,7 +852,7 @@
                     prim.actionManager.processTrigger(ActionManager.OnPickUpTrigger, actionEvent);
 
                     // OnPickTrigger
-                    if (Math.abs(this._pickStartingPosition.x - ppi.canvasPointerPos.x) < ActionManager.DragMovementThreshold && Math.abs(this._pickStartingPosition.y - ppi.canvasPointerPos.y) < ActionManager.DragMovementThreshold) {
+                    if (Math.abs(this._pickStartingPosition.x - ppi.canvasPointerPos.x) < Scene.DragMovementThreshold && Math.abs(this._pickStartingPosition.y - ppi.canvasPointerPos.y) < Scene.DragMovementThreshold) {
                         prim.actionManager.processTrigger(ActionManager.OnPickTrigger, actionEvent);
                     }
                 }
@@ -1122,33 +1162,35 @@
         }
 
         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.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() {
-            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.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() {
@@ -1158,19 +1200,20 @@
 
             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` +
                     ` - 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` +
                     `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` + 
-                    `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 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 Local  Trans: ${this.updateLocalTransformCounter.current}, (avg:${format(this.updateLocalTransformCounter.lastSecAverage)}, t:${format(this.updateLocalTransformCounter.total)})\n` + 
                     ` - Update Global Trans: ${this.updateGlobalTransformCounter.current}, (avg:${format(this.updateGlobalTransformCounter.lastSecAverage)}, t:${format(this.updateGlobalTransformCounter.total)})\n` + 
-                    ` - BoundingInfo Recompute: ${this.boundingInfoRecomputeCounter.current}, (avg:${format(this.boundingInfoRecomputeCounter.lastSecAverage)}, t:${format(this.boundingInfoRecomputeCounter.total)})`;
+                    ` - BoundingInfo Recompute: ${this.boundingInfoRecomputeCounter.current}, (avg:${format(this.boundingInfoRecomputeCounter.lastSecAverage)}, t:${format(this.boundingInfoRecomputeCounter.total)})\n` +
+                    ` - LayoutBoundingInfo Recompute: ${this.layoutBoundingInfoUpdateCounter.current}, (avg:${format(this.layoutBoundingInfoUpdateCounter.lastSecAverage)}, t:${format(this.layoutBoundingInfoUpdateCounter.total)})` ;
             this._profileInfoText.text = p;
         }
 
@@ -1189,35 +1232,51 @@
         }
 
         public _addGroupRenderCount(count: number) {
-            this._groupRenderCounter.addCount(count, false);
+            if (this._groupRenderCounter) {
+                this._groupRenderCounter.addCount(count, false);
+            }
         }
 
         public _addUpdateTransparentDataCount(count: number) {
-            this._updateTransparentDataCounter.addCount(count, false);
-        }
-
-        public addCachedGroupRenderCounter(count: number) {
-            this._cachedGroupRenderCounter.addCount(count, false);
+            if (this._updateTransparentDataCounter) {
+                this._updateTransparentDataCounter.addCount(count, false);
+            }
         }
 
         public addUpdateCachedStateCounter(count: number) {
-            this._updateCachedStateCounter.addCount(count, false);
+            if (this._updateCachedStateCounter) {
+                this._updateCachedStateCounter.addCount(count, false);
+            }
         }
 
         public addUpdateLayoutCounter(count: number) {
-            this._updateLayoutCounter.addCount(count, false);
+            if (this._updateLayoutCounter) {
+                this._updateLayoutCounter.addCount(count, false);
+            }
         }
 
         public addUpdatePositioningCounter(count: number) {
-            this._updatePositioningCounter.addCount(count, false);
+            if (this._updatePositioningCounter) {
+                this._updatePositioningCounter.addCount(count, false);
+            }
         }
 
         public addupdateLocalTransformCounter(count: number) {
-            this._updateLocalTransformCounter.addCount(count, false);
+            if (this._updateLocalTransformCounter) {
+                this._updateLocalTransformCounter.addCount(count, false);
+            }
         }
 
         public addUpdateGlobalTransformCounter(count: number) {
-            this._updateGlobalTransformCounter.addCount(count, false);
+            if (this._updateGlobalTransformCounter) {
+                this._updateGlobalTransformCounter.addCount(count, false);
+            }
+        }
+
+        public addLayoutBoundingInfoUpdateCounter(count: number) {
+            if (this._layoutBoundingInfoUpdateCounter) {
+                this._layoutBoundingInfoUpdateCounter.addCount(count, false);
+            }
         }
 
         private _renderObservable: Observable<Canvas2D>;
@@ -1262,25 +1321,29 @@
         private _designUseHorizAxis: boolean;
         public  _primitiveCollisionManager: PrimitiveCollisionManagerBase;
 
-        public _renderingSize: Size;
-
-        private _drawCallsOpaqueCounter      : PerfCounter;
-        private _drawCallsAlphaTestCounter   : PerfCounter;
-        private _drawCallsTransparentCounter : PerfCounter;
-        private _groupRenderCounter          : PerfCounter;
-        private _updateTransparentDataCounter: PerfCounter;
-        private _cachedGroupRenderCounter    : PerfCounter;
-        private _updateCachedStateCounter    : PerfCounter;
-        private _updateLayoutCounter         : PerfCounter;
-        private _updatePositioningCounter    : PerfCounter;
-        private _updateGlobalTransformCounter: PerfCounter;
-        private _updateLocalTransformCounter : PerfCounter;
-        private _boundingInfoRecomputeCounter: PerfCounter;
+        public _canvasLevelScale: Vector2;
+        public  _renderingSize: Size;
+        private _curHWScale;
+
+        private _drawCallsOpaqueCounter          : PerfCounter;
+        private _drawCallsAlphaTestCounter       : PerfCounter;
+        private _drawCallsTransparentCounter     : PerfCounter;
+        private _groupRenderCounter              : PerfCounter;
+        private _updateTransparentDataCounter    : PerfCounter;
+        private _updateCachedStateCounter        : PerfCounter;
+        private _updateLayoutCounter             : PerfCounter;
+        private _updatePositioningCounter        : PerfCounter;
+        private _updateGlobalTransformCounter    : PerfCounter;
+        private _updateLocalTransformCounter     : PerfCounter;
+        private _boundingInfoRecomputeCounter    : PerfCounter;
+        private _layoutBoundingInfoUpdateCounter : PerfCounter;
+        private _canvasRenderTimeCounter         : PerfCounter;
 
         private _profilingCanvas: Canvas2D;
         private _profileInfoText: Text2D;
 
         private static _v = Vector3.Zero(); // Must stay zero
+        private static _cv1 = Vector2.Zero(); // Must stay zero
         private static _m = Matrix.Identity();
         private static _mI = Matrix.Identity(); // Must stay identity
         private static tS = Vector3.Zero();
@@ -1322,8 +1385,8 @@
                 group.levelVisible = proj.z >= 0 && proj.z < 1.0;
 
                 let s = this.scale;
-                group.x = Math.round(proj.x/s);
-                group.y = Math.round((rh - proj.y)/s);
+                group.x = Math.round(proj.x / s);
+                group.y = Math.round((rh - proj.y) / s);
             }
 
             // If it's a WorldSpaceCanvas and it's tracking a node, let's update the WSC transformation data
@@ -1420,6 +1483,7 @@
                 this._setRenderingScale(scale);
             }
         }
+        private static _pCLS = Vector2.Zero();
 
         private _updateCanvasState(forceRecompute: boolean) {
             // Check if the update has already been made for this render Frame
@@ -1427,23 +1491,51 @@
                 return;
             }
 
+            // Detect a change of HWRendering scale
+            let hwsl = this.engine.getHardwareScalingLevel();
+            this._curHWScale = hwsl;
+
             // Detect a change of rendering size
             let renderingSizeChanged = false;
-            let newWidth = this.engine.getRenderWidth();
+            let newWidth = this.engine.getRenderWidth() * hwsl;
             if (newWidth !== this._renderingSize.width) {
                 renderingSizeChanged = true;
             }
             this._renderingSize.width = newWidth;
 
-            let newHeight = this.engine.getRenderHeight();
+            let newHeight = this.engine.getRenderHeight() * hwsl;
             if (newHeight !== this._renderingSize.height) {
                 renderingSizeChanged = true;
             }
             this._renderingSize.height = newHeight;
 
+            let prevCLS = Canvas2D._pCLS;
+            prevCLS.copyFrom(this._canvasLevelScale);
+
+            // If there's a design size, update the scale according to the renderingSize
+            if (this._designSize) {
+                let scale: number;
+                if (this._designUseHorizAxis) {
+                    scale = this._renderingSize.width / (this._designSize.width * hwsl);
+                } else {
+                    scale = this._renderingSize.height / (this._designSize.height * hwsl);
+                }
+                this.size = this._designSize.clone();
+                this._canvasLevelScale.copyFromFloats(scale, scale);
+            } else {
+                let ratio = 1 / this._curHWScale;
+                this._canvasLevelScale.copyFromFloats(ratio, ratio);
+            }
+
+            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.actualSize = this._renderingSize.clone();
                 this.size = this._renderingSize.clone();
                 if (this._background) {
                     this._background.size = this.size;
@@ -1453,22 +1545,10 @@
                 this._setLayoutDirty();
             }
 
-            // If there's a design size, update the scale according to the renderingSize
-            if (this._designSize) {
-                let scale: number;
-                if (this._designUseHorizAxis) {
-                    scale = this._renderingSize.width / this._designSize.width;
-                } else {
-                    scale = this._renderingSize.height / this._designSize.height;
-                }
-                this.size = this._designSize.clone();
-                this.actualSize = this._designSize.clone();
-                this.scale = scale;
-            }
-
             var context = new PrepareRender2DContext();
 
             ++this._globalTransformProcessStep;
+            this._setFlags(SmartPropertyPrim.flagLocalTransformDirty|SmartPropertyPrim.flagGlobalTransformDirty);
             this.updateCachedStates(false);
 
             this._prepareGroupRender(context);
@@ -1479,8 +1559,8 @@
         /**
          * Method that renders the Canvas, you should not invoke
          */
+        @logMethod("==========CANVAS RENDER===============")
         private _render() {
-
             this._initPerfMetrics();
 
             if (this._renderObservable && this._renderObservable.hasObservers()) {
@@ -1549,18 +1629,19 @@
             let isCanvas = parent == null;
             let scale: Vector2;
             if (noResizeScale) {
-                scale = isCanvas ? Canvas2D._unS : group.parent.actualScale;
+                scale = isCanvas ? Canvas2D._unS : group.parent.actualScale.multiply(this._canvasLevelScale);
             } else {
-                scale = group.actualScale;
+                scale = group.actualScale.multiply(this._canvasLevelScale);
             }
 
             // Determine size
             let size = group.actualSize;
-            size = new Size(Math.ceil(size.width * scale.x), Math.ceil(size.height * scale.y));
-            let originalSize = size.clone();
+            let scaledSize = new Size(size.width * scale.x, size.height * scale.y);
+            let roundedScaledSize = new Size(Math.ceil(scaledSize.width), Math.ceil(scaledSize.height));
+            let originalSize = scaledSize.clone();
             if (minSize) {
-                size.width = Math.max(minSize.width, size.width);
-                size.height = Math.max(minSize.height, size.height);
+                roundedScaledSize.width = Math.max(minSize.width, roundedScaledSize.width);
+                roundedScaledSize.height = Math.max(minSize.height, roundedScaledSize.height);
             }
 
             let mapArray = this._groupCacheMaps.getOrAddWithFactory(key, () => new Array<MapTexture>());
@@ -1570,7 +1651,7 @@
             var map: MapTexture;
             for (var _map of mapArray) {
                 map = _map;
-                let node = map.allocateRect(size);
+                let node = map.allocateRect(roundedScaledSize);
                 if (node) {
                     res = { node: node, texture: map }
                     break;
@@ -1582,18 +1663,24 @@
                 let mapSize = new Size(Canvas2D._groupTextureCacheSize, Canvas2D._groupTextureCacheSize);
 
                 // Check if the predefined size would fit, other create a custom size using the nearest bigger power of 2
-                if (size.width > mapSize.width || size.height > mapSize.height) {
-                    mapSize.width = Math.pow(2, Math.ceil(Math.log(size.width) / Math.log(2)));
-                    mapSize.height = Math.pow(2, Math.ceil(Math.log(size.height) / Math.log(2)));
+                if (roundedScaledSize.width > mapSize.width || roundedScaledSize.height > mapSize.height) {
+                    mapSize.width = Math.pow(2, Math.ceil(Math.log(roundedScaledSize.width) / Math.log(2)));
+                    mapSize.height = Math.pow(2, Math.ceil(Math.log(roundedScaledSize.height) / Math.log(2)));
                 }
 
                 let id = `groupsMapChache${this._mapCounter++}forCanvas${this.id}`;
-                map = new MapTexture(id, this._scene, mapSize, useMipMap ? Texture.TRILINEAR_SAMPLINGMODE : Texture.BILINEAR_SAMPLINGMODE, useMipMap);
+                map = new MapTexture(id, this._scene, mapSize, useMipMap ? Texture.TRILINEAR_SAMPLINGMODE : Texture.BILINEAR_SAMPLINGMODE, useMipMap, 2);
                 map.hasAlpha = true;
                 map.anisotropicFilteringLevel = 4;
                 mapArray.splice(0, 0, map);
 
-                let node = map.allocateRect(size);
+                //let debug = false;
+
+                //if (debug) {
+                //    let sprite = new Sprite2D(map, { parent: this, x: 10, y: 10, id: "__cachedSpriteOfGroup__Debug", alignToPixel: true });
+                //}
+
+                let node = map.allocateRect(roundedScaledSize);
                 res = { node: node, texture: map }
             }
 
@@ -1601,6 +1688,8 @@
             // Don't do it in case of the group being a worldspace canvas (because its texture is bound to a WorldSpaceCanvas node)
             if (group !== <any>this || this._isScreenSpace) {
                 let node: PackedRect = res.node;
+                let pos = Canvas2D._cv1;
+                node.getInnerPosToRef(pos);
 
                 // Special case if the canvas is entirely cached: create a group that will have a single sprite it will be rendered specifically at the very end of the rendering process
 
@@ -1610,14 +1699,14 @@
                         this._cachedCanvasGroup.dispose();
                     }
                     this._cachedCanvasGroup = Group2D._createCachedCanvasGroup(this);
-                    sprite = new Sprite2D(map, { parent: this._cachedCanvasGroup, id: "__cachedCanvasSprite__", spriteSize: originalSize, spriteLocation: node.pos });
+                    sprite = new Sprite2D(map, { parent: this._cachedCanvasGroup, id: "__cachedCanvasSprite__", spriteSize: originalSize, size: size, alignToPixel: true, spriteLocation: pos });
                     sprite.zOrder = 1;
                     sprite.origin = Vector2.Zero();
                 }
 
                 // Create a Sprite that will be used to render this cache, the "__cachedSpriteOfGroup__" starting id is a hack to bypass exception throwing in case of the Canvas doesn't normally allows direct primitives
                 else {
-                    sprite = new Sprite2D(map, { parent: parent, id: `__cachedSpriteOfGroup__${group.id}`, x: group.actualPosition.x, y: group.actualPosition.y, spriteSize: originalSize, spriteLocation: node.pos, dontInheritParentScale: true });
+                    sprite = new Sprite2D(map, { parent: parent, id: `__cachedSpriteOfGroup__${group.id}`, x: group.x, y: group.y, spriteSize: originalSize, size: size, spriteLocation: pos, alignToPixel: true, dontInheritParentScale: true });
                     sprite.origin = group.origin.clone();
                     sprite.addExternalData("__cachedGroup__", group);
                     sprite.pointerEventObservable.add((e, s) => {

+ 100 - 31
canvas2D/src/Engine/babylon.canvas2dLayoutEngine.ts

@@ -61,18 +61,20 @@
         // A very simple (no) layout computing...
         // 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
+        @logMethod()
         public updateLayout(prim: Prim2DBase) {
 
             // If this prim is layoutDiry we update  its layoutArea and also the one of its direct children
             if (prim._isFlagSet(SmartPropertyPrim.flagLayoutDirty)) {
+                prim._clearFlags(SmartPropertyPrim.flagLayoutDirty);
                 for (let child of prim.children) {
                     this._doUpdate(child);
                 }
-                prim._clearFlags(SmartPropertyPrim.flagLayoutDirty);
             }
 
         }
 
+        @logMethod()
         private _doUpdate(prim: Prim2DBase) {
             // Canvas ?
             if (prim instanceof Canvas2D) {
@@ -86,7 +88,12 @@
 
             // Indirect child of Canvas
             else {
-                prim.layoutArea = prim.parent.contentArea;
+                let contentArea = prim.parent.contentArea;
+
+                // Can be null if the parent's content area depend of its children, the computation will be done in many passes
+                if (contentArea) {
+                    prim.layoutArea = contentArea;
+                }
             }
         }
 
@@ -143,47 +150,89 @@
 
         private _isHorizontal: boolean = true;
 
+        private static stackPanelLayoutArea = Size.Zero();
         private static dstOffset = Vector4.Zero();
         private static dstArea = Size.Zero();
 
+        private static computeCounter = 0;
+
         public updateLayout(prim: Prim2DBase) {
             if (prim._isFlagSet(SmartPropertyPrim.flagLayoutDirty)) {
 
+                let primLayoutArea = prim.layoutArea;
+                let isSizeAuto = prim.isSizeAuto;
+
+                // If we're not in autoSize the layoutArea of the prim having the stack panel must be computed in order for us to compute the children' position.
+                // If there's at least one auto size (Horizontal or Vertical) we will have to figure the layoutArea ourselves
+                if (!primLayoutArea && !isSizeAuto) {
+                    return;
+                }
+
+//                console.log("Compute Stack Panel Layout " + ++StackPanelLayoutEngine.computeCounter);
+
                 let x = 0;
                 let y = 0;
-                let h = this.isHorizontal;
+                let horizonStackPanel = this.isHorizontal;
+
+                // If the stack panel is horizontal we check if the primitive height is auto or not, if it's auto then we have to compute the required height, otherwise we just take the actualHeight. If the stack panel is vertical we do the same but with width
                 let max = 0;
 
+                let stackPanelLayoutArea = StackPanelLayoutEngine.stackPanelLayoutArea;
+                if (horizonStackPanel) {
+                    if (prim.isVerticalSizeAuto) {
+                        max = 0;
+                        stackPanelLayoutArea.height = 0;
+                    } else {
+                        max = prim.layoutArea.height;
+                        stackPanelLayoutArea.height = prim.layoutArea.height;
+                        stackPanelLayoutArea.width = 0;
+                    }
+                } else {
+                    if (prim.isHorizontalSizeAuto) {
+                        max = 0;
+                        stackPanelLayoutArea.width = 0;
+                    } else {
+                        max = prim.layoutArea.width;
+                        stackPanelLayoutArea.width = prim.layoutArea.width;
+                        stackPanelLayoutArea.height = 0;
+                    }
+                }
+
                 for (let child of prim.children) {
                     if (child._isFlagSet(SmartPropertyPrim.flagNoPartOfLayout)) {
                         continue;
                     }
-                    let layoutArea: Size;
+
                     if (child._hasMargin) {
-                        child.margin.computeWithAlignment(prim.layoutArea, child.actualSize, child.marginAlignment, child.actualScale, StackPanelLayoutEngine.dstOffset, StackPanelLayoutEngine.dstArea, true);
-                        layoutArea = StackPanelLayoutEngine.dstArea.clone();
-                        child.layoutArea = layoutArea;
+
+                        // Calling computeWithAlignment will return us the area taken by "child" which is its layoutArea
+                        // We also have the dstOffset which will give us the y position in horizontal mode or x position in vertical mode.
+                        //  The alignment offset on the other axis is simply ignored as it doesn't make any sense (e.g. horizontal alignment is ignored in horizontal mode)
+                        child.margin.computeWithAlignment(stackPanelLayoutArea, child.actualSize, child.marginAlignment, child.actualScale, StackPanelLayoutEngine.dstOffset, StackPanelLayoutEngine.dstArea, true);
+
+                        child.layoutArea = StackPanelLayoutEngine.dstArea;
+
                     } else {
-                        layoutArea = child.layoutArea;
-                        child.margin.computeArea(child.actualSize, layoutArea);
+                        child.margin.computeArea(child.actualSize, child.actualScale, StackPanelLayoutEngine.dstArea);
+                        child.layoutArea = StackPanelLayoutEngine.dstArea;
                     }
 
-                    max = Math.max(max, h ? layoutArea.height : layoutArea.width);
-
+                    max = Math.max(max, horizonStackPanel ? StackPanelLayoutEngine.dstArea.height : StackPanelLayoutEngine.dstArea.width);
                 }
 
                 for (let child of prim.children) {
                     if (child._isFlagSet(SmartPropertyPrim.flagNoPartOfLayout)) {
                         continue;
                     }
-                    child.layoutAreaPos = new Vector2(x, y);
 
                     let layoutArea = child.layoutArea;
 
-                    if (h) {
+                    if (horizonStackPanel) {
+                        child.layoutAreaPos = new Vector2(x, 0);
                         x += layoutArea.width;
                         child.layoutArea = new Size(layoutArea.width, max);
                     } else {
+                        child.layoutAreaPos = new Vector2(0, y);
                         y += layoutArea.height;
                         child.layoutArea = new Size(max, layoutArea.height);
                     }
@@ -321,20 +370,25 @@
 
         private static dstOffset = Vector4.Zero();
         private static dstArea = Size.Zero();
+        private static dstAreaPos = Vector2.Zero();
 
         public updateLayout(prim: Prim2DBase) {
             if (prim._isFlagSet(SmartPropertyPrim.flagLayoutDirty)) {
 
+                if (!prim.layoutArea) {
+                    return;
+                }
+
                 for (let child of prim.children) {
                     if (child._isFlagSet(SmartPropertyPrim.flagNoPartOfLayout)) {
                         continue;
                     }
                     if (child._hasMargin) {
                         child.margin.computeWithAlignment(prim.layoutArea, child.actualSize, child.marginAlignment, child.actualScale, GridPanelLayoutEngine.dstOffset, GridPanelLayoutEngine.dstArea, true);
-                        child.layoutArea = GridPanelLayoutEngine.dstArea.clone();
                     } else {
-                        child.margin.computeArea(child.actualSize, child.layoutArea);
+                        child.margin.computeArea(child.actualSize, child.actualScale, GridPanelLayoutEngine.dstArea);
                     }
+                    child.layoutArea = GridPanelLayoutEngine.dstArea;
                 }
 
                 this._updateGrid(prim);
@@ -344,7 +398,8 @@
                 let cl = this._columns.length;
                 let columnWidth = 0;
                 let rowHeight = 0;
-                let layoutArea = new BABYLON.Size(0, 0);
+                let dstArea = GridPanelLayoutEngine.dstArea;
+                let dstAreaPos = GridPanelLayoutEngine.dstAreaPos;
 
                 for(let i = 0; i < _children.length; i++){
                     let children = _children[i];
@@ -382,13 +437,17 @@
                                     }
                                     
                                 }
+                                
+                                dstArea.width = columnWidth;
+                                dstArea.height = rowHeight;
 
-                                layoutArea.width = columnWidth;
-                                layoutArea.height = rowHeight;                                
-
-                                child.margin.computeWithAlignment(layoutArea, child.actualSize, child.marginAlignment, child.actualScale, GridPanelLayoutEngine.dstOffset, GridPanelLayoutEngine.dstArea);
-                                child.layoutAreaPos = new BABYLON.Vector2(left + GridPanelLayoutEngine.dstOffset.x, bottom + GridPanelLayoutEngine.dstOffset.y);
+                                child.layoutArea = dstArea;
                                 
+                                dstAreaPos.x = left;
+                                dstAreaPos.y = bottom;
+
+                                child.layoutAreaPos = dstAreaPos;
+
                                 bottom = oBottom;
                                 rowHeight = oRowHeight;
                                 
@@ -417,7 +476,7 @@
             let row = rows[rowNum];
             let maxHeight = 0;
 
-            if(children){
+            if(children && children[rowNum]){
 
                 for(let i = 0; i < cl; i++){
                     let child = children[rowNum][i];
@@ -448,11 +507,13 @@
             if(children){
 
                 for(let i = 0; i < rl; i++){
-                    let child = children[i][colNum];
-                    if(child){
-                        let span = (<GridData>child.layoutData).columnSpan;
-                        if(maxWidth < child.layoutArea.width/span){
-                            maxWidth = child.layoutArea.width/span;
+                    if(children[i]){
+                        let child = children[i][colNum];
+                        if(child){
+                            let span = (<GridData>child.layoutData).columnSpan;
+                            if(maxWidth < child.layoutArea.width/span){
+                                maxWidth = child.layoutArea.width/span;
+                            }
                         }
                     }
                 }
@@ -533,7 +594,8 @@
 
                 }else if(row.heightType == GridDimensionDefinition.Pixels){
 
-                    this._rowHeights[i] = row.heightPixels;
+                    let maxChildHeight = this._getMaxChildHeightInRow(i);
+                    this._rowHeights[i] = Math.max(row.heightPixels, maxChildHeight);
                     rowHeights += this._rowHeights[i];
 
                 }else if(row.heightType == GridDimensionDefinition.Stars){
@@ -556,7 +618,10 @@
 
                     let rowIndex = starIndexes[i];
 
-                    this._rowHeights[rowIndex] = (this._rows[rowIndex].height / totalStars) * remainingHeight;
+                    let starHeight = (this._rows[rowIndex].height / totalStars) * remainingHeight;
+                    let maxChildHeight = this._getMaxChildHeightInRow(i);
+
+                    this._rowHeights[rowIndex] = Math.max(starHeight, maxChildHeight);
 
                 }
             }
@@ -578,7 +643,8 @@
 
                 }else if(column.widthType == GridDimensionDefinition.Pixels){
 
-                    this._columnWidths[i] = column.widthPixels;
+                    let maxChildWidth = this._getMaxChildWidthInColumn(i);
+                    this._columnWidths[i] = Math.max(column.widthPixels, maxChildWidth);
                     columnWidths += this._columnWidths[i];
 
                 }else if(column.widthType == GridDimensionDefinition.Stars){
@@ -601,7 +667,10 @@
 
                     let columnIndex = starIndexes[i];
 
-                    this._columnWidths[columnIndex] = (this._columns[columnIndex].width / totalStars) * remainingWidth;
+                    let starWidth = (this._columns[columnIndex].width / totalStars) * remainingWidth;
+                    let maxChildWidth = this._getMaxChildWidthInColumn(i);
+
+                    this._columnWidths[columnIndex] = Math.max(starWidth, maxChildWidth);
 
                 }
             }

+ 10 - 20
canvas2D/src/Engine/babylon.ellipse2d.ts

@@ -168,21 +168,6 @@
         public static acutalSizeProperty: Prim2DPropInfo;
         public static subdivisionsProperty: Prim2DPropInfo;
 
-        @instanceLevelProperty(Shape2D.SHAPE2D_PROPCOUNT + 1, pi => Ellipse2D.acutalSizeProperty = pi, false, true)
-        /**
-         * Get/Set the size of the ellipse
-         */
-        public get actualSize(): Size {
-            if (this._actualSize) {
-                return this._actualSize;
-            }
-            return this.size;
-        }
-
-        public set actualSize(value: Size) {
-            this._actualSize = value;
-        }
-
         @modelLevelProperty(Shape2D.SHAPE2D_PROPCOUNT + 2, pi => Ellipse2D.subdivisionsProperty = pi)
         /**
          * Get/set the number of subdivisions used to draw the ellipsis. Default is 64.
@@ -218,6 +203,7 @@
          * - 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
          * - 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.
          * - zOrder: override the zOrder with the specified value
          * - origin: define the normalized origin point location, default [0.5;0.5]
@@ -260,6 +246,7 @@
             scaleX                ?: number,
             scaleY                ?: number,
             dontInheritParentScale?: boolean,
+            alignToPixel          ?: boolean,
             opacity               ?: number,
             zOrder                ?: number, 
             origin                ?: Vector2,
@@ -289,7 +276,7 @@
             paddingLeft           ?: number | string,
             paddingRight          ?: number | string,
             paddingBottom         ?: number | string,
-            padding               ?: string,
+            padding               ?: number | string,
         }) {
 
             // Avoid checking every time if the object exists
@@ -434,21 +421,24 @@
             return res;
         }
 
+        private static _riv0 = new Vector2(0,0);
         protected refreshInstanceDataPart(part: InstanceDataBase): boolean {
             if (!super.refreshInstanceDataPart(part)) {
                 return false;
             }
+
+            //let s = Ellipse2D._riv0;
+            //this.getActualGlobalScaleToRef(s);
+
             if (part.id === Shape2D.SHAPE2D_BORDERPARTID) {
                 let d = <Ellipse2DInstanceData>part;
                 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) {
                 let d = <Ellipse2DInstanceData>part;
                 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;
         }

+ 161 - 41
canvas2D/src/Engine/babylon.fontTexture.ts

@@ -14,6 +14,10 @@
          */
         bottomRightUV: Vector2;
 
+        xOffset: number;
+        yOffset: number;
+        xAdvance: number;
+
         charWidth: number;
     }
 
@@ -22,12 +26,13 @@
      */
     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);
 
             this._cachedFontId = null;
             this._charInfos = new StringDictionary<CharInfo>();
+            this._isPremultipliedAlpha = premultipliedAlpha;
         }
 
         /**
@@ -46,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
          */
         public get spaceWidth(): number {
@@ -144,6 +156,7 @@
         protected _spaceWidth;
         protected _superSample: boolean;
         protected _signedDistanceField: boolean;
+        protected _isPremultipliedAlpha: boolean;
         protected _cachedFontId: string;
     }
 
@@ -154,7 +167,8 @@
         textureSize : Size;
         atlasName   : string;
         padding     : Vector4;       // Left, Top, Right, Bottom
-        lineHeight: number;
+        lineHeight  : number;
+        baseLine    : number;
         textureUrl  : string;
         textureFile : string;
     }
@@ -169,11 +183,12 @@
                             textureUrl: string = null,
                             noMipmap: boolean = false,
                             invertY: boolean = true,
-                            samplingMode: number = Texture.TRILINEAR_SAMPLINGMODE, 
+                            samplingMode: number = Texture.TRILINEAR_SAMPLINGMODE,
+                            premultipliedAlpha: boolean = false,
                             onLoad: () => 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();
             xhr.onreadystatechange = () => {
@@ -331,6 +346,7 @@
         private _xMargin: number;
         private _yMargin: number;
         private _offset: number;
+        private _baseLine: number;
         private _currentFreePosition: Vector2;
         private _curCharCount = 0;
         private _lastUpdateCharCount = -1;
@@ -339,35 +355,36 @@
         private _sdfContext: CanvasRenderingContext2D;
         private _sdfScale: number;
         private _usedCounter = 1;
+        public debugMode: boolean;
 
         get isDynamicFontTexture(): boolean {
             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 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);
             if (ft) {
                 ++ft._usedCounter;
                 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;
             dic.add(lfn, 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");
             if (!dic) {
                 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);
             if (--font._usedCounter === 0) {
                 dic.remove(lfn);
@@ -389,6 +406,7 @@
             super(null, scene, true, false, samplingMode);
 
             this.name = name;
+            this.debugMode = false;
 
             this.wrapU = Texture.CLAMP_ADDRESSMODE;
             this.wrapV = Texture.CLAMP_ADDRESSMODE;
@@ -396,8 +414,10 @@
             this._sdfScale = 8;
             this._signedDistanceField = signedDistanceField;
             this._superSample = false;
+            this._isPremultipliedAlpha = !signedDistanceField;
+            this.name = `FontTexture ${font}`;
 
-            // SDF will use supersample 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) {
                 let sfont = this.getSuperSampleFont(font);
                 if (sfont) {
@@ -413,19 +433,22 @@
             this._context.fillStyle = "white";
             this._context.textBaseline = "top";
 
-            var res = this.getFontHeight(font);
+            var res = this.getFontHeight(font, "j$|");
             this._lineHeightSuper = res.height; //+4;
             this._lineHeight = this._superSample ? (Math.ceil(this._lineHeightSuper / 2)) : this._lineHeightSuper;
-            this._offset = res.offset - 1;
-            this._xMargin = 1 + Math.ceil(this._lineHeightSuper / 15);    // Right now this empiric formula seems to work...
-            this._yMargin = this._xMargin;
+            this._offset = res.offset;
+            res = this.getFontHeight(font, "f");
+            this._baseLine = res.height + res.offset - this._offset;
 
-            var maxCharWidth = this._context.measureText("W").width;
+            var maxCharWidth = Math.max(this._context.measureText("W").width, this._context.measureText("_").width);
             this._spaceWidthSuper = this._context.measureText(" ").width;
             this._spaceWidth = this._superSample ? (this._spaceWidthSuper / 2) : this._spaceWidthSuper;
 
+            this._xMargin = Math.ceil(maxCharWidth / 32);
+            this._yMargin = this._xMargin;
+
             // This is an approximate size, but should always be able to fit at least the maxCharCount
-            var totalEstSurface = (this._lineHeightSuper + this._yMargin) * (maxCharWidth + this._xMargin) * maxCharCount;
+            var totalEstSurface = (Math.ceil(this._lineHeightSuper) + (this._yMargin*2)) * (Math.ceil(maxCharWidth) + (this._xMargin*2)) * maxCharCount;
             var edge = Math.sqrt(totalEstSurface);
             var textSize = Math.pow(2, Math.ceil(Math.log(edge) / Math.log(2)));
 
@@ -447,13 +470,13 @@
             this._context.clearRect(0, 0, textureSize.width, textureSize.height);
 
             // Create a canvas for the signed distance field mode, we only have to store one char, the purpose is to render a char scaled _sdfScale times
-            //  into this 2D context, then get the bitmap data, create the sdf char and push the result in the _context (which hold the whole Font Texture content)
+            //  into this 2D context, then get the bitmap data, create the SDF char and push the result in the _context (which hold the whole Font Texture content)
             // So you can see this context as an intermediate one, because it is.
             if (this._signedDistanceField) {
                 let sdfC = document.createElement("canvas");
                 let s = this._sdfScale;
-                sdfC.width = maxCharWidth * s;
-                sdfC.height = this._lineHeightSuper * s;
+                sdfC.width = (Math.ceil(maxCharWidth) + this._xMargin * 2) * s;
+                sdfC.height = (Math.ceil(this._lineHeightSuper) + this._yMargin * 2) * s;
                 let sdfCtx = sdfC.getContext("2d");
                 sdfCtx.scale(s, s);
                 sdfCtx.textBaseline = "top";
@@ -467,13 +490,50 @@
 
             this._currentFreePosition = Vector2.Zero();
 
-            // Add the basic ASCII based characters
+            // Add the basic ASCII based characters                                                               
             for (let i = 0x20; i < 0x7F; i++) {
                 var c = String.fromCharCode(i);
                 this.getChar(c);
             }
 
             this.update();
+
+            //this._saveToImage("");
+            
+        }
+
+        private _saveToImage(url: string) {
+            let base64Image = this._canvas.toDataURL("image/png");
+
+            //Creating a link if the browser have the download attribute on the a tag, to automatically start download generated image.
+            if (("download" in document.createElement("a"))) {
+                var a = window.document.createElement("a");
+                a.href = base64Image;
+                var date = new Date();
+                var stringDate = (date.getFullYear() + "-" + (date.getMonth() + 1)).slice(-2) +
+                    "-" +
+                    date.getDate() +
+                    "_" +
+                    date.getHours() +
+                    "-" +
+                    ('0' + date.getMinutes()).slice(-2);
+                a.setAttribute("download", "screenshot_" + stringDate + ".png");
+
+                window.document.body.appendChild(a);
+
+                a.addEventListener("click",
+                    () => {
+                        a.parentElement.removeChild(a);
+                    });
+                a.click();
+
+                //Or opening a new tab with the image if it is not possible to automatically start download.
+            } else {
+                var newWindow = window.open("");
+                var img = newWindow.document.createElement("img");
+                img.src = base64Image;
+                newWindow.document.body.appendChild(img);
+            }
         }
 
         /**
@@ -497,10 +557,10 @@
             var textureSize = this.getSize();
 
             // we reached the end of the current line?
-            let width = Math.round(measure.width);
+            let width = Math.ceil(measure.width + 0.5);
             if (this._currentFreePosition.x + width + this._xMargin > textureSize.width) {
                 this._currentFreePosition.x = 0;
-                this._currentFreePosition.y += this._lineHeightSuper + this._yMargin;
+                this._currentFreePosition.y += Math.ceil(this._lineHeightSuper + this._yMargin*2);
 
                 // No more room?
                 if (this._currentFreePosition.y > textureSize.height) {
@@ -508,22 +568,69 @@
                 }
             }
 
-            // In sdf mode we render the character in an intermediate 2D context which scale the character this._sdfScale times (which is required to compute the sdf map accurately)
+            let curPosX = this._currentFreePosition.x + 0.5;
+            let curPosY = this._currentFreePosition.y + 0.5;
+            let curPosXMargin = curPosX + this._xMargin;
+            let curPosYMargin = curPosY + this._yMargin;
+
+            let drawDebug = (ctx: CanvasRenderingContext2D) => {
+                ctx.strokeStyle = "green";
+                ctx.beginPath();
+                ctx.rect(curPosXMargin, curPosYMargin, width, this._lineHeightSuper);
+                ctx.closePath();
+                ctx.stroke();
+
+                ctx.strokeStyle = "blue";
+                ctx.beginPath();
+                ctx.moveTo(curPosXMargin, curPosYMargin + Math.round(this._baseLine));
+                ctx.lineTo(curPosXMargin + width, curPosYMargin + Math.round(this._baseLine));
+                ctx.closePath();
+                ctx.stroke();
+            }
+
+            // In SDF mode we render the character in an intermediate 2D context which scale the character this._sdfScale times (which is required to compute the SDF map accurately)
             if (this._signedDistanceField) {
+                let s = this._sdfScale;
                 this._sdfContext.clearRect(0, 0, this._sdfCanvas.width, this._sdfCanvas.height);
-                this._sdfContext.fillText(char, 0, -this._offset);
-                let data = this._sdfContext.getImageData(0, 0, width*this._sdfScale, this._sdfCanvas.height);
 
+                // Coordinates are subject to the context's scale
+                this._sdfContext.fillText(char, this._xMargin + 0.5, this._yMargin + 0.5 - this._offset);
+
+                // Canvas Pixel Coordinates, no scale
+                let data = this._sdfContext.getImageData(0, 0, (width + (this._xMargin * 2)) * s, this._sdfCanvas.height);
                 let res = this._computeSDFChar(data);
-                this._context.putImageData(res, this._currentFreePosition.x, this._currentFreePosition.y);
+                this._context.putImageData(res, curPosX, curPosY);
+                if (this.debugMode) {
+                    drawDebug(this._context);
+                }
             } else {
+                if (this.debugMode) {
+                    drawDebug(this._context);
+                }
+
                 // Draw the character in the HTML canvas
-                this._context.fillText(char, this._currentFreePosition.x, this._currentFreePosition.y - this._offset);
+                this._context.fillText(char, curPosXMargin, curPosYMargin - this._offset);
+
+                // Premul Alpha manually
+                let id = this._context.getImageData(curPosXMargin, curPosYMargin, width, this._lineHeightSuper);
+                for (let i = 0; i < id.data.length; i += 4) {
+                    let v = id.data[i + 3];
+                    if (v > 0 && v < 255) {
+                        id.data[i + 0] = v;
+                        id.data[i + 1] = v;
+                        id.data[i + 2] = v;
+                        id.data[i + 3] = v;
+                    }
+
+                }
+                this._context.putImageData(id, curPosXMargin, curPosYMargin);
             }
 
             // Fill the CharInfo object
-            info.topLeftUV = new Vector2(this._currentFreePosition.x / textureSize.width, this._currentFreePosition.y / textureSize.height);
-            info.bottomRightUV = new Vector2((this._currentFreePosition.x + width) / textureSize.width, info.topLeftUV.y + ((this._lineHeightSuper + 2) / textureSize.height));
+            info.topLeftUV = new Vector2((curPosXMargin-0.5) / textureSize.width, (this._currentFreePosition.y-0.5 + this._yMargin) / textureSize.height);
+            info.bottomRightUV = new Vector2((curPosXMargin-0.5 + width) / textureSize.width, info.topLeftUV.y + (this._lineHeightSuper / textureSize.height));
+            info.yOffset = info.xOffset = 0;
+            //console.log(`Char: ${char}, Offset: ${curPosX}, ${this._currentFreePosition.y + this._yMargin}, Size: ${width}, ${this._lineHeightSuper}, UV: ${info.topLeftUV}, ${info.bottomRightUV}`);
 
             if (this._signedDistanceField) {
                 let off = 1/textureSize.width;
@@ -532,13 +639,14 @@
             }
 
             info.charWidth = this._superSample ? (width/2) : width;
+            info.xAdvance = info.charWidth;
 
             // Add the info structure
             this._charInfos.add(char, info);
             this._curCharCount++;
 
             // Set the next position
-            this._currentFreePosition.x += width + this._xMargin;
+            this._currentFreePosition.x += Math.ceil(width + this._xMargin*2);
 
             return info;
         }
@@ -710,7 +818,7 @@
         }
 
         // More info here: https://videlais.com/2014/03/16/the-many-and-varied-problems-with-measuring-font-height-for-html5-canvas/
-        private getFontHeight(font: string): {height: number, offset: number} {
+        private getFontHeight(font: string, chars: string): {height: number, offset: number} {
             var fontDraw = document.createElement("canvas");
             fontDraw.width = 600;
             fontDraw.height = 600;
@@ -719,14 +827,16 @@
             ctx.textBaseline = 'top';
             ctx.fillStyle = 'white';
             ctx.font = font;
-            ctx.fillText('jH|', 0, 0);
+            ctx.fillText(chars, 0, 0);
             var pixels = ctx.getImageData(0, 0, fontDraw.width, fontDraw.height).data;
+
             var start = -1;
             var end = -1;
             for (var row = 0; row < fontDraw.height; row++) {
                 for (var column = 0; column < fontDraw.width; column++) {
                     var index = (row * fontDraw.width + column) * 4;
-                    if (pixels[index] === 0) {
+                    let pix = pixels[index];
+                    if (pix === 0) {
                         if (column === fontDraw.width - 1 && start !== -1) {
                             end = row;
                             row = fontDraw.height;
@@ -742,7 +852,7 @@
                     }
                 }
             }
-            return { height: (end - start)+1, offset: start-1}
+            return { height: (end - start)+1, offset: start}
         }
 
         public get canRescale(): boolean {
@@ -827,13 +937,15 @@
             return obj;
         }
 
-        private _buildCharInfo(initialLine: string, obj: any, textureSize: Size, invertY: boolean, chars: StringDictionary<CharInfo>) {
+        private _buildCharInfo(bfi: BitmapFontInfo, initialLine: string, obj: any, textureSize: Size, invertY: boolean, chars: StringDictionary<CharInfo>) {
             let char: string = null;
             let x: number = null;
             let y: number = null;
-            let xadv: number = null;
             let width: number = null;
             let height: number = null;
+            let xoffset = 0;
+            let yoffset = 0;
+            let xadvance = 0;
             let ci = new CharInfo();
             for (let key in obj) {
                 let value = obj[key];
@@ -854,15 +966,22 @@
                         height = value;
                         break;
                     case "xadvance":
-                        xadv = value;
+                        xadvance = value;
+                        break;
+                    case "xoffset":
+                        xoffset = value;
+                        break;
+                    case "yoffset":
+                        yoffset = value;
                         break;
                 }
             }
 
             if (x != null && y != null && width != null && height != null && char != null) {
-                if (xadv) {
-                    width = xadv;
-                }
+                ci.xAdvance = xadvance;
+                ci.xOffset = xoffset;
+                ci.yOffset = bfi.lineHeight -height - yoffset;
+
                 if (invertY) {
                     ci.topLeftUV = new Vector2(1 - (x / textureSize.width), 1 - (y / textureSize.height));
                     ci.bottomRightUV = new Vector2(1 - ((x + width) / textureSize.width), 1 - ((y + height) / textureSize.height));
@@ -895,6 +1014,7 @@
             //common
             var commonObj = this._parseStrToObj(fontStr.match(BMFontLoaderTxt.COMMON_EXP)[0]);
             bfi.lineHeight = commonObj["lineHeight"];
+            bfi.baseLine = commonObj["base"];
             bfi.textureSize = new Size(commonObj["scaleW"], commonObj["scaleH"]);
 
             var maxTextureSize = scene.getEngine()._gl.getParameter(0xd33);
@@ -918,7 +1038,7 @@
                         let charLines = fontStr.match(BMFontLoaderTxt.CHAR_EXP);
                         for (let i = 0, li = charLines.length; i < li; i++) {
                             let charObj = this._parseStrToObj(charLines[i]);
-                            this._buildCharInfo(charLines[i], charObj, bfi.textureSize, invertY, bfi.charDic);
+                            this._buildCharInfo(bfi, charLines[i], charObj, bfi.textureSize, invertY, bfi.charDic);
                         }
 
                         //kerning

+ 46 - 66
canvas2D/src/Engine/babylon.group2d.ts

@@ -53,7 +53,7 @@
          * - layoutEngine: either an instance of a layout engine based class (StackPanel.Vertical, StackPanel.Horizontal) or a string ('canvas' for Canvas layout, 'StackPanel' or 'HorizontalStackPanel' for horizontal Stack Panel layout, 'VerticalStackPanel' for vertical Stack Panel layout).
          * - isVisible: true if the group must be visible, false for hidden. Default is true.
          * - isPickable: if true the Primitive can be used with interaction mode and will issue Pointer Event. If false it will be ignored for interaction/intersection test. Default value is true.
-         * - isContainer: if true the Primitive acts as a container for interaction, if the primitive is not pickable or doesn't intersection, no further test will be perform on its children. If set to false, children will always be considered for intersection/interaction. Default value is true.
+         * - isContainer: if true the Primitive acts as a container for interaction, if the primitive is not pickable or doesn't intersect, no further test will be perform on its children. If set to false, children will always be considered for intersection/interaction. Default value is true.
          * - childrenFlatZOrder: if true all the children (direct and indirect) will share the same Z-Order. Use this when there's a lot of children which don't overlap. The drawing order IS NOT GUARANTED!
          * - levelCollision: this primitive is an actor of the Collision Manager and only this level will be used for collision (i.e. not the children). Use deepCollision if you want collision detection on the primitives and its children.
          * - deepCollision: this primitive is an actor of the Collision Manager, this level AND ALSO its children will be used for collision (note: you don't need to set the children as level/deepCollision).
@@ -87,7 +87,7 @@
             trackNode               ?: Node,
             trackNodeOffset         ?: Vector3,
             opacity                 ?: number,
-            zOrder                  ?: number, 
+            zOrder                  ?: number,
             origin                  ?: Vector2,
             size                    ?: Size,
             width                   ?: number,
@@ -113,7 +113,7 @@
             paddingLeft             ?: number | string,
             paddingRight            ?: number | string,
             paddingBottom           ?: number | string,
-            padding                 ?: string,
+            padding                 ?: number | string,
 
         }) {
             if (settings == null) {
@@ -126,16 +126,18 @@
 
             let size = (!settings.size && !settings.width && !settings.height) ? null : (settings.size || (new Size(settings.width || 0, settings.height || 0)));
 
-            this._trackedNode = (settings.trackNode == null) ? null : settings.trackNode;
-            this._trackedNodeOffset = (settings.trackNodeOffset == null) ? null : settings.trackNodeOffset;
-            if (this._trackedNode && this.owner) {
-                this.owner._registerTrackedNode(this);
+            if (!(this instanceof WorldSpaceCanvas2D)) {
+                this._trackedNode = (settings.trackNode == null) ? null : settings.trackNode;
+                this._trackedNodeOffset = (settings.trackNodeOffset == null) ? null : settings.trackNodeOffset;
+                if (this._trackedNode && this.owner) {
+                    this.owner._registerTrackedNode(this);
+                }
             }
 
             this._cacheBehavior = (settings.cacheBehavior == null) ? Group2D.GROUPCACHEBEHAVIOR_FOLLOWCACHESTRATEGY : settings.cacheBehavior;
             let rd = this._renderableData;
             if (rd) {
-                rd._noResizeOnScale = (this.cacheBehavior & Group2D.GROUPCACHEBEHAVIOR_NORESIZEONSCALE) !== 0;                
+                rd._noResizeOnScale = (this.cacheBehavior & Group2D.GROUPCACHEBEHAVIOR_NORESIZEONSCALE) !== 0;
             }
             this.size = size;
             this._viewportPosition = Vector2.Zero();
@@ -249,7 +251,7 @@
 
         @instanceLevelProperty(Prim2DBase.PRIM2DBASE_PROPCOUNT + 1, pi => Group2D.sizeProperty = pi, false, true)
         public get size(): Size {
-            return this._size;
+            return this.internalGetSize();
         }
 
         /**
@@ -264,49 +266,6 @@
             return this._viewportSize;
         }
 
-        @instanceLevelProperty(Prim2DBase.PRIM2DBASE_PROPCOUNT + 2, pi => Group2D.actualSizeProperty = pi)
-        /**
-         * Get the actual size of the group, if the size property is not null, this value will be the same, but if size is null, actualSize will return the size computed from the group's bounding content.
-         */
-        public get actualSize(): Size {
-            // The computed size will be floor on both width and height
-            let actualSize: Size;
-
-            // Return the actualSize if set
-            if (this._actualSize) {
-                return this._actualSize;
-            }
-
-            // Return the size if set by the user
-            if (this._size) {
-                actualSize = new Size(Math.ceil(this._size.width), Math.ceil(this._size.height));
-            }
-
-            // Otherwise the size is computed based on the boundingInfo of the layout (or bounding info) content
-            else {
-                let m = this.layoutBoundingInfo.max();
-                actualSize = new Size(Math.ceil(m.x), Math.ceil(m.y));
-            }
-
-            // Compare the size with the one we previously had, if it differs we set the property dirty and trigger a GroupChanged to synchronize a displaySprite (if any)
-            if (!actualSize.equals(this._actualSize)) {
-                this.onPrimitivePropertyDirty(Group2D.actualSizeProperty.flagId);
-                this._actualSize = actualSize;
-                this.handleGroupChanged(Group2D.actualSizeProperty);
-            }
-
-            return actualSize;
-        }
-
-        public set actualSize(value: Size) {
-            if (!this._actualSize) {
-                this._actualSize = value.clone();
-            } else {
-                this._actualSize.copyFrom(value);
-            }
-        }
-
-
         /**
          * Get/set the Cache Behavior, used in case the Canvas Cache Strategy is set to CACHESTRATEGY_ALLGROUPS. Can be either GROUPCACHEBEHAVIOR_CACHEINPARENTGROUP, GROUPCACHEBEHAVIOR_DONTCACHEOVERRIDE or GROUPCACHEBEHAVIOR_FOLLOWCACHESTRATEGY. See their documentation for more information.
          * GROUPCACHEBEHAVIOR_NORESIZEONSCALE can also be set if you set it at creation time.
@@ -398,8 +357,12 @@
 
             let s = this.actualSize;
             let a = this.actualScale;
-            let sw = Math.ceil(s.width * a.x);
-            let sh = Math.ceil(s.height * a.y);
+            let ss = this.owner._canvasLevelScale;
+            let hwsl = 1/this.owner.engine.getHardwareScalingLevel();
+            //let sw = Math.ceil(s.width * a.x * ss.x/* * hwsl*/);
+            //let sh = Math.ceil(s.height * a.y *ss.y/* *  hwsl*/);
+            let sw = s.width * a.x * ss.x;
+            let sh = s.height * a.y *ss.y;
 
             // The dimension must be overridden when using the designSize feature, the ratio is maintain to compute a uniform scale, which is mandatory but if the designSize's ratio is different from the rendering surface's ratio, content will be clipped in some cases.
             // So we set the width/height to the rendering's one because that's what we want for the viewport!
@@ -413,7 +376,7 @@
             if (!this._isCachedGroup) {
                 // Compute the WebGL viewport's location/size
                 let t = this._globalTransform.getTranslation();
-                let rs = this.owner._renderingSize;
+                let rs = this.owner._renderingSize.multiplyByFloats(hwsl, hwsl);
                 sh = Math.min(sh, rs.height - t.y);
                 sw = Math.min(sw, rs.width - t.x);
                 let x = t.x;
@@ -440,7 +403,9 @@
                 // If it's a force refresh, prepare all the children
                 if (context.forceRefreshPrimitive) {
                     for (let p of this._children) {
-                        p._prepareRender(context);
+                        if (!p.isDisposed) {
+                            p._prepareRender(context);
+                        }
                     }
                 } else {
                     // Each primitive that changed at least once was added into the primDirtyList, we have to sort this level using
@@ -841,6 +806,8 @@
 
         private static _uV = new Vector2(1, 1);
         private static _s = Size.Zero();
+        private static _v1 = Vector2.Zero();
+        private static _s2 = Size.Zero();
         private _bindCacheTarget() {
             let curWidth: number;
             let curHeight: number;
@@ -851,11 +818,11 @@
             let isCanvas = this.parent == null;
             let scale: Vector2;
             if (noResizeScale) {
-                scale = isCanvas ? Group2D._uV: this.parent.actualScale;
+                scale = isCanvas ? Group2D._uV: this.parent.actualScale.multiply(this.owner._canvasLevelScale);
             } else {
-                scale = this.actualScale;
+                scale = this.actualScale.multiply(this.owner._canvasLevelScale);
             }
-
+            let actualSize = this.actualSize;
             if (isCanvas && this.owner.cachingStrategy===Canvas2D.CACHESTRATEGY_CANVAS && this.owner.isScreenSpace) {
                 if(this.owner.designSize || this.owner.fitRenderingDevice){
                     Group2D._s.width = this.owner.engine.getRenderWidth();
@@ -865,21 +832,22 @@
                     Group2D._s.copyFrom(this.owner.size);
                 }
             } else {
-                Group2D._s.width = Math.ceil(this.actualSize.width * scale.x * rs);
-                Group2D._s.height = Math.ceil(this.actualSize.height * scale.y * rs);
+                Group2D._s.width  = Math.ceil(actualSize.width  * scale.x * rs);
+                Group2D._s.height = Math.ceil(actualSize.height * scale.y * rs);
             }
 
             let sizeChanged = !Group2D._s.equals(rd._cacheSize);
 
             if (rd._cacheNode) {
-                let size = rd._cacheNode.contentSize;
+                let size = Group2D._s;
+                rd._cacheNode.getInnerSizeToRef(size);
 
                 // Check if we have to deallocate because the size is too small
                 if ((size.width < Group2D._s.width) || (size.height < Group2D._s.height)) {
                     // For Screen space: over-provisioning of 7% more to avoid frequent resizing for few pixels...
                     // 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);
                     //console.log(`[${this._globalTransformProcessStep}] Resize group ${this.id}, width: ${curWidth}, height: ${curHeight}`);
                     rd._cacheTexture.freeRect(rd._cacheNode);
@@ -897,6 +865,12 @@
                 }
                 rd._cacheRenderSprite = res.sprite;
                 sizeChanged = true;
+            } else if (sizeChanged) {
+                let sprite = rd._cacheRenderSprite;
+                if (sprite) {
+                    sprite.size = actualSize;
+                    sprite.spriteSize = new Size(actualSize.width * scale.x * rs, actualSize.height * scale.y * rs);
+                }
             }
 
             if (sizeChanged) {
@@ -909,8 +883,9 @@
                 this._setFlags(SmartPropertyPrim.flagWorldCacheChanged);
             }
 
-            let n = rd._cacheNode;
-            rd._cacheTexture.bindTextureForPosSize(n.pos, Group2D._s, true);
+            let pos = Group2D._v1;
+            rd._cacheNode.getInnerPosToRef(pos);
+            rd._cacheTexture.bindTextureForPosSize(pos, Group2D._s, true);
         }
 
         private _unbindCacheTarget() {
@@ -962,6 +937,11 @@
                 case Group2D.actualSizeProperty.id:
                     cachedSprite.size = this.actualSize.clone();
                     break;
+                case Group2D.xProperty.id:
+                    cachedSprite.x = this.x;
+                    break;
+                case Group2D.yProperty.id:
+                    cachedSprite.y = this.y;
             }
         }
 

+ 18 - 13
canvas2D/src/Engine/babylon.lines2d.ts

@@ -315,9 +315,6 @@
         }
 
         protected updateLevelBoundingInfo(): boolean {
-            if (!this._size) {
-                return false;
-            }
             if (!this._boundingMin) {
                 this._computeLines2D();
             }
@@ -336,6 +333,7 @@
          * - 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
          * - 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.
          * - zOrder: override the zOrder with the specified value
          * - origin: define the normalized origin point location, default [0.5;0.5]
@@ -380,6 +378,7 @@
             scaleX                ?: number,
             scaleY                ?: number,
             dontInheritParentScale?: boolean,
+            alignToPixel          ?: boolean,
             opacity               ?: number,
             zOrder                ?: number, 
             origin                ?: Vector2,
@@ -409,7 +408,7 @@
             paddingLeft           ?: number | string,
             paddingRight          ?: number | string,
             paddingBottom         ?: number | string,
-            padding               ?: string,
+            padding               ?: number | string,
         }) {
 
             if (!settings) {
@@ -423,8 +422,6 @@
             this._borderVB = null;
             this._borderIB = null;
 
-            this._size = Size.Zero();
-
             this._boundingMin = null;
             this._boundingMax = null;
 
@@ -1152,12 +1149,12 @@
                 let pta = this._primTriArray;
                 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;
                 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._curA,  Lines2D._prevB, Lines2D._curB);
@@ -1173,15 +1170,15 @@
                     for (let i = 0; i < l; i += 3) {
                         Lines2D._curA.x = points[tri[i + 0] * 2 + 0];
                         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.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.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);
                     }
@@ -1200,8 +1197,16 @@
             }
 
             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.height = bs.y;
+            this._actualSize = null;
         }
 
         public get size(): Size {

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

@@ -1,11 +1,12 @@
 module BABYLON {
     export const enum ShaderDataType {
-        Vector2, Vector3, Vector4, Matrix, float, Color3, Color4, Size
+        Vector2, Vector3, Vector4, float, Color3, Color4, Size
     }
 
     export class GroupInstanceInfo {
         constructor(owner: Group2D, mrc: ModelRenderCache, partCount: number) {
             this._partCount = partCount;
+            this._primCount = 0;
             this.owner = owner;
             this.modelRenderCache = mrc;
             this.modelRenderCache.addRef();
@@ -18,11 +19,26 @@
             this.opaqueDirty = this.alphaTestDirty = this.transparentDirty = this.transparentOrderDirty = false;
         }
 
+        public incPrimCount() {
+            ++this._primCount;
+        }
+
         public dispose(): boolean {
             if (this._isDisposed) {
                 return false;
             }
 
+            // Disposed is called when a primitive instance is disposed, so we decrement the counter
+            --this._primCount;
+
+            // If the counter is still greater than 0 there's still other primitives using this GII
+            if (this._primCount > 0) {
+                return false;
+            }
+
+            // We're going to dispose this GII, first remove it from the dictionary
+            this.owner._renderableData._renderGroupInstancesInfo.remove(this.modelRenderCache.modelKey);
+
             if (this.modelRenderCache) {
                 this.modelRenderCache.dispose();
                 this.modelRenderCache = null;
@@ -50,6 +66,10 @@
             return true;
         }
 
+        public get isDisposed(): boolean {
+            return this._isDisposed;
+        }
+
         private _isDisposed: boolean;
         owner: Group2D;
 
@@ -126,6 +146,7 @@
         }
 
         private _partCount: number;
+        private _primCount: number;
         private _strides: number[];
         private _usedShaderCategories: string[];
         private _opaqueData: GroupInfoPartData[];

A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 986 - 399
canvas2D/src/Engine/babylon.prim2dBase.ts


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

@@ -640,7 +640,7 @@
             });
 
             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 {
                 this._AABBRenderPrim.wireFrameGroups.set("main", g);
                 this._AABBRenderPrim.wireFrameGroupsDirty();

+ 16 - 26
canvas2D/src/Engine/babylon.rectangle2d.ts

@@ -170,25 +170,6 @@
         public static notRoundedProperty: Prim2DPropInfo;
         public static roundRadiusProperty: Prim2DPropInfo;
 
-        @instanceLevelProperty(Shape2D.SHAPE2D_PROPCOUNT + 1, pi => Rectangle2D.actualSizeProperty = pi, false, true)
-        /**
-         * Get/set the rectangle size (width/height)
-         */
-        public get actualSize(): Size {
-            if (this._actualSize) {
-                return this._actualSize;
-            }
-            return this.size;
-        }
-
-        public set actualSize(value: Size) {
-            if (!this._actualSize) {
-                this._actualSize = value.clone();
-            } else {
-                this._actualSize.copyFrom(value);
-            }
-        }
-
         @modelLevelProperty(Shape2D.SHAPE2D_PROPCOUNT + 2, pi => Rectangle2D.notRoundedProperty = pi)
         /**
          * Get if the rectangle is notRound (returns true) or rounded (returns false).
@@ -307,6 +288,7 @@
          * - 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
          * - 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.
          * - zOrder: override the zOrder with the specified value
          * - origin: define the normalized origin point location, default [0.5;0.5]
@@ -348,6 +330,7 @@
             scaleX                ?: number,
             scaleY                ?: number,
             dontInheritParentScale?: boolean,
+            alignToPixel          ?: boolean,
             opacity               ?: number,
             zOrder                ?: number, 
             origin                ?: Vector2,
@@ -377,7 +360,7 @@
             paddingLeft           ?: number | string,
             paddingRight          ?: number | string,
             paddingBottom         ?: number | string,
-            padding               ?: string,
+            padding               ?: number | string,
         }) {
 
             // Avoid checking every time if the object exists
@@ -577,15 +560,19 @@
             }
         }
 
-        protected _getActualSizeFromContentToRef(primSize: Size, newPrimSize: Size) {
+        protected _getActualSizeFromContentToRef(primSize: Size, paddingOffset: Vector4, newPrimSize: Size) {
             // Fall back to default implementation if there's no round Radius
             if (this._notRounded) {
-                super._getActualSizeFromContentToRef(primSize, newPrimSize);
+                super._getActualSizeFromContentToRef(primSize, paddingOffset, newPrimSize);
             } else {
                 let rr = Math.round((this.roundRadius - (this.roundRadius / Math.sqrt(2))) * 1.3);
                 newPrimSize.copyFrom(primSize);
                 newPrimSize.width  += rr * 2;
                 newPrimSize.height += rr * 2;
+                paddingOffset.x += rr;
+                paddingOffset.y += rr;
+                paddingOffset.z += rr;
+                paddingOffset.w += rr;
             }
         }
 
@@ -600,21 +587,24 @@
             return res;
         }
 
+        private static _riv0 = new Vector2(0,0);
         protected refreshInstanceDataPart(part: InstanceDataBase): boolean {
             if (!super.refreshInstanceDataPart(part)) {
                 return false;
             }
+
+            //let s = Rectangle2D._riv0;
+            //this.getActualGlobalScaleToRef(s);
+
             if (part.id === Shape2D.SHAPE2D_BORDERPARTID) {
                 let d = <Rectangle2DInstanceData>part;
                 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) {
                 let d = <Rectangle2DInstanceData>part;
                 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;
         }

+ 70 - 69
canvas2D/src/Engine/babylon.renderablePrim2d.ts

@@ -80,15 +80,24 @@
         attributeName: string;
         category: string;
         size: number;
-        shaderOffset: number;
         instanceOffset: StringDictionary<number>;
         dataType: ShaderDataType;
+
+        curCategory: string;
+        curCategoryOffset: number;
+
         //uniformLocation: WebGLUniformLocation;
 
         delimitedCategory: string;
 
         constructor() {
+            this.attributeName = null;
+            this.category = null;
+            this.size = null;
             this.instanceOffset = new StringDictionary<number>();
+            this.dataType = 0;
+            this.curCategory = "";
+            this.curCategoryOffset = 0;
         }
 
         setSize(val) {
@@ -107,8 +116,8 @@
                 this.dataType = ShaderDataType.Vector4;
                 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") {
                 this.size = 4;
@@ -181,14 +190,6 @@
                         array[offset] = v;
                         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:
                     {
                         let s = <Size>val;
@@ -233,16 +234,25 @@
                 if (info.category && InstanceClassInfo._CurCategories.indexOf(info.delimitedCategory) === -1) {
                     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;
                 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);
                 }
             }
@@ -284,6 +294,15 @@
         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()
         get opacity(): number {
             return null;
@@ -430,29 +449,21 @@
             for (let part of this._instanceDataParts) {
                 part.freeElements();
                 gii = part.groupInstanceInfo;
+                part.groupInstanceInfo = null;
             }
+
             if (gii) {
-                let usedCount = 0;
                 if (gii.hasOpaqueData) {
-                    let od = gii.opaqueData[0];
-                    usedCount += od._partData.usedElementCount;
                     gii.opaqueDirty = true;
                 }
                 if (gii.hasAlphaTestData) {
-                    let atd = gii.alphaTestData[0];
-                    usedCount += atd._partData.usedElementCount;
                     gii.alphaTestDirty = true;
                 }
                 if (gii.hasTransparentData) {
-                    let td = gii.transparentData[0];
-                    usedCount += td._partData.usedElementCount;
                     gii.transparentDirty = true;
                 }
 
-                if (usedCount === 0 && gii.modelRenderCache!=null) {
-                    this.renderGroup._renderableData._renderGroupInstancesInfo.remove(gii.modelRenderCache.modelKey);
-                    gii.dispose();
-                }
+                gii.dispose();
 
                 if (this._modelRenderCache) {
                     this._modelRenderCache.dispose();
@@ -460,6 +471,7 @@
                 }
 
             }
+
             this._instanceDataParts = null;
         }
 
@@ -577,6 +589,9 @@
                 part.groupInstanceInfo = gii;
             }
 
+            // Increment the primitive count as one more primitive is using this GroupInstanceInfo
+            gii.incPrimCount();
+
             return gii;
         }
 
@@ -660,6 +675,9 @@
             if (!gii) {
                 gii = rd._renderGroupInstancesInfo.get(this.modelKey);
             }
+            if (gii.isDisposed) {
+                return;
+            }
 
             let isTransparent = this.isTransparent;
             let isAlphaTest = this.isAlphaTest;
@@ -824,23 +842,7 @@
             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
@@ -928,10 +930,11 @@
         }
 
         private static _uV = new Vector2(1, 1);
-        private static _s = Vector3.Zero();
+        private static _s = Vector2.Zero();
         private static _r = Quaternion.Identity();
-        private static _t = Vector3.Zero();
-        private static _uV3 = new Vector3(1, 1, 1);
+        private static _t = Vector2.Zero();
+        private static _iV2 = new Vector2(1, 1); // Must stay identity vector3
+
         /**
          * Update the instanceDataBase level properties of a part
          * @param part the part to update
@@ -939,16 +942,29 @@
          */
         protected updateInstanceDataPart(part: InstanceDataBase, positionOffset: Vector2 = null) {
             let t = this._globalTransform.multiply(this.renderGroup.invGlobalTransform);    // Compute the transformation into the renderGroup's space
-            let rgScale = this._areSomeFlagsSet(SmartPropertyPrim.flagDontInheritParentScale) ? RenderablePrim2D._uV : this.renderGroup.actualScale;         // We still need to apply the scale of the renderGroup to our rendering, so get it.
+            let scl = RenderablePrim2D._s;
+            let trn = RenderablePrim2D._t;
+            let rot = t.decompose(scl, trn);
+            let pas = this.actualScale;
+            //let cachedGroup = (this.getExternalData<Group2D>("__cachedGroup__") !== null);
+            let canvasScale = /*cachedGroup ? RenderablePrim2D._iV2 :  */this.owner._canvasLevelScale;
+            scl.x = pas.x * canvasScale.x * this._postScale.x;
+            scl.y = pas.y * canvasScale.y * this._postScale.y;
+            trn.multiplyInPlace(canvasScale);
+            t = Matrix2D.Compose(this.applyActualScaleOnTransform() ? scl : RenderablePrim2D._iV2, rot, trn);
+
+            //console.log(`Update Instance Data Part: ${this.id}`);
+
             let size = (<Size>this.renderGroup.viewportSize);
             let zBias = this.actualZOffset;
 
             let offX = 0;
             let offY = 0;
+
             // If there's an offset, apply the global transformation matrix on it to get a global offset
             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
@@ -960,26 +976,11 @@
             let w = size.width;
             let h = size.height;
             let invZBias = 1 / zBias;
-            let tx = new Vector4(t.m[0] * rgScale.x * 2/* / w*/, t.m[4] * rgScale.x * 2/* / w*/, 0/*t.m[8]*/, ((t.m[12] + offX) * rgScale.x * 2 / w) - 1);
-            let ty = new Vector4(t.m[1] * rgScale.y * 2/* / h*/, t.m[5] * rgScale.y * 2/* / h*/, 0/*t.m[9]*/, ((t.m[13] + offY) * rgScale.y * 2 / h) - 1);
-
-            if (!this.applyActualScaleOnTransform()) {
-                t.m[0] = tx.x, t.m[4] = tx.y, t.m[12] = tx.w;
-                t.m[1] = ty.x, t.m[5] = ty.y, t.m[13] = ty.w;
-                let las = this.actualScale;
-                t.decompose(RenderablePrim2D._s, RenderablePrim2D._r, RenderablePrim2D._t);
-                let scale = new Vector3(RenderablePrim2D._s.x / las.x, RenderablePrim2D._s.y / las.y, 1);
-                t = Matrix.Compose(scale, RenderablePrim2D._r, RenderablePrim2D._t);
-                tx = new Vector4(t.m[0], t.m[4], 0, t.m[12]);
-                ty = new Vector4(t.m[1], t.m[5], 0, t.m[13]);
-            }
-
-            tx.x /= w;
-            tx.y /= w;
 
-            ty.x /= h;
-            ty.y /= h;
+            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.transformY = ty;
             part.opacity = this.actualOpacity;

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

@@ -126,9 +126,9 @@
             return cat;
         }
 
-        protected applyActualScaleOnTransform(): boolean {
-            return false;
-        }
+        //protected applyActualScaleOnTransform(): boolean {
+        //    return false;
+        //}
 
         protected refreshInstanceDataPart(part: InstanceDataBase): boolean {
             if (!super.refreshInstanceDataPart(part)) {
@@ -146,9 +146,9 @@
                     } else if (fill instanceof GradientColorBrush2D) {
                         d.fillGradientColor1 = fill.color1;
                         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;
                     }
                 }
@@ -166,9 +166,9 @@
                     } else if (border instanceof GradientColorBrush2D) {
                         d.borderGradientColor1 = border.color1;
                         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;
                     }
                 }

+ 44 - 3
canvas2D/src/Engine/babylon.smartPropertyPrim.ts

@@ -675,6 +675,7 @@
             } 
         }
 
+        @logProp()
         protected _triggerPropertyChanged(propInfo: Prim2DPropInfo, newValue: any) {
             if (this.isDisposed) {
                 return;
@@ -1103,16 +1104,18 @@
         }
 
         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
             if (this instanceof Prim2DBase) {
                 let curprim: Prim2DBase = (<any>this);
                 while (curprim) {
-                    curprim._setFlags(SmartPropertyPrim.flagBoundingInfoDirty);
+                    curprim._setFlags(SmartPropertyPrim.flagBoundingInfoDirty|SmartPropertyPrim.flagLayoutBoundingInfoDirty);
                     if (curprim.isSizeAuto) {
                         curprim.onPrimitivePropertyDirty(Prim2DBase.sizeProperty.flagId);
-                        curprim._setFlags(SmartPropertyPrim.flagPositioningDirty);
+                        if (curprim._isFlagSet(SmartPropertyPrim.flagUsePositioning)) {
+                            curprim._setFlags(SmartPropertyPrim.flagPositioningDirty);
+                        }
                     }
 
                     if (curprim instanceof Group2D) {
@@ -1196,6 +1199,7 @@
         /**
          * Retrieve the boundingInfo for this Primitive, computed based on the primitive itself and NOT its children
          */
+        @logProp()
         public get levelBoundingInfo(): BoundingInfo2D {
             if (this._isFlagSet(SmartPropertyPrim.flagLevelBoundingInfoDirty)) {
                 if (this.updateLevelBoundingInfo()) {
@@ -1281,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 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
@@ -1305,6 +1342,10 @@
         public static flagLayoutBoundingInfoDirty = 0x0200000;    // set if the layout bounding info is dirty
         public static flagCollisionActor          = 0x0400000;    // set if the primitive is part of the collision engine
         public static flagModelUpdate             = 0x0800000;    // set if the primitive's model data is to update
+        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 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   _flags              : number;

+ 9 - 38
canvas2D/src/Engine/babylon.sprite2d.ts

@@ -145,24 +145,6 @@
             this._updateSpriteScaleFactor();
         }
 
-        @instanceLevelProperty(RenderablePrim2D.RENDERABLEPRIM2D_PROPCOUNT + 3, pi => Sprite2D.actualSizeProperty = pi, false, true)
-        /**
-         * Get/set the actual size of the sprite to display
-         */
-        public get actualSize(): Size {
-            if (this._actualSize) {
-                return this._actualSize;
-            }
-            return this.size;
-        }
-
-        public set actualSize(value: Size) {
-            if (!this._actualSize) {
-                this._actualSize = value.clone();
-            } else {
-                this._actualSize.copyFrom(value);
-            }
-        }
 
         @instanceLevelProperty(RenderablePrim2D.RENDERABLEPRIM2D_PROPCOUNT + 4, pi => Sprite2D.spriteSizeProperty = pi, false, true)
         /**
@@ -242,17 +224,6 @@
         //    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 {
             BoundingInfo2D.CreateFromSizeToRef(this.size, this._levelBoundingInfo);
             return true;
@@ -291,15 +262,14 @@
          * - 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
          * - 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.
          * - zOrder: override the zOrder with the specified value
          * - 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.
          * - 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
          * - 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.
          * - 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.
@@ -335,6 +305,7 @@
             scaleX                ?: number,
             scaleY                ?: number,
             dontInheritParentScale?: boolean,
+            alignToPixel          ?: boolean,
             opacity               ?: number,
             zOrder                ?: number, 
             origin                ?: Vector2,
@@ -343,7 +314,6 @@
             spriteScaleFactor     ?: Vector2,
             scale9                ?: Vector4,
             invertY               ?: boolean,
-            alignToPixel          ?: boolean,
             isVisible             ?: boolean,
             isPickable            ?: boolean,
             isContainer           ?: boolean,
@@ -363,7 +333,7 @@
             paddingLeft           ?: number | string,
             paddingRight          ?: number | string,
             paddingBottom         ?: number | string,
-            padding               ?: string,
+            padding               ?: number | string,
         }) {
 
             if (!settings) {
@@ -373,14 +343,16 @@
             super(settings);
 
             this.texture = texture;
-            this.texture.wrapU = Texture.CLAMP_ADDRESSMODE;
-            this.texture.wrapV = Texture.CLAMP_ADDRESSMODE;
+            // This is removed to let the user the possibility to setup the addressing mode he wants
+            //this.texture.wrapU = Texture.CLAMP_ADDRESSMODE;
+            //this.texture.wrapV = Texture.CLAMP_ADDRESSMODE;
             this._useSize = false;
             this._spriteSize = (settings.spriteSize!=null) ? settings.spriteSize.clone() : null;
             this._spriteLocation = (settings.spriteLocation!=null) ? settings.spriteLocation.clone() : new Vector2(0, 0);
             if (settings.size != null) {
                 this.size = settings.size;
             }
+            this._updatePositioningState();
             this.spriteFrame = 0;
             this.invertY = (settings.invertY == null) ? false : settings.invertY;
             this.alignToPixel = (settings.alignToPixel == null) ? true : settings.alignToPixel;
@@ -556,8 +528,8 @@
             if (s == null || sS == null) {
                 return;
             }
-            this.scaleX = s.width / sS.width;
-            this.scaleY = s.height / sS.height;
+            this._postScale.x = s.width / sS.width;
+            this._postScale.y = s.height / sS.height;
         }
 
         private _texture: Texture;
@@ -569,7 +541,6 @@
         private _spriteFrame: number;
         private _scale9: Vector4;
         private _invertY: boolean;
-        private _alignToPixel: boolean;
     }
 
     export class Sprite2DInstanceData extends InstanceDataBase {

A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 120 - 32
canvas2D/src/Engine/babylon.text2d.ts


+ 1 - 33
canvas2D/src/Engine/babylon.wireFrame2d.ts

@@ -233,25 +233,6 @@
             this.internalSetSize(value);
         }
 
-        @instanceLevelProperty(RenderablePrim2D.RENDERABLEPRIM2D_PROPCOUNT + 2, pi => WireFrame2D.actualSizeProperty = pi, false, true)
-        /**
-         * Get/set the actual size of the sprite to display
-         */
-        public get actualSize(): Size {
-            if (this._actualSize) {
-                return this._actualSize;
-            }
-            return this.size;
-        }
-
-        public set actualSize(value: Size) {
-            if (!this._actualSize) {
-                this._actualSize.clone();
-            } else {
-                this._actualSize.copyFrom(value);
-            }
-        }
-
         protected updateLevelBoundingInfo(): boolean {
             let v = this._computeMinMaxTrans();
             BoundingInfo2D.CreateFromMinMaxToRef(v.x, v.z, v.y, v.w, this._levelBoundingInfo);
@@ -337,7 +318,7 @@
             paddingLeft           ?: number | string,
             paddingRight          ?: number | string,
             paddingBottom         ?: number | string,
-            padding               ?: string,
+            padding               ?: number | string,
         }) {
 
             if (!settings) {
@@ -425,11 +406,6 @@
             if (!super.refreshInstanceDataPart(part)) {
                 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;
         }
 
@@ -471,13 +447,5 @@
         constructor(partId: number) {
             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;
+        }
+        
+    }
+
+}

+ 316 - 6
canvas2D/src/Tools/babylon.math2D.ts

@@ -1,5 +1,270 @@
 module BABYLON {
 
+    /**
+       * 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 {
+
+        public static Zero(): Matrix2D {
+            return new Matrix2D();
+        }
+        
+        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;
+        }
+
+        public static FromMatrix(source: Matrix): Matrix2D {
+            let result = new Matrix2D();
+            Matrix2D.FromMatrixToRef(source, result);
+            return result;
+        }
+
+        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];
+        }
+
+        public static Rotation(angle: number): Matrix2D {
+            var result = new Matrix2D();
+
+            Matrix2D.RotationToRef(angle, result);
+
+            return result;
+        }
+
+        public static RotationToRef(angle: number, result: Matrix2D): void {
+            var s = Math.sin(angle);
+            var c = Math.cos(angle);
+
+            result.m[0] = c;    result.m[1] = s;
+            result.m[2] = -s;   result.m[3] = c;
+            result.m[4] = 0;    result.m[5] = 0;
+        }
+
+        public static Translation(x: number, y: number): Matrix2D {
+            var result = new Matrix2D();
+
+            Matrix2D.TranslationToRef(x, y, result);
+
+            return result;
+        }
+
+        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 static Scaling(x: number, y: number): Matrix2D {
+            var result = new Matrix2D();
+
+            Matrix2D.ScalingToRef(x, y, result);
+
+            return result;
+        }
+
+        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;
+        }
+
+        public m = new Float32Array(6);
+
+        public static Identity(): Matrix2D {
+            let res = new Matrix2D();
+            Matrix2D.IdentityToRef(res);
+            return res;
+        }
+
+        public static IdentityToRef(res: Matrix2D) {
+            res.m[1] = res.m[2] = res.m[4] = res[5] = 0;
+            res.m[0] = res.m[3] = 1;
+        }
+
+        public static FromQuaternion(quaternion: Quaternion): Matrix2D {
+            let result = new Matrix2D();
+            Matrix2D.FromQuaternionToRef(quaternion, result);
+            return result;
+        }
+
+        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;
+
+            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;
+        }
+
+        public static Compose(scale: Vector2, rotation: number, translation: Vector2): Matrix2D {
+            var result = Matrix2D.Scaling(scale.x, scale.y);
+
+            var rotationMatrix = Matrix2D.Rotation(rotation);
+            result = result.multiply(rotationMatrix);
+
+            result.setTranslation(translation);
+
+            return result;
+        }
+
+        public static Invert(source: Matrix2D): Matrix2D {
+            let result = new Matrix2D();
+            source.invertToRef(result);
+            return result;
+        }
+
+        public clone(): Matrix2D {
+            let result = new Matrix2D();
+            result.copyFrom(this);
+            return result;
+        }
+
+        public copyFrom(other: Matrix2D) {
+            for (let i = 0; i < 6; i++) {
+                this.m[i] = other.m[i];
+            }
+        }
+
+        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 {
+            return this.m[0] * this.m[3] - this.m[1] * this.m[2];
+        }
+
+        public invertToThis() {
+            this.invertToRef(this);
+        }
+
+        public invert(): Matrix2D {
+            let res = new Matrix2D();
+            this.invertToRef(res);
+            return res;
+        }
+
+        // http://mathworld.wolfram.com/MatrixInverse.html
+        public invertToRef(res: Matrix2D) {
+            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 det = this.determinant();
+            if (det < (Epsilon * Epsilon)) {
+                throw new Error("Can't invert matrix, near null determinant");
+            }
+
+            let detDiv = 1 / det;
+
+            let det4 = l2 * l5 - l3 * l4;
+            let det5 = l1 * l4 - l0 * l5;
+
+            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) {
+            this.multiplyToRef(other, this);
+        }
+
+        public multiply(other: Matrix2D): Matrix2D {
+            let res = new Matrix2D();
+            this.multiplyToRef(other, res);
+            return res;
+        }
+
+        public multiplyToRef(other: Matrix2D, result: Matrix2D) {
+            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 {
+            let res = Vector2.Zero();
+            this.transformFloatsToRef(x, y, res);
+            return res;
+        }
+
+        public transformFloatsToRef(x: number, y: number, r: Vector2) {
+            r.x = x * this.m[0] + y * this.m[2] + this.m[4];
+            r.y = x * this.m[1] + y * this.m[3] + this.m[5];
+        }
+
+        public transformPoint(p: Vector2): Vector2 {
+            let res = Vector2.Zero();
+            this.transformFloatsToRef(p.x, p.y, res);
+            return res;
+        }
+
+        public transformPointToRef(p: Vector2, r: Vector2) {
+            this.transformFloatsToRef(p.x, p.y, r);
+        }
+
+        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);
+        }
+    }
+
+    /**
+     * Stores information about a 2D Triangle.
+     * This class stores the 3 vertices but also the center and radius of the triangle
+     */
     export class Tri2DInfo {
         /**
          * Construct an instance of Tri2DInfo, you can either pass null to a, b and c and the instance will be allocated "clear", or give actual triangle info and the center/radius will be computed
@@ -39,10 +304,13 @@
             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();
         }
@@ -64,12 +332,22 @@
         }
     }
 
+    /**
+     * Stores an array of 2D Triangles.
+     * Internally the data is stored as a Float32Array to minimize the memory footprint.
+     * This can use the Tri2DInfo class as proxy for storing/retrieving data.
+     * The array can't grow, it's fixed size.
+     */
     export class Tri2DArray {
         constructor(count: number) {
             this._count = count;
             this._array = new Float32Array(9 * count);
         }
 
+        /**
+         * Clear the content and allocate a new array to store the given count of triangles
+         * @param count The new count of triangles to store
+         */
         public clear(count: number) {
             if (this._count === count) {
                 return;
@@ -79,6 +357,13 @@
             this._array = new Float32Array(9 * count);
         }
 
+        /**
+         * Store a given triangle at the given index
+         * @param index the 0 based index to store the triangle in the array
+         * @param a the A vertex of the triangle
+         * @param b the B vertex of the triangle
+         * @param c the C vertex of the triangle
+         */
         public storeTriangle(index: number, a: Vector2, b: Vector2, c: Vector2) {
             let center = new Vector2((a.x + b.x + c.x) / 3, (a.y + b.y + c.y) / 3);
 
@@ -123,7 +408,13 @@
             tri2dInfo.radius   = this._array[offset + 8];
         }
 
-        public transformAndStoreToTri2DInfo(index: number, tri2dInfo: Tri2DInfo, transform: Matrix) {
+        /**
+         * Transform the given triangle and store its result in the array
+         * @param index The index to store the result to
+         * @param tri2dInfo The triangle to transform
+         * @param transform The transformation matrix
+         */
+        public transformAndStoreToTri2DInfo(index: number, tri2dInfo: Tri2DInfo, transform: Matrix2D) {
             if (index >= this._count) {
                 throw new Error(`Can't fetch the triangle at index ${index}, max index is ${this._count - 1}`);
             }
@@ -139,10 +430,19 @@
             tri2dInfo.transformInPlace(transform);
         }
 
+        /**
+         * Get the element count that can be stored in this array
+         * @returns {} 
+         */
         public get count(): number {
             return this._count;
         }
 
+        /**
+         * Check if a given point intersects with at least one of the triangles stored in the array.
+         * If true is returned the point is intersecting with at least one triangle, false if it doesn't intersect with any of them
+         * @param p The point to check
+         */
         public doesContain(p: Vector2): boolean {
             Tri2DArray._checkInitStatics();
             let a = Tri2DArray.tempT[0];
@@ -156,7 +456,14 @@
             return false;
         }
 
-        public static doesIntersect(setA: Tri2DArray, setB: Tri2DArray, bToATransform: Matrix): boolean {
+        /**
+         * Make a intersection test between two sets of triangles. The triangles of setB will be transformed to the frame of reference of the setA using the given bToATransform matrix.
+         * If true is returned at least one triangle intersects with another of the other set, otherwise false is returned.
+         * @param setA The first 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
+         */
+        public static doesIntersect(setA: Tri2DArray, setB: Tri2DArray, bToATransform: Matrix2D): boolean {
             Tri2DArray._checkInitStatics();
 
             let a = Tri2DArray.tempT[0];
@@ -209,6 +516,9 @@
         private static tempT: Tri2DInfo[] = null;
     }
 
+    /**
+     * Some 2D Math helpers functions
+     */
     class Math2D {
 
         static Dot(a: Vector2, b: Vector2): number {

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

@@ -9,6 +9,7 @@ attribute float index;
 att vec2 zBias;
 att vec4 transformX;
 att vec4 transformY;
+att vec3 renderingInfo;
 att float opacity;
 
 #ifdef Border
@@ -104,6 +105,18 @@ void main(void) {
 	pos.xy = pos2.xy * properties.xy;
 	pos.z = 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 vec4 transformX;
 att vec4 transformY;
+att vec3 renderingInfo;
 att float opacity;
 
 #ifdef FillSolid
@@ -64,6 +65,18 @@ void main(void) {
 	pos.xy = position.xy;
 	pos.z = 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 vec4 transformX;
 att vec4 transformY;
+att vec3 renderingInfo;
 att float opacity;
 
 #ifdef Border
@@ -202,6 +203,18 @@ void main(void) {
 	pos.xy = pos2.xy * properties.xy;
 	pos.z = 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);
 }

+ 24 - 8
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
 #define att attribute
 #else
@@ -25,6 +25,7 @@ att vec4 scale9;
 att vec2 zBias;
 att vec4 transformX;
 att vec4 transformY;
+att vec3 renderingInfo;
 att float opacity;
 
 // Uniforms
@@ -76,13 +77,15 @@ void main(void) {
 		vUV.y = 1.0 - vUV.y;
 	}
 
+	//vUV.x += 0.5 / textureSize.x;
+
 	vec4 pos;
-	if (alignToPixel == 1.0)
-	{
-		pos.xy = floor(pos2.xy * sizeUV * textureSize);
-	} else {
+	//if (alignToPixel == 1.0)
+	//{
+	//	pos.xy = floor(pos2.xy * sizeUV * textureSize);
+	//} else {
 		pos.xy = pos2.xy * sizeUV * textureSize;
-	}
+	//}
 
 #ifdef Scale9
 	if (invertY == 1.0) {
@@ -92,7 +95,7 @@ void main(void) {
 	}
 	else {
 		vTopLeftUV = topLeftUV;
-		vBottomRightUV = vec2(topLeftUV.x, topLeftUV.y + sizeUV.y);
+		vBottomRightUV = vec2(topLeftUV.x + sizeUV.x, topLeftUV.y + sizeUV.y);
 		vScale9 = scale9;
 	}
 	vScaleFactor = scaleFactor;
@@ -101,5 +104,18 @@ void main(void) {
 	vOpacity = opacity;
 	pos.z = 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)) * irw) + irw / 2.0;
+		y = (floor((y / irh)) * irh) + irh / 2.0;
+	}
+
+	gl_Position = vec4(x, y, zBias.x, 1.0);
 }	

+ 7 - 0
canvas2D/src/shaders/text2d.fragment.fx

@@ -22,7 +22,14 @@ void main(void) {
 	gl_FragColor = vec4(vColor.xyz*dist, vColor.a);
 #else
 	vec4 color = texture2D(diffuseSampler, vUV);
+	if (color.a == 0.0) {
+		discard;
+	}
+#ifdef FontTexture
+	gl_FragColor = vec4(color.xxxx)*vColor;
+#else
 	gl_FragColor = color*vColor;
 #endif
+#endif
 
 }

+ 18 - 3
canvas2D/src/shaders/text2d.vertex.fx

@@ -11,6 +11,7 @@ att vec2 zBias;
 
 att vec4 transformX;
 att vec4 transformY;
+att vec3 renderingInfo;
 att float opacity;
 
 att vec2 topLeftUV;
@@ -52,13 +53,27 @@ void main(void) {
 	}
 
 	// Align texture coordinate to texel to enhance rendering quality
-	vUV = (floor(vUV*textureSize) + vec2(0.0, 0.0)) / textureSize;
+//	vUV = (floor(vUV*textureSize) + vec2(0.5, 0.5)) / textureSize;
+	//vUV.x += 0.5 / textureSize.x;
 
 	vColor = color;
 	vColor.a *= opacity;
 	vec4 pos;
-	pos.xy = floor(pos2.xy * superSampleFactor * sizeUV * textureSize);	// Align on target pixel to avoid bad interpolation
+	pos.xy = pos2.xy * superSampleFactor * sizeUV * textureSize;
 	pos.z = 1.0;
 	pos.w = 1.0;
-	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)) * irw) + irw / 2.0;
+		y = (floor((y / irh)) * irh) + irh / 2.0;
+	}
+
+	gl_Position = vec4(x, y, zBias.x, 1.0);
 }

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

@@ -18,6 +18,7 @@ att vec3 properties;
 att vec2 zBias;
 att vec4 transformX;
 att vec4 transformY;
+att vec3 renderingInfo;
 att float opacity;
 
 // Uniforms
@@ -30,11 +31,17 @@ void main(void) {
 	vec4 p = vec4(pos.xy, 1.0, 1.0);
 	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);
+}

+ 33 - 0
contributing.md

@@ -0,0 +1,33 @@
+# Contributing to Babylon.js
+
+The foundation of **Babylon.js** is simplicity. 
+
+A developer should be able to quickly and easily learn to use the API. 
+
+Simplicity and a low barrier to entry are must-have features of every API. If you have any second thoughts about the complexity of a design, it is almost always much better to cut the feature from the current release and spend more time to get the design right for the next release. 
+
+You can always add to an API, you cannot ever remove anything from one. If the design does not feel right, and you ship it anyway, you are likely to regret having done so.
+
+That's why many of the guidelines of this document are obvious and serve only one purpose: Simplicity.
+
+## Forum and Github issues
+
+Since the very beginning, Babylon.js relies on a great forum and a tremendous community: http://www.html5gamedevs.com/forum/16-babylonjs/.
+Please use the forum for **ANY questions you may have**.
+
+Please use the Github issues **only** for:
+- Bugs
+- Feature requests
+
+We will try to enforce these rules as we consider the forum is a better place for discussions and learnings.
+
+## Pull requests
+
+We are not complicated people, but we still have some [coding guidelines](http://doc.babylonjs.com/generals/Approved_Naming_Conventions)
+Before submitting your PR, just check that everything goes well by [creating the minified version](http://doc.babylonjs.com/generals/Creating_the_Mini-fied_Version)
+
+Need help contributing, here are some links:
+  - [Gulp](https://github.com/BabylonJS/Babylon.js/tree/master/Tools/Gulp) to build from command line.
+  - [VSCode Editor](https://code.visualstudio.com/), Microsoft Code editor, see [Julian Chenard's post](http://pixelcodr.com/tutos/contribute/contribute.html) a Microsoft code editor.
+  - [Visual Studio](http://doc.babylonjs.com/generals/setup_visualStudio), Microsoft's IDE.
+  - [Forum thread](http://www.html5gamedevs.com/topic/20456-contributing-on-babylonjs/) for assistance from our very helpful family.

A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 29 - 28
dist/preview release/babylon.core.js


A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 7682 - 6996
dist/preview release/babylon.d.ts


A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 39 - 37
dist/preview release/babylon.js


A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 3291 - 1041
dist/preview release/babylon.max.js


A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 7682 - 6996
dist/preview release/babylon.module.d.ts


A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 39 - 37
dist/preview release/babylon.noworker.js


A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 278 - 100
dist/preview release/canvas2D/babylon.canvas2d.d.ts


A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 2281 - 916
dist/preview release/canvas2D/babylon.canvas2d.js


A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 12 - 12
dist/preview release/canvas2D/babylon.canvas2d.min.js


A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 4 - 4
dist/preview release/inspector/babylon.inspector.bundle.js


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

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

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

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

+ 562 - 50
dist/preview release/inspector/babylon.inspector.js

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

A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 3 - 3
dist/preview release/inspector/babylon.inspector.min.js


+ 2 - 5
dist/preview release/loaders/babylon.glTFFileLoader.js

@@ -497,9 +497,6 @@ var BABYLON;
         var nodesToRootToAdd = [];
         getNodesToRoot(gltfRuntime, newSkeleton, skins, nodesToRoot);
         newSkeleton.bones = [];
-        if (nodesToRoot.length === 0) {
-            newSkeleton.needInitialSkinMatrix = true;
-        }
         // Joints
         for (var i = 0; i < skins.jointNames.length; i++) {
             var jointNode = getJointNode(gltfRuntime, skins.jointNames[i]);
@@ -728,11 +725,11 @@ var BABYLON;
             var mat = BABYLON.Matrix.FromArray(node.matrix);
             mat.decompose(scaling, rotation, position);
             configureNode(newNode, position, rotation, scaling);
-            newNode.computeWorldMatrix(true);
         }
         else {
             configureNode(newNode, BABYLON.Vector3.FromArray(node.translation), BABYLON.Quaternion.FromArray(node.rotation), BABYLON.Vector3.FromArray(node.scale));
         }
+        newNode.computeWorldMatrix(true);
     };
     /**
     * Imports a node
@@ -859,7 +856,7 @@ var BABYLON;
                 var translation = node.translation || [0, 0, 0];
                 var rotation = node.rotation || [0, 0, 0, 1];
                 var scale = node.scale || [1, 1, 1];
-                configureNode(lastNode, BABYLON.Vector3.FromArray(translation), BABYLON.Quaternion.RotationAxis(BABYLON.Vector3.FromArray(rotation).normalize(), rotation[3]), BABYLON.Vector3.FromArray(scale));
+                configureNode(lastNode, BABYLON.Vector3.FromArray(translation), BABYLON.Quaternion.FromArray(rotation), BABYLON.Vector3.FromArray(scale));
             }
             lastNode.updateCache(true);
             node.babylonNode = lastNode;

A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 2 - 2
dist/preview release/loaders/babylon.glTFFileLoader.min.js


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

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

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

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

A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 1 - 0
dist/preview release/materialsLibrary/babylon.customMaterial.min.js


A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 1 - 1
dist/preview release/materialsLibrary/babylon.furMaterial.js


A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 1 - 1
dist/preview release/materialsLibrary/babylon.furMaterial.min.js


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

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

A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 209 - 0
dist/preview release/materialsLibrary/babylon.shadowOnlyMaterial.js


A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 1 - 0
dist/preview release/materialsLibrary/babylon.shadowOnlyMaterial.min.js


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

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

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

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

A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 1 - 1
dist/preview release/materialsLibrary/babylon.waterMaterial.min.js


+ 11 - 0
dist/preview release/proceduralTexturesLibrary/babylon.normalMapProceduralTexture.d.ts

@@ -0,0 +1,11 @@
+/// <reference path="../../../dist/preview release/babylon.d.ts" />
+declare module BABYLON {
+    class NormalMapProceduralTexture extends ProceduralTexture {
+        private _baseTexture;
+        constructor(name: string, size: number, scene: Scene, fallbackTexture?: Texture, generateMipMaps?: boolean);
+        updateShaderUniforms(): void;
+        render(useCameraPostProcess?: boolean): void;
+        resize(size: any, generateMipMaps: any): void;
+        baseTexture: Texture;
+    }
+}

A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 46 - 0
dist/preview release/proceduralTexturesLibrary/babylon.normalMapProceduralTexture.js


A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 1 - 0
dist/preview release/proceduralTexturesLibrary/babylon.normalMapProceduralTexture.min.js


+ 8 - 0
dist/preview release/proceduralTexturesLibrary/babylon.waterProceduralTexture.d.ts

@@ -0,0 +1,8 @@
+/// <reference path="../../../dist/preview release/babylon.d.ts" />
+declare module BABYLON {
+    class WaterProceduralTexture extends ProceduralTexture {
+        private _time;
+        constructor(name: string, size: number, scene: Scene, fallbackTexture?: Texture, generateMipMaps?: boolean);
+        render(useCameraPostProcess?: boolean): void;
+    }
+}

A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 28 - 0
dist/preview release/proceduralTexturesLibrary/babylon.waterProceduralTexture.js


A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 1 - 0
dist/preview release/proceduralTexturesLibrary/babylon.waterProceduralTexture.min.js


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

@@ -1,17 +1,26 @@
-# 2.6.0:
+# 3.0.0:
+
+## Core engine
 
 ### Major updates
- - WebGL2 context support.WebGL2 is initialized instead of WebGL 1 when available ([deltakosh](https://github.com/deltakosh))
+ - WebGL2 context support. WebGL2 is now used instead of WebGL 1 when available. [More info here](http://doc.babylonjs.com/overviews/webgl2) ([deltakosh](https://github.com/deltakosh))
+ - Complete WebVR 1.1 support including controllers for HTC Vive and Occulus. [More info here](http://doc.babylonjs.com/overviews/webvr_camera) ([raanan](https://github.com/raananw))
+ - Added support for Exponential Shadow maps to replace Variance Shadow maps. [Demo](http://www.babylonjs.com/Demos/AdvancedShadows/) ([deltakosh](https://github.com/deltakosh))
  - Support for [Vertex Array Objects](https://www.opengl.org/registry/specs/ARB/vertex_array_object.txt) ([deltakosh](https://github.com/deltakosh))
+ - Support for multisample render targets. [Demo](http://www.babylonjs-playground.com/#12MKMN) ([deltakosh](https://github.com/deltakosh))
  - New Unity 5 Editor Toolkit. Complete pipeline integration [Doc](TODO) - ([MackeyK24](https://github.com/MackeyK24))
  - New DebugLayer. [Doc](TODO) - ([temechon](https://github.com/temechon))
  - New `VideoTexture.CreateFromWebCam` to generate video texture using WebRTC. [Demo](https://www.babylonjs-playground.com#1R77YT#2) - (Sebastien Vandenberghe)(https://github.com/sebavanmicrosoft) / ([deltakosh](https://github.com/deltakosh))
- - New `HolographicCamera` to support rendering on Windows Holographic. - ([sebavan](https://github.com/sebavan))
  - New Facet Data feature ([jerome](https://github.com/jbousquie))
  - 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))
+ - All deprecated functions and properties were removed ([deltakosh](https://github.com/deltakosh))
 
 ### Updates
+- Introduced `boundingBox.centerWorld` and `boundingBox.extendSizeWorld` ([deltakosh](https://github.com/deltakosh))
+- Improved FXAA post-process ([deltakosh](https://github.com/deltakosh))
+- Added `Light.customProjectionMatrixBuilder` to allow developers to define their own projection matrix for shadows ([deltakosh](https://github.com/deltakosh))
+- Added `set()` function to all basic types ([deltakosh](https://github.com/deltakosh))
 - Added `HDRCubeTextureAssetTask` to AssetManager ([deltakosh](https://github.com/deltakosh))
 - Engine now uses range based fog ([deltakosh](https://github.com/deltakosh))
 - `VertexBuffer.updatable` is now serialized ([deltakosh](https://github.com/deltakosh))
@@ -23,31 +32,81 @@
 - GroundMesh : `getHeightAtCoordinates()`, `getNormalAtCoordinates()` and `getNormalAtCoordinatesToRef()` can now work with rotated grounds ([jerome](https://github.com/jbousquie))  
 - `GroundMesh`, `facetData` and `SolidParticleSystem` improvement in normal computations ([jerome](https://github.com/jbousquie))   
 - Added `AbstractMesh.addRotation()` ([jerome](https://github.com/jbousquie))  
+- Added `Quaternion.RotationQuaternionFromAxis()` and `Quaternion.RotationQuaternionFromAxisToRef()` ([jerome](https://github.com/jbousquie), thanks to [abow](https://github.com/abow))   
+- Added parameters `uvs` and `colors` to `MeshBuilder.CreateRibbon()` ([jerome](https://github.com/jbousquie))  
+- Added `Curve3.CreateCatmullRomSpline()` ([jerome](https://github.com/jbousquie) and [BitOfGold](https://github.com/BitOfGold))  
+- Added the optional parameter`colorFilter` to `CreateGroundFromHeightMap()` ([jerome](https://github.com/jbousquie))  
+- Improved the internal code of `Vector3.RotationFromAxisToRef()` ([jerome](https://github.com/jbousquie), thanks to [abow](https://github.com/abow))  
+- GroundMeshes are now serialized correctly ([deltakosh](https://github.com/deltakosh))
+- Added `mesh.markVerticesDataAsUpdatable()` to allow a specific vertexbuffer to become updatable ([deltakosh](https://github.com/deltakosh)) 
+- Added `POINTERTAP` and `POINTERDOUBLETAP` PointerEventTypes to register new Observer mask. (Demo here)[http://www.babylonjs-playground.com/?30] ([yuccai](https://github.com/yuccai))
+- Added OnDoublePickTrigger for ActionManager ([yuccai](https://github.com/yuccai))
+- Added Scene.DoubleClickDelay to set the timing within a double click event like PointerEventTypes.POINTERDOUBLETAP or ActionManager.OnDoublePickTrigger has to be processed ([yuccai](https://github.com/yuccai))
+- New material: `ShadowOnlyMaterial` to display shadows on transparent surfaces ([deltakosh](https://github.com/deltakosh)) 
+- Added `VertexBuffer.TangentKind` to specify tangents in place of shader-calculated tangents ([dewadswo](https://github.com/dewadswo), [bghgary](https://github.com/bghgary))
+ 
+### Bug fixes
+- Fixed a bug with spotlight direction ([deltakosh](https://github.com/deltakosh)) 
+- Fixed an issue with Mesh.attachToBone when a mesh is moving and an animation is changed ([abow](https://github.com/abow))
+- Fixed an issue withaspect ratio when using CreateScreenshot ([deltakosh](https://github.com/deltakosh))
+- Fixed SPS particle initial status when used as updatable with a `positionFunction` in `addShape()` ([jerome](https://github.com/jbousquie))  
+- Fixed SPS particle access start index when used with `setParticles(start, end)` ([jerome](https://github.com/jbousquie))  
+
+### API Documentation
+`- File `abstractMesh.ts` documented  ([jerome](https://github.com/jbousquie))  
+- File `mesh.ts` documented ([jerome](https://github.com/jbousquie))  
+- File `groundMesh.ts` documented ([jerome](https://github.com/jbousquie))  
+- File `instancedMesh.ts` documented ([jerome](https://github.com/jbousquie))  
+- File `lineMesh.ts` documented ([jerome](https://github.com/jbousquie))  
+- File `vertexData.ts` documented ([jerome](https://github.com/jbousquie))  
+- File `subMesh.ts` documented ([jerome](https://github.com/jbousquie))  
+- File `vertexBuffer.ts` documented ([jerome](https://github.com/jbousquie))  
+- File `math.ts` documented ([jerome](https://github.com/jbousquie))
+- File `light.ts` documented ([jerome](https://github.com/jbousquie))  
+- File `directionalLight.ts` documented ([jerome](https://github.com/jbousquie))  
+- File `hemisphericLight.ts` documented ([jerome](https://github.com/jbousquie))  
+- File `pointLight.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))  
+
+### Breaking changes
+- WebVRCamera:
+  - `requestVRFullscreen` has been removed. Call `attachControl()` inside a user-interaction callback to start sending frames to the VR display
+  - `setPositionOffset` has been used to change the position offset. it is now done using `camera.position`
+- Ray :
+  - `show` has been removed. Use new `RayHelper.show()` instead
+  - `hide` has been removed. Use new `RayHelper.hide()` instead
+- AbstractMesh:
+  - `onPhysicsCollide` has been removed. Use `mesh.physicsImpostor.registerOnPhysicsCollide()` instead
+  - `setPhysicsState` has been removed. Use `new PhysicsImpostor()` instead
+  - `getPhysicsMass` has been removed. Use `mesh.physicsImpostor.getParam("mass")` instead
+  - `getPhysicsFriction` has been removed. Use `mesh.physicsImpostor.getParam("friction")` instead
+  - `getPhysicsRestitution` has been removed. Use `mesh.physicsImpostor.getParam("restitution")` instead
+  - `updatePhysicsBodyPosition` has been removed. Changes are synchronized automatically now
+- Mesh:
+  - `updateVerticesDataDirectly` has been removed. Use `mesh.updateVerticesData()` instead
+- SsaoRenderingPipeline:
+  - `getBlurHPostProcess` has been removed. Blur post-process is no more required
+  - `getBlurVPostProcess` has been removed. Blur post-process is no more required
+- Scene:
+  - `setGravity` has been removed. Use `scene.getPhysicsEngine().setGravity()` instead
+  - `createCompoundImpostor` has been removed. Use PhysicsImpostor parent/child instead
+- ActionManager:
+  - `LongPressDelay` and `DragMovementThreshold` are now respectively Scene.LongPressDelay and Scene.DragMovementThreshold
  
-### Canvas2D
+## Canvas2D
 
-#### Major Updates
+### Major Updates
  - Added text alignment and word wrap to Text2D ([abow](https://github.com/abow))
  - Support of [Scale9Sprite](http://doc.babylonjs.com/overviews/Canvas2D_Sprite2D#scale9sprite-feature) feature in Sprite2D ([nockawa](https://github.com/nockawa))
  - Support of [AtlasPicture](http://doc.babylonjs.com/overviews/Canvas2D_AtlasPicture) to store many pictures into a bit one, with the possibility to create one/many Sprite2D out of it. ([nockawa](https://github.com/nockawa))
  - Support of BMFont with the BitmaptFontTexture class, Text2D has now a bitmapFontTexture setting in the constructor to display text using a BitmapFontTexture ([nockawa](https://github.com/nockawa))
 
-#### Minor Updates
+### Minor Updates
  - WorldSpaceCanvas: TrackNode feature, a WSC can follow a Scene Node with an optional billboarding feature (always facing the camera)[Demo](http://babylonjs-playground.com/#1KYG17#1)
  - WorldSpaceCanvas: new setting unitScaleFactor to generated a bigger canvas than the world space mesh size. If you create a WSC with a size of 200;100 and a uSF of 3, the 3D Plane displaying the canvas will be 200;100 of scene units, the WSC will be 600;300 of pixels units.
 
-#### Bug Fixing
+### Bug Fixing
  - Fix Rotation issue when the Parent's Primitive hadn't a identity scale. ([nockawa](https://github.com/nockawa))
  - Primitive's position computed from TrackedNode are now hidden when the node is out of the Viewing Frustum ([nockawa](https://github.com/nockawa))
  - WorldSpaceCanvas: sideOrientation is finally working, you can try Mesh.DOUBLESIDE to make you Canvas visible on both sides. ([nockawa](https://github.com/nockawa))
-
-
-### Exporters
-    
-### API doc
-
-### Bug fixes
- - Fixed an issue with Mesh.attachToBone when a mesh is moving and an animation is changed ([abow](https://github.com/abow))
- - Fixed an issue withaspect ratio when using CreateScreenshot ([deltakosh](https://github.com/deltakosh))
-
-### Breaking changes

+ 4 - 0
inspector/sass/_tabPanel.scss

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

+ 1 - 0
inspector/sass/_tree.scss

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

+ 139 - 107
inspector/src/Inspector.ts

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

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

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

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

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

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

@@ -0,0 +1,59 @@
+module INSPECTOR {
+
+    export class SoundAdapter
+        extends Adapter
+        implements ISoundInteractions {
+
+        constructor(obj: BABYLON.Sound) {
+            super(obj);
+        }
+
+        /** Returns the name displayed in the tree */
+        public id(): string {
+            let str = '';
+            if (this._obj.name) {
+                str = this._obj.name;
+            } // otherwise nothing displayed        
+            return str;
+        }
+
+        /** Returns the type of this object - displayed in the tree */
+        public type(): string {
+            return Helpers.GET_TYPE(this._obj);
+        }
+
+        /** Returns the list of properties to be displayed for this adapter */
+        public getProperties(): Array<PropertyLine> {
+            let propertiesLines: Array<PropertyLine> = [];
+            let camToDisplay = [];
+            // The if is there to work with the min version of babylon
+
+            let soundProperties = PROPERTIES['Sound'].properties;
+
+
+            for (let dirty of soundProperties) {
+                let infos = new Property(dirty, this._obj);
+                propertiesLines.push(new PropertyLine(infos));
+            }
+            return propertiesLines;
+        }
+
+        public getTools(): Array<AbstractTreeTool> {
+            let tools = [];
+            tools.push(new SoundInteractions(this));
+            return tools;
+        }
+
+        public setPlaying(callback: Function) {
+            if ((this._obj as BABYLON.Sound).isPlaying) {
+                (this._obj as BABYLON.Sound).pause();
+            }
+            else {
+                (this._obj as BABYLON.Sound).play();
+            }
+            (this._obj as BABYLON.Sound).onended = () => {
+                callback();
+            }
+        }
+    }
+}

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

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

+ 197 - 131
inspector/src/properties.ts

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

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

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

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

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

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


Nem az összes módosított fájl került megjelenítésre, mert túl sok fájl változott