瀏覽代碼

Merge branch 'master' into master

David Catuhe 8 年之前
父節點
當前提交
49b1e834a6
共有 100 個文件被更改,包括 18363 次插入10359 次删除
  1. 1 1
      .travis.yml
  2. 3350 1056
      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. 17 2
      Exporters/3ds Max/BabylonExport.Entities/BabylonShadowGenerator.cs
  8. 二進制
      Exporters/3ds Max/Max2Babylon-0.6.0.zip
  9. 二進制
      Exporters/3ds Max/Max2Babylon-0.8.0.zip
  10. 1 1
      Exporters/3ds Max/Max2Babylon/2017/Max2Babylon2017.csproj
  11. 1 0
      Exporters/3ds Max/Max2Babylon/Exporter/BabylonExporter.Mesh.cs
  12. 5 5
      Exporters/3ds Max/Max2Babylon/Exporter/BabylonExporter.ShadowGenerator.cs
  13. 1 2
      Exporters/3ds Max/Max2Babylon/Forms/CameraPropertiesForm.Designer.cs
  14. 3 4
      Exporters/3ds Max/Max2Babylon/Forms/LightPropertiesForm.Designer.cs
  15. 1 1
      Exporters/3ds Max/Max2Babylon/Forms/LightPropertiesForm.cs
  16. 1 3
      Exporters/3ds Max/Max2Babylon/Forms/ObjectPropertiesForm.Designer.cs
  17. 13 13
      Exporters/Blender/io_export_babylon.py
  18. 9 6
      Exporters/Maya/Tools/babylonReskinTool.mel
  19. 0 0
      Exporters/Unity 5/EditorToolkit/Redist/readme.md
  20. 1 0
      Playground/debug.html
  21. 1 0
      Playground/frame.html
  22. 1 1
      Playground/frame.js
  23. 3 0
      Playground/index-local.html
  24. 11 0
      Playground/index.html
  25. 27 0
      Playground/index.js
  26. 140 0
      Playground/index2_5.html
  27. 82 0
      Playground/scripts/pointer events handling.js
  28. 2 1
      Playground/scripts/scripts.txt
  29. 1 1
      Playground/scripts/shadows.js
  30. 二進制
      Playground/textures/babylonjs.mp4
  31. 二進制
      Playground/textures/babylonjs.webm
  32. 644 560
      Tools/Gulp/config.json
  33. 16 11
      Tools/Gulp/gulp-addModuleExports.js
  34. 1 1
      Tools/Gulp/gulpfile.js
  35. 4 4
      Tools/Gulp/package.json
  36. 二進制
      assets/sounds/explosion.wav
  37. 二進制
      assets/sounds/jump.wav
  38. 二進制
      assets/textures/Ground.jpg
  39. 二進制
      assets/textures/babylonjs.mp4
  40. 二進制
      assets/textures/babylonjs.webm
  41. 101 97
      canvas2D/readme.md
  42. 10 6
      canvas2D/src/Engine/babylon.bounding2d.ts
  43. 164 101
      canvas2D/src/Engine/babylon.canvas2d.ts
  44. 3 0
      canvas2D/src/Engine/babylon.canvas2dLayoutEngine.ts
  45. 9 4
      canvas2D/src/Engine/babylon.ellipse2d.ts
  46. 161 41
      canvas2D/src/Engine/babylon.fontTexture.ts
  47. 57 28
      canvas2D/src/Engine/babylon.group2d.ts
  48. 17 12
      canvas2D/src/Engine/babylon.lines2d.ts
  49. 22 1
      canvas2D/src/Engine/babylon.modelRenderCache.ts
  50. 611 404
      canvas2D/src/Engine/babylon.prim2dBase.ts
  51. 1 1
      canvas2D/src/Engine/babylon.primitiveCollisionManager.ts
  52. 9 4
      canvas2D/src/Engine/babylon.rectangle2d.ts
  53. 71 70
      canvas2D/src/Engine/babylon.renderablePrim2d.ts
  54. 7 7
      canvas2D/src/Engine/babylon.shape2d.ts
  55. 38 2
      canvas2D/src/Engine/babylon.smartPropertyPrim.ts
  56. 3 15
      canvas2D/src/Engine/babylon.sprite2d.ts
  57. 96 24
      canvas2D/src/Engine/babylon.text2d.ts
  58. 0 13
      canvas2D/src/Engine/babylon.wireFrame2d.ts
  59. 249 0
      canvas2D/src/Tools/babylon.c2dlogging.ts
  60. 160 432
      canvas2D/src/Tools/babylon.math2D.ts
  61. 14 1
      canvas2D/src/shaders/ellipse2d.vertex.fx
  62. 14 1
      canvas2D/src/shaders/lines2d.vertex.fx
  63. 14 1
      canvas2D/src/shaders/rect2d.vertex.fx
  64. 24 8
      canvas2D/src/shaders/sprite2d.vertex.fx
  65. 7 0
      canvas2D/src/shaders/text2d.fragment.fx
  66. 18 3
      canvas2D/src/shaders/text2d.vertex.fx
  67. 13 6
      canvas2D/src/shaders/wireframe2d.vertex.fx
  68. 33 0
      contributing.md
  69. 29 28
      dist/preview release/babylon.core.js
  70. 2702 2247
      dist/preview release/babylon.d.ts
  71. 42 38
      dist/preview release/babylon.js
  72. 2856 1094
      dist/preview release/babylon.max.js
  73. 2702 2247
      dist/preview release/babylon.module.d.ts
  74. 41 37
      dist/preview release/babylon.noworker.js
  75. 165 253
      dist/preview release/canvas2D/babylon.canvas2d.d.ts
  76. 1615 1103
      dist/preview release/canvas2D/babylon.canvas2d.js
  77. 12 12
      dist/preview release/canvas2D/babylon.canvas2d.min.js
  78. 4 4
      dist/preview release/inspector/babylon.inspector.bundle.js
  79. 4 0
      dist/preview release/inspector/babylon.inspector.css
  80. 246 3
      dist/preview release/inspector/babylon.inspector.d.ts
  81. 1091 259
      dist/preview release/inspector/babylon.inspector.js
  82. 3 3
      dist/preview release/inspector/babylon.inspector.min.js
  83. 8 8
      dist/preview release/loaders/babylon.glTFFileLoader.d.ts
  84. 33 24
      dist/preview release/loaders/babylon.glTFFileLoader.js
  85. 2 2
      dist/preview release/loaders/babylon.glTFFileLoader.min.js
  86. 33 0
      dist/preview release/loaders/babylon.objFileLoader.js
  87. 1 1
      dist/preview release/loaders/babylon.objFileLoader.min.js
  88. 1 1
      dist/preview release/loaders/babylon.stlFileLoader.min.js
  89. 16 0
      dist/preview release/materialsLibrary/babylon.customMaterial.d.ts
  90. 403 0
      dist/preview release/materialsLibrary/babylon.customMaterial.js
  91. 1 0
      dist/preview release/materialsLibrary/babylon.customMaterial.min.js
  92. 10 5
      dist/preview release/materialsLibrary/babylon.fireMaterial.js
  93. 1 1
      dist/preview release/materialsLibrary/babylon.fireMaterial.min.js
  94. 11 6
      dist/preview release/materialsLibrary/babylon.furMaterial.js
  95. 1 1
      dist/preview release/materialsLibrary/babylon.furMaterial.min.js
  96. 14 9
      dist/preview release/materialsLibrary/babylon.gradientMaterial.js
  97. 1 1
      dist/preview release/materialsLibrary/babylon.gradientMaterial.min.js
  98. 10 5
      dist/preview release/materialsLibrary/babylon.gridMaterial.js
  99. 14 9
      dist/preview release/materialsLibrary/babylon.lavaMaterial.js
  100. 0 0
      dist/preview release/materialsLibrary/babylon.lavaMaterial.min.js

+ 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

File diff suppressed because it is too large
+ 3350 - 1056
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;
+        }
     }
 }

+ 17 - 2
Exporters/3ds Max/BabylonExport.Entities/BabylonShadowGenerator.cs

@@ -15,13 +15,19 @@ namespace BabylonExport.Entities
         public string lightId { get; set; }
 
         [DataMember]
-        public bool useVarianceShadowMap { get; set; }
+        public bool useExponentialShadowMap { get; set; }
 
         [DataMember]
         public bool usePoissonSampling { get; set; }
 
         [DataMember]
-        public bool useBlurVarianceShadowMap { get; set; }
+        public bool useBlurExponentialShadowMap { get; set; }
+
+        [DataMember]
+        public float? depthScale { get; set; }
+
+        [DataMember]
+        public float darkness { get; set; }
 
         [DataMember]
         public float blurScale { get; set; }
@@ -35,5 +41,14 @@ namespace BabylonExport.Entities
         [DataMember]
         public bool forceBackFacesOnly { get; set; }
 
+        public BabylonShadowGenerator()
+        {
+            darkness = 0;
+            blurScale = 2;
+            blurBoxOffset = 0;
+            bias = 0.00005f;
+            depthScale = null;
+            forceBackFacesOnly = false;
+        }
     }
 }

二進制
Exporters/3ds Max/Max2Babylon-0.6.0.zip


二進制
Exporters/3ds Max/Max2Babylon-0.8.0.zip


+ 1 - 1
Exporters/3ds Max/Max2Babylon/2017/Max2Babylon2017.csproj

@@ -23,7 +23,7 @@
     <DebugSymbols>true</DebugSymbols>
     <DebugType>full</DebugType>
     <Optimize>false</Optimize>
-    <OutputPath>C:\Program Files\Autodesk\3ds Max 2017\bin\assemblies\</OutputPath>
+    <OutputPath>c:\Program Files\Autodesk\3ds Max 2017\bin\assemblies\</OutputPath>
     <DefineConstants>TRACE;DEBUG;MAX2017</DefineConstants>
     <ErrorReport>prompt</ErrorReport>
     <WarningLevel>4</WarningLevel>

+ 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)

+ 5 - 5
Exporters/3ds Max/Max2Babylon/Exporter/BabylonExporter.ShadowGenerator.cs

@@ -20,7 +20,7 @@ namespace Max2Babylon
             babylonShadowGenerator.bias = lightNode.GetFloatProperty("babylonjs_shadows_bias", 0.00005f);
             babylonShadowGenerator.forceBackFacesOnly = lightNode.GetBoolProperty("babylonjs_forcebackfaces");
 
-            var shadowsType = lightNode.GetStringProperty("babylonjs_shadows_type", "Blurred Variance");
+            var shadowsType = lightNode.GetStringProperty("babylonjs_shadows_type", "Blurred ESM");
 
             switch (shadowsType)
             {
@@ -29,11 +29,11 @@ namespace Max2Babylon
                 case "Poisson Sampling":
                     babylonShadowGenerator.usePoissonSampling = true;
                     break;
-                case "Variance":
-                    babylonShadowGenerator.useVarianceShadowMap = true;
+                case "ESM":
+                    babylonShadowGenerator.useExponentialShadowMap = true;
                     break;
-                case"Blurred Variance":
-                    babylonShadowGenerator.useBlurVarianceShadowMap = true;
+                case"Blurred ESM":
+                    babylonShadowGenerator.useBlurExponentialShadowMap = true;
                     babylonShadowGenerator.blurScale = lightNode.GetFloatProperty("babylonjs_shadows_blurScale", 2);
                     babylonShadowGenerator.blurBoxOffset = lightNode.GetFloatProperty("babylonjs_shadows_blurBoxOffset", 1);
                     break;

+ 1 - 2
Exporters/3ds Max/Max2Babylon/Forms/CameraPropertiesForm.Designer.cs

@@ -310,7 +310,7 @@
             // label6
             // 
             this.label6.AutoSize = true;
-            this.label6.Location = new System.Drawing.Point(16, 58);
+            this.label6.Location = new System.Drawing.Point(16, 57);
             this.label6.Name = "label6";
             this.label6.Size = new System.Drawing.Size(34, 13);
             this.label6.TabIndex = 6;
@@ -319,7 +319,6 @@
             // cbCameraType
             // 
             this.cbCameraType.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
-            this.cbCameraType.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
             this.cbCameraType.FormattingEnabled = true;
             this.cbCameraType.Items.AddRange(new object[] {
             "AnaglyphArcRotateCamera",

+ 3 - 4
Exporters/3ds Max/Max2Babylon/Forms/LightPropertiesForm.Designer.cs

@@ -324,7 +324,7 @@
             // label6
             // 
             this.label6.AutoSize = true;
-            this.label6.Location = new System.Drawing.Point(18, 92);
+            this.label6.Location = new System.Drawing.Point(18, 91);
             this.label6.Name = "label6";
             this.label6.Size = new System.Drawing.Size(34, 13);
             this.label6.TabIndex = 8;
@@ -342,13 +342,12 @@
             // cbCameraType
             // 
             this.cbCameraType.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
-            this.cbCameraType.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
             this.cbCameraType.FormattingEnabled = true;
             this.cbCameraType.Items.AddRange(new object[] {
             "Hard shadows",
             "Poisson Sampling",
-            "Variance",
-            "Blurred Variance"});
+            "ESM",
+            "Blurred ESM"});
             this.cbCameraType.Location = new System.Drawing.Point(21, 108);
             this.cbCameraType.Name = "cbCameraType";
             this.cbCameraType.Size = new System.Drawing.Size(289, 21);

+ 1 - 1
Exporters/3ds Max/Max2Babylon/Forms/LightPropertiesForm.cs

@@ -36,7 +36,7 @@ namespace Max2Babylon
             Tools.PrepareNumericUpDown(nupBias, lights, "babylonjs_shadows_bias", 0.00005f);
             Tools.PrepareNumericUpDown(nupBlurScale, lights, "babylonjs_shadows_blurScale", 2);
             Tools.PrepareNumericUpDown(nupBlurBoxOffset, lights, "babylonjs_shadows_blurBoxOffset", 1);
-            Tools.PrepareComboBox(cbCameraType, lights[0], "babylonjs_shadows_type", "Blurred Variance");
+            Tools.PrepareComboBox(cbCameraType, lights[0], "babylonjs_shadows_type", "Blurred ESM");
         }
 
         private void butOK_Click(object sender, EventArgs e)

+ 1 - 3
Exporters/3ds Max/Max2Babylon/Forms/ObjectPropertiesForm.Designer.cs

@@ -412,7 +412,7 @@
             // label6
             // 
             this.label6.AutoSize = true;
-            this.label6.Location = new System.Drawing.Point(18, 27);
+            this.label6.Location = new System.Drawing.Point(18, 26);
             this.label6.Name = "label6";
             this.label6.Size = new System.Drawing.Size(50, 13);
             this.label6.TabIndex = 8;
@@ -421,7 +421,6 @@
             // cbImpostor
             // 
             this.cbImpostor.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
-            this.cbImpostor.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
             this.cbImpostor.FormattingEnabled = true;
             this.cbImpostor.Items.AddRange(new object[] {
             "None",
@@ -681,7 +680,6 @@
             // cbDistanceModel
             // 
             this.cbDistanceModel.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
-            this.cbDistanceModel.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
             this.cbDistanceModel.FormattingEnabled = true;
             this.cbDistanceModel.Items.AddRange(new object[] {
             "linear",

+ 13 - 13
Exporters/Blender/io_export_babylon.py

@@ -100,8 +100,8 @@ HEMI_LIGHT = 3
 NO_SHADOWS = 'NONE'
 STD_SHADOWS = 'STD'
 POISSON_SHADOWS = 'POISSON'
-VARIANCE_SHADOWS = 'VARIANCE'
-BLUR_VARIANCE_SHADOWS = 'BLUR_VARIANCE'
+ESM_SHADOWS = 'ESM'
+BLUR_ESM_SHADOWS = 'BLUR_ESM'
 
 # used in Texture constructor, defined in BABYLON.Texture
 CLAMP_ADDRESSMODE = 0
@@ -1656,12 +1656,12 @@ class ShadowGenerator:
         self.mapSize = lamp.data.shadowMapSize
         self.shadowBias = lamp.data.shadowBias
 
-        if lamp.data.shadowMap == VARIANCE_SHADOWS:
-            self.useVarianceShadowMap = True
+        if lamp.data.shadowMap == ESM_SHADOWS:
+            self.useExponentialShadowMap = True
         elif lamp.data.shadowMap == POISSON_SHADOWS:
             self.usePoissonSampling = True
-        elif lamp.data.shadowMap == BLUR_VARIANCE_SHADOWS:
-            self.useBlurVarianceShadowMap = True
+        elif lamp.data.shadowMap == BLUR_ESM_SHADOWS:
+            self.useBlurExponentialShadowMap = True
             self.shadowBlurScale = lamp.data.shadowBlurScale
             self.shadowBlurBoxOffset = lamp.data.shadowBlurBoxOffset
 
@@ -1677,12 +1677,12 @@ class ShadowGenerator:
         write_string(file_handler, 'lightId', self.lightId)
         write_float(file_handler, 'bias', self.shadowBias)
 
-        if hasattr(self, 'useVarianceShadowMap') :
-            write_bool(file_handler, 'useVarianceShadowMap', self.useVarianceShadowMap)
+        if hasattr(self, 'useExponentialShadowMap') :
+            write_bool(file_handler, 'useExponentialShadowMap', self.useExponentialShadowMap)
         elif hasattr(self, 'usePoissonSampling'):
             write_bool(file_handler, 'usePoissonSampling', self.usePoissonSampling)
-        elif hasattr(self, 'useBlurVarianceShadowMap'):
-            write_bool(file_handler, 'useBlurVarianceShadowMap', self.useBlurVarianceShadowMap)
+        elif hasattr(self, 'useBlurExponentialShadowMap'):
+            write_bool(file_handler, 'useBlurExponentialShadowMap', self.useBlurExponentialShadowMap)
             write_int(file_handler, 'blurScale', self.shadowBlurScale)
             write_int(file_handler, 'blurBoxOffset', self.shadowBlurBoxOffset)
 
@@ -2713,8 +2713,8 @@ bpy.types.Lamp.shadowMap = bpy.props.EnumProperty(
     items = ((NO_SHADOWS           , 'None'         , 'No Shadow Maps'),
              (STD_SHADOWS          , 'Standard'     , 'Use Standard Shadow Maps'),
              (POISSON_SHADOWS      , 'Poisson'      , 'Use Poisson Sampling'),
-             (VARIANCE_SHADOWS     , 'Variance'     , 'Use Variance Shadow Maps'),
-             (BLUR_VARIANCE_SHADOWS, 'Blur Variance', 'Use Blur Variance Shadow Maps')
+             (ESM_SHADOWS          , 'ESM'          , 'Use Exponential Shadow Maps'),
+             (BLUR_ESM_SHADOWS     , 'Blur ESM'     , 'Use Blur Exponential Shadow Maps')
             ),
     default = NO_SHADOWS
 )
@@ -2809,7 +2809,7 @@ class ObjectPanel(bpy.types.Panel):
             layout.prop(ob.data, 'shadowBias')
 
             box = layout.box()
-            box.label(text="Blur Variance Shadows")
+            box.label(text="Blur ESM Shadows")
             box.prop(ob.data, 'shadowBlurScale')
             box.prop(ob.data, 'shadowBlurBoxOffset')
 

+ 9 - 6
Exporters/Maya/Tools/babylonReskinTool.mel

@@ -1,9 +1,10 @@
 global proc reskinSelectedMeshes() {
-    $influencers = `intSliderGrp -q -value myReskinInfluencers`;
     $selection = `ls -sl`;
     $selected = size($selection);
     if ($selected > 0) {
         $skinName = `textFieldGrp -q -text myReskinName`;
+        $regenerate = `radioButtonGrp -q -select myReskinGenerate`;
+        $influencers = `intSliderGrp -q -value myReskinInfluencers`;
         if ($skinName != "") {
             $textField_exists = `objExists $skinName`;
             if ($textField_exists == 0) {
@@ -13,7 +14,8 @@ global proc reskinSelectedMeshes() {
                 if ($selected > 1) {
                     $duplicateObj = `duplicate $selection`;
                     $createGrp = `group -n tempGroup`;
-                    $combine = `polyUnite -n $skinName $createGrp`;
+                    $mergeType = $regenerate;
+                    $combine = `polyUnite -muv $mergeType -n $skinName $createGrp`;
                     $deleteHistory = `delete -ch $combine`;
                     delete $createGrp;
                 } else {
@@ -26,7 +28,7 @@ global proc reskinSelectedMeshes() {
                 $transfer = `copySkinWeights -nm -sa "closestPoint" -ia "closestJoint"`;
                 $cleared = `textFieldGrp -edit -text "" myReskinName`;
                 $deleted = `delete $selection`;
-                $deselect = `select -cl`;
+                select -cl;
                 waitCursor -state 0;
             } else {
                 error ("Skin name is already in use: " + $skinName);
@@ -42,8 +44,9 @@ global proc reskinSelectedMeshes() {
 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 8 -fieldMinValue 1 -fieldMaxValue 8 -value 4 myReskinInfluencers;
+    textFieldGrp -label "Skin Name" -text "" myReskinName;
+    intSliderGrp -label "Max Influencers" -field true -minValue 1 -maxValue 4 -fieldMinValue 1 -fieldMaxValue 4 -value 4 myReskinInfluencers;
+    radioButtonGrp -label "UV Map Generation" -numberOfRadioButtons 2 -labelArray2 "Merge By Names" "Merge By Set Links" -select 1 myReskinGenerate;
     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>

+ 1 - 1
Playground/frame.js

@@ -1,5 +1,5 @@
 (function () {
-    var snippetUrl = "//babylonjs-api.azurewebsites.net/api/snippet";
+    var snippetUrl = "https://babylonjs-api.azurewebsites.net/api/snippet";
     var currentSnippetToken;
     var engine;
     var fpsLabel = document.getElementById("fpsLabel");

+ 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);

二進制
Playground/textures/babylonjs.mp4


二進制
Playground/textures/babylonjs.webm


File diff suppressed because it is too large
+ 644 - 560
Tools/Gulp/config.json


+ 16 - 11
Tools/Gulp/gulp-addModuleExports.js

@@ -10,19 +10,24 @@ module.exports = function (varName) {
           '};\n';
 
         var extendsAddition =
-        'var __extends = (this && this.__extends) || function (d, b) {\n' +
-          'for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];\n' +
-          'function __() { this.constructor = d; }\n' +
-          '__.prototype = b.prototype;\n' +
-          'd.prototype = new __();\n' +
-        '};\n';
+        `var __extends = (this && this.__extends) || (function () {
+            var extendStatics = Object.setPrototypeOf ||
+                ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
+                function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
+            return function (d, b) {
+                extendStatics(d, b);
+                function __() { this.constructor = d; }
+                d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
+            };
+        })();
+        `;
 
         var decorateAddition =
-        'var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {\n' +
-            'var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;\n' +
-            'if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);\n' +
-            'else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;\n' +
-            'return c > 3 && r && Object.defineProperty(target, key, r), r;\n' +
+        'var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {\n' +
+            'var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;\n' +
+            'if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);\n' +
+            'else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;\n' +
+            'return c > 3 && r && Object.defineProperty(target, key, r), r;\n' +
         '};\n';
 
         if (file.isNull()) {

+ 1 - 1
Tools/Gulp/gulpfile.js

@@ -31,7 +31,7 @@ var includeShadersStream;
 var shadersStream;
 var workersStream;
 
-var extendsSearchRegex = /var\s__extends[\s\S]+?\};/g;
+var extendsSearchRegex = /var\s__extends[\s\S]+?\}\)\(\);/g;
 var decorateSearchRegex = /var\s__decorate[\s\S]+?\};/g;
 
 /**

+ 4 - 4
Tools/Gulp/package.json

@@ -1,6 +1,6 @@
 {
   "name": "BabylonJS",
-  "version": "2.5.0",
+  "version": "3.0.0",
   "description": "Babylon.js is a 3D engine based on webgl and javascript",
   "main": "",
   "repository": { "url": "https://github.com/BabylonJS/Babylon.js/" },
@@ -8,10 +8,10 @@
   "license": "(Apache-2.0)",
   "devDependencies": {
     "gulp": "^3.8.11",
-    "gulp-uglify": "~1.5.3",
+    "gulp-uglify": "^2.1.2",
     "gulp-sourcemaps": "~1.9.1",
-    "typescript": "^2.1.4",
-    "gulp-typescript": "^3.1.3",
+    "typescript": "~2.2.2",
+    "gulp-typescript": "^3.1.6",
     "through2": "~0.6.5",
     "gulp-util": "~3.0.4",
     "gulp-concat": "~2.5.2",

二進制
assets/sounds/explosion.wav


二進制
assets/sounds/jump.wav


二進制
assets/textures/Ground.jpg


二進制
assets/textures/babylonjs.mp4


二進制
assets/textures/babylonjs.webm


+ 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
+```
+

+ 10 - 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
@@ -232,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;
@@ -264,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;
@@ -278,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;
@@ -297,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));
@@ -306,7 +310,7 @@
             this._worldAABB.w = Math.max(Math.max(p[0].y, p[1].y), Math.max(p[2].y, p[3].y));
         }
 
-        public worldMatrixAccess: () => Matrix;
+        public worldMatrixAccess: () => Matrix2D;
 
         public get worldAABBDirtyObservable(): Observable<BoundingInfo2D> {
             if (!this._worldAABBDirtyObservable) {

+ 164 - 101
canvas2D/src/Engine/babylon.canvas2d.ts

@@ -87,20 +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._layoutBoundingInfoUpdateCounter = new PerfCounter();
-
             this._cachedCanvasGroup = null;
 
             this._renderingGroupObserver = null;
@@ -169,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) {
@@ -198,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();
                 });
             }
 
@@ -230,57 +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;
         }
@@ -293,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);
@@ -325,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);
                 });
             }
 
@@ -500,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);
 
@@ -521,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) {
@@ -536,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;
@@ -796,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);
                     }
                 }
             }
@@ -817,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);
                     }
                 }
@@ -1127,35 +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._layoutBoundingInfoUpdateCounter.fetchNewFrame();
+            this.drawCallsOpaqueCounter.fetchNewFrame();
+            this.drawCallsAlphaTestCounter.fetchNewFrame();
+            this.drawCallsTransparentCounter.fetchNewFrame();
+            this.groupRenderCounter.fetchNewFrame();
+            this.updateTransparentDataCounter.fetchNewFrame();
+            this.updateCachedStateCounter.fetchNewFrame();
+            this.updateLayoutCounter.fetchNewFrame();
+            this.updatePositioningCounter.fetchNewFrame();
+            this.updateLocalTransformCounter.fetchNewFrame();
+            this.updateGlobalTransformCounter.fetchNewFrame();
+            this.boundingInfoRecomputeCounter.fetchNewFrame();
+            this.layoutBoundingInfoUpdateCounter.fetchNewFrame();
+            this.canvasRenderTimeCounter.beginMonitoring();
         }
 
         private _fetchPerfMetrics() {
-            this._drawCallsOpaqueCounter.addCount(0, true);
-            this._drawCallsAlphaTestCounter.addCount(0, true);
-            this._drawCallsTransparentCounter.addCount(0, true);
-            this._groupRenderCounter.addCount(0, true);
-            this._updateTransparentDataCounter.addCount(0, true);
-            this._cachedGroupRenderCounter.addCount(0, true);
-            this._updateCachedStateCounter.addCount(0, true);
-            this._updateLayoutCounter.addCount(0, true);
-            this._updatePositioningCounter.addCount(0, true);
-            this._updateLocalTransformCounter.addCount(0, true);
-            this._updateGlobalTransformCounter.addCount(0, true);
-            this._boundingInfoRecomputeCounter.addCount(0, true);
-            this._layoutBoundingInfoUpdateCounter.addCount(0, true);
+            this.drawCallsOpaqueCounter.addCount(0, true);
+            this.drawCallsAlphaTestCounter.addCount(0, true);
+            this.drawCallsTransparentCounter.addCount(0, true);
+            this.groupRenderCounter.addCount(0, true);
+            this.updateTransparentDataCounter.addCount(0, true);
+            this.updateCachedStateCounter.addCount(0, true);
+            this.updateLayoutCounter.addCount(0, true);
+            this.updatePositioningCounter.addCount(0, true);
+            this.updateLocalTransformCounter.addCount(0, true);
+            this.updateGlobalTransformCounter.addCount(0, true);
+            this.boundingInfoRecomputeCounter.addCount(0, true);
+            this.layoutBoundingInfoUpdateCounter.addCount(0, true);
+            this.canvasRenderTimeCounter.endMonitoring(true);
         }
 
         private _updateProfileCanvas() {
@@ -1165,13 +1200,13 @@
 
             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` + 
@@ -1208,12 +1243,6 @@
             }
         }
 
-        public addCachedGroupRenderCounter(count: number) {
-            if (this._cachedGroupRenderCounter) {
-                this._cachedGroupRenderCounter.addCount(count, false);
-            }
-        }
-
         public addUpdateCachedStateCounter(count: number) {
             if (this._updateCachedStateCounter) {
                 this._updateCachedStateCounter.addCount(count, false);
@@ -1292,14 +1321,15 @@
         private _designUseHorizAxis: boolean;
         public  _primitiveCollisionManager: PrimitiveCollisionManagerBase;
 
-        public _renderingSize: Size;
+        public _canvasLevelScale: Vector2;
+        public  _renderingSize: Size;
+        private _curHWScale;
 
         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;
@@ -1307,11 +1337,13 @@
         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();
@@ -1353,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
@@ -1442,15 +1474,16 @@
             }
 
             // Clip values if needed
-            edge = Math.min(edge, this._maxAdaptiveWorldSpaceCanvasSize);
+            edge = Math.min(edge, this._maxAdaptiveWorldSpaceCanvasSize-4); // -4 is to consider the border of 2 pixels, other we couldn't allocate a rect
 
             let newScale = edge / ((isW) ? this.size.width : this.size.height);
-            if (newScale !== this.scale) {
+            if (newScale !== this._renderableData._renderingScale) {
                 let scale = newScale;
-//                console.log(`New adaptive scale for Canvas ${this.id}, w: ${w}, h: ${h}, scale: ${scale}, edge: ${edge}, isW: ${isW}`);
+                //console.log(`New adaptive scale for Canvas ${this.id}, w: ${w}, h: ${h}, scale: ${scale}, edge: ${edge}, isW: ${isW}`);
                 this._setRenderingScale(scale);
             }
         }
+        private static _pCLS = Vector2.Zero();
 
         private _updateCanvasState(forceRecompute: boolean) {
             // Check if the update has already been made for this render Frame
@@ -1458,20 +1491,49 @@
                 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.size = this._renderingSize.clone();
@@ -1483,21 +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.scale = scale;
-            }
-
             var context = new PrepareRender2DContext();
 
             ++this._globalTransformProcessStep;
+            this._setFlags(SmartPropertyPrim.flagLocalTransformDirty|SmartPropertyPrim.flagGlobalTransformDirty);
             this.updateCachedStates(false);
 
             this._prepareGroupRender(context);
@@ -1508,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()) {
@@ -1574,22 +1625,26 @@
             let key = `${useMipMap ? "MipMap" : "NoMipMap"}_${anisotropicLevel}`;
 
             let rd = group._renderableData;
+            let rs = rd._renderingScale;
             let noResizeScale = rd._noResizeOnScale;
             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);
             }
+            scale.x *= rs;
+            scale.y *= rs;
 
             // 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>());
@@ -1599,7 +1654,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;
@@ -1611,18 +1666,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 }
             }
 
@@ -1630,6 +1691,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
 
@@ -1639,14 +1702,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) => {

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

@@ -61,6 +61,7 @@
         // 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
@@ -73,6 +74,7 @@
 
         }
 
+        @logMethod()
         private _doUpdate(prim: Prim2DBase) {
             // Canvas ?
             if (prim instanceof Canvas2D) {
@@ -93,6 +95,7 @@
                     prim.layoutArea = contentArea;
                 }
             }
+            C2DLogging.setPostMessage(() => `Prim: ${prim.id} has layoutArea: ${prim.layoutArea}`);
         }
 
         get isChildPositionAllowed(): boolean {

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

@@ -203,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]
@@ -245,6 +246,7 @@
             scaleX                ?: number,
             scaleY                ?: number,
             dontInheritParentScale?: boolean,
+            alignToPixel          ?: boolean,
             opacity               ?: number,
             zOrder                ?: number, 
             origin                ?: Vector2,
@@ -419,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

+ 57 - 28
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,
@@ -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();
@@ -348,15 +350,26 @@
 
             // Update the Global Transformation and visibility status of the changed primitives
             let rd = this._renderableData;
-            if ((rd._primDirtyList.length > 0) || context.forceRefreshPrimitive) {
-                sortedDirtyList = rd._primDirtyList.sort((a, b) => a.hierarchyDepth - b.hierarchyDepth);
+            let curPrimDirtyList = rd._primDirtyList;
+            if ((curPrimDirtyList.length > 0) || context.forceRefreshPrimitive) {
+                // From now on we use the 'curPrimDirtyList' variable to process the primitives that was marked as dirty
+                // But we also allocate a new array in the object's member to get the prim that will be dirty again during the process
+                //  and that would need another process next time.
+                rd._primDirtyList = new Array<Prim2DBase>();
+
+                // Sort the primitives to process them from the highest in the tree to the lowest
+                sortedDirtyList = curPrimDirtyList.sort((a, b) => a.hierarchyDepth - b.hierarchyDepth);
                 this.updateCachedStatesOf(sortedDirtyList, true);
             }
 
             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!
@@ -370,7 +383,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;
@@ -388,7 +401,7 @@
                 this._viewportSize.height = sh;
             }
 
-            if ((rd._primDirtyList.length > 0) || context.forceRefreshPrimitive) {
+            if ((curPrimDirtyList.length > 0) || context.forceRefreshPrimitive) {
                 // If the group is cached, set the dirty flag to true because of the incoming changes
                 this._cacheGroupDirty = this._isCachedGroup;
 
@@ -397,13 +410,15 @@
                 // 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
                     //  the hierarchyDepth in order to prepare primitives from top to bottom
                     if (!sortedDirtyList) {
-                        sortedDirtyList = rd._primDirtyList.sort((a, b) => a.hierarchyDepth - b.hierarchyDepth);
+                        sortedDirtyList = curPrimDirtyList.sort((a, b) => a.hierarchyDepth - b.hierarchyDepth);
                     }
 
                     sortedDirtyList.forEach(p => {
@@ -417,15 +432,14 @@
                 }
 
                 // Everything is updated, clear the dirty list
-                rd._primDirtyList.forEach(p => {
+                curPrimDirtyList.forEach(p => {
                     if (rd._primNewDirtyList.indexOf(p) === -1) {
                         p._resetPropertiesDirty();
                     } else {
                         p._setFlags(SmartPropertyPrim.flagNeedRefresh);
                     }
                 });
-                rd._primDirtyList.splice(0);
-                rd._primDirtyList = rd._primDirtyList.concat(rd._primNewDirtyList);
+                rd._primDirtyList = curPrimDirtyList.concat(rd._primNewDirtyList);
             }
 
             // A renderable group has a list of direct children that are also renderable groups, we recurse on them to also prepare them
@@ -798,6 +812,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;
@@ -808,11 +824,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();
@@ -822,21 +838,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._s2;
+                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);
@@ -854,6 +871,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) {
@@ -866,8 +889,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() {
@@ -919,6 +943,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;
             }
         }
 

+ 17 - 12
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,
@@ -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[];

File diff suppressed because it is too large
+ 611 - 404
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();

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

@@ -288,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]
@@ -329,6 +330,7 @@
             scaleX                ?: number,
             scaleY                ?: number,
             dontInheritParentScale?: boolean,
+            alignToPixel          ?: boolean,
             opacity               ?: number,
             zOrder                ?: number, 
             origin                ?: Vector2,
@@ -585,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;
         }

+ 71 - 70
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;
                     }
                 }

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

@@ -675,6 +675,7 @@
             } 
         }
 
+        @logProp()
         protected _triggerPropertyChanged(propInfo: Prim2DPropInfo, newValue: any) {
             if (this.isDisposed) {
                 return;
@@ -1103,13 +1104,13 @@
         }
 
         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);
                         if (curprim._isFlagSet(SmartPropertyPrim.flagUsePositioning)) {
@@ -1198,6 +1199,7 @@
         /**
          * Retrieve the boundingInfo for this Primitive, computed based on the primitive itself and NOT its children
          */
+        @logProp()
         public get levelBoundingInfo(): BoundingInfo2D {
             if (this._isFlagSet(SmartPropertyPrim.flagLevelBoundingInfoDirty)) {
                 if (this.updateLevelBoundingInfo()) {
@@ -1283,6 +1285,39 @@
             }
         }
 
+        public _getFlagsDebug(flags: number): string {
+            let res = "";
+            if (flags & SmartPropertyPrim.flagNoPartOfLayout)          res += "NoPartOfLayout, ";
+            if (flags & SmartPropertyPrim.flagLevelBoundingInfoDirty)  res += "LevelBoundingInfoDirty, ";
+            if (flags & SmartPropertyPrim.flagModelDirty)              res += "ModelDirty, ";
+            if (flags & SmartPropertyPrim.flagLayoutDirty)             res += "LayoutDirty, ";
+            if (flags & SmartPropertyPrim.flagLevelVisible)            res += "LevelVisible, ";
+            if (flags & SmartPropertyPrim.flagBoundingInfoDirty)       res += "BoundingInfoDirty, ";
+            if (flags & SmartPropertyPrim.flagIsPickable)              res += "IsPickable, ";
+            if (flags & SmartPropertyPrim.flagIsVisible)               res += "IsVisible, ";
+            if (flags & SmartPropertyPrim.flagVisibilityChanged)       res += "VisibilityChanged, ";
+            if (flags & SmartPropertyPrim.flagPositioningDirty)        res += "PositioningDirty, ";
+            if (flags & SmartPropertyPrim.flagTrackedGroup)            res += "TrackedGroup, ";
+            if (flags & SmartPropertyPrim.flagWorldCacheChanged)       res += "WorldCacheChanged, ";
+            if (flags & SmartPropertyPrim.flagChildrenFlatZOrder)      res += "ChildrenFlatZOrder, ";
+            if (flags & SmartPropertyPrim.flagZOrderDirty)             res += "ZOrderDirty, ";
+            if (flags & SmartPropertyPrim.flagActualOpacityDirty)      res += "ActualOpacityDirty, ";
+            if (flags & SmartPropertyPrim.flagPrimInDirtyList)         res += "PrimInDirtyList, ";
+            if (flags & SmartPropertyPrim.flagIsContainer)             res += "IsContainer, ";
+            if (flags & SmartPropertyPrim.flagNeedRefresh)             res += "NeedRefresh, ";
+            if (flags & SmartPropertyPrim.flagActualScaleDirty)        res += "ActualScaleDirty, ";
+            if (flags & SmartPropertyPrim.flagDontInheritParentScale)  res += "DontInheritParentScale, ";
+            if (flags & SmartPropertyPrim.flagGlobalTransformDirty)    res += "GlobalTransformDirty, ";
+            if (flags & SmartPropertyPrim.flagLayoutBoundingInfoDirty) res += "LayoutBoundingInfoDirty, ";
+            if (flags & SmartPropertyPrim.flagCollisionActor)          res += "CollisionActor, ";
+            if (flags & SmartPropertyPrim.flagModelUpdate)             res += "ModelUpdate, ";
+            if (flags & SmartPropertyPrim.flagLocalTransformDirty)     res += "LocalTransformDirty, ";
+            if (flags & SmartPropertyPrim.flagUsePositioning)          res += "UsePositioning, ";
+            if (flags & SmartPropertyPrim.flagComputingPositioning)    res += "ComputingPositioning, ";
+
+            return res.slice(0, res.length - 2);
+        }
+
         public static flagNoPartOfLayout          = 0x0000001;    // set if the primitive's position/size must not be computed by Layout Engine
         public static 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
@@ -1310,6 +1345,7 @@
         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;

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

@@ -224,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;
@@ -273,15 +262,14 @@
          * - scale: the initial scale of the primitive. default is 1. You can alternatively use scaleX &| scaleY to apply non uniform scale
          * - 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.
@@ -317,6 +305,7 @@
             scaleX                ?: number,
             scaleY                ?: number,
             dontInheritParentScale?: boolean,
+            alignToPixel          ?: boolean,
             opacity               ?: number,
             zOrder                ?: number, 
             origin                ?: Vector2,
@@ -325,7 +314,6 @@
             spriteScaleFactor     ?: Vector2,
             scale9                ?: Vector4,
             invertY               ?: boolean,
-            alignToPixel          ?: boolean,
             isVisible             ?: boolean,
             isPickable            ?: boolean,
             isContainer           ?: boolean,
@@ -364,6 +352,7 @@
             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;
@@ -552,7 +541,6 @@
         private _spriteFrame: number;
         private _scale9: Vector4;
         private _invertY: boolean;
-        private _alignToPixel: boolean;
     }
 
     export class Sprite2DInstanceData extends InstanceDataBase {

File diff suppressed because it is too large
+ 96 - 24
canvas2D/src/Engine/babylon.text2d.ts


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

@@ -406,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;
         }
 
@@ -452,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;
+        }
+        
+    }
+
+}

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

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

+ 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.xxx*vColor.xyz*vColor.a, color.x*vColor.a);
+#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) + 0.5) * irw) + irw / 2.0) + 0.5*irw;
+		y = ((floor((y / irh) + 0.5) * irh) + irh / 2.0) + 0.5*irh;
+	}
+
+	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.

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


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


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


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


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


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


File diff suppressed because it is too large
+ 165 - 253
dist/preview release/canvas2D/babylon.canvas2d.d.ts


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


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


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


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

@@ -8,6 +8,7 @@
   display: flex;
   font-size: 0.9em;
   font-family: "Inconsolata", sans-serif;
+  background-color: #242424;
   /**
  * A tool contained in the tree panel (available for each item of the tree)
  */
@@ -86,6 +87,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 +246,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; }

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

@@ -18,11 +18,21 @@ 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, newColors?: {
+            backgroundColor?: string;
+            backgroundColorLighter?: string;
+            backgroundColorLighter2?: string;
+            backgroundColorLighter3?: string;
+            color?: string;
+            colorTop?: string;
+            colorBot?: string;
+        });
         /**
          * 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 +100,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[];
@@ -132,6 +165,96 @@ declare module INSPECTOR {
             type: typeof BABYLON.PBRMaterial;
             properties: string[];
         };
+        'Canvas2D': {
+            type: typeof BABYLON.Canvas2D;
+        };
+        'Canvas2DEngineBoundData': {
+            type: typeof BABYLON.Canvas2DEngineBoundData;
+        };
+        'Ellipse2D': {
+            type: typeof BABYLON.Ellipse2D;
+        };
+        'Ellipse2DInstanceData': {
+            type: typeof BABYLON.Ellipse2DInstanceData;
+        };
+        'Ellipse2DRenderCache': {
+            type: typeof BABYLON.Ellipse2DRenderCache;
+        };
+        'Group2D': {
+            type: typeof BABYLON.Group2D;
+        };
+        'IntersectInfo2D': {
+            type: typeof BABYLON.IntersectInfo2D;
+        };
+        'Lines2D': {
+            type: typeof BABYLON.Lines2D;
+        };
+        'Lines2DInstanceData': {
+            type: typeof BABYLON.Lines2DInstanceData;
+        };
+        'Lines2DRenderCache': {
+            type: typeof BABYLON.Lines2DRenderCache;
+        };
+        'PrepareRender2DContext': {
+            type: typeof BABYLON.PrepareRender2DContext;
+        };
+        'Prim2DBase': {
+            type: typeof BABYLON.Prim2DBase;
+        };
+        'Prim2DClassInfo': {
+            type: typeof BABYLON.Prim2DClassInfo;
+        };
+        'Prim2DPropInfo': {
+            type: typeof BABYLON.Prim2DPropInfo;
+        };
+        'Rectangle2D': {
+            type: typeof BABYLON.Rectangle2D;
+        };
+        'Rectangle2DInstanceData': {
+            type: typeof BABYLON.Rectangle2DInstanceData;
+        };
+        'Rectangle2DRenderCache': {
+            type: typeof BABYLON.Rectangle2DRenderCache;
+        };
+        'Render2DContext': {
+            type: typeof BABYLON.Render2DContext;
+        };
+        'RenderablePrim2D': {
+            type: typeof BABYLON.RenderablePrim2D;
+        };
+        'ScreenSpaceCanvas2D': {
+            type: typeof BABYLON.ScreenSpaceCanvas2D;
+        };
+        'Shape2D': {
+            type: typeof BABYLON.Shape2D;
+        };
+        'Shape2DInstanceData': {
+            type: typeof BABYLON.Shape2DInstanceData;
+        };
+        'Sprite2D': {
+            type: typeof BABYLON.Sprite2D;
+        };
+        'Sprite2DInstanceData': {
+            type: typeof BABYLON.Sprite2DInstanceData;
+        };
+        'Sprite2DRenderCache': {
+            type: typeof BABYLON.Sprite2DRenderCache;
+        };
+        'Text2D': {
+            type: typeof BABYLON.Text2D;
+        };
+        'Text2DInstanceData': {
+            type: typeof BABYLON.Text2DInstanceData;
+        };
+        'Text2DRenderCache': {
+            type: typeof BABYLON.Text2DRenderCache;
+        };
+        'WorldSpaceCanvas2D': {
+            type: typeof BABYLON.WorldSpaceCanvas2D;
+        };
+        'WorldSpaceCanvas2DNode': {
+            type: typeof BABYLON.WorldSpaceCanvas2DNode;
+        };
     };
 }
 
@@ -177,6 +300,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 +312,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 +764,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 +811,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 +977,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 +1117,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 +1195,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
      */

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


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


+ 8 - 8
dist/preview release/loaders/babylon.glTFFileLoader.d.ts

@@ -326,7 +326,7 @@ declare module BABYLON {
     */
     class GLTFFileLoaderBase {
         static CreateRuntime(parsedData: any, scene: Scene, rootUrl: string): IGLTFRuntime;
-        static LoadBufferAsync(gltfRuntime: IGLTFRuntime, id: string, onSuccess: (buffer: ArrayBufferView) => void, onError: () => void): void;
+        static LoadBufferAsync(gltfRuntime: IGLTFRuntime, id: string, onSuccess: (buffer: ArrayBufferView) => void, onError: () => void, onProgress?: () => void): void;
         static LoadTextureBufferAsync(gltfRuntime: IGLTFRuntime, id: string, onSuccess: (buffer: ArrayBufferView) => void, onError: () => void): void;
         static CreateTextureAsync(gltfRuntime: IGLTFRuntime, id: string, buffer: ArrayBufferView, onSuccess: (texture: Texture) => void, onError: () => void): void;
         static LoadShaderStringAsync(gltfRuntime: IGLTFRuntime, id: string, onSuccess: (shaderString: string) => void, onError: () => void): void;
@@ -355,13 +355,13 @@ declare module BABYLON {
         /**
         * Import meshes
         */
-        importMeshAsync(meshesNames: any, scene: Scene, data: any, rootUrl: string, onSuccess?: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onError?: () => void): boolean;
+        importMeshAsync(meshesNames: any, scene: Scene, data: any, rootUrl: string, onSuccess?: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onError?: () => void, onProgress?: () => void): boolean;
         /**
         * Load scene
         */
-        loadAsync(scene: Scene, data: string | ArrayBuffer, rootUrl: string, onSuccess: () => void, onError: () => void): boolean;
+        loadAsync(scene: Scene, data: string, rootUrl: string, onSuccess: () => void, onError: () => void): boolean;
         private _loadShadersAsync(gltfRuntime, onload);
-        private _loadBuffersAsync(gltfRuntime, onload);
+        private _loadBuffersAsync(gltfRuntime, onload, onProgress?);
         private _createNodes(gltfRuntime);
     }
 }
@@ -446,7 +446,7 @@ declare module BABYLON {
         * Defines an override for loading the runtime
         * Return true to stop further extensions from loading the runtime
         */
-        loadRuntimeAsync(scene: Scene, data: string | ArrayBuffer, rootUrl: string, onSuccess: (gltfRuntime: IGLTFRuntime) => void, onError: () => void): boolean;
+        loadRuntimeAsync(scene: Scene, data: string, rootUrl: string, onSuccess: (gltfRuntime: IGLTFRuntime) => void, onError: () => void): boolean;
         /**
          * Defines an onverride for creating gltf runtime
          * Return true to stop further extensions from creating the runtime
@@ -456,7 +456,7 @@ declare module BABYLON {
         * Defines an override for loading buffers
         * Return true to stop further extensions from loading this buffer
         */
-        loadBufferAsync(gltfRuntime: IGLTFRuntime, id: string, onSuccess: (buffer: ArrayBufferView) => void, onError: () => void): boolean;
+        loadBufferAsync(gltfRuntime: IGLTFRuntime, id: string, onSuccess: (buffer: ArrayBufferView) => void, onError: () => void, onProgress?: () => void): boolean;
         /**
         * Defines an override for loading texture buffers
         * Return true to stop further extensions from loading this texture data
@@ -477,9 +477,9 @@ declare module BABYLON {
         * Return true to stop further extensions from loading this material
         */
         loadMaterialAsync(gltfRuntime: IGLTFRuntime, id: string, onSuccess: (material: Material) => void, onError: () => void): boolean;
-        static LoadRuntimeAsync(scene: Scene, data: string | ArrayBuffer, rootUrl: string, onSuccess: (gltfRuntime: IGLTFRuntime) => void, onError: () => void): void;
+        static LoadRuntimeAsync(scene: Scene, data: string, rootUrl: string, onSuccess: (gltfRuntime: IGLTFRuntime) => void, onError: () => void): void;
         static LoadRuntimeExtensionsAsync(gltfRuntime: IGLTFRuntime, onSuccess: () => void, onError: () => void): void;
-        static LoadBufferAsync(gltfRuntime: IGLTFRuntime, id: string, onSuccess: (bufferView: ArrayBufferView) => void, onError: () => void): void;
+        static LoadBufferAsync(gltfRuntime: IGLTFRuntime, id: string, onSuccess: (bufferView: ArrayBufferView) => void, onError: () => void, onProgress?: () => void): void;
         static LoadTextureAsync(gltfRuntime: IGLTFRuntime, id: string, onSuccess: (texture: Texture) => void, onError: () => void): void;
         static LoadShaderStringAsync(gltfRuntime: IGLTFRuntime, id: string, onSuccess: (shaderData: string) => void, onError: () => void): void;
         static LoadMaterialAsync(gltfRuntime: IGLTFRuntime, id: string, onSuccess: (material: Material) => void, onError: () => void): void;

+ 33 - 24
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]);
@@ -605,6 +602,7 @@ var BABYLON;
                 var tempVertexData = new BABYLON.VertexData();
                 var primitive = mesh.primitives[i];
                 if (primitive.mode !== 4) {
+                    // continue;
                 }
                 var attributes = primitive.attributes;
                 var accessor = null;
@@ -695,6 +693,7 @@ var BABYLON;
             }
             for (var i = 0; i < mesh.primitives.length; i++) {
                 if (mesh.primitives[i].mode !== 4) {
+                    //continue;
                 }
                 var subMesh = new BABYLON.SubMesh(index, verticesStarts[index], verticesCounts[index], indexStarts[index], indexCounts[index], newMesh, newMesh, true);
                 index++;
@@ -728,11 +727,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 +858,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;
@@ -1155,13 +1154,13 @@ var BABYLON;
             }
             return gltfRuntime;
         };
-        GLTFFileLoaderBase.LoadBufferAsync = function (gltfRuntime, id, onSuccess, onError) {
+        GLTFFileLoaderBase.LoadBufferAsync = function (gltfRuntime, id, onSuccess, onError, onProgress) {
             var buffer = gltfRuntime.buffers[id];
             if (BABYLON.GLTFUtils.IsBase64(buffer.uri)) {
                 setTimeout(function () { return onSuccess(new Uint8Array(BABYLON.GLTFUtils.DecodeBase64(buffer.uri))); });
             }
             else {
-                BABYLON.Tools.LoadFile(gltfRuntime.rootUrl + buffer.uri, function (data) { return onSuccess(new Uint8Array(data)); }, null, null, true, onError);
+                BABYLON.Tools.LoadFile(gltfRuntime.rootUrl + buffer.uri, function (data) { return onSuccess(new Uint8Array(data)); }, onProgress, null, true, onError);
             }
         };
         GLTFFileLoaderBase.LoadTextureBufferAsync = function (gltfRuntime, id, onSuccess, onError) {
@@ -1367,7 +1366,7 @@ var BABYLON;
         /**
         * Import meshes
         */
-        GLTFFileLoader.prototype.importMeshAsync = function (meshesNames, scene, data, rootUrl, onSuccess, onError) {
+        GLTFFileLoader.prototype.importMeshAsync = function (meshesNames, scene, data, rootUrl, onSuccess, onError, onProgress) {
             var _this = this;
             scene.useRightHandedSystem = true;
             var gltfRuntime = BABYLON.GLTFFileLoaderExtension.LoadRuntimeAsync(scene, data, rootUrl, function (gltfRuntime) {
@@ -1411,7 +1410,7 @@ var BABYLON;
                             onSuccess(meshes, null, skeletons);
                         }
                     });
-                });
+                }, onProgress);
                 if (GLTFFileLoader.IncrementalLoading && onSuccess) {
                     onSuccess(meshes, null, skeletons);
                 }
@@ -1476,7 +1475,7 @@ var BABYLON;
             }
         };
         ;
-        GLTFFileLoader.prototype._loadBuffersAsync = function (gltfRuntime, onload) {
+        GLTFFileLoader.prototype._loadBuffersAsync = function (gltfRuntime, onload, onProgress) {
             var hasBuffers = false;
             var processBuffer = function (buf, buffer) {
                 BABYLON.GLTFFileLoaderExtension.LoadBufferAsync(gltfRuntime, buf, function (bufferView) {
@@ -1828,7 +1827,7 @@ var BABYLON;
         * Defines an override for loading buffers
         * Return true to stop further extensions from loading this buffer
         */
-        GLTFFileLoaderExtension.prototype.loadBufferAsync = function (gltfRuntime, id, onSuccess, onError) {
+        GLTFFileLoaderExtension.prototype.loadBufferAsync = function (gltfRuntime, id, onSuccess, onError, onProgress) {
             return false;
         };
         /**
@@ -1880,11 +1879,11 @@ var BABYLON;
                 });
             });
         };
-        GLTFFileLoaderExtension.LoadBufferAsync = function (gltfRuntime, id, onSuccess, onError) {
+        GLTFFileLoaderExtension.LoadBufferAsync = function (gltfRuntime, id, onSuccess, onError, onProgress) {
             GLTFFileLoaderExtension.ApplyExtensions(function (loaderExtension) {
-                return loaderExtension.loadBufferAsync(gltfRuntime, id, onSuccess, onError);
+                return loaderExtension.loadBufferAsync(gltfRuntime, id, onSuccess, onError, onProgress);
             }, function () {
-                BABYLON.GLTFFileLoaderBase.LoadBufferAsync(gltfRuntime, id, onSuccess, onError);
+                BABYLON.GLTFFileLoaderBase.LoadBufferAsync(gltfRuntime, id, onSuccess, onError, onProgress);
             });
         };
         GLTFFileLoaderExtension.LoadTextureAsync = function (gltfRuntime, id, onSuccess, onError) {
@@ -1935,11 +1934,16 @@ var BABYLON;
 //# sourceMappingURL=babylon.glTFFileLoaderExtension.js.map
 
 /// <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 __extends = (this && this.__extends) || (function () {
+    var extendStatics = Object.setPrototypeOf ||
+        ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
+        function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
+    return function (d, b) {
+        extendStatics(d, b);
+        function __() { this.constructor = d; }
+        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
+    };
+})();
 var BABYLON;
 (function (BABYLON) {
     var BinaryExtensionBufferName = "binary_glTF";
@@ -2079,11 +2083,16 @@ var BABYLON;
 //# sourceMappingURL=babylon.glTFBinaryExtension.js.map
 
 /// <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 __extends = (this && this.__extends) || (function () {
+    var extendStatics = Object.setPrototypeOf ||
+        ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
+        function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
+    return function (d, b) {
+        extendStatics(d, b);
+        function __() { this.constructor = d; }
+        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
+    };
+})();
 var BABYLON;
 (function (BABYLON) {
     ;

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


+ 33 - 0
dist/preview release/loaders/babylon.objFileLoader.js

@@ -83,6 +83,8 @@ var BABYLON;
                     else if (key === "d") {
                         //d is dissolve for current material. It mean alpha for BABYLON
                         material.alpha = value;
+                        //Texture
+                        //This part can be improved by adding the possible options of texture
                     }
                     else if (key === "map_ka") {
                         // ambient texture map with a loaded image
@@ -99,6 +101,13 @@ var BABYLON;
                         material.specularTexture = MTLFileLoader._getTexture(rootUrl, value, scene);
                     }
                     else if (key === "map_ns") {
+                        //Specular
+                        //Specular highlight component
+                        //We must first get the folder of the image
+                        //
+                        //Not supported by BABYLON
+                        //
+                        //    continue;
                     }
                     else if (key === "map_bump") {
                         //The bump texture
@@ -107,33 +116,46 @@ var BABYLON;
                     else if (key === "map_d") {
                         // The dissolve of the material
                         material.opacityTexture = MTLFileLoader._getTexture(rootUrl, value, scene);
+                        //Options for illumination
                     }
                     else if (key === "illum") {
                         //Illumination
                         if (value === "0") {
+                            //That mean Kd == Kd
                         }
                         else if (value === "1") {
+                            //Color on and Ambient on
                         }
                         else if (value === "2") {
+                            //Highlight on
                         }
                         else if (value === "3") {
+                            //Reflection on and Ray trace on
                         }
                         else if (value === "4") {
+                            //Transparency: Glass on, Reflection: Ray trace on
                         }
                         else if (value === "5") {
+                            //Reflection: Fresnel on and Ray trace on
                         }
                         else if (value === "6") {
+                            //Transparency: Refraction on, Reflection: Fresnel off and Ray trace on
                         }
                         else if (value === "7") {
+                            //Transparency: Refraction on, Reflection: Fresnel on and Ray trace on
                         }
                         else if (value === "8") {
+                            //Reflection on and Ray trace off
                         }
                         else if (value === "9") {
+                            //Transparency: Glass on, Reflection: Ray trace off
                         }
                         else if (value === "10") {
+                            //Casts shadows onto invisible surfaces
                         }
                     }
                     else {
+                        // console.log("Unhandled expression at line : " + i +'\n' + "with value : " + line);
                     }
                 }
                 //At the end of the file, add the last material
@@ -517,6 +539,7 @@ var BABYLON;
                 //Comment or newLine
                 if (line.length === 0 || line.charAt(0) === '#') {
                     continue;
+                    //Get information about one position possible for the vertices
                 }
                 else if ((result = this.vertexPattern.exec(line)) !== null) {
                     //Create a Vector3 with the position x, y, z
@@ -538,6 +561,8 @@ var BABYLON;
                     // ["vt 0.1 0.2 0.3", "0.1", "0.2"]
                     //Add the Vector in the list of uvs
                     uvs.push(new BABYLON.Vector2(parseFloat(result[1]), parseFloat(result[2])));
+                    //Identify patterns of faces
+                    //Face could be defined in different type of pattern
                 }
                 else if ((result = this.facePattern3.exec(line)) !== null) {
                     //Value of result:
@@ -566,6 +591,8 @@ var BABYLON;
                     //Set the data for this face
                     setDataForCurrentFaceWithPattern1(result[1].trim().split(" "), // ["1", "2", "3"]
                     1);
+                    //Define a mesh or an object
+                    //Each time this keyword is analysed, create a new Object with all data for creating a babylonMesh
                 }
                 else if (this.group.test(line) || this.obj.test(line)) {
                     //Create a new mesh corresponding to the name of the group.
@@ -587,6 +614,7 @@ var BABYLON;
                     hasMeshes = true;
                     isFirstMaterial = true;
                     increment = 1;
+                    //Keyword for applying a material
                 }
                 else if (this.usemtl.test(line)) {
                     //Get the name of the material
@@ -616,12 +644,17 @@ var BABYLON;
                         meshesFromObj[meshesFromObj.length - 1].materialName = materialNameFromObj;
                         isFirstMaterial = false;
                     }
+                    //Keyword for loading the mtl file
                 }
                 else if (this.mtllib.test(line)) {
                     //Get the name of mtl file
                     fileToLoad = line.substring(7).trim();
+                    //Apply smoothing
                 }
                 else if (this.smooth.test(line)) {
+                    // smooth shading => apply smoothing
+                    //Toda  y I don't know it work with babylon and with obj.
+                    //With the obj file  an integer is set
                 }
                 else {
                     //If there is another possibility

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


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

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

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

File diff suppressed because it is too large
+ 1 - 0
dist/preview release/materialsLibrary/babylon.customMaterial.min.js


+ 10 - 5
dist/preview release/materialsLibrary/babylon.fireMaterial.js

@@ -1,9 +1,14 @@
 /// <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 __extends = (this && this.__extends) || (function () {
+    var extendStatics = Object.setPrototypeOf ||
+        ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
+        function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
+    return function (d, b) {
+        extendStatics(d, b);
+        function __() { this.constructor = d; }
+        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
+    };
+})();
 var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
     var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
     if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);

File diff suppressed because it is too large
+ 1 - 1
dist/preview release/materialsLibrary/babylon.fireMaterial.min.js


File diff suppressed because it is too large
+ 11 - 6
dist/preview release/materialsLibrary/babylon.furMaterial.js


File diff suppressed because it is too large
+ 1 - 1
dist/preview release/materialsLibrary/babylon.furMaterial.min.js


+ 14 - 9
dist/preview release/materialsLibrary/babylon.gradientMaterial.js

@@ -1,9 +1,14 @@
 /// <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 __extends = (this && this.__extends) || (function () {
+    var extendStatics = Object.setPrototypeOf ||
+        ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
+        function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
+    return function (d, b) {
+        extendStatics(d, b);
+        function __() { this.constructor = d; }
+        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
+    };
+})();
 var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
     var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
     if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
@@ -47,10 +52,10 @@ var BABYLON;
             _this.SHADOW2 = false;
             _this.SHADOW3 = false;
             _this.SHADOWS = false;
-            _this.SHADOWVSM0 = false;
-            _this.SHADOWVSM1 = false;
-            _this.SHADOWVSM2 = false;
-            _this.SHADOWVSM3 = false;
+            _this.SHADOWESM0 = false;
+            _this.SHADOWESM1 = false;
+            _this.SHADOWESM2 = false;
+            _this.SHADOWESM3 = false;
             _this.SHADOWPCF0 = false;
             _this.SHADOWPCF1 = false;
             _this.SHADOWPCF2 = false;

File diff suppressed because it is too large
+ 1 - 1
dist/preview release/materialsLibrary/babylon.gradientMaterial.min.js


+ 10 - 5
dist/preview release/materialsLibrary/babylon.gridMaterial.js

@@ -1,9 +1,14 @@
 /// <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 __extends = (this && this.__extends) || (function () {
+    var extendStatics = Object.setPrototypeOf ||
+        ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
+        function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
+    return function (d, b) {
+        extendStatics(d, b);
+        function __() { this.constructor = d; }
+        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
+    };
+})();
 var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
     var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
     if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);

+ 14 - 9
dist/preview release/materialsLibrary/babylon.lavaMaterial.js

@@ -1,9 +1,14 @@
 /// <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 __extends = (this && this.__extends) || (function () {
+    var extendStatics = Object.setPrototypeOf ||
+        ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
+        function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
+    return function (d, b) {
+        extendStatics(d, b);
+        function __() { this.constructor = d; }
+        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
+    };
+})();
 var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
     var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
     if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
@@ -46,10 +51,10 @@ var BABYLON;
             _this.SHADOW2 = false;
             _this.SHADOW3 = false;
             _this.SHADOWS = false;
-            _this.SHADOWVSM0 = false;
-            _this.SHADOWVSM1 = false;
-            _this.SHADOWVSM2 = false;
-            _this.SHADOWVSM3 = false;
+            _this.SHADOWESM0 = false;
+            _this.SHADOWESM1 = false;
+            _this.SHADOWESM2 = false;
+            _this.SHADOWESM3 = false;
             _this.SHADOWPCF0 = false;
             _this.SHADOWPCF1 = false;
             _this.SHADOWPCF2 = false;

+ 0 - 0
dist/preview release/materialsLibrary/babylon.lavaMaterial.min.js


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