Procházet zdrojové kódy

Merge branch 'master' into master

javalang před 8 roky
rodič
revize
7c98d4e04e
100 změnil soubory, kde provedl 103228 přidání a 13445 odebrání
  1. 1 0
      .gitignore
  2. 1 1
      .travis.yml
  3. 24 0
      .vscode/launch.json
  4. 1 0
      .vscode/settings.json
  5. 3350 1056
      Exporters/3ds Max/ActionsBuilder/Sources/babylon.max.js
  6. 3 0
      Exporters/3ds Max/BabylonExport.Entities/BabylonAbstractMesh.cs
  7. 16 0
      Exporters/3ds Max/BabylonExport.Entities/BabylonDirectionalLight.cs
  8. 0 3
      Exporters/3ds Max/BabylonExport.Entities/BabylonMesh.cs
  9. 9 0
      Exporters/3ds Max/BabylonExport.Entities/BabylonPBRMaterial.cs
  10. 17 2
      Exporters/3ds Max/BabylonExport.Entities/BabylonShadowGenerator.cs
  11. 4 0
      Exporters/3ds Max/BabylonExport.Entities/BabylonTexture.cs
  12. binární
      Exporters/3ds Max/Max2Babylon-0.6.0.zip
  13. binární
      Exporters/3ds Max/Max2Babylon-0.8.0.zip
  14. 1 1
      Exporters/3ds Max/Max2Babylon/2017/Max2Babylon2017.csproj
  15. 1 0
      Exporters/3ds Max/Max2Babylon/Exporter/BabylonExporter.Mesh.cs
  16. 5 5
      Exporters/3ds Max/Max2Babylon/Exporter/BabylonExporter.ShadowGenerator.cs
  17. 1 2
      Exporters/3ds Max/Max2Babylon/Forms/CameraPropertiesForm.Designer.cs
  18. 3 4
      Exporters/3ds Max/Max2Babylon/Forms/LightPropertiesForm.Designer.cs
  19. 1 1
      Exporters/3ds Max/Max2Babylon/Forms/LightPropertiesForm.cs
  20. 1 3
      Exporters/3ds Max/Max2Babylon/Forms/ObjectPropertiesForm.Designer.cs
  21. binární
      Exporters/Blender/Blender2Babylon-5.2.zip
  22. 13 13
      Exporters/Blender/io_export_babylon.py
  23. 2 2
      Exporters/Blender/src/babylon-js/__init__.py
  24. 4 1
      Exporters/Blender/src/babylon-js/json_exporter.py
  25. 5 2
      Exporters/Blender/src/babylon-js/world.py
  26. 26 6
      Exporters/Maya/Tools/babylonReskinTool.mel
  27. 0 0
      Exporters/Unity 5/EditorToolkit/Redist/readme.md
  28. 0 1109
      Playground/bootstrap/css/bootstrap-responsive.css
  29. 0 9
      Playground/bootstrap/css/bootstrap-responsive.min.css
  30. 0 6167
      Playground/bootstrap/css/bootstrap.css
  31. 0 9
      Playground/bootstrap/css/bootstrap.min.css
  32. binární
      Playground/bootstrap/img/glyphicons-halflings-white.png
  33. binární
      Playground/bootstrap/img/glyphicons-halflings.png
  34. 0 2280
      Playground/bootstrap/js/bootstrap.js
  35. 0 6
      Playground/bootstrap/js/bootstrap.min.js
  36. 459 0
      Playground/css/index.css
  37. 153 96
      Playground/debug.html
  38. 38 36
      Playground/frame.html
  39. 14 8
      Playground/frame.js
  40. 0 1
      Playground/hand.minified-1.2.js
  41. 123 65
      Playground/index-local.html
  42. 0 124
      Playground/index.css
  43. 151 96
      Playground/index.html
  44. 187 0
      Playground/index2_5.html
  45. 63 0
      Playground/js/actions.js
  46. 253 33
      Playground/index.js
  47. 0 0
      Playground/js/libs/fileSaver.js
  48. 13 13
      Playground/jszip.min.js
  49. 587 0
      Playground/js/libs/split.js
  50. 6 4
      Playground/package.json
  51. 82 0
      Playground/scripts/pointer events handling.js
  52. 30 29
      Playground/scripts/scripts.txt
  53. 1 1
      Playground/scripts/shadows.js
  54. 0 146
      Playground/splitbox.css
  55. 0 116
      Playground/splitbox.js
  56. 55 0
      Playground/test.html
  57. binární
      Playground/textures/babylonjs.mp4
  58. binární
      Playground/textures/babylonjs.webm
  59. 0 2
      Playground/xtag.min.js
  60. 676 560
      Tools/Gulp/config.json
  61. 189 183
      Tools/Gulp/custom.config.json
  62. 16 11
      Tools/Gulp/gulp-addModuleExports.js
  63. 9 1
      Tools/Gulp/gulpfile.js
  64. 6 5
      Tools/Gulp/package.json
  65. 240 0
      Tools/Gulp/profiling.html
  66. 12512 0
      Tools/Npm/Oimo.js
  67. 20676 0
      Tools/Npm/babylon.canvas2d.js
  68. 31 0
      Tools/Npm/babylon.core.js
  69. 43 0
      Tools/Npm/babylon.js
  70. 61376 0
      Tools/Npm/babylon.max.js
  71. 41 0
      Tools/Npm/babylon.noworker.js
  72. 1 0
      Tools/Npm/getfiles.bat
  73. 3 2
      Tools/Npm/package.json
  74. binární
      assets/sounds/explosion.wav
  75. binární
      assets/sounds/jump.wav
  76. binární
      assets/textures/Ground.jpg
  77. binární
      assets/textures/babylonjs.mp4
  78. binární
      assets/textures/babylonjs.webm
  79. 101 97
      canvas2D/readme.md
  80. 10 6
      canvas2D/src/Engine/babylon.bounding2d.ts
  81. 164 101
      canvas2D/src/Engine/babylon.canvas2d.ts
  82. 3 0
      canvas2D/src/Engine/babylon.canvas2dLayoutEngine.ts
  83. 9 4
      canvas2D/src/Engine/babylon.ellipse2d.ts
  84. 79 13
      canvas2D/src/Engine/babylon.fontTexture.ts
  85. 57 28
      canvas2D/src/Engine/babylon.group2d.ts
  86. 17 12
      canvas2D/src/Engine/babylon.lines2d.ts
  87. 22 1
      canvas2D/src/Engine/babylon.modelRenderCache.ts
  88. 611 404
      canvas2D/src/Engine/babylon.prim2dBase.ts
  89. 1 1
      canvas2D/src/Engine/babylon.primitiveCollisionManager.ts
  90. 9 4
      canvas2D/src/Engine/babylon.rectangle2d.ts
  91. 71 70
      canvas2D/src/Engine/babylon.renderablePrim2d.ts
  92. 7 7
      canvas2D/src/Engine/babylon.shape2d.ts
  93. 38 2
      canvas2D/src/Engine/babylon.smartPropertyPrim.ts
  94. 3 15
      canvas2D/src/Engine/babylon.sprite2d.ts
  95. 80 20
      canvas2D/src/Engine/babylon.text2d.ts
  96. 0 13
      canvas2D/src/Engine/babylon.wireFrame2d.ts
  97. 249 0
      canvas2D/src/Tools/babylon.c2dlogging.ts
  98. 160 432
      canvas2D/src/Tools/babylon.math2D.ts
  99. 14 1
      canvas2D/src/shaders/ellipse2d.vertex.fx
  100. 0 0
      canvas2D/src/shaders/lines2d.vertex.fx

+ 1 - 0
.gitignore

@@ -165,3 +165,4 @@ node_modules
 localDev/src/*
 /dist/preview release/babylon.custom.js
 /dist/preview release/babylon.custom.max.js
+/localDev/src/index.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

+ 24 - 0
.vscode/launch.json

@@ -2,6 +2,18 @@
     "version": "0.1.0",
     "configurations": [
         {
+            "name": "Launch sandbox (Chrome)",
+            "type": "chrome",
+            "request": "launch",
+            "url": "http://localhost:1338/sandbox/index-local.html",
+            "webRoot": "${workspaceRoot}/",
+            "sourceMaps": true,
+            "userDataDir": "${workspaceRoot}/.tempChromeProfileForDebug",
+            "runtimeArgs": [
+                "--enable-unsafe-es3-apis" 
+            ]
+        },         
+        {
             "name": "Launch playground (Chrome)",
             "type": "chrome",
             "request": "launch",
@@ -84,6 +96,18 @@
             "runtimeArgs": [
                 "--enable-unsafe-es3-apis" 
             ]
+        },
+        {
+            "name": "Launch Build Validation (Chrome)",
+            "type": "chrome",
+            "request": "launch",
+            "url": "http://localhost:1338/tests/validation/index.html",
+            "webRoot": "${workspaceRoot}/",
+            "sourceMaps": true,
+            "userDataDir": "${workspaceRoot}/.tempChromeProfileForDebug",
+            "runtimeArgs": [
+                "--enable-unsafe-es3-apis" 
+            ]
         }
     ]
 }

+ 1 - 0
.vscode/settings.json

@@ -9,6 +9,7 @@
         "**/.vs": true,        
         "**/.tempChromeProfileForDebug": true,
         "**/node_modules": true,
+        "**/dist": true,
         "**/temp": true,
         "**/.temp": true,
         "**/*.d.ts": true,

Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 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

@@ -169,6 +169,9 @@ namespace BabylonExport.Entities
         [DataMember]
         public bool disableLighting { get; set; }
 
+        [DataMember]
+        public bool twoSidedLighting { get; set; }
+
         public BabylonPBRMaterial() : base()
         {
             customType = "BABYLON.PBRMaterial";
@@ -180,6 +183,7 @@ namespace BabylonExport.Entities
             cameraExposure = 1.0f;
             cameraContrast = 1.0f;
             indexOfRefraction = 0.66f;
+            twoSidedLighting = false;
             useRadianceOverAlpha = true;
             useSpecularOverAlpha = true;
             usePhysicalLightFalloff = true;
@@ -209,5 +213,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;
+        }
     }
 }

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

@@ -71,6 +71,9 @@ namespace BabylonExport.Entities
         [DataMember]
         public string[] extensions { get; set; }
 
+        [DataMember]
+        public int samplingMode { get; set; }
+
         public BabylonTexture()
         {
             level = 1.0f;
@@ -85,6 +88,7 @@ namespace BabylonExport.Entities
             wrapV = 1;
             hasAlpha = false;
             coordinatesIndex = 0;
+            samplingMode = 3;
         }
     }
 }

binární
Exporters/3ds Max/Max2Babylon-0.6.0.zip


binární
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",

binární
Exporters/Blender/Blender2Babylon-5.2.zip


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

+ 2 - 2
Exporters/Blender/src/babylon-js/__init__.py

@@ -1,7 +1,7 @@
 bl_info = {
     'name': 'Babylon.js',
     'author': 'David Catuhe, Jeff Palmer',
-    'version': (5, 2, 0),
+    'version': (5, 2, 1),
     'blender': (2, 76, 0),
     'location': 'File > Export > Babylon.js (.babylon)',
     'description': 'Export Babylon.js scenes (.babylon)',
@@ -11,7 +11,7 @@ bl_info = {
 
 # allow module to be changed during a session (dev purposes)
 if "bpy" in locals():
-    print('Reloading TOB exporter')
+    print('Reloading .babylon exporter')
     import imp
     imp.reload(animation)
     imp.reload(armature)

+ 4 - 1
Exporters/Blender/src/babylon-js/json_exporter.py

@@ -66,6 +66,7 @@ class JsonExporter:
             self.materials = []
             self.multiMaterials = []
             self.sounds = []
+            self.needPhysics = False
 
             # Scene level sound
             if scene.attachedSound != '':
@@ -102,6 +103,8 @@ class JsonExporter:
                             Logger.log(self.fatalError)
                             return
 
+                        if hasattr(mesh, 'physicsImpostor'): self.needPhysics = True
+                        
                         if hasattr(mesh, 'instances'):
                             self.meshesAndNodes.append(mesh)
                         else:
@@ -161,7 +164,7 @@ class JsonExporter:
         file_handler = open(self.filepathMinusExtension + '.babylon', 'w', encoding='utf8')
         file_handler.write('{')
         file_handler.write('"producer":{"name":"Blender","version":"' + bpy.app.version_string + '","exporter_version":"' + format_exporter_version() + '","file":"' + JsonExporter.nameSpace + '.babylon"},\n')
-        self.world.to_scene_file(file_handler)
+        self.world.to_scene_file(file_handler, self.needPhysics)
 
         # Materials
         file_handler.write(',\n"materials":[')

+ 5 - 2
Exporters/Blender/src/babylon-js/world.py

@@ -31,12 +31,15 @@ class World:
 
         Logger.log('Python World class constructor completed')
 # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-    def to_scene_file(self, file_handler):
+    def to_scene_file(self, file_handler, needPhysics):
         write_bool(file_handler, 'autoClear', self.autoClear, True)
         write_color(file_handler, 'clearColor', self.clear_color)
         write_color(file_handler, 'ambientColor', self.ambient_color)
         write_vector(file_handler, 'gravity', self.gravity)
-
+        
+        if needPhysics:
+            write_bool(file_handler, 'physicsEnabled', True)
+            
         if hasattr(self, 'fogMode'):
             write_int(file_handler, 'fogMode', self.fogMode)
             write_color(file_handler, 'fogColor', self.fogColor)

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

@@ -1,10 +1,27 @@
 global proc reskinSelectedMeshes() {
-    $influencers = `intSliderGrp -q -value myReskinInfluencers`;
     $selection = `ls -sl`;
     $selected = size($selection);
     if ($selected > 0) {
         $skinName = `textFieldGrp -q -text myReskinName`;
+        $copyName = `textFieldGrp -q -text myUvsetName`;
+        $regenerate = `radioButtonGrp -q -select myReskinGenerate`;
+        $influencers = `intSliderGrp -q -value myReskinInfluencers`;
         if ($skinName != "") {
+            if ($copyName != "") {
+                for ($i = 0; $i < $selected; $i++) {
+                    string $selectedObject = $selection[$i];
+                    select $selectedObject;
+                    string $uvSets[] = `polyUVSet -q -allUVSets`;
+                    int $uvSize = `size($uvSets)`;
+                    if ($uvSize > 0) {
+                        string $defaultSet = $uvSets[0];
+                        if ($defaultSet != $copyName) {
+                            polyUVSet -copy -uvSet $defaultSet -nuv $copyName;
+                        }
+                    }
+                }
+                select $selection;
+            }
             $textField_exists = `objExists $skinName`;
             if ($textField_exists == 0) {
                 waitCursor -state 1;
@@ -13,7 +30,8 @@ global proc reskinSelectedMeshes() {
                 if ($selected > 1) {
                     $duplicateObj = `duplicate $selection`;
                     $createGrp = `group -n tempGroup`;
-                    $combine = `polyUnite -n $skinName $createGrp`;
+                    $mergeType = ($regenerate - 1);
+                    $combine = `polyUnite -muv $mergeType -n $skinName $createGrp`;
                     $deleteHistory = `delete -ch $combine`;
                     delete $createGrp;
                 } else {
@@ -26,7 +44,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 +60,10 @@ 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;
+    textFieldGrp -label "Copy Set Name" -text "" myUvsetName;
+    radioButtonGrp -label "UV Map Generation" -numberOfRadioButtons 3 -labelArray3 "No Merge" "Same Name" "Set Links" -select 2 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


Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 0 - 1109
Playground/bootstrap/css/bootstrap-responsive.css


Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 0 - 9
Playground/bootstrap/css/bootstrap-responsive.min.css


Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 0 - 6167
Playground/bootstrap/css/bootstrap.css


Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 0 - 9
Playground/bootstrap/css/bootstrap.min.css


binární
Playground/bootstrap/img/glyphicons-halflings-white.png


binární
Playground/bootstrap/img/glyphicons-halflings.png


Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 0 - 2280
Playground/bootstrap/js/bootstrap.js


Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 0 - 6
Playground/bootstrap/js/bootstrap.min.js


+ 459 - 0
Playground/css/index.css

@@ -0,0 +1,459 @@
+@import url("https://fonts.googleapis.com/css?family=Montserrat:300,400");
+@import url("https://maxcdn.bootstrapcdn.com/font-awesome/4.6.3/css/font-awesome.min.css");
+html,
+body {
+    width: 100%;
+    height: 100%;
+    margin: 0;
+    padding: 0;
+    overflow: hidden;
+    font-family: sans-serif;
+}
+.wrapper {
+    height: calc(100% - 40px - 30px); /* nvabar top and bottom*/
+    width: 100%;
+    display: -ms-flexbox;
+    display: flex;
+    -ms-flex-direction: row;
+    flex-direction: row;
+}
+.wrapper .gutter {
+    background-color: #f7f7f7;
+    background-repeat: no-repeat;
+    background-position: 50%;
+}
+.wrapper .gutter.light {
+    background-color: #f7f7f7;
+}
+.wrapper .gutter.dark {
+    background-color: #333;
+}
+
+.wrapper .gutter:hover {
+    cursor: ew-resize;
+}
+.wrapper .gutter.gutter-vertical {
+    background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAB4AAAAFAQMAAABo7865AAAABlBMVEVHcEzMzMzyAv2sAAAAAXRSTlMAQObYZgAAABBJREFUeF5jOAMEEAIEEFwAn3kMwcB6I2AAAAAASUVORK5CYII=");
+}
+.wrapper .gutter.gutter-horizontal {
+    background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAeCAYAAADkftS9AAAAIklEQVQoU2M4c+bMfxAGAgYYmwGrIIiDjrELjpo5aiZeMwF+yNnOs5KSvgAAAABJRU5ErkJggg==");
+}
+.wrapper #jsEditor {
+    padding-top:5px;
+    height: 100%;
+}
+
+.wrapper #jsEditor.light {
+    background-color: white;
+}
+.wrapper #jsEditor.dark {
+    background-color: #1e1e1e;
+}
+.wrapper #canvasZone {
+    height: 100%;
+}
+#renderCanvas {
+    width: 100%;
+    height: 100%;
+    touch-action: none;
+}
+#fpsLabel {
+    position: absolute;
+    right: 10px;
+    top: 50px;
+    cursor: default;
+    z-index:10;
+    background-color: #7283a0;
+    color:white;
+    padding:5px;
+    border-radius: 3px;
+    font-family: 'Montserrat'
+}
+.navbar {
+    height: 40px;
+    width: 100%;
+    font-family: "Montserrat";
+    font-weight: 400;
+    -webkit-user-select: none;
+    -moz-user-select: none;
+    -ms-user-select: none;
+    user-select: none;
+    position: relative;
+    z-index:5;
+    line-height: 40px;
+}
+.navbar.dark {
+    background-color: #333;
+    box-shadow: 0 3px 10px #000;
+}
+.navbar.light {
+    background-color: #efefef;
+    box-shadow: 0 3px 10px #999;
+}
+.navbar .title {
+    height: 40px;
+    padding-left: 10px;
+    color: #15A4FA;
+    display: inline-block;
+}
+.navbar .version {
+    height: 40px;
+    display: inline-block;
+    color: #7283a0;
+    margin-right: 20px;
+}
+.navbar .category {
+    height: 40px;
+    margin: 0 15px 0 15px;
+    display: inline-block;
+}
+.navbar .category.right {
+    position: absolute;
+    right: 0;
+    top: 0;
+}
+.button {
+    display: inline-block;
+    height: 25px;
+    line-height: 25px;
+    color: white;
+    background-color: #7283a0;
+    margin: 0 2px 0 2px;
+    padding: 0 10px 0 10px;
+    font-size: 0.85em;
+    border-radius: 3px;
+}
+
+.button i {
+    margin-left: 10px;
+}
+.button:hover {
+    cursor: pointer;
+    background-color: #15A4FA;
+}
+.navbar .button.run {
+    height: 30px;
+    line-height: 30px;
+    background-color: #15A4FA;
+    font-size: 1.0em;
+}
+.navbar .select {
+    position: relative;
+}
+.navbar .select:after {
+    font-family: 'FontAwesome', sans-serif;
+    content: "\00a0 \00a0 \00a0 \f078";
+}
+.navbar .select .toDisplay {
+    border: 1px solid #7283a0;
+    position: absolute;
+    z-index: 10;
+    left: 0;
+    top: 25px;
+    min-width: 100%;
+    display: none;
+}
+.navbar .select .toDisplay .option {
+    font-size: 0.9em;
+    height: 35px;
+    line-height: 35px;
+    padding: 0px 5px 0px 5px;
+    text-align: center;
+    border-bottom : 1px solid rgba(0,0,0,0.1);
+}
+
+.navbar .select .toDisplay .option.light:hover {
+    cursor: pointer;
+    background-color: #d9d9d9;
+}
+
+
+.navbar .select .toDisplay .option.dark {
+    background-color: #333;
+    color: white;
+}
+.navbar .select .toDisplay .option.light {
+    background-color: white;
+    color: #7283a0;
+}
+.navbar .select .toDisplay .option.dark:hover {
+    cursor: pointer;
+    background-color: #555;
+}
+
+.navbar .select .toDisplayBig {
+    border: 1px solid #7283a0;
+    border-radius: 5px;
+    position: absolute;
+    z-index: 10;
+    top: 32px;
+    width:550px;
+    max-height:350px;
+    right:0;
+    position:absolute;
+    font-size:0.8em;
+    display: none;
+    
+}
+
+.navbar .select .toDisplayBig.light {
+    background-color: white;    
+    color: #15A4FA;
+}
+
+.navbar .select .toDisplayBig.dark {
+    background-color: #333;    
+    color:white;
+}
+
+.navbar .select .toDisplayBig ul {
+    column-count: 3;        
+    padding:0;
+    margin:0;
+    list-style: none;
+}
+
+.navbar .select .toDisplayBig ul li {
+    padding:0 5px 0 5px;
+}
+
+.navbar .select .toDisplayBig ul li:hover {
+    cursor: pointer;
+}
+.navbar .select .toDisplayBig ul li.light:hover {
+    background-color: #d9d9d9;
+}
+.navbar .select .toDisplayBig ul li.dark:hover {
+    background-color: #555;
+}
+
+
+.navbar .select .toDisplayBig a {
+    text-decoration: none;
+}
+
+.navbar .select .toDisplayBig a.dark {
+    color: white;
+}
+
+.navbar .select .toDisplayBig a.light {
+    color: #7283a0;
+}
+
+
+
+.navbar .check:after {
+    font-family: 'FontAwesome', sans-serif;
+    content: "\00a0 \00a0 \00a0 \f14a";
+}
+.navbar .check.uncheck {
+    background-color: #8290aa;
+}
+.navbar .check.uncheck:after {
+    font-family: 'FontAwesome', sans-serif;
+    content: "\00a0 \00a0 \00a0 \f096";
+}
+#errorZone {
+    display:none;
+    position: absolute;
+    width: 50%;
+    left: 25%;
+    bottom: 40px;
+    background-color: #C73228;
+    padding:20px;
+    border-radius: 5px;
+    color:white;
+    font-family: 'Inconsolata';
+}
+#errorZone button {
+    position:absolute;
+    top : 3px;
+    right: 10px;
+    padding: 0;
+    cursor: pointer;
+    background: transparent;
+    border: 0;
+    -webkit-appearance: none;
+    color: #000;
+    text-shadow: 0 1px 0 #fff;
+    opacity: .4;
+    font-size: 1.8em;
+}
+
+/* Navbar bottom */
+
+.navbarBottom {
+    height:30px;
+    width:100%;
+    line-height:30px;
+    position:relative;
+    font-family: 'Montserrat';
+}
+.navbarBottom.dark {
+    background-color: #333;
+}
+.navbarBottom.light {
+    background-color: #efefef;
+}
+
+.navbarBottom #statusBar {
+    line-height:30px;
+    color: #E74C3C;
+    font-family: 'Inconsolata';
+    padding-left:20px;
+}
+
+
+.navbarBottom .links {
+    position:absolute;
+    right : 0;
+    top:-1px;
+    height:30px;
+    padding-right:20px;
+}
+.navbarBottom .links .link{
+    height:30px;
+    display:inline-block;
+    color:#999;
+    padding: 0 10px 0 10px;
+    margin : 0 5px 0 5px;
+    font-size:0.8em;
+}
+.navbarBottom .links .link.light:hover{
+    color:#999;
+    background-color:#333;
+}
+.navbarBottom .links .link.dark:hover{
+    color:#333;
+    background-color:#eee;
+}
+.navbarBottom .links .link a{
+    text-decoration: none;
+    color:#999;
+    display: inline-block;
+}
+
+/* MONACO */
+
+.monaco-editor .container:before,
+.monaco-editor .row:before {
+    content: "";
+    display: inherit;
+}
+.monaco-editor .container:after,
+.monaco-editor .row:after {
+    clear: inherit;
+}
+.monaco-editor .container {
+    width: auto;
+    margin: inherit;
+    padding: inherit;
+}
+.monaco-editor .close {
+    float: none;
+    font-size: inherit;
+    font-weight: inherit;
+    line-height: inherit;
+    color: inherit;
+    text-shadow: inherit;
+    opacity: inherit;
+    filter: inherit;
+}
+.monaco-editor .row {
+    margin: inherit;
+}
+.monaco-editor .invisible {
+    visibility: visible;
+}
+.monaco-editor .view-lines {
+    font-family: 'Inconsolata' !important;
+}
+/* Save form & co */
+
+.save-message {
+    display: none;
+    position:absolute;
+    top:40px; /* navbar top */
+    width: 100%;
+    z-index:5;
+    text-align: center;
+    font-size: 0.8em;
+    line-height: 2em;
+    cursor:pointer;
+}
+
+.save-message.light {
+    background-color: rgba(239, 239, 239, 0.9);
+    color: #7283a0;
+}
+
+.save-message.dark {
+    background-color: rgba(51, 51, 51, 0.9);
+    color: #eee;
+}
+
+.save-layer {
+    display: none;
+    position: absolute;
+    top: 0;
+    left: 0;
+    width: 100%;
+    height: 100%;
+    background-color: rgba(120, 120, 120, .5);
+    text-align: center;
+}
+.save-layer .save-form {
+    position: absolute;
+    top: 150px;
+    left: calc(50% - 205px);
+    width: 410px;
+    height: 370px;
+    padding-top: 15px;
+    -webkit-border-radius: 6px;
+    -moz-border-radius: 6px;
+    border-radius: 6px;
+    background-color: rgba(27, 27, 27, 0.75);
+    border-color: #252525;
+    color: white;
+    font-family: "Montserrat";
+    font-size: 14px;
+}
+.save-layer .save-form .separator {
+    width: 350px;
+    border-bottom: 1px solid #999;
+    margin: auto;
+    margin-bottom: 10px;
+}
+.save-layer .save-form input,
+.save-layer .save-form textarea {
+    display:block;
+    width: 350px;
+    margin:auto;
+    margin-bottom: 20px;
+    font-family: "Montserrat";
+    padding:5px;
+}
+
+/*Media queries*/
+
+@media (max-width: 1600px) {
+    .desktopOnly {
+        display: none !important;
+    }
+}
+@media (max-width: 1375px) {
+    .desktopOnly {
+        display: none !important;
+    }
+    .desktopTabletOnly {
+        display: none !important;
+    }
+}
+@media (max-width: 975px) {
+    .title {
+        display : none !important;
+    }
+    .version {
+        display : none !important;
+    }
+}

+ 153 - 96
Playground/debug.html

@@ -1,132 +1,189 @@
 <!DOCTYPE html>
 <html>
+
 <head>
     <title>Babylon.js Playground</title>
+    <meta charset='utf-8' />
+    <meta name="viewport" content="width=device-width, user-scalable=no">
     <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.js"></script>
-    <!--x-tag-->
-    <script src="xtag.min.js"></script>
-    <script src="splitbox.js"></script>
-    <link href="splitbox.css" rel="stylesheet" />
+    <!--For canvas/code separator-->
+    <script src="js/libs/split.js"></script>
+
+    <script src="https://cdnjs.cloudflare.com/ajax/libs/dat-gui/0.6.2/dat.gui.min.js"></script>
     <!-- jszip -->
-    <script src="jszip.min.js"></script>
-    <script src="fileSaver.js"></script>
-    <!-- Bootstrap -->
-    <link href="bootstrap/css/bootstrap.css" rel="stylesheet">
+    <script src="js/libs/jszip.min.js"></script>
+    <script src="js/libs/fileSaver.js"></script>
+    <!--Monaco-->
     <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/babylon.max.js"></script>
-    <script src="https://babylonjs.azurewebsites.net/babylon.canvas2d.js"></script>
-    
-    <script src="https://babylonjs.azurewebsites.net/lib/babylon.fireMaterial.js"></script>
-    <script src="https://babylonjs.azurewebsites.net/lib/babylon.waterMaterial.js"></script>
-    <script src="https://babylonjs.azurewebsites.net/lib/babylon.lavaMaterial.js"></script>
-    <script src="https://babylonjs.azurewebsites.net/lib/babylon.normalMaterial.js"></script>
-    <script src="https://babylonjs.azurewebsites.net/lib/babylon.skyMaterial.js"></script>
-    <script src="https://babylonjs.azurewebsites.net/lib/babylon.triPlanarMaterial.js"></script>
-    <script src="https://babylonjs.azurewebsites.net/lib/babylon.terrainMaterial.js"></script>
-    <script src="https://babylonjs.azurewebsites.net/lib/babylon.gradientMaterial.js"></script>
-    <script src="https://babylonjs.azurewebsites.net/lib/babylon.furMaterial.js"></script>
-    <script src="https://babylonjs.azurewebsites.net/lib/babylon.gridMaterial.js"></script>
-
-    <script src="https://babylonjs.azurewebsites.net/lib/babylon.brickProceduralTexture.js"></script>
-    <script src="https://babylonjs.azurewebsites.net/lib/babylon.cloudProceduralTexture.js"></script>
-    <script src="https://babylonjs.azurewebsites.net/lib/babylon.fireProceduralTexture.js"></script>
-    <script src="https://babylonjs.azurewebsites.net/lib/babylon.grassProceduralTexture.js"></script>
-    <script src="https://babylonjs.azurewebsites.net/lib/babylon.marbleProceduralTexture.js"></script>
-    <script src="https://babylonjs.azurewebsites.net/lib/babylon.roadProceduralTexture.js"></script>
-    <script src="https://babylonjs.azurewebsites.net/lib/babylon.starfieldProceduralTexture.js"></script>
-    <script src="https://babylonjs.azurewebsites.net/lib/babylon.woodProceduralTexture.js"></script>
-
-    <script src="https://babylonjs.azurewebsites.net/lib/babylon.asciiArtPostProcess.js"></script>
-    <script src="https://babylonjs.azurewebsites.net/lib/babylon.digitalRainPostProcess.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>
+    <script src="https://www.babylonjs.com/cannon.js"></script>
+    <script src="https://www.babylonjs.com/Oimo.js"></script>
+    <script src="https://www.babylonjs.com/babylon.max.js"></script>
+    <script src="https://www.babylonjs.com/babylon.canvas2d.js"></script>
+    <script src="https://www.babylonjs.com/babylon.inspector.bundle.js"></script>
+
+    <script src="https://www.babylonjs.com/lib/babylon.fireMaterial.min.js"></script>
+    <script src="https://www.babylonjs.com/lib/babylon.waterMaterial.min.js"></script>
+    <script src="https://www.babylonjs.com/lib/babylon.lavaMaterial.min.js"></script>
+    <script src="https://www.babylonjs.com/lib/babylon.normalMaterial.min.js"></script>
+    <script src="https://www.babylonjs.com/lib/babylon.skyMaterial.min.js"></script>
+    <script src="https://www.babylonjs.com/lib/babylon.triPlanarMaterial.min.js"></script>
+    <script src="https://www.babylonjs.com/lib/babylon.terrainMaterial.min.js"></script>
+    <script src="https://www.babylonjs.com/lib/babylon.gradientMaterial.min.js"></script>
+    <script src="https://www.babylonjs.com/lib/babylon.furMaterial.min.js"></script>
+    <script src="https://www.babylonjs.com/lib/babylon.gridMaterial.min.js"></script>
+    <script src="https://www.babylonjs.com/lib/babylon.shadowOnlyMaterial.min.js"></script>
+
+    <script src="https://www.babylonjs.com/lib/babylon.brickProceduralTexture.min.js"></script>
+    <script src="https://www.babylonjs.com/lib/babylon.cloudProceduralTexture.min.js"></script>
+    <script src="https://www.babylonjs.com/lib/babylon.fireProceduralTexture.min.js"></script>
+    <script src="https://www.babylonjs.com/lib/babylon.grassProceduralTexture.min.js"></script>
+    <script src="https://www.babylonjs.com/lib/babylon.marbleProceduralTexture.min.js"></script>
+    <script src="https://www.babylonjs.com/lib/babylon.roadProceduralTexture.min.js"></script>
+    <script src="https://www.babylonjs.com/lib/babylon.starfieldProceduralTexture.min.js"></script>
+    <script src="https://www.babylonjs.com/lib/babylon.woodProceduralTexture.min.js"></script>
+
+    <script src="https://www.babylonjs.com/lib/babylon.asciiArtPostProcess.min.js"></script>
+    <script src="https://www.babylonjs.com/lib/babylon.digitalRainPostProcess.min.js"></script>
+
+    <script src="https://www.babylonjs.com/lib/babylon.glTFFileLoader.js"></script>
+    <script src="https://www.babylonjs.com/lib/babylon.objFileLoader.js"></script>
+    <script src="https://www.babylonjs.com/lib/babylon.stlFileLoader.js"></script>
 
     <script src="https://rawgit.com/BabylonJS/Extensions/master/ClonerSystem/src/babylonx.cloner.js"></script>
+
     <script src="https://rawgit.com/BabylonJS/Extensions/master/CompoundShader/src/babylonx.CompoundShader.js"></script>
-    <link href="index.css" rel="stylesheet" />
+    <link href="css/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 class="navbar">
+        <div class="title">
+            Babylon.js Playground
+        </div>
+        <div class="version" id="mainTitle">
+            v3.0-alpha
+        </div>
+
+        <div class="category">
+            <div class="button run" id="runButton">Run <i class="fa fa-play" aria-hidden="true"></i></div>
+        </div>
+
+
+        <div class="category">
+            <div class="button" id="newButton">New<i class="fa fa-file" aria-hidden="true"></i></div>
+            <div class="button" id="clearButton">Clear<i class="fa fa-trash" aria-hidden="true"></i></div>
+        </div>
+
+        <div class="category">
+            <div class="button" id="saveButton">Save <i class="fa fa-floppy-o" aria-hidden="true"></i></div>
+            <div class="button" id="zipButton">Zip<i class="fa fa-download" aria-hidden="true"></i></div>
+        </div>
+
+
+        <div class="category desktopOnly">
+            <div class="button select"><span id="currentFontSize">Font: 14</span>
+                <div class="toDisplay">
+                    <div class="option" onclick="setFontSize(12);">12</div>
+                    <div class="option" onclick="setFontSize(14);">14</div>
+                    <div class="option" onclick="setFontSize(16);">16</div>
+                    <div class="option" onclick="setFontSize(18);">18</div>
+                    <div class="option" onclick="setFontSize(20);">20</div>
+                    <div class="option" onclick="setFontSize(22);">22</div>
+                </div>
             </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 class="button select">Theme
+                <div class="toDisplay">
+                    <div class="option" id="darkTheme">Dark</div>
+                    <div class="option" id="lightTheme">Light</div>
+                </div>
             </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="category desktopTabletOnly">
+            <div class="button select">Settings
+                <div class="toDisplay">
+                    <div class="option" id='safemodeToggle'>Safe mode <i class="fa fa-square-o" aria-hidden="true"></i></div>
+                    <div class="option checked" id="editorButton">Editor <i class="fa fa-check-square" aria-hidden="true"></i>
+                    </div>
+                    <div class="option" id="fullscreenButton">Fullscreen</div>
+                    <div class="option" id="metadataButton">Metadata</div>
+                </div>
             </div>
-            <div class="btn-group pull-right">
-                <button class="btn" id="fullscreenButton">Fullscreen</button>
+
+            <div class="button check uncheck" id="debugButton">Debug layer</div>
+        </div>
+
+
+
+        <div class="category right">
+            <div class="button select desktopTabletOnly"><span id="currentVersion">Version: Latest</span>
+                <div class="toDisplay">
+                    <div class="option" onclick="setVersion('latest');">Latest</div>
+                    <div class="option" onclick="setVersion('2.5');">2.5</div>
+                </div>
             </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 class="button select"> <span id="currentScript">Scenes</span>
+                <div class="toDisplayBig">
+                    <ul id="scriptsList">
+                    </ul>
+                </div>
             </div>
         </div>
+        <div class="save-message" id="saveMessage">
+            This PG has no metadata. Click save to add them.
+        </div>
     </div>
 
-    <x-splitbox>
+    <div class="wrapper">
         <div id="jsEditor"></div>
-        <div splitter></div>
         <div id="canvasZone">
             <canvas touch-action="none" id="renderCanvas"></canvas>
         </div>
-    </x-splitbox>
+    </div>
 
     <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 class="navbarBottom">
+        <div id="statusBar"></div>
+        <div class="links">
+            <div class='link'> <a target='_new' href="http://www.html5gamedevs.com/forum/16-babylonjs/">Forum</a></div>
+            <div class='link'><a target='_new' href="https://www.babylonjs.com/sandbox">Sandbox</a></div>
+            <div class='link'><a target='_new' href="https://github.com/BabylonJS/Babylon.js/wiki">Wiki</a></div>
+            <div class='link'><a target='_new' href="https://doc.babylonjs.com">Documentation</a></div>
+            <div class='link'><a target='_new' href="https://doc.babylonjs.com/playground">Playground Search</a></div>
+        </div>
+    </div>
+
+    <div id="saveLayer" class="save-layer">
+        <div class="save-form">
+            <label for="saveFormTitle">TITLE</label>
+            <div class="separator"></div>
+            <input type="text" maxlength="120" id="saveFormTitle" class="save-form-title">
+
+            <label for="saveFormDescription">DESCRIPTION</label>
+            <div class="separator"></div>
+            <textarea id="saveFormDescription" rows="4" cols="10"></textarea>
+
+            <label for="saveFormTags">TAGS (separated by comma)</label>
+            <div class="separator"></div>
+            <textarea id="saveFormTags" rows="4" cols="10"></textarea>
+
+            <div class="save-form-buttons" id="saveFormButtons">
+
+                <div id="saveFormButtonOk" class="button">OK</div>
+                <div id="saveFormButtonCancel" class="button">Cancel</div>
+            </div>
         </div>
     </div>
 
     <script src="https://code.jquery.com/jquery.js"></script>
-    <script src="bootstrap/js/bootstrap.js"></script>
-    <script src="index.js"></script>
+
+    <script src="js/actions.js"></script>
+    <script src="js/index.js"></script>
 </body>
-</html>
+
+</html>

+ 38 - 36
Playground/frame.html

@@ -1,47 +1,48 @@
 <!DOCTYPE html>
 <html>
+
 <head>
     <title>Babylon.js Playground</title>
-    <script src="hand.minified-1.2.js"></script>
     <script src="https://code.jquery.com/pep/0.4.2/pep.min.js"></script>
-    <script src="https://babylonjs.azurewebsites.net/poly2tri.js"></script>    
-    <!-- Babylon.js -->    
-    <script src="https://babylonjs.azurewebsites.net/cannon.js"></script>
-    <script src="https://babylonjs.azurewebsites.net/Oimo.js"></script>
-    <script src="https://babylonjs.azurewebsites.net/babylon.js"></script>
-    <script src="https://babylonjs.azurewebsites.net/babylon.canvas2d.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>
-    
+    <!-- Babylon.js -->
+    <script src="https://www.babylonjs.com/cannon.js"></script>
+    <script src="https://www.babylonjs.com/Oimo.js"></script>
+    <script src="https://www.babylonjs.com/babylon.js"></script>
+    <script src="https://www.babylonjs.com/babylon.canvas2d.js"></script>
+
+    <script src="https://www.babylonjs.com/lib/babylon.fireMaterial.min.js"></script>
+    <script src="https://www.babylonjs.com/lib/babylon.waterMaterial.min.js"></script>
+    <script src="https://www.babylonjs.com/lib/babylon.lavaMaterial.min.js"></script>
+    <script src="https://www.babylonjs.com/lib/babylon.normalMaterial.min.js"></script>
+    <script src="https://www.babylonjs.com/lib/babylon.skyMaterial.min.js"></script>
+    <script src="https://www.babylonjs.com/lib/babylon.triPlanarMaterial.min.js"></script>
+    <script src="https://www.babylonjs.com/lib/babylon.terrainMaterial.min.js"></script>
+    <script src="https://www.babylonjs.com/lib/babylon.gradientMaterial.min.js"></script>
+    <script src="https://www.babylonjs.com/lib/babylon.furMaterial.min.js"></script>
+    <script src="https://www.babylonjs.com/lib/babylon.gridMaterial.min.js"></script>
+    <script src="https://www.babylonjs.com/lib/babylon.shadowOnlyMaterial.min.js"></script>
+
+    <script src="https://www.babylonjs.com/lib/babylon.brickProceduralTexture.min.js"></script>
+    <script src="https://www.babylonjs.com/lib/babylon.cloudProceduralTexture.min.js"></script>
+    <script src="https://www.babylonjs.com/lib/babylon.fireProceduralTexture.min.js"></script>
+    <script src="https://www.babylonjs.com/lib/babylon.grassProceduralTexture.min.js"></script>
+    <script src="https://www.babylonjs.com/lib/babylon.marbleProceduralTexture.min.js"></script>
+    <script src="https://www.babylonjs.com/lib/babylon.roadProceduralTexture.min.js"></script>
+    <script src="https://www.babylonjs.com/lib/babylon.starfieldProceduralTexture.min.js"></script>
+    <script src="https://www.babylonjs.com/lib/babylon.woodProceduralTexture.min.js"></script>
+
+    <script src="https://www.babylonjs.com/lib/babylon.asciiArtPostProcess.min.js"></script>
+    <script src="https://www.babylonjs.com/lib/babylon.digitalRainPostProcess.min.js"></script>
+
+    <script src="https://www.babylonjs.com/lib/babylon.glTFFileLoader.js"></script>
+    <script src="https://www.babylonjs.com/lib/babylon.objFileLoader.js"></script>
+    <script src="https://www.babylonjs.com/lib/babylon.stlFileLoader.js"></script>
+
     <script src="https://rawgit.com/BabylonJS/Extensions/master/ClonerSystem/src/babylonx.cloner.js"></script>
     <script src="https://rawgit.com/BabylonJS/Extensions/master/CompoundShader/src/babylonx.CompoundShader.js"></script>
     <link href="frame.css" rel="stylesheet" />
 </head>
+
 <body>
     <canvas touch-action="none" id="renderCanvas"></canvas>
 
@@ -53,4 +54,5 @@
     <script src="https://code.jquery.com/jquery.js"></script>
     <script src="frame.js"></script>
 </body>
-</html>
+
+</html>

+ 14 - 8
Playground/frame.js

@@ -1,5 +1,5 @@
 (function () {
-    var snippetUrl = "//babylonjs-api.azurewebsites.net/api/snippet";
+    var snippetUrl = "https://babylonjs-api2.azurewebsites.net/snippets";
     var currentSnippetToken;
     var engine;
     var fpsLabel = document.getElementById("fpsLabel");
@@ -15,6 +15,7 @@
             if (xhr.readyState === 4) {
                 if (xhr.status === 200) {
                     blockEditorChange = true;
+                    console.log(xhr.responseText);
                     jsEditor.setValue(xhr.responseText);
                     jsEditor.setPosition({ lineNumber: 0, column: 0 });
                     blockEditorChange = false;
@@ -30,6 +31,10 @@
         xhr.send(null);
     };
 
+    var showError = function(error) {
+        console.warn(error);
+    };
+
     compileAndRun = function (code) {
         try {
 
@@ -103,7 +108,7 @@
             }
 
         } catch (e) {
-            showError(e.message);
+            // showError(e.message);
         }
     };
     window.addEventListener("resize", function () {
@@ -122,7 +127,7 @@
         }
 
         location.hash = splits.join("#");
-    }
+    };
 
     var checkHash = function () {
         if (location.hash) {
@@ -133,18 +138,19 @@
                 xmlHttp.onreadystatechange = function () {
                     if (xmlHttp.readyState === 4) {
                         if (xmlHttp.status === 200) {
-                            var snippet = JSON.parse(xmlHttp.responseText);
-                            compileAndRun(snippet.code.toString());
+                            var snippetCode = JSON.parse(JSON.parse(xmlHttp.responseText)[0].jsonPayload).code;
+                            compileAndRun(snippetCode);
 
                             document.getElementById("refresh").addEventListener("click", function () {
-                                compileAndRun(snippet.code.toString());
+                                compileAndRun(snippetCode);
                             });
                         }
                     }
-                }
+                };
 
                 var hash = location.hash.substr(1);
                 currentSnippetToken = hash.split("#")[0];
+                if(!hash.split("#")[1]) hash += "#0";
 
                 xmlHttp.open("GET", snippetUrl + "/" + hash.replace("#", "/"));
                 xmlHttp.send();
@@ -154,7 +160,7 @@
 
             }
         }
-    }
+    };
 
     checkHash();
 

Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 0 - 1
Playground/hand.minified-1.2.js


+ 123 - 65
Playground/index-local.html

@@ -1,101 +1,159 @@
 <!DOCTYPE html>
 <html>
+
 <head>
     <title>Babylon.js Playground</title>
+    <meta charset='utf-8' />
+    <meta name="viewport" content="width=device-width, user-scalable=no">
     <script src="https://code.jquery.com/pep/0.4.2/pep.min.js"></script>
-    <script src="http://www.babylonjs.com/poly2tri.js"></script>
+    <!--For canvas/code separator-->
+    <script src="js/libs/split.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="js/libs/jszip.min.js"></script>
+    <script src="js/libs/fileSaver.js"></script>
+    <!--Monaco-->
     <script src="node_modules/monaco-editor/min/vs/loader.js"></script>
-    <!-- Babylon.js -->    
-	<script src="../tools/DevLoader/BabylonLoader.js"></script>
-    <link href="index.css" rel="stylesheet" />
+    <!-- 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="css/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 class="navbar">
+        <div class="title">
+            Babylon.js Playground
+        </div>
+        <div class="version" id="mainTitle">
+            v3.0-alpha
+        </div>
+
+        <div class="category">
+            <div class="button run" id="runButton">Run <i class="fa fa-play" aria-hidden="true"></i></div>
+        </div>
+
+
+        <div class="category">
+            <div class="button" id="newButton">New<i class="fa fa-file" aria-hidden="true"></i></div>
+            <div class="button" id="clearButton">Clear<i class="fa fa-trash" aria-hidden="true"></i></div>
+        </div>
+
+        <div class="category">
+            <div class="button" id="saveButton">Save <i class="fa fa-floppy-o" aria-hidden="true"></i></div>
+            <div class="button" id="zipButton">Zip<i class="fa fa-download" aria-hidden="true"></i></div>
+        </div>
+
+
+        <div class="category desktopOnly">
+            <div class="button select"><span id="currentFontSize">Font: 14</span>
+                <div class="toDisplay">
+                    <div class="option" onclick="setFontSize(12);">12</div>
+                    <div class="option" onclick="setFontSize(14);">14</div>
+                    <div class="option" onclick="setFontSize(16);">16</div>
+                    <div class="option" onclick="setFontSize(18);">18</div>
+                    <div class="option" onclick="setFontSize(20);">20</div>
+                    <div class="option" onclick="setFontSize(22);">22</div>
+                </div>
             </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 class="button select">Theme
+                <div class="toDisplay">
+                    <div class="option" id="darkTheme">Dark</div>
+                    <div class="option" id="lightTheme">Light</div>
+                </div>
             </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="category desktopTabletOnly">
+            <div class="button select">Settings
+                <div class="toDisplay">
+                    <div class="option" id='safemodeToggle'>Safe mode <i class="fa fa-square-o" aria-hidden="true"></i></div>
+                    <div class="option checked" id="editorButton">Editor <i class="fa fa-check-square" aria-hidden="true"></i>
+                    </div>
+                    <div class="option" id="fullscreenButton">Fullscreen</div>
+                    <div class="option" id="metadataButton">Metadata</div>
+                </div>
             </div>
-            <div class="btn-group pull-right">
-                <button class="btn" id="fullscreenButton">Fullscreen</button>
+
+            <div class="button check uncheck" id="debugButton">Debug layer</div>
+        </div>
+
+
+
+        <div class="category right">
+            <div class="button select desktopTabletOnly"><span id="currentVersion">Version: Latest</span>
+                <div class="toDisplay">
+                    <div class="option" onclick="setVersion('latest');">Latest</div>
+                    <div class="option" onclick="setVersion('2.5');">2.5</div>
+                </div>
             </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 class="button select"> <span id="currentScript">Scenes</span>
+                <div class="toDisplayBig">
+                    <ul id="scriptsList">
+                    </ul>
+                </div>
             </div>
         </div>
+        <div class="save-message" id="saveMessage">
+            This PG has no metadata. Click save to add them.
+        </div>
     </div>
 
-    <x-splitbox>
+    <div class="wrapper">
         <div id="jsEditor"></div>
-        <div splitter></div>
         <div id="canvasZone">
             <canvas touch-action="none" id="renderCanvas"></canvas>
         </div>
-    </x-splitbox>
+    </div>
 
     <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="http://www.babylonjs.com/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 class="navbarBottom">
+        <div id="statusBar"></div>
+        <div class="links">
+            <div class='link'> <a target='_new' href="http://www.html5gamedevs.com/forum/16-babylonjs/">Forum</a></div>
+            <div class='link'><a target='_new' href="https://www.babylonjs.com/sandbox">Sandbox</a></div>
+            <div class='link'><a target='_new' href="https://github.com/BabylonJS/Babylon.js/wiki">Wiki</a></div>
+            <div class='link'><a target='_new' href="https://doc.babylonjs.com">Documentation</a></div>
+            <div class='link'><a target='_new' href="https://doc.babylonjs.com/playground">Playground Search</a></div>
+        </div>
+    </div>
+
+    <div id="saveLayer" class="save-layer">
+        <div class="save-form">
+            <label for="saveFormTitle">TITLE</label>
+            <div class="separator"></div>
+            <input type="text" maxlength="120" id="saveFormTitle" class="save-form-title">
+
+            <label for="saveFormDescription">DESCRIPTION</label>
+            <div class="separator"></div>
+            <textarea id="saveFormDescription" rows="4" cols="10"></textarea>
+
+            <label for="saveFormTags">TAGS (separated by comma)</label>
+            <div class="separator"></div>
+            <textarea id="saveFormTags" rows="4" cols="10"></textarea>
+
+            <div class="save-form-buttons" id="saveFormButtons">
+
+                <div id="saveFormButtonOk" class="button">OK</div>
+                <div id="saveFormButtonCancel" class="button">Cancel</div>
+            </div>
         </div>
     </div>
 
-    <script src="http://code.jquery.com/jquery.js"></script>
-    <script src="bootstrap/js/bootstrap.min.js"></script>
+    <script src="https://code.jquery.com/jquery.js"></script>
+
+    <script src="js/actions.js"></script>
+    <script src="js/index.js"></script>
     <script>
         BABYLONDEVTOOLS.Loader.require('index.js')
             .load();
     </script>
 </body>
-</html>
+
+</html>

+ 0 - 124
Playground/index.css

@@ -1,124 +0,0 @@
-html, body {
-    overflow: hidden;
-    width: 100%;
-    height: 100%;
-    background-color: #272822;
-}
-
-x-splitbox {
-    position: absolute;
-    left: 0px;
-    top: 50px;
-    width: 100%;
-    bottom: 40px;
-    height: auto;
-}
-
-    x-splitbox > [splitter]:after {
-        display: none;
-    }
-
-
-#jsEditor {
-    min-width: 250px;
-}
-
-#canvasZone {
-    min-width: 250px;
-    height: 100%;
-}
-
-#renderCanvas {
-    width: 100%;
-    height: 100%;
-    touch-action: none;
-}
-
-ul#scriptsList {
-    overflow-y: auto;
-    height: 600px;
-    -webkit-column-count: 3;
-    -moz-column-count: 3;
-    column-count: 3;
-    padding: 10px
-}
-
-#fpsLabel {
-    position: absolute;
-    right: 10px;
-    top: 70px;
-    cursor: default;
-}
-
-#topbar {
-    padding: 5px;
-}
-
-.navbar .brand {
-    margin-left: 0px;
-}
-
-#errorZone {
-    position: absolute;
-    width: 50%;
-    left: 25%;
-    bottom: 40px;
-}
-
-#statusBar {
-    padding: 10px 15px 10px;
-    color: #999;
-}
-
-@media (max-width: 800px) {
-    .desktopOnly {
-        display: none !important;
-    }
-}
-
-@media (max-width: 1100px) {
-    .largeOnly {
-        display: none !important;
-    }
-}
-
-@media (max-width: 550px) {
-    .btn-group > .btn, .btn-group > .dropdown-menu, .btn-group > .popover {
-        font-size: 12px !important;
-    }
-}
-
-/* MONACO */
-.monaco-editor .container:before, .monaco-editor .row:before {
-    content: "";
-    display: inherit;
-}
-
-.monaco-editor .container:after, .monaco-editor .row:after {
-    clear: inherit;
-}
-
-.monaco-editor .container {
-    width: auto;
-    margin: inherit;
-    padding: inherit;
-}
-
-.monaco-editor .close {
-    float: none;
-    font-size: inherit;
-    font-weight: inherit;
-    line-height: inherit;
-    color: inherit;
-    text-shadow: inherit;
-    opacity: inherit;
-    filter: inherit;
-}
-
-.monaco-editor .row {
-    margin: inherit;
-}
-
-.monaco-editor .invisible {
-    visibility: visible;
-}

+ 151 - 96
Playground/index.html

@@ -1,133 +1,188 @@
 <!DOCTYPE html>
 <html>
+
 <head>
     <title>Babylon.js Playground</title>
+    <meta charset='utf-8' />
+    <meta name="viewport" content="width=device-width, user-scalable=no">
     <script src="https://code.jquery.com/pep/0.4.2/pep.min.js"></script>
-    <script src="https://babylonjs.azurewebsites.net/poly2tri.js"></script>
+    <!--For canvas/code separator-->
+    <script src="js/libs/split.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="js/libs/jszip.min.js"></script>
+    <script src="js/libs/fileSaver.js"></script>
+    <!--Monaco-->
     <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/babylon.js"></script>
-    <script src="https://babylonjs.azurewebsites.net/babylon.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>
-    
+    <script src="https://www.babylonjs.com/cannon.js"></script>
+    <script src="https://www.babylonjs.com/Oimo.js"></script>
+    <script src="https://www.babylonjs.com/babylon.js"></script>
+    <script src="https://www.babylonjs.com/babylon.canvas2d.js"></script>
+    <script src="https://www.babylonjs.com/babylon.inspector.bundle.js"></script>
+
+    <script src="https://www.babylonjs.com/lib/babylon.fireMaterial.min.js"></script>
+    <script src="https://www.babylonjs.com/lib/babylon.waterMaterial.min.js"></script>
+    <script src="https://www.babylonjs.com/lib/babylon.lavaMaterial.min.js"></script>
+    <script src="https://www.babylonjs.com/lib/babylon.normalMaterial.min.js"></script>
+    <script src="https://www.babylonjs.com/lib/babylon.skyMaterial.min.js"></script>
+    <script src="https://www.babylonjs.com/lib/babylon.triPlanarMaterial.min.js"></script>
+    <script src="https://www.babylonjs.com/lib/babylon.terrainMaterial.min.js"></script>
+    <script src="https://www.babylonjs.com/lib/babylon.gradientMaterial.min.js"></script>
+    <script src="https://www.babylonjs.com/lib/babylon.furMaterial.min.js"></script>
+    <script src="https://www.babylonjs.com/lib/babylon.gridMaterial.min.js"></script>
+    <script src="https://www.babylonjs.com/lib/babylon.shadowOnlyMaterial.min.js"></script>
+
+    <script src="https://www.babylonjs.com/lib/babylon.brickProceduralTexture.min.js"></script>
+    <script src="https://www.babylonjs.com/lib/babylon.cloudProceduralTexture.min.js"></script>
+    <script src="https://www.babylonjs.com/lib/babylon.fireProceduralTexture.min.js"></script>
+    <script src="https://www.babylonjs.com/lib/babylon.grassProceduralTexture.min.js"></script>
+    <script src="https://www.babylonjs.com/lib/babylon.marbleProceduralTexture.min.js"></script>
+    <script src="https://www.babylonjs.com/lib/babylon.roadProceduralTexture.min.js"></script>
+    <script src="https://www.babylonjs.com/lib/babylon.starfieldProceduralTexture.min.js"></script>
+    <script src="https://www.babylonjs.com/lib/babylon.woodProceduralTexture.min.js"></script>
+
+    <script src="https://www.babylonjs.com/lib/babylon.asciiArtPostProcess.min.js"></script>
+    <script src="https://www.babylonjs.com/lib/babylon.digitalRainPostProcess.min.js"></script>
+
+    <script src="https://www.babylonjs.com/lib/babylon.glTFFileLoader.js"></script>
+    <script src="https://www.babylonjs.com/lib/babylon.objFileLoader.js"></script>
+    <script src="https://www.babylonjs.com/lib/babylon.stlFileLoader.js"></script>
+
     <script src="https://rawgit.com/BabylonJS/Extensions/master/ClonerSystem/src/babylonx.cloner.js"></script>
+
     <script src="https://rawgit.com/BabylonJS/Extensions/master/CompoundShader/src/babylonx.CompoundShader.js"></script>
-    <link href="index.css" rel="stylesheet" />
+    <link href="css/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 class="navbar">
+        <div class="title">
+            Babylon.js Playground
+        </div>
+        <div class="version" id="mainTitle">
+            v3.0-alpha
+        </div>
+
+        <div class="category">
+            <div class="button run" id="runButton">Run <i class="fa fa-play" aria-hidden="true"></i></div>
+        </div>
+
+
+        <div class="category">
+            <div class="button" id="newButton">New<i class="fa fa-file" aria-hidden="true"></i></div>
+            <div class="button" id="clearButton">Clear<i class="fa fa-trash" aria-hidden="true"></i></div>
+        </div>
+
+        <div class="category">
+            <div class="button" id="saveButton">Save <i class="fa fa-floppy-o" aria-hidden="true"></i></div>
+            <div class="button" id="zipButton">Zip<i class="fa fa-download" aria-hidden="true"></i></div>
+        </div>
+
+
+        <div class="category desktopOnly">
+            <div class="button select"><span id="currentFontSize">Font: 14</span>
+                <div class="toDisplay">
+                    <div class="option" onclick="setFontSize(12);">12</div>
+                    <div class="option" onclick="setFontSize(14);">14</div>
+                    <div class="option" onclick="setFontSize(16);">16</div>
+                    <div class="option" onclick="setFontSize(18);">18</div>
+                    <div class="option" onclick="setFontSize(20);">20</div>
+                    <div class="option" onclick="setFontSize(22);">22</div>
+                </div>
             </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 class="button select">Theme
+                <div class="toDisplay">
+                    <div class="option" id="darkTheme">Dark</div>
+                    <div class="option" id="lightTheme">Light</div>
+                </div>
             </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="category desktopTabletOnly">
+            <div class="button select">Settings
+                <div class="toDisplay">
+                    <div class="option" id='safemodeToggle'>Safe mode <i class="fa fa-square-o" aria-hidden="true"></i></div>
+                    <div class="option checked" id="editorButton">Editor <i class="fa fa-check-square" aria-hidden="true"></i>
+                    </div>
+                    <div class="option" id="fullscreenButton">Fullscreen</div>
+                    <div class="option" id="metadataButton">Metadata</div>
+                </div>
             </div>
-            <div class="btn-group pull-right">
-                <button class="btn" id="fullscreenButton">Fullscreen</button>
+
+            <div class="button check uncheck" id="debugButton">Debug layer</div>
+        </div>
+
+
+
+        <div class="category right">
+            <div class="button select desktopTabletOnly"><span id="currentVersion">Version: Latest</span>
+                <div class="toDisplay">
+                    <div class="option" onclick="setVersion('latest');">Latest</div>
+                    <div class="option" onclick="setVersion('2.5');">2.5</div>
+                </div>
             </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 class="button select"> <span id="currentScript">Scenes</span>
+                <div class="toDisplayBig">
+                    <ul id="scriptsList">
+                    </ul>
+                </div>
             </div>
         </div>
+        <div class="save-message" id="saveMessage">
+            This PG has no metadata. Click save to add them.
+        </div>
     </div>
 
-    <x-splitbox>
+    <div class="wrapper">
         <div id="jsEditor"></div>
-        <div splitter></div>
         <div id="canvasZone">
             <canvas touch-action="none" id="renderCanvas"></canvas>
         </div>
-    </x-splitbox>
+    </div>
 
     <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 class="navbarBottom">
+        <div id="statusBar"></div>
+        <div class="links">
+            <div class='link'><a target='_new' href="https://www.netlify.com/">Deployed by Netlify</a></div>
+            <div class='link'> <a target='_new' href="http://www.html5gamedevs.com/forum/16-babylonjs/">Forum</a></div>
+            <div class='link'><a target='_new' href="https://www.babylonjs.com/sandbox">Sandbox</a></div>            
+            <div class='link'><a target='_new' href="https://doc.babylonjs.com">Documentation</a></div>
+            <div class='link'><a target='_new' href="https://doc.babylonjs.com/playground">Search</a></div>
+        </div>
+    </div>
+
+    <div id="saveLayer" class="save-layer">
+        <div class="save-form">
+            <label for="saveFormTitle">TITLE</label>
+            <div class="separator"></div>
+            <input type="text" maxlength="120" id="saveFormTitle" class="save-form-title">
+
+            <label for="saveFormDescription">DESCRIPTION</label>
+            <div class="separator"></div>
+            <textarea id="saveFormDescription" rows="4" cols="10"></textarea>
+
+            <label for="saveFormTags">TAGS (separated by comma)</label>
+            <div class="separator"></div>
+            <textarea id="saveFormTags" rows="4" cols="10"></textarea>
+
+            <div class="save-form-buttons" id="saveFormButtons">
+
+                <div id="saveFormButtonOk" class="button">OK</div>
+                <div id="saveFormButtonCancel" class="button">Cancel</div>
+            </div>
         </div>
     </div>
 
     <script src="https://code.jquery.com/jquery.js"></script>
-    <script src="bootstrap/js/bootstrap.min.js"></script>
-    <script src="index.js"></script>
+
+    <script src="js/actions.js"></script>
+    <script src="js/index.js"></script>
 </body>
+
 </html>

+ 187 - 0
Playground/index2_5.html

@@ -0,0 +1,187 @@
+<!DOCTYPE html>
+<html>
+
+<head>
+    <title>Babylon.js Playground</title>
+    <meta charset='utf-8' />
+    <meta name="viewport" content="width=device-width, user-scalable=no">
+    <script src="https://code.jquery.com/pep/0.4.2/pep.min.js"></script>
+    <!--For canvas/code separator-->
+    <script src="js/libs/split.js"></script>
+
+    <script src="https://cdnjs.cloudflare.com/ajax/libs/dat-gui/0.6.2/dat.gui.min.js"></script>
+    <!-- jszip -->
+    <script src="js/libs/jszip.min.js"></script>
+    <script src="js/libs/fileSaver.js"></script>
+    <!--Monaco-->
+    <script src="node_modules/monaco-editor/min/vs/loader.js"></script>
+    <!-- Babylon.js -->
+    <script src="https://www.babylonjs.com/cannon.js"></script>
+    <script src="https://www.babylonjs.com/Oimo.js"></script>
+    <script src="https://www.babylonjs.com/versions/babylon.2.5.js"></script>
+    <script src="https://www.babylonjs.com/versions/babylon.2.5.canvas2d.js"></script>
+    <script src="https://www.babylonjs.com/babylon.inspector.bundle.js"></script>
+
+    <script src="https://www.babylonjs.com/lib/babylon.fireMaterial.min.js"></script>
+    <script src="https://www.babylonjs.com/lib/babylon.waterMaterial.min.js"></script>
+    <script src="https://www.babylonjs.com/lib/babylon.lavaMaterial.min.js"></script>
+    <script src="https://www.babylonjs.com/lib/babylon.normalMaterial.min.js"></script>
+    <script src="https://www.babylonjs.com/lib/babylon.skyMaterial.min.js"></script>
+    <script src="https://www.babylonjs.com/lib/babylon.triPlanarMaterial.min.js"></script>
+    <script src="https://www.babylonjs.com/lib/babylon.terrainMaterial.min.js"></script>
+    <script src="https://www.babylonjs.com/lib/babylon.gradientMaterial.min.js"></script>
+    <script src="https://www.babylonjs.com/lib/babylon.furMaterial.min.js"></script>
+    <script src="https://www.babylonjs.com/lib/babylon.gridMaterial.min.js"></script>
+    <script src="https://www.babylonjs.com/lib/babylon.shadowOnlyMaterial.min.js"></script>
+
+    <script src="https://www.babylonjs.com/lib/babylon.brickProceduralTexture.min.js"></script>
+    <script src="https://www.babylonjs.com/lib/babylon.cloudProceduralTexture.min.js"></script>
+    <script src="https://www.babylonjs.com/lib/babylon.fireProceduralTexture.min.js"></script>
+    <script src="https://www.babylonjs.com/lib/babylon.grassProceduralTexture.min.js"></script>
+    <script src="https://www.babylonjs.com/lib/babylon.marbleProceduralTexture.min.js"></script>
+    <script src="https://www.babylonjs.com/lib/babylon.roadProceduralTexture.min.js"></script>
+    <script src="https://www.babylonjs.com/lib/babylon.starfieldProceduralTexture.min.js"></script>
+    <script src="https://www.babylonjs.com/lib/babylon.woodProceduralTexture.min.js"></script>
+
+    <script src="https://www.babylonjs.com/lib/babylon.asciiArtPostProcess.min.js"></script>
+    <script src="https://www.babylonjs.com/lib/babylon.digitalRainPostProcess.min.js"></script>
+
+    <script src="https://www.babylonjs.com/lib/babylon.glTFFileLoader.js"></script>
+    <script src="https://www.babylonjs.com/lib/babylon.objFileLoader.js"></script>
+    <script src="https://www.babylonjs.com/lib/babylon.stlFileLoader.js"></script>
+
+    <script src="https://rawgit.com/BabylonJS/Extensions/master/ClonerSystem/src/babylonx.cloner.js"></script>
+    <link href="css/index.css" rel="stylesheet" />
+</head>
+
+<body>
+    <div class="navbar">
+        <div class="title">
+            Babylon.js Playground
+        </div>
+        <div class="version" id="mainTitle">
+            v3.0-alpha
+        </div>
+
+        <div class="category">
+            <div class="button run" id="runButton">Run <i class="fa fa-play" aria-hidden="true"></i></div>
+        </div>
+
+
+        <div class="category">
+            <div class="button" id="newButton">New<i class="fa fa-file" aria-hidden="true"></i></div>
+            <div class="button" id="clearButton">Clear<i class="fa fa-trash" aria-hidden="true"></i></div>
+        </div>
+
+        <div class="category">
+            <div class="button" id="saveButton">Save <i class="fa fa-floppy-o" aria-hidden="true"></i></div>
+            <div class="button" id="zipButton">Zip<i class="fa fa-download" aria-hidden="true"></i></div>
+        </div>
+
+
+        <div class="category desktopOnly">
+            <div class="button select"><span id="currentFontSize">Font: 14</span>
+                <div class="toDisplay">
+                    <div class="option" onclick="setFontSize(12);">12</div>
+                    <div class="option" onclick="setFontSize(14);">14</div>
+                    <div class="option" onclick="setFontSize(16);">16</div>
+                    <div class="option" onclick="setFontSize(18);">18</div>
+                    <div class="option" onclick="setFontSize(20);">20</div>
+                    <div class="option" onclick="setFontSize(22);">22</div>
+                </div>
+            </div>
+            <div class="button select">Theme
+                <div class="toDisplay">
+                    <div class="option" id="darkTheme">Dark</div>
+                    <div class="option" id="lightTheme">Light</div>
+                </div>
+            </div>
+        </div>
+        <div class="category desktopTabletOnly">
+            <div class="button select">Settings
+                <div class="toDisplay">
+                    <div class="option" id='safemodeToggle'>Safe mode <i class="fa fa-square-o" aria-hidden="true"></i></div>
+                    <div class="option checked" id="editorButton">Editor <i class="fa fa-check-square" aria-hidden="true"></i>
+                    </div>
+                    <div class="option" id="fullscreenButton">Fullscreen</div>
+                    <div class="option" id="metadataButton">Metadata</div>
+                </div>
+            </div>
+
+            <div class="button check uncheck" id="debugButton">Debug layer</div>
+        </div>
+
+
+
+        <div class="category right">
+            <div class="button select desktopTabletOnly"><span id="currentVersion">Version: Latest</span>
+                <div class="toDisplay">
+                    <div class="option" onclick="setVersion('latest');">Latest</div>
+                    <div class="option" onclick="setVersion('2.5');">2.5</div>
+                </div>
+            </div>
+            <div class="button select"> <span id="currentScript">Scenes</span>
+                <div class="toDisplayBig">
+                    <ul id="scriptsList">
+                    </ul>
+                </div>
+            </div>
+        </div>
+        <div class="save-message" id="saveMessage">
+            This PG has no metadata. Click save to add them.
+        </div>
+    </div>
+
+    <div class="wrapper">
+        <div id="jsEditor"></div>
+        <div id="canvasZone">
+            <canvas touch-action="none" id="renderCanvas"></canvas>
+        </div>
+    </div>
+
+    <span class="label" id="fpsLabel">FPS</span>
+
+    <div id="errorZone">
+    </div>
+
+    <div class="navbarBottom">
+        <div id="statusBar"></div>
+        <div class="links">
+            <div class='link'> <a target='_new' href="http://www.html5gamedevs.com/forum/16-babylonjs/">Forum</a></div>
+            <div class='link'><a target='_new' href="https://www.babylonjs.com/sandbox">Sandbox</a></div>
+            <div class='link'><a target='_new' href="https://github.com/BabylonJS/Babylon.js/wiki">Wiki</a></div>
+            <div class='link'><a target='_new' href="https://doc.babylonjs.com">Documentation</a></div>
+            <div class='link'><a target='_new' href="https://doc.babylonjs.com/playground">Playground Search</a></div>
+        </div>
+    </div>
+
+    <div id="saveLayer" class="save-layer">
+        <div class="save-form">
+            <label for="saveFormTitle">TITLE</label>
+            <div class="separator"></div>
+            <input type="text" maxlength="120" id="saveFormTitle" class="save-form-title">
+            <label for="saveFormDescription">DESCRIPTION</label>
+            <div class="separator"></div>
+            <textarea id="saveFormDescription" rows="4" cols="10"></textarea>
+            <label for="saveFormTags">TAGS (separated by comma)</label>
+            <div class="separator"></div>
+            <textarea id="saveFormTags" rows="4" cols="10"></textarea>
+            <div class="save-form-buttons" id="saveFormButtons">
+
+                <div id="saveFormButtonOk" class="button">OK</div>
+                <div id="saveFormButtonCancel" class="button">Cancel</div>
+            </div>
+        </div>
+    </div>
+
+    <script src="https://code.jquery.com/jquery.js"></script>
+
+    <script>
+        Split(['#jsEditor', '#canvasZone']);
+    </script>
+
+    <script src="js/actions.js"></script>
+    <script src="js/index.js"></script>
+</body>
+
+</html>

+ 63 - 0
Playground/js/actions.js

@@ -0,0 +1,63 @@
+(function () {
+
+    var allSelect = document.querySelectorAll('.select');
+    var allToDisplay = document.querySelectorAll('.toDisplay');
+    var allToDisplayBig = document.querySelectorAll('.toDisplayBig');
+
+    var removeAllOptions = function () {
+        for (var index = 0; index < allToDisplay.length; index++) {
+            var a = allToDisplay[index];
+            if (a.style.display == 'block') {
+                a.style.display = 'none';
+            }
+        }
+        for (var index = 0; index < allToDisplayBig.length; index++) {
+            var b = allToDisplayBig[index];
+            if (b.style.display == 'block') {
+                b.style.display = 'none';
+            }
+        }
+    }
+
+    // Remove displayed options
+    window.addEventListener('click', function () {
+        removeAllOptions();
+    });
+
+    // Handle click on select elements
+    for (var index = 0; index < allSelect.length; index++) {
+        var s = allSelect[index];
+        // Get child called to display
+        s.addEventListener('click', function (e) {
+            var toDisplay = this.querySelector('.toDisplay');
+            if (toDisplay) {
+                if (toDisplay.style.display == 'block') {
+                    toDisplay.style.display = 'none';
+                } else {
+                    removeAllOptions();
+                    toDisplay.style.display = 'block';
+                }
+            }
+            toDisplay = this.querySelector('.toDisplayBig');
+            if (toDisplay) {
+                if (toDisplay.style.display == 'block') {
+                    toDisplay.style.display = 'none';
+                } else {
+                    removeAllOptions();
+                    toDisplay.style.display = 'block';
+                }
+            }
+            e.preventDefault();
+            e.stopPropagation();
+        });
+    }
+
+    document.querySelector('#safemodeToggle').addEventListener('click', function () {
+        this.classList.toggle('checked');
+        if (this.classList.contains('checked')) {
+            this.innerHTML = 'Safe mode <i class="fa fa-check-square" aria-hidden="true"></i>';
+        } else {
+            this.innerHTML = 'Safe mode <i class="fa fa-square-o" aria-hidden="true"></i>';
+        }
+    })
+})();

Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 253 - 33
Playground/index.js


Playground/fileSaver.js → Playground/js/libs/fileSaver.js


Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 13 - 13
Playground/jszip.min.js


+ 587 - 0
Playground/js/libs/split.js

@@ -0,0 +1,587 @@
+// The programming goals of Split.js are to deliver readable, understandable and
+// maintainable code, while at the same time manually optimizing for tiny minified file size,
+// browser compatibility without additional requirements, graceful fallback (IE8 is supported)
+// and very few assumptions about the user's page layout.
+//
+// Make sure all browsers handle this JS library correctly with ES5.
+// More information here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Strict_mode
+'use strict';
+
+// A wrapper function that does a couple things:
+//
+// 1. Doesn't pollute the global namespace. This is important for a library.
+// 2. Allows us to mount the library in different module systems, as well as
+//    directly in the browser.
+(function() {
+
+// Save the global `this` for use later. In this case, since the library only
+// runs in the browser, it will refer to `window`. Also, figure out if we're in IE8
+// or not. IE8 will still render correctly, but will be static instead of draggable.
+//
+// Save a couple long function names that are used frequently.
+// This optimization saves around 400 bytes.
+//
+// Set a float fudging global, used when dividing and setting sizes to long floats.
+// There's a chance that sometimes the sum of the floats would end up being slightly
+// larger than 100%, breaking the layout. The float fudging value is subtracted from
+// the percentage size.
+var global = this
+  , isIE8 = global.attachEvent && !global[addEventListener]
+  , document = global.document
+  , addEventListener = 'addEventListener'
+  , removeEventListener = 'removeEventListener'
+  , getBoundingClientRect = 'getBoundingClientRect'
+  , FLOAT_FUDGING = 0.5
+
+  // This library only needs two helper functions:
+  //
+  // The first determines which prefixes of CSS calc we need.
+  // We only need to do this once on startup, when this anonymous function is called.
+  // 
+  // Tests -webkit, -moz and -o prefixes. Modified from StackOverflow:
+  // http://stackoverflow.com/questions/16625140/js-feature-detection-to-detect-the-usage-of-webkit-calc-over-calc/16625167#16625167
+  , calc = (function () {
+        var el
+          , prefixes = ["", "-webkit-", "-moz-", "-o-"]
+
+        for (var i = 0; i < prefixes.length; i++) {
+            el = document.createElement('div')
+            el.style.cssText = "width:" + prefixes[i] + "calc(9px)"
+
+            if (el.style.length) {
+                return prefixes[i] + "calc"
+            }
+        }
+    })()
+
+  // The second helper function allows elements and string selectors to be used
+  // interchangeably. In either case an element is returned. This allows us to
+  // do `Split(elem1, elem2)` as well as `Split('#id1', '#id2')`.
+  , elementOrSelector = function (el) {
+        if (typeof el === 'string' || el instanceof String) {
+            return document.querySelector(el)
+        } else {
+            return el
+        }
+    }
+
+  // The main function to initialize a split. Split.js thinks about each pair
+  // of elements as an independant pair. Dragging the gutter between two elements
+  // only changes the dimensions of elements in that pair. This is key to understanding
+  // how the following functions operate, since each function is bound to a pair.
+  // 
+  // A pair object is shaped like this:
+  // 
+  // {
+  //     a: DOM element,
+  //     b: DOM element,
+  //     aMin: Number,
+  //     bMin: Number,
+  //     dragging: Boolean,
+  //     parent: DOM element,
+  //     isFirst: Boolean,
+  //     isLast: Boolean,
+  //     direction: 'horizontal' | 'vertical'
+  // }
+  //
+  // The basic sequence:
+  // 
+  // 1. Set defaults to something sane. `options` doesn't have to be passed at all.
+  // 2. Initialize a bunch of strings based on the direction we're splitting.
+  //    A lot of the behavior in the rest of the library is paramatized down to
+  //    rely on CSS strings and classes.
+  // 3. Define the dragging helper functions, and a few helpers to go with them.
+  // 4. Loop through the elements while pairing them off. Every pair gets an
+  //    `pair` object, a gutter, and special isFirst/isLast properties.
+  // 5. Actually size the pair elements, insert gutters and attach event listeners.
+  , Split = function (ids, options) {
+    var dimension
+      , i
+      , clientDimension
+      , clientAxis
+      , position
+      , gutterClass
+      , paddingA
+      , paddingB
+      , pairs = []
+
+    // 1. Set defaults to something sane. `options` doesn't have to be passed at all,
+    // so create an options object if none exists. Pixel values 10, 100 and 30 are
+    // arbitrary but feel natural.
+    options = typeof options !== 'undefined' ?  options : {}
+
+    if (typeof options.gutterSize === 'undefined') options.gutterSize = 10
+    if (typeof options.minSize === 'undefined') options.minSize = 100
+    if (typeof options.snapOffset === 'undefined') options.snapOffset = 30
+    if (typeof options.direction === 'undefined') options.direction = 'horizontal'
+    if (typeof options.elementStyle === 'undefined') options.elementStyle = function (dimension, size, gutterSize) {
+        var style = {}
+
+        if (typeof size !== 'string' && !(size instanceof String)) {
+            if (!isIE8) {
+                style[dimension] = calc + '(' + size + '% - ' + gutterSize + 'px)'
+            } else {
+                style[dimension] = size + '%'
+            }
+        } else {
+            style[dimension] = size
+        }
+
+        return style
+    }
+    if (typeof options.gutterStyle === 'undefined') options.gutterStyle = function (dimension, gutterSize) {
+        var style = {}
+
+        style[dimension] = gutterSize + 'px'
+
+        return style
+    }
+
+    // 2. Initialize a bunch of strings based on the direction we're splitting.
+    // A lot of the behavior in the rest of the library is paramatized down to
+    // rely on CSS strings and classes.
+    if (options.direction == 'horizontal') {
+        dimension = 'width'
+        clientDimension = 'clientWidth'
+        clientAxis = 'clientX'
+        position = 'left'
+        gutterClass = 'gutter gutter-horizontal'
+        paddingA = 'paddingLeft'
+        paddingB = 'paddingRight'
+        if (!options.cursor) options.cursor = 'ew-resize'
+    } else if (options.direction == 'vertical') {
+        dimension = 'height'
+        clientDimension = 'clientHeight'
+        clientAxis = 'clientY'
+        position = 'top'
+        gutterClass = 'gutter gutter-vertical'
+        paddingA = 'paddingTop'
+        paddingB = 'paddingBottom'
+        if (!options.cursor) options.cursor = 'ns-resize'
+    }
+
+    // 3. Define the dragging helper functions, and a few helpers to go with them.
+    // Each helper is bound to a pair object that contains it's metadata. This
+    // also makes it easy to store references to listeners that that will be
+    // added and removed.
+    // 
+    // Even though there are no other functions contained in them, aliasing
+    // this to self saves 50 bytes or so since it's used so frequently.
+    //
+    // The pair object saves metadata like dragging state, position and
+    // event listener references.
+    //
+    // startDragging calls `calculateSizes` to store the inital size in the pair object.
+    // It also adds event listeners for mouse/touch events,
+    // and prevents selection while dragging so avoid the selecting text.
+    var startDragging = function (e) {
+            // Alias frequently used variables to save space. 200 bytes.
+            var self = this
+              , a = self.a
+              , b = self.b
+
+            // Call the onDragStart callback.
+            if (!self.dragging && options.onDragStart) {
+                options.onDragStart()
+            }
+
+            // Don't actually drag the element. We emulate that in the drag function.
+            e.preventDefault()
+
+            // Set the dragging property of the pair object.
+            self.dragging = true
+
+            // Create two event listeners bound to the same pair object and store
+            // them in the pair object.
+            self.move = drag.bind(self)
+            self.stop = stopDragging.bind(self)
+
+            // All the binding. `window` gets the stop events in case we drag out of the elements.
+            global[addEventListener]('mouseup', self.stop)
+            global[addEventListener]('touchend', self.stop)
+            global[addEventListener]('touchcancel', self.stop)
+
+            self.parent[addEventListener]('mousemove', self.move)
+            self.parent[addEventListener]('touchmove', self.move)
+
+            // Disable selection. Disable!
+            a[addEventListener]('selectstart', noop)
+            a[addEventListener]('dragstart', noop)
+            b[addEventListener]('selectstart', noop)
+            b[addEventListener]('dragstart', noop)
+
+            a.style.userSelect = 'none'
+            a.style.webkitUserSelect = 'none'
+            a.style.MozUserSelect = 'none'
+            a.style.pointerEvents = 'none'
+
+            b.style.userSelect = 'none'
+            b.style.webkitUserSelect = 'none'
+            b.style.MozUserSelect = 'none'
+            b.style.pointerEvents = 'none'
+
+            // Set the cursor, both on the gutter and the parent element.
+            // Doing only a, b and gutter causes flickering.
+            self.gutter.style.cursor = options.cursor
+            self.parent.style.cursor = options.cursor
+
+            // Cache the initial sizes of the pair.
+            calculateSizes.call(self)
+        }
+
+      // stopDragging is very similar to startDragging in reverse.
+      , stopDragging = function () {
+            var self = this
+              , a = self.a
+              , b = self.b
+
+            if (self.dragging && options.onDragEnd) {
+                options.onDragEnd()
+            }
+
+            self.dragging = false
+
+            // Remove the stored event listeners. This is why we store them.
+            global[removeEventListener]('mouseup', self.stop)
+            global[removeEventListener]('touchend', self.stop)
+            global[removeEventListener]('touchcancel', self.stop)
+
+            self.parent[removeEventListener]('mousemove', self.move)
+            self.parent[removeEventListener]('touchmove', self.move)
+
+            // Delete them once they are removed. I think this makes a difference
+            // in memory usage with a lot of splits on one page. But I don't know for sure.
+            delete self.stop
+            delete self.move
+
+            a[removeEventListener]('selectstart', noop)
+            a[removeEventListener]('dragstart', noop)
+            b[removeEventListener]('selectstart', noop)
+            b[removeEventListener]('dragstart', noop)
+
+            a.style.userSelect = ''
+            a.style.webkitUserSelect = ''
+            a.style.MozUserSelect = ''
+            a.style.pointerEvents = ''
+
+            b.style.userSelect = ''
+            b.style.webkitUserSelect = ''
+            b.style.MozUserSelect = ''
+            b.style.pointerEvents = ''
+
+            self.gutter.style.cursor = ''
+            self.parent.style.cursor = ''
+        }
+
+      // drag, where all the magic happens. The logic is really quite simple:
+      // 
+      // 1. Ignore if the pair is not dragging.
+      // 2. Get the offset of the event.
+      // 3. Snap offset to min if within snappable range (within min + snapOffset).
+      // 4. Actually adjust each element in the pair to offset.
+      // 
+      // ---------------------------------------------------------------------
+      // |    | <- this.aMin               ||              this.bMin -> |    |
+      // |    |  | <- this.snapOffset      ||     this.snapOffset -> |  |    |
+      // |    |  |                         ||                        |  |    |
+      // |    |  |                         ||                        |  |    |
+      // ---------------------------------------------------------------------
+      // | <- this.start                                        this.size -> |
+      , drag = function (e) {
+            var offset
+
+            if (!this.dragging) return
+
+            // Get the offset of the event from the first side of the
+            // pair `this.start`. Supports touch events, but not multitouch, so only the first
+            // finger `touches[0]` is counted.
+            if ('touches' in e) {
+                offset = e.touches[0][clientAxis] - this.start
+            } else {
+                offset = e[clientAxis] - this.start
+            }
+
+            // If within snapOffset of min or max, set offset to min or max.
+            // snapOffset buffers aMin and bMin, so logic is opposite for both.
+            // Include the appropriate gutter sizes to prevent overflows.
+            if (offset <= this.aMin + options.snapOffset + this.aGutterSize) {
+                offset = this.aMin + this.aGutterSize
+            } else if (offset >= this.size - (this.bMin + options.snapOffset + this.bGutterSize)) {
+                offset = this.size - (this.bMin + this.bGutterSize)
+            }
+
+            offset = offset - FLOAT_FUDGING
+
+            // Actually adjust the size.
+            adjust.call(this, offset)
+
+            // Call the drag callback continously. Don't do anything too intensive
+            // in this callback.
+            if (options.onDrag) {
+                options.onDrag()
+            }
+        }
+
+      // Cache some important sizes when drag starts, so we don't have to do that
+      // continously:
+      // 
+      // `size`: The total size of the pair. First element + second element + first gutter + second gutter.
+      // `percentage`: The percentage between 0-100 that the pair occupies in the parent.
+      // `start`: The leading side of the first element.
+      //
+      // ------------------------------------------------ - - - - - - - - - - -
+      // |      aGutterSize -> |||                      |                     |
+      // |                     |||                      |                     |
+      // |                     |||                      |                     |
+      // |                     ||| <- bGutterSize       |                     |
+      // ------------------------------------------------ - - - - - - - - - - -
+      // | <- start                             size -> |       parentSize -> |
+      , calculateSizes = function () {
+            // Figure out the parent size minus padding.
+            var computedStyle = global.getComputedStyle(this.parent)
+              , parentSize = this.parent[clientDimension] - parseFloat(computedStyle[paddingA]) - parseFloat(computedStyle[paddingB])
+
+            this.size = this.a[getBoundingClientRect]()[dimension] + this.b[getBoundingClientRect]()[dimension] + this.aGutterSize + this.bGutterSize
+            this.percentage = Math.min(this.size / parentSize * 100, 100)
+            this.start = this.a[getBoundingClientRect]()[position]
+        }
+
+      // Actually adjust the size of elements `a` and `b` to `offset` while dragging.
+      // calc is used to allow calc(percentage + gutterpx) on the whole split instance,
+      // which allows the viewport to be resized without additional logic.
+      // Element a's size is the same as offset. b's size is total size - a size.
+      // Both sizes are calculated from the initial parent percentage, then the gutter size is subtracted.
+      , adjust = function (offset) {
+            setElementSize(this.a, (offset / this.size * this.percentage), this.aGutterSize)
+            setElementSize(this.b, (this.percentage - (offset / this.size * this.percentage)), this.bGutterSize)
+        }
+      , setElementSize = function (el, size, gutterSize) {
+            // Split.js allows setting sizes via numbers (ideally), or if you must,
+            // by string, like '300px'. This is less than ideal, because it breaks
+            // the fluid layout that `calc(% - px)` provides. You're on your own if you do that,
+            // make sure you calculate the gutter size by hand.
+            var style = options.elementStyle(dimension, size, gutterSize)
+              , props = Object.keys(style)
+
+            for (var i = 0; i < props.length; i++) {
+                el.style[props[i]] = style[props[i]]
+            }
+        }
+      , setGutterSize = function (gutter, gutterSize) {
+            var style = options.gutterStyle(dimension, gutterSize)
+              , props = Object.keys(style)
+
+            for (var i = 0; i < props.length; i++) {
+                gutter.style[props[i]] = style[props[i]]
+            }
+        }
+
+      // No-op function to prevent default. Used to prevent selection.
+      , noop = function () { return false }
+
+      // All DOM elements in the split should have a common parent. We can grab
+      // the first elements parent and hope users read the docs because the
+      // behavior will be whacky otherwise.
+      , parent = elementOrSelector(ids[0]).parentNode
+
+    // Set default options.sizes to equal percentages of the parent element.
+    if (!options.sizes) {
+        var percent = 100 / ids.length
+
+        options.sizes = []
+
+        for (i = 0; i < ids.length; i++) {
+            options.sizes.push(percent)
+        }
+    }
+
+    // Standardize minSize to an array if it isn't already. This allows minSize
+    // to be passed as a number.
+    if (!Array.isArray(options.minSize)) {
+        var minSizes = []
+
+        for (i = 0; i < ids.length; i++) {
+            minSizes.push(options.minSize)
+        }
+
+        options.minSize = minSizes
+    }
+
+    // 5. Loop through the elements while pairing them off. Every pair gets a
+    // `pair` object, a gutter, and isFirst/isLast properties.
+    //
+    // Basic logic:
+    //
+    // - Starting with the second element `i > 0`, create `pair` objects with
+    //   `a = ids[i - 1]` and `b = ids[i]`
+    // - Set gutter sizes based on the _pair_ being first/last. The first and last
+    //   pair have gutterSize / 2, since they only have one half gutter, and not two.
+    // - Create gutter elements and add event listeners.
+    // - Set the size of the elements, minus the gutter sizes.
+    //
+    // -----------------------------------------------------------------------
+    // |     i=0     |         i=1         |        i=2       |      i=3     |
+    // |             |       isFirst       |                  |     isLast   |
+    // |           pair 0                pair 1             pair 2           |
+    // |             |                     |                  |              |
+    // -----------------------------------------------------------------------
+    for (i = 0; i < ids.length; i++) {
+        var el = elementOrSelector(ids[i])
+          , isFirstPair = (i == 1)
+          , isLastPair = (i == ids.length - 1)
+          , size = options.sizes[i]
+          , gutterSize = options.gutterSize
+          , pair
+          , parentFlexDirection = window.getComputedStyle(parent).flexDirection
+          , temp
+
+        if (i > 0) {
+            // Create the pair object with it's metadata.
+            pair = {
+                a: elementOrSelector(ids[i - 1]),
+                b: el,
+                aMin: options.minSize[i - 1],
+                bMin: options.minSize[i],
+                dragging: false,
+                parent: parent,
+                isFirst: isFirstPair,
+                isLast: isLastPair,
+                direction: options.direction
+            }
+
+            // For first and last pairs, first and last gutter width is half.
+            pair.aGutterSize = options.gutterSize
+            pair.bGutterSize = options.gutterSize
+
+            if (isFirstPair) {
+                pair.aGutterSize = options.gutterSize / 2
+            }
+
+            if (isLastPair) {
+                pair.bGutterSize = options.gutterSize / 2
+            }
+
+            // if the parent has a reverse flex-direction, switch the pair elements.
+            if (parentFlexDirection === 'row-reverse' || parentFlexDirection === 'column-reverse') {
+                temp = pair.a;
+                pair.a = pair.b;
+                pair.b = temp;
+            }
+        }
+
+        // Determine the size of the current element. IE8 is supported by
+        // staticly assigning sizes without draggable gutters. Assigns a string
+        // to `size`.
+        // 
+        // IE9 and above
+        if (!isIE8) {
+            // Create gutter elements for each pair.
+            if (i > 0) {
+                var gutter = document.createElement('div')
+
+                gutter.className = gutterClass
+
+                setGutterSize(gutter, gutterSize)
+
+                gutter[addEventListener]('mousedown', startDragging.bind(pair))
+                gutter[addEventListener]('touchstart', startDragging.bind(pair))
+
+                parent.insertBefore(gutter, el)
+
+                pair.gutter = gutter
+            }
+
+            // Half-size gutters for first and last elements.
+            if (i === 0 || i == ids.length - 1) {
+                gutterSize = options.gutterSize / 2
+            }
+        }
+
+        // Set the element size to our determined size.
+        setElementSize(el, size, gutterSize)
+
+        if (i > 0) {
+            var aSize = pair.a[getBoundingClientRect]()[dimension]
+              , bSize = pair.b[getBoundingClientRect]()[dimension]
+
+            if (aSize < pair.aMin) {
+                pair.aMin = aSize
+            }
+
+            if (bSize < pair.bMin) {
+                pair.bMin = bSize
+            }
+        }
+
+        // After the first iteration, and we have a pair object, append it to the
+        // list of pairs.
+        if (i > 0) {
+            pairs.push(pair)
+        }
+    }
+
+    return {
+        setSizes: function (sizes) {
+            for (var i = 0; i < sizes.length; i++) {
+                if (i > 0) {
+                    var pair = pairs[i - 1]
+
+                    setElementSize(pair.a, sizes[i - 1], pair.aGutterSize)
+                    setElementSize(pair.b, sizes[i], pair.bGutterSize)
+                }
+            }
+        },
+        getSizes: function () {
+            var sizes = []
+
+            for (var i = 0; i < pairs.length; i++) {
+                var pair = pairs[i]
+                  , computedStyle = global.getComputedStyle(pair.parent)
+                  , parentSize = pair.parent[clientDimension] - parseFloat(computedStyle[paddingA]) - parseFloat(computedStyle[paddingB])
+
+                sizes.push((pair.a[getBoundingClientRect]()[dimension] + pair.aGutterSize) / parentSize * 100)
+
+                if (i === pairs.length - 1) {
+                    sizes.push((pair.b[getBoundingClientRect]()[dimension] + pair.bGutterSize) / parentSize * 100)
+                }
+            }
+
+            return sizes
+        },
+        collapse: function (i) {
+            var pair
+
+            if (i === pairs.length) {
+                pair = pairs[i - 1]
+
+                calculateSizes.call(pair)
+                adjust.call(pair, pair.size - pair.bGutterSize)
+            } else {
+                pair = pairs[i]
+
+                calculateSizes.call(pair)
+                adjust.call(pair, pair.aGutterSize)
+            }
+        },
+        destroy: function () {
+            for (var i = 0; i < pairs.length; i++) {
+                pairs[i].parent.removeChild(pairs[i].gutter)
+                pairs[i].a.style[dimension] = ''
+                pairs[i].b.style[dimension] = ''
+            }
+        }
+    }
+}
+
+// Play nicely with module systems, and the browser too if you include it raw.
+if (typeof exports !== 'undefined') {
+    if (typeof module !== 'undefined' && module.exports) {
+        exports = module.exports = Split
+    }
+    exports.Split = Split
+} else {
+    global.Split = Split
+}
+
+// Call our wrapper function with the current global. In this case, `window`.
+}).call(window);

+ 6 - 4
Playground/package.json

@@ -1,12 +1,14 @@
 {
   "name": "babylonjsplayground",
-  "version": "2.5.0",
+  "version": "2.6.0",
   "description": "Babylon.js is a 3D engine based on webgl and javascript",
   "main": "",
-  "repository": { "url": "https://github.com/BabylonJS/Babylon.js/" },
-  "readme": "https://github.com/BabylonJS/Babylon.js/edit/master/readme.md",
+  "repository": {
+    "url": "https://github.com/BabylonJS/Babylon.js/"
+  },
+  "readme": "https://github.com/BabylonJS/Babylon.js/blob/master/readme.md",
   "license": "(Apache-2.0)",
   "devDependencies": {
     "monaco-editor": "^0.7.0"
   }
-}
+}

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

+ 30 - 29
Playground/scripts/scripts.txt

@@ -1,29 +1,30 @@
-Basic scene
-Basic elements
-Rotation and scaling
-Materials
-Cameras
-Lights
-Animations
-Sprites
-Collisions
-Intersections
-Picking
-Particles
-Environment
-Height map
-Shadows
-Import meshes
-Actions
-Drag and drop
-Fresnel
-Easing functions
-ProceduralTexture
-Basic sounds
-Sound on mesh
-SSAO rendering pipeline
-Volumetric Light Scattering
-HDR Rendering Pipeline
-Refraction and Reflection
-PBR
-Instanced bones
+basic scene
+basic elements
+rotation and scaling
+materials
+cameras
+lights
+animations
+sprites
+collisions
+intersections
+picking
+particles
+environment
+height map
+shadows
+import meshes
+actions
+drag and drop
+fresnel
+easing functions
+proceduralTexture
+basic sounds
+sound on mesh
+ssao rendering pipeline
+volumetric Light Scattering
+hdr Rendering Pipeline
+refraction and Reflection
+pbr
+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);

+ 0 - 146
Playground/splitbox.css

@@ -1,146 +0,0 @@
-x-splitbox {
-  position: relative;
-  display: -webkit-box;      /* OLD - iOS 6-, Safari 3.1-6 */
-  display: -moz-box;         /* OLD - Firefox 19- (buggy but mostly works) */
-  display: -ms-flexbox;      /* TWEENER - IE 10 */
-  display: -webkit-flex;     /* NEW - Chrome */
-  display: flex;             /* NEW, Spec - Opera 12.1, Firefox 20+ */
-  height: 100%;
-  overflow: hidden;
-  -webkit-box-sizing: border-box;
-  -moz-box-sizing: border-box;
-  -ms-box-sizing: border-box;
-  box-sizing: border-box;
-  -webkit-box-orient: horizontal;
-  -moz-box-orient: horizontal;
-  -ms-box-orient: horizontal;
-  box-orient: horizontal;
-  -webkit-flex-direction: row;
-  -moz-flex-direction: row;
-  -ms-flex-direction: row;
-  flex-direction: row;
-}
-
-x-splitbox[direction="column"] {
-  -webkit-box-orient: vertical;
-  -moz-box-orient: vertical;
-  -ms-box-orient: vertical;
-  box-orient: vertical;
-  -webkit-flex-direction: column;
-  -moz-flex-direction: column;
-  -ms-flex-direction: column;
-  flex-direction: column;
-}
-
-x-splitbox > *:not([splitter]) {
-  min-width: 0;
-  min-height: 0;
-  -webkit-box-flex: 1;
-  -moz-box-flex: 1;
-  -webkit-flex: 1;
-  flex: 1;
-  -ms-flex: auto;
-  -webkit-box-sizing: border-box;
-  -moz-box-sizing: border-box;
-  -ms-box-sizing: border-box;
-  box-sizing: border-box;
-}
-
-x-splitbox[dragging], x-splitbox > [splitter] {
-  -moz-user-select: -moz-none;
-  -khtml-user-select: none;
-  -webkit-user-select: none;
-  -ms-user-select: none;
-  user-select: none;
-  -webkit-user-drag: none;
-}
-
-x-splitbox > [splitter] {
-  display: block;
-  position: relative;
-  min-width: 0px !important;
-  max-width: 0px !important;
-  cursor: ew-resize;
-  background: #fff;
-  opacity: 0.6;
-}
-
-  x-splitbox > [splitter]:before {
-    content: " ";
-    display: block;
-    position: absolute;
-    width: 0.8em;
-    height: 100%;
-    opacity: 0;
-    background: inherit;
-    -webkit-box-sizing: border-box;
-    -moz-box-sizing: border-box;
-    -ms-box-sizing: border-box;
-    box-sizing: border-box;
-    -webkit-transform: translate(-50%, 0);
-    -ms-transform: translate(-50%, 0);
-    transform: translate(-50%, 0);
-  }
-
-  x-splitbox > [splitter]:after {
-    content: url('data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMWVtIiB3aWR0aD0iMWVtIiB2aWV3Qm94PSIwIDAgMTAyNCAxMDI0Ij48cGF0aCBmaWxsPSJyZ2JhKDAsMCwwLDAuNzUpIiBkPSJNNzU4IDIzNGwyMzIgMjc4LTIzMiAyNzgtNjYtNTQgMTg2LTIyNC0xODYtMjI0ek00NzAgNTU0di04NGg4NHY4NGgtODR6TTcyNiA0NzB2ODRoLTg2di04NGg4NnpNMjk4IDU1NHYtODRoODZ2ODRoLTg2ek0zMzIgMjg4bC0xODYgMjI0IDE4NiAyMjQtNjYgNTQtMjMyLTI3OCAyMzItMjc4eiI+PC9wYXRoPjwvc3ZnPg==');
-    position: absolute;
-    top: 50%;
-    left: 50%;
-    height: 1em;
-    padding: 0.05em;
-    background: inherit;
-    border-radius: 100%;
-    -webkit-box-shadow: 0 1px 1px 0px rgba(0,0,0,0.4);
-    -ms-box-shadow: 0 1px 1px 0px rgba(0,0,0,0.4);
-    box-shadow: 0 1px 1px 0px rgba(0,0,0,0.4);
-    -webkit-transform: translate(-50%, -50%);
-    -ms-transform: translate(-50%, -50%);
-    transform: translate(-50%, -50%);
-  }
-
-  x-splitbox[direction="column"] > [splitter] {
-    cursor: ns-resize;
-    min-width: auto !important;
-    max-width: none !important;
-    min-height: 0px !important;
-    max-height: 0px !important;
-  }
-
-  x-splitbox[direction="column"] > [splitter]:before {
-    width: 100%;
-    height: 0.8em;
-    -webkit-transform: translate(0%, -50%);
-    -ms-transform: translate(0%, -50%);
-    transform: translate(0%, -50%);
-  }
-
-  x-splitbox[direction="column"] > [splitter]:after {
-    -webkit-box-shadow: 1px 0 1px 0px rgba(0,0,0,0.4);
-    -ms-box-shadow: 1px 0 1px 0px rgba(0,0,0,0.4);
-    box-shadow: 1px 0 1px 0px rgba(0,0,0,0.4);
-    -webkit-transform: translate(-50%, -50%) rotate(90deg);
-    -ms-transform: translate(-50%, -50%) rotate(90deg);
-    transform: translate(-50%, -50%) rotate(90deg);
-  }
-
-  x-splitbox > [splitter]:hover, x-splitbox > [splitter][dragging] {
-    opacity: 1;
-    z-index: 2;
-  }
-
-  x-splitbox > [splitter][dragging]:before {
-    opacity: 0.3;
-  }
-
-
-@media screen and (max-device-width: 415px) {
-  x-splitbox > [splitter]:before {
-    display: block;
-  }
-
-    x-splitbox[direction="column"] > [splitter] {
-      display: block;
-    }
-}
-

+ 0 - 116
Playground/splitbox.js

@@ -1,116 +0,0 @@
-(function () {
-
-    function startDrag(node, splitter, event) {
-
-        node.setAttribute('dragging', '');
-        node.xtag.splitter = splitter;
-        splitter.setAttribute('dragging', '');
-        splitter.style.zIndex = node.xtag.splitZ = (node.xtag.splitZ || 0) + 1;
-
-        var props = getProps(node);
-        var lastCoord = event[props.page] - node[props.edge];
-        var next = splitter.nextElementSibling, next = !next.hasAttribute('splitter') && next;
-        var previous = splitter.previousElementSibling, previous = !previous.hasAttribute('splitter') && previous;
-        var startingTotal = next[props.size] + previous[props.size];
-
-        setPercents(node, props);
-
-        node.xtag.drag = xtag.addEvent(node, 'move', function (e) {
-            var delta = e[props.page] - node[props.edge] - lastCoord;
-            var nextSize = next[props.size];
-            var prevSize = previous[props.size];
-            var nextMod = nextSize - delta;
-            var prevMod = prevSize + delta;
-
-            if (delta > 0) {
-                if (nextSize > 0) {
-                    if (nextMod <= 0 || prevMod >= startingTotal || prevMod > startingTotal || nextMod > startingTotal) {
-                        prevMod = startingTotal;
-                        nextMod = 0;
-                    }
-                    setMinMax(next, props, nextMod);
-                    setMinMax(previous, props, prevMod);
-                }
-            }
-
-            else if (delta < 0) {
-                if (prevSize > 0) {
-                    if (prevMod <= 0 || nextMod >= startingTotal || prevMod > startingTotal || nextMod > startingTotal) {
-                        nextMod = startingTotal;
-                        prevMod = 0;
-                    }
-                    setMinMax(next, props, nextMod);
-                    setMinMax(previous, props, prevMod);
-                }
-            }
-
-            lastCoord = e[props.page] - node[props.edge];
-        });
-    }
-
-    function getProps(node) {
-        return node.xtag.props = (node.direction == 'column') ? {
-            page: 'pageY',
-            size: 'clientHeight',
-            edge: 'clientTop',
-            parentSize: node.clientHeight
-        } : {
-            page: 'pageX',
-            size: 'clientWidth',
-            edge: 'clientLeft',
-            parentSize: node.clientWidth
-        };
-    }
-
-    function setPercents(node, props, setup) {
-        node.xtag.panels = xtag.queryChildren(node, '*:not([splitter])').map(function (el) {
-            setMinMax(el, props, el[props.size], setup);
-            return el;
-        });
-    }
-
-    function setMinMax(panel, props, value, setup) {
-        panel.style.flex = panel.style[xtag.prefix.lowercase + 'Flex'] = (setup ? '0 0 ' : '1 1 ') + (value / props.parentSize) * 100 + '%';
-    }
-
-    function stopDrag(node) {
-        if (node.xtag.drag) {
-            xtag.removeEvent(node, node.xtag.drag);
-            node.removeAttribute('dragging');
-            node.xtag.splitter.removeAttribute('dragging');
-            node.xtag.splitter = null;
-            node.xtag.drag = null;
-        }
-    }
-
-    xtag.addEvent(window, 'tapend', function (e) {
-        xtag.query(document, 'x-splitbox[dragging]').forEach(stopDrag);
-    })
-
-    xtag.register('x-splitbox', {
-        events: {
-            'tapstart:delegate(x-splitbox > [splitter])': function (e) {
-                startDrag(e.currentTarget, this, e);
-            },
-            dragstart: function (e) {
-                if (this.hasAttribute('dragging')) {
-                    e.preventDefault();
-                    return false;
-                }
-            },
-            contextmemu: function (e) {
-                e.preventDefault();
-            }
-        },
-        accessors: {
-            direction: {
-                attribute: { def: 'row' },
-                set: function (direction) {
-                    setPercents(this, getProps(this), true);
-                }
-            }
-        }
-    });
-
-})();
-

+ 55 - 0
Playground/test.html

@@ -0,0 +1,55 @@
+<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="metadataButton">+Meta data</button>
+        <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 class="save-message" id="saveMessage">
+    This PG has no metadata. Click save to add them.
+</div>

binární
Playground/textures/babylonjs.mp4


binární
Playground/textures/babylonjs.webm


Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 0 - 2
Playground/xtag.min.js


Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 676 - 560
Tools/Gulp/config.json


+ 189 - 183
Tools/Gulp/custom.config.json

@@ -11,189 +11,195 @@
       "!../../src/**/*.d.ts"
     ],
     "files": [
-      "../../src/Math/babylon.math.js",
-      "../../src/babylon.mixins.js",
-      "../../src/Tools/babylon.decorators.js",
-      "../../src/Tools/babylon.observable.js",
-      "../../src/Tools/babylon.database.js",
-      "../../src/Tools/babylon.tools.tga.js",
-      "../../src/Tools/babylon.smartArray.js",
-      "../../src/Tools/babylon.stringDictionary.js",
-      "../../src/Tools/babylon.tools.js",
-      "../../src/States/babylon.alphaCullingState.js",
-      "../../src/States/babylon.depthCullingState.js",
-      "../../src/States/babylon.stencilState.js",
-      "../../src/babylon.engine.js",
-      "../../src/babylon.node.js",
-      "../../src/Tools/babylon.filesInput.js",
-      "../../src/Collisions/babylon.pickingInfo.js",
-      "../../src/Culling/babylon.boundingSphere.js",
-      "../../src/Culling/babylon.boundingBox.js",
-      "../../src/Culling/babylon.boundingInfo.js",
-      "../../src/Culling/babylon.ray.js",
-      "../../src/Mesh/babylon.abstractMesh.js",
-      "../../src/Lights/babylon.light.js",
-      "../../src/Lights/babylon.pointLight.js",
-      "../../src/Lights/babylon.spotLight.js",
-      "../../src/Lights/babylon.hemisphericLight.js",
-      "../../src/Lights/babylon.directionalLight.js",
-      "../../src/Lights/Shadows/babylon.shadowGenerator.js",
-      "../../src/Collisions/babylon.collider.js",
-      "../../src/Collisions/babylon.collisionCoordinator.js",
-      "../../src/Cameras/babylon.camera.js",
-      "../../src/Cameras/babylon.cameraInputsManager.js",
-      "../../src/Cameras/Inputs/babylon.freecamera.input.mouse.js",
-      "../../src/Cameras/Inputs/babylon.freecamera.input.keyboard.js",
-      "../../src/Cameras/Inputs/babylon.freecamera.input.touch.js",
-      "../../src/Cameras/Inputs/babylon.freecamera.input.deviceorientation.js",
-      "../../src/Cameras/Inputs/babylon.freecamera.input.gamepad.js",
-      "../../src/Cameras/Inputs/babylon.arcrotatecamera.input.keyboard.js",
-      "../../src/Cameras/Inputs/babylon.arcrotatecamera.input.mousewheel.js",
-      "../../src/Cameras/Inputs/babylon.arcrotatecamera.input.pointers.js",
-      "../../src/Cameras/Inputs/babylon.arcrotatecamera.input.gamepad.js",
-      "../../src/Cameras/Inputs/babylon.arcrotatecamera.input.vrdeviceorientation.js",
-      "../../src/Cameras/babylon.targetCamera.js",
-      "../../src/Cameras/babylon.freeCamera.js",
-      "../../src/Cameras/babylon.freeCameraInputsManager.js",
-      "../../src/Cameras/babylon.followCamera.js",
-      "../../src/Cameras/babylon.touchCamera.js",
-      "../../src/Cameras/babylon.arcRotateCamera.js",
-      "../../src/Cameras/babylon.arcRotateCameraInputsManager.js",
-      "../../src/Rendering/babylon.renderingManager.js",
-      "../../src/Rendering/babylon.renderingGroup.js",
-      "../../src/babylon.scene.js",
-      "../../src/Mesh/babylon.buffer.js",
-      "../../src/Mesh/babylon.vertexBuffer.js",
-      "../../src/Mesh/babylon.instancedMesh.js",
-      "../../src/Mesh/babylon.mesh.js",
-      "../../src/Mesh/babylon.subMesh.js",
-      "../../src/Mesh/babylon.meshBuilder.js",
-      "../../src/Materials/Textures/babylon.baseTexture.js",
-      "../../src/Materials/Textures/babylon.texture.js",
-      "../../src/Materials/Textures/babylon.cubeTexture.js",
-      "../../src/Materials/Textures/babylon.renderTargetTexture.js",
-      "../../src/Materials/Textures/Procedurals/babylon.proceduralTexture.js",
-      "../../src/Materials/Textures/babylon.mirrorTexture.js",
-      "../../src/Materials/Textures/babylon.refractionTexture.js",
-      "../../src/Materials/Textures/babylon.dynamicTexture.js",
-      "../../src/Materials/Textures/babylon.videoTexture.js",
-      "../../src/Materials/Textures/Procedurals/babylon.customProceduralTexture.js",
-      "../../src/Materials/babylon.effect.js",
-      "../../src/Materials/babylon.materialHelper.js",
-      "../../src/Materials/babylon.fresnelParameters.js",
-      "../../src/Materials/babylon.material.js",
-      "../../src/Materials/babylon.standardMaterial.js",
-      "../../src/Materials/babylon.multiMaterial.js",
-      "../../src/Loading/babylon.sceneLoader.js",
-      "../../src/Loading/Plugins/babylon.babylonFileLoader.js",
-      "../../src/Sprites/babylon.spriteManager.js",
-      "../../src/Sprites/babylon.sprite.js",
-      "../../src/Layer/babylon.layer.js",
-      "../../src/Particles/babylon.particle.js",
-      "../../src/Particles/babylon.particleSystem.js",
-      "../../src/Animations/babylon.animation.js",
-      "../../src/Animations/babylon.animatable.js",
-      "../../src/Animations/babylon.easing.js",
-      "../../src/Bones/babylon.bone.js",
-      "../../src/Bones/babylon.boneIKController.js",
-      "../../src/Bones/babylon.boneLookController.js",
-      "../../src/Bones/babylon.skeleton.js",
-      "../../src/PostProcess/babylon.postProcess.js",
-      "../../src/PostProcess/babylon.postProcessManager.js",
-      "../../src/PostProcess/babylon.passPostProcess.js",
-      "../../src/Physics/babylon.physicsJoint.js",
-      "../../src/Physics/babylon.physicsImpostor.js",
-      "../../src/Physics/babylon.physicsEngine.js",
-      "../../src/Mesh/babylon.mesh.vertexData.js",
-      "../../src/Tools/babylon.tags.js",
-      "../../src/Tools/babylon.andOrNotEvaluator.js",
-      "../../src/PostProcess/RenderPipeline/babylon.postProcessRenderPass.js",
-      "../../src/PostProcess/RenderPipeline/babylon.postProcessRenderEffect.js",
-      "../../src/PostProcess/RenderPipeline/babylon.postProcessRenderPipeline.js",
-      "../../src/PostProcess/RenderPipeline/babylon.postProcessRenderPipelineManager.js",
-      "../../src/Rendering/babylon.boundingBoxRenderer.js",
-      "../../src/Actions/babylon.condition.js",
-      "../../src/Actions/babylon.action.js",
-      "../../src/Actions/babylon.actionManager.js",
-      "../../src/Actions/babylon.interpolateValueAction.js",
-      "../../src/Actions/babylon.directActions.js",
-      "../../src/Mesh/babylon.geometry.js",
-      "../../src/Mesh/babylon.groundMesh.js",
-      "../../src/Mesh/babylon.instancedMesh.js",
-      "../../src/Mesh/babylon.linesMesh.js",
-      "../../src/Tools/babylon.loadingScreen.js",
-      "../../src/Audio/babylon.audioEngine.js",
-      "../../src/Audio/babylon.sound.js",
-      "../../src/Audio/babylon.soundtrack.js",
-      "../../src/Layer/babylon.highlightlayer.js",
-      "../../src/Math/babylon.math.SIMD.js",
-      "../../src/Tools/babylon.rectPackingMap.js",
-      "../../src/Tools/babylon.dynamicFloatArray.js",
-      "../../src/Materials/Textures/babylon.mapTexture.js",
-      "../../src/Materials/babylon.shaderMaterial.js",
-      "../../src/Tools/babylon.tools.dds.js",
-      "../../src/Physics/Plugins/babylon.cannonJSPlugin.js",
-      "../../src/Physics/Plugins/babylon.oimoJSPlugin.js",
-      "../../src/PostProcess/babylon.displayPassPostProcess.js",
-      "../../src/Mesh/babylon.meshSimplification.js",
-      "../../src/Tools/babylon.sceneSerializer.js",
-      "../../src/Tools/babylon.earcut.js",
-      "../../src/Mesh/babylon.csg.js",
-      "../../src/PostProcess/babylon.vrDistortionCorrectionPostProcess.js",
-      "../../src/Tools/babylon.virtualJoystick.js",
-      "../../src/Cameras/babylon.virtualJoysticksCamera.js",      
-      "../../src/Cameras/Inputs/babylon.freecamera.input.virtualjoystick.js",
-      "../../src/PostProcess/babylon.anaglyphPostProcess.js",
-      "../../src/Rendering/babylon.outlineRenderer.js",
-      "../../src/Tools/babylon.assetsManager.js",
-      "../../src/Cameras/VR/babylon.vrCameraMetrics.js",
-      "../../src/Cameras/VR/babylon.webVRCamera.js",
-      "../../src/Tools/babylon.sceneOptimizer.js",
-      "../../src/Mesh/babylon.meshLODLevel.js",
-      "../../src/Materials/Textures/babylon.rawTexture.js",
-      "../../src/Mesh/babylon.polygonMesh.js",
-      "../../src/Culling/Octrees/babylon.octree.js",
-      "../../src/Culling/Octrees/babylon.octreeBlock.js",
-      "../../src/PostProcess/babylon.blurPostProcess.js",
-      "../../src/PostProcess/babylon.refractionPostProcess.js",
-      "../../src/PostProcess/babylon.blackAndWhitePostProcess.js",
-      "../../src/PostProcess/babylon.convolutionPostProcess.js",
-      "../../src/PostProcess/babylon.filterPostProcess.js",
-      "../../src/PostProcess/babylon.fxaaPostProcess.js",
-      "../../src/PostProcess/babylon.stereoscopicInterlacePostProcess.js",
-      "../../src/LensFlare/babylon.lensFlare.js",
-      "../../src/LensFlare/babylon.lensFlareSystem.js",
-      "../../src/Cameras/babylon.deviceOrientationCamera.js",
-      "../../src/Cameras/VR/babylon.vrDeviceOrientationCamera.js",
-      "../../src/Cameras/babylon.universalCamera.js",
-      "../../src/Tools/babylon.gamepads.js",
-      "../../src/Cameras/babylon.gamepadCamera.js",
-      "../../src/Audio/babylon.analyser.js",
-      "../../src/Rendering/babylon.depthRenderer.js",
-      "../../src/PostProcess/babylon.ssaoRenderingPipeline.js",
-      "../../src/PostProcess/babylon.volumetricLightScatteringPostProcess.js",
-      "../../src/PostProcess/babylon.lensRenderingPipeline.js",
-      "../../src/PostProcess/babylon.colorCorrectionPostProcess.js",
-      "../../src/Cameras/babylon.stereoscopicCameras.js",
-      "../../src/PostProcess/babylon.hdrRenderingPipeline.js",
-      "../../src/Rendering/babylon.edgesRenderer.js",
-      "../../src/PostProcess/babylon.tonemapPostProcess.js",
-      "../../src/Probes/babylon.reflectionProbe.js",
-      "../../src/Particles/babylon.solidParticle.js",
-      "../../src/Particles/babylon.solidParticleSystem.js",
-      "../../src/Tools/HDR/babylon.tools.cubemapToSphericalPolynomial.js",
-      "../../src/Tools/HDR/babylon.tools.panoramaToCubemap.js",
-      "../../src/Tools/HDR/babylon.tools.hdr.js",
-      "../../src/Tools/HDR/babylon.tools.pmremgenerator.js",
-      "../../src/Materials/Textures/babylon.hdrCubeTexture.js",
-      "../../src/Debug/babylon.skeletonViewer.js",
-      "../../src/Debug/babylon.axesViewer.js",
-      "../../src/Debug/babylon.boneAxesViewer.js",
-      "../../src/Materials/Textures/babylon.colorGradingTexture.js",
-      "../../src/Materials/babylon.colorCurves.js",
-      "../../src/Materials/babylon.pbrMaterial.js",      
-      "../../src/Debug/babylon.debugLayer.js",
-      "../../src/PostProcess/babylon.standardRenderingPipeline.js"
+            "../../src/Math/babylon.math.js",
+            "../../src/babylon.mixins.js",
+            "../../src/Tools/babylon.decorators.js",
+            "../../src/Tools/babylon.observable.js",
+            "../../src/Tools/babylon.database.js",
+            "../../src/Tools/babylon.tga.js",
+            "../../src/Tools/babylon.smartArray.js",
+            "../../src/Tools/babylon.stringDictionary.js",
+            "../../src/Tools/babylon.tools.js",
+            "../../src/States/babylon.alphaCullingState.js",
+            "../../src/States/babylon.depthCullingState.js",
+            "../../src/States/babylon.stencilState.js",
+            "../../src/Tools/babylon.loadingScreen.js",
+            "../../src/babylon.engine.js",
+            "../../src/babylon.node.js",
+            "../../src/Tools/babylon.filesInput.js",
+            "../../src/Collisions/babylon.pickingInfo.js",
+            "../../src/Culling/babylon.boundingSphere.js",
+            "../../src/Culling/babylon.boundingBox.js",
+            "../../src/Culling/babylon.boundingInfo.js",
+            "../../src/Culling/babylon.ray.js",
+            "../../src/Debug/babylon.rayHelper.js",
+            "../../src/Mesh/babylon.abstractMesh.js",
+            "../../src/Lights/babylon.light.js",
+            "../../src/Lights/babylon.pointLight.js",
+            "../../src/Lights/babylon.spotLight.js",
+            "../../src/Lights/babylon.hemisphericLight.js",
+            "../../src/Lights/babylon.directionalLight.js",
+            "../../src/Lights/Shadows/babylon.shadowGenerator.js",
+            "../../src/Collisions/babylon.collider.js",
+            "../../src/Collisions/babylon.collisionCoordinator.js",
+            "../../src/Cameras/babylon.camera.js",
+            "../../src/Cameras/babylon.cameraInputsManager.js",
+            "../../src/Cameras/Inputs/babylon.freeCameraMouseInput.js",
+            "../../src/Cameras/Inputs/babylon.freeCameraKeyboardMoveInput.js",
+            "../../src/Cameras/Inputs/babylon.freeCameraTouchInput.js",
+            "../../src/Cameras/Inputs/babylon.freeCameraDeviceOrientationInput.js",
+            "../../src/Cameras/Inputs/babylon.freeCameraGamepadInput.js",
+            "../../src/Cameras/Inputs/babylon.arcRotateCameraKeyboardMoveInput.js",
+            "../../src/Cameras/Inputs/babylon.arcRotateCameraMouseWheelInput.js",
+            "../../src/Cameras/Inputs/babylon.arcRotateCameraPointersInput.js",
+            "../../src/Cameras/Inputs/babylon.arcRotateCameraGamepadInput.js",
+            "../../src/Cameras/Inputs/babylon.arcRotateCameraVRDeviceOrientationInput.js",
+            "../../src/Cameras/babylon.targetCamera.js",
+            "../../src/Cameras/babylon.freeCamera.js",
+            "../../src/Cameras/babylon.freeCameraInputsManager.js",
+            "../../src/Cameras/babylon.followCamera.js",
+            "../../src/Cameras/babylon.touchCamera.js",
+            "../../src/Cameras/babylon.arcRotateCamera.js",
+            "../../src/Cameras/babylon.arcRotateCameraInputsManager.js",
+            "../../src/Rendering/babylon.renderingManager.js",
+            "../../src/Rendering/babylon.renderingGroup.js",
+            "../../src/PostProcess/babylon.postProcessManager.js",
+            "../../src/PostProcess/RenderPipeline/babylon.postProcessRenderPipelineManager.js",
+            "../../src/Rendering/babylon.boundingBoxRenderer.js",
+            "../../src/babylon.scene.js",
+            "../../src/Mesh/babylon.buffer.js",
+            "../../src/Mesh/babylon.vertexBuffer.js",
+            "../../src/Mesh/babylon.instancedMesh.js",
+            "../../src/Mesh/babylon.mesh.js",
+            "../../src/Mesh/babylon.subMesh.js",
+            "../../src/Mesh/babylon.meshBuilder.js",
+            "../../src/Materials/Textures/babylon.baseTexture.js",
+            "../../src/Materials/Textures/babylon.texture.js",
+            "../../src/Materials/Textures/babylon.cubeTexture.js",
+            "../../src/Materials/Textures/babylon.renderTargetTexture.js",
+            "../../src/Materials/Textures/Procedurals/babylon.proceduralTexture.js",
+            "../../src/Materials/Textures/babylon.mirrorTexture.js",
+            "../../src/Materials/Textures/babylon.refractionTexture.js",
+            "../../src/Materials/Textures/babylon.dynamicTexture.js",
+            "../../src/Materials/Textures/babylon.videoTexture.js",
+            "../../src/Materials/Textures/Procedurals/babylon.customProceduralTexture.js",
+            "../../src/Materials/babylon.effect.js",
+            "../../src/Materials/babylon.materialHelper.js",
+            "../../src/Materials/babylon.fresnelParameters.js",
+            "../../src/Materials/babylon.material.js",
+            "../../src/Materials/babylon.pushMaterial.js",
+            "../../src/Materials/babylon.standardMaterial.js",
+            "../../src/Materials/babylon.multiMaterial.js",
+            "../../src/Loading/babylon.sceneLoader.js",
+            "../../src/Loading/Plugins/babylon.babylonFileLoader.js",
+            "../../src/Sprites/babylon.spriteManager.js",
+            "../../src/Sprites/babylon.sprite.js",
+            "../../src/Layer/babylon.layer.js",
+            "../../src/Particles/babylon.particle.js",
+            "../../src/Particles/babylon.particleSystem.js",
+            "../../src/Animations/babylon.animation.js",
+            "../../src/Animations/babylon.animatable.js",
+            "../../src/Animations/babylon.easing.js",
+            "../../src/Bones/babylon.bone.js",
+            "../../src/Bones/babylon.boneIKController.js",
+            "../../src/Bones/babylon.boneLookController.js",
+            "../../src/Bones/babylon.skeleton.js",
+            "../../src/PostProcess/babylon.postProcess.js",
+            "../../src/PostProcess/babylon.passPostProcess.js",
+            "../../src/Physics/babylon.physicsJoint.js",
+            "../../src/Physics/babylon.physicsImpostor.js",
+            "../../src/Physics/babylon.physicsEngine.js",
+            "../../src/Mesh/babylon.mesh.vertexData.js",
+            "../../src/Tools/babylon.tags.js",
+            "../../src/Tools/babylon.andOrNotEvaluator.js",
+            "../../src/PostProcess/RenderPipeline/babylon.postProcessRenderPass.js",
+            "../../src/PostProcess/RenderPipeline/babylon.postProcessRenderEffect.js",
+            "../../src/PostProcess/RenderPipeline/babylon.postProcessRenderPipeline.js",
+            "../../src/Actions/babylon.condition.js",
+            "../../src/Actions/babylon.action.js",
+            "../../src/Actions/babylon.actionManager.js",
+            "../../src/Actions/babylon.interpolateValueAction.js",
+            "../../src/Actions/babylon.directActions.js",
+            "../../src/Mesh/babylon.geometry.js",
+            "../../src/Mesh/babylon.groundMesh.js",
+            "../../src/Mesh/babylon.instancedMesh.js",
+            "../../src/Mesh/babylon.linesMesh.js",
+            "../../src/Audio/babylon.audioEngine.js",
+            "../../src/Audio/babylon.sound.js",
+            "../../src/Audio/babylon.soundtrack.js",
+            "../../src/Layer/babylon.highlightlayer.js",
+            "../../src/Math/babylon.math.SIMD.js",
+            "../../src/Tools/babylon.rectPackingMap.js",
+            "../../src/Tools/babylon.dynamicFloatArray.js",
+            "../../src/Materials/Textures/babylon.mapTexture.js",
+            "../../src/Materials/babylon.shaderMaterial.js",
+            "../../src/Tools/babylon.dds.js",
+            "../../src/Tools/babylon.khronosTextureContainer.js",
+            "../../src/Physics/Plugins/babylon.cannonJSPlugin.js",
+            "../../src/Physics/Plugins/babylon.oimoJSPlugin.js",
+            "../../src/PostProcess/babylon.displayPassPostProcess.js",
+            "../../src/Mesh/babylon.meshSimplification.js",
+            "../../src/Tools/babylon.sceneSerializer.js",
+            "../../src/Tools/babylon.earcut.js",
+            "../../src/Mesh/babylon.csg.js",
+            "../../src/PostProcess/babylon.vrDistortionCorrectionPostProcess.js",
+            "../../src/Tools/babylon.virtualJoystick.js",
+            "../../src/Cameras/babylon.virtualJoysticksCamera.js",
+            "../../src/Cameras/Inputs/babylon.freeCameraVirtualJoystickInput.js",
+            "../../src/PostProcess/babylon.anaglyphPostProcess.js",
+            "../../src/Rendering/babylon.outlineRenderer.js",
+            "../../src/Tools/babylon.assetsManager.js",
+            "../../src/Cameras/VR/babylon.vrCameraMetrics.js",
+            "../../src/Cameras/VR/babylon.webVRCamera.js",
+            "../../src/Tools/babylon.sceneOptimizer.js",
+            "../../src/Mesh/babylon.meshLODLevel.js",
+            "../../src/Materials/Textures/babylon.rawTexture.js",
+            "../../src/Mesh/babylon.polygonMesh.js",
+            "../../src/Culling/Octrees/babylon.octree.js",
+            "../../src/Culling/Octrees/babylon.octreeBlock.js",
+            "../../src/PostProcess/babylon.blurPostProcess.js",
+            "../../src/PostProcess/babylon.refractionPostProcess.js",
+            "../../src/PostProcess/babylon.blackAndWhitePostProcess.js",
+            "../../src/PostProcess/babylon.convolutionPostProcess.js",
+            "../../src/PostProcess/babylon.filterPostProcess.js",
+            "../../src/PostProcess/babylon.fxaaPostProcess.js",
+            "../../src/PostProcess/babylon.stereoscopicInterlacePostProcess.js",
+            "../../src/LensFlare/babylon.lensFlare.js",
+            "../../src/LensFlare/babylon.lensFlareSystem.js",
+            "../../src/Cameras/babylon.deviceOrientationCamera.js",
+            "../../src/Cameras/VR/babylon.vrDeviceOrientationCamera.js",
+            "../../src/Cameras/babylon.universalCamera.js",
+            "../../src/Tools/babylon.gamepads.js",
+            "../../src/Tools/babylon.extendedGamepad.js",
+            "../../src/Cameras/babylon.gamepadCamera.js",
+            "../../src/Audio/babylon.analyser.js",
+            "../../src/Rendering/babylon.depthRenderer.js",
+            "../../src/PostProcess/babylon.ssaoRenderingPipeline.js",
+            "../../src/PostProcess/babylon.volumetricLightScatteringPostProcess.js",
+            "../../src/PostProcess/babylon.lensRenderingPipeline.js",
+            "../../src/PostProcess/babylon.colorCorrectionPostProcess.js",
+            "../../src/Cameras/babylon.stereoscopicCameras.js",
+            "../../src/PostProcess/babylon.hdrRenderingPipeline.js",
+            "../../src/Rendering/babylon.edgesRenderer.js",
+            "../../src/PostProcess/babylon.tonemapPostProcess.js",
+            "../../src/Probes/babylon.reflectionProbe.js",
+            "../../src/Particles/babylon.solidParticle.js",
+            "../../src/Particles/babylon.solidParticleSystem.js",
+            "../../src/Tools/HDR/babylon.cubemapToSphericalPolynomial.js",
+            "../../src/Tools/HDR/babylon.panoramaToCubemap.js",
+            "../../src/Tools/HDR/babylon.hdr.js",
+            "../../src/Tools/HDR/babylon.pmremgenerator.js",
+            "../../src/Materials/Textures/babylon.hdrCubeTexture.js",
+            "../../src/Debug/babylon.skeletonViewer.js",
+            "../../src/Debug/babylon.axesViewer.js",
+            "../../src/Debug/babylon.boneAxesViewer.js",
+            "../../src/Materials/Textures/babylon.colorGradingTexture.js",
+            "../../src/Materials/babylon.colorCurves.js",
+            "../../src/Materials/babylon.pbrMaterial.js",
+            "../../src/Debug/babylon.debugLayer.js",
+            "../../src/PostProcess/babylon.standardRenderingPipeline.js",
+            "../../src/Morph/babylon.morphTarget.js",
+            "../../src/Morph/babylon.morphTargetManager.js"
     ]
   }
 }

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

+ 9 - 1
Tools/Gulp/gulpfile.js

@@ -26,12 +26,14 @@ var zip = require('gulp-zip');
 var config = require("./config.json");
 var customConfig = require("./custom.config.json");
 
+var del = require('del');
+
 var debug = require('gulp-debug');
 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;
 
 /**
@@ -393,3 +395,9 @@ gulp.task("zip-blender" , function() {
     .pipe(zip('Blender2Babylon-5.2.zip'))
     .pipe(gulp.dest('../../Exporters/Blender'));
 });
+
+gulp.task('clean-JS-MAP', function () {
+	  return del([
+		  '../../src/**/*.js.map','../../src/**/*.js'
+	  ], {force: true});
+	});

+ 6 - 5
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": "^2.0.1",
+    "gulp-uglify": "^2.1.2",
     "gulp-sourcemaps": "~1.9.1",
-    "typescript": "~2.1.4",
-    "gulp-typescript": "^3.1.5",
+    "typescript": "~2.2.2",
+    "gulp-typescript": "^3.1.6",
     "through2": "~0.6.5",
     "gulp-util": "~3.0.4",
     "gulp-concat": "~2.5.2",
@@ -32,7 +32,8 @@
     "style-loader": "^0.13.1",
     "exports-loader": "^0.6.3",
     "imports-loader": "^0.7.0",
-    "gulp-zip": "~3.2.0"
+    "gulp-zip": "~3.2.0",
+    "del": "2.2.2"
   },
   "scripts": {
     "install": "npm --prefix ../../Playground/ install ../../Playground/ && gulp typescript-compile && gulp typescript-libraries && gulp deployLocalDev"

+ 240 - 0
Tools/Gulp/profiling.html

@@ -0,0 +1,240 @@
+<html>
+<head>
+    <title>Customize BJS for a specific Scene</title>
+    <meta charset="UTF-8">
+    <script src="../../dist/preview release/babylon.js"></script>
+    <style>
+    input.path {width:600px;}
+    input.filename {width:200px;}
+    em {color:red;}
+    </style>
+    
+</head>
+<body onload="readConfigFile()">
+Obtain a FireFox performance file by:
+<ol>
+	<li>Make sure scene uses Babylon MAX.</li>
+	<li>Add the temporary Javascript line <em>window.alert('Turn on Performance Recording')</em> just prior to Engine Instancing line.
+	<li>Load the scene, turn on performance profiling, &amp; click ok to the temporary alert.</li>
+	<li>Do anything that might call code in babylon.js not yet encountered.</li>
+	<li>Stop recording, and save the data as a file.</li>
+</ol>
+On this page:
+<ol>
+	<li>Select File with 'Browse' button below, and pick the file saved from above.</li>
+	<li>Make any changes of name to babylon file names &amp; directory..</li>
+	<li>Click Generate. Tip: change Firefox Option for Downloads to <em>Always ask me where to save files</em> to avoid having to move custom config to Gulp Directory.</li>
+	<li>Copy the 'custom.cofig.json' file generated in Downloads directory to the Gulp directory.</li>
+	<li>Run: 'Gulp build-custom' then test with scene.  Tip: test with the max version generated.</li>
+	<li>If need stuff did not get recorded in performance file, then select file(s) &amp; click Generate again.</li>
+</ol>
+	<form>
+		<input type="radio" name="browser" id="firefox" checked="checked"><label for="firefox"> Firefox</label>
+		<input type="radio" name="browser" id="chrome" disabled data-toggle="tooltip" title="Not yet implemented, Go for it!"><label for="chrome"> Chrome</label>
+		<input type="radio" name="browser" id="edge"   disabled data-toggle="tooltip" title="Not yet implemented, Go for it!"><label for="edge"> Edge</label><br>
+		
+		<label>Profiling file: <input type="file" id="upload_file" name="upload" accept="text/*" multiple="" onchange="assignProfile(this.files[0])"/></label><br><br>
+		
+		Output Directory: <input class="path"     type="text" id="directory"   maxlength="256" value="C:/"> (clear for default of <em>../../dist/preview release</em>)<br>
+		Filename:         <input class="filename" type="text" id="filename"    maxlength="32"  value="babylon.custom.max.js">         
+		minFilename:      <input class="filename" type="text" id="minFilename" maxlength="32"  value="babylon.custom.js"><br>         
+        Files Not In Recording: (Select those to still keep)
+			<input type="button" value="Generate Custom Config" onclick="generate()"><br>
+        <select id="discards" multiple size="50">
+        </select>
+
+	</form>
+	<script>
+	    //  each "File" is a: [keep: boolean, fullPath: string, search]
+	    //  search is initially the file name without the .js.  
+	    var files;
+    	var reg = new RegExp('babylon\\.\\w+');
+	
+	    var FIRE_FOX = 0;
+	    var CHROME   = 1;
+	    var EDGE     = 3;
+	    
+	    function readConfigFile() {
+	    	// read the regular config file, not custom, in-case custom has already been reduced
+	    	// the regular config file has files in 2 separate sections
+	        BABYLON.Tools.LoadFile("./config.json",
+	                function(data){
+	        	        var startInd = data.indexOf('"files": [') + 11; // 11 for "files": [
+	        	        var endInd = data.indexOf(']', startInd);
+	        	        var fileNames = data.substring(startInd, endInd);
+	        	        fileNames += ","; // for spliting once glued to part 2
+	        	        
+	        	        var extras = data.indexOf('"extras"');
+	        	        startInd = data.indexOf('"files": [', extras) + 11; // 11 for "files": [
+	        	        endInd = data.indexOf(']', startInd);
+	        	        fileNames += data.substring(startInd, endInd);
+	        	        
+	        	        fileNames = fileNames.replace(/(\r\n|\n|\r)/gm,""); // strip all line breaks
+	        	        fileNames = fileNames.replace(/\s+/g, ""); // strip all whitespace
+	        	        fileNames = fileNames.split(',');
+
+	        	        var len = fileNames.length;
+                        files = new Array(len);
+                        for (var i = 0; i < len; i++) {
+                        	var name = fileNames[i].match(reg)[0].substring(8);  // remove the babylon.
+                        	files[i] = [false, fileNames[i], name];
+                        }
+						appendSecondarySearches("math.js", "mathtools|color3|color4|vector2|vector3|vector4|size|quaternion|matrix|plane|viewport|frustum|space|axis|bezierCurve|orientation|angle|arc2|path2|path3d|curve3|sphericalHarmonics|mathTmp");
+
+						// force stuff to always be added
+						appendSecondarySearches("decorators.js", "engine"); //needed for Serialize
+						appendSecondarySearches("stringDictionary.js", "engine"); //needed in Engine Constructor
+						appendSecondarySearches("postProcessRenderPipelineManager.js", "scene"); //needed in Scene Constructor		
+						appendSecondarySearches("boundingBoxRenderer.js", "scene"); //needed in Scene Constructor		
+						appendSecondarySearches("collisionCoordinator.js", "scene"); //needed in Scene Constructor, from a called set of this.workerCollisions = false;
+						appendSecondarySearches("collider.js", "abstractMesh"); // needed in abstractMesh constructor
+						appendSecondarySearches("videoTexture.js", "engine"); //needed in Engine._setTexture()	
+						
+						// there should always some detection of FreeCamera or ArcRotateCamera, but maybe not all inputs got recorded
+						appendSecondarySearches("cameraInputsManager.js", "freeCamera\\w+|arcRotateCamera\\w+");
+						
+						appendSecondarySearches("freeCamera.js", "freeCamera\\w+");
+						appendSecondarySearches("freeCameraInputsManager.js", "freeCamera\\w+");
+						appendSecondarySearches("freeCameraMouseInput.js"            , "freeCamera\\w+");
+						appendSecondarySearches("freeCameraKeyboardMoveInput.js"     , "freeCamera\\w+");
+						appendSecondarySearches("freeCameraTouchInput.js"            , "freeCamera\\w+");
+						appendSecondarySearches("freeCameraDeviceOrientationInput.js", "freeCamera\\w+");
+						appendSecondarySearches("freeCameraGamepadInput.js"          , "freeCamera\\w+");
+						appendSecondarySearches("freeCameraVirtualJoystickInput.js"  , "freeCamera\\w+");
+						
+						appendSecondarySearches("arcRotateCamera.js", "arcRotateCamera\\w+");
+						appendSecondarySearches("arcRotateCameraInputsManager.js", "arcRotateCamera\\w+");
+						appendSecondarySearches("arcRotateCameraKeyboardMoveInput.js"       , "arcRotateCamera\\w+");
+						appendSecondarySearches("arcRotateCameraMouseWheelInput.js"         , "arcRotateCamera\\w+");
+						appendSecondarySearches("arcRotateCameraPointersInput.js"           , "arcRotateCamera\\w+");
+						appendSecondarySearches("arcRotateCameraGamepadInput.js"            , "arcRotateCamera\\w+");
+						appendSecondarySearches("arcRotateCameraVRDeviceOrientationInput.js", "arcRotateCamera\\w+");
+						
+						// these are internal classes where class name has a leading '_'
+						appendSecondarySearches("alphaCullingState.js"   , "engine");
+						appendSecondarySearches("depthCullingState.js"   , "_depthCullingState");
+						appendSecondarySearches("stencilState.js"        , "_stencilState");
+						
+						// dependencies with few / no methods, so no performance to record.
+						appendSecondarySearches("pushMaterial.js", "standardMaterial");
+                        
+	                }, null, true
+	        );
+	    }
+	    
+	    // add addition conditions to match a file to.
+	    // additionals is a string with all separated with a '|'
+	    function appendSecondarySearches(baseFilename, additionals) {
+	    	for (var i = 0, len = files.length; i < len; i++) {
+	    		if (files[i][1].indexOf(baseFilename) !== -1) {
+	    			files[i][2] += "|" + additionals;
+	    			return;
+	    		}
+	    	}
+	    	throw "'" + baseFilename + "' not found as a base file name";
+	    }
+	
+	    function assignProfile(file) {
+	        BABYLON.Tools.ReadFile(file, analyse, null, false);
+	    }
+	    
+	    function analyse(data){
+	    	// make sure max was used
+	    	if (!data.match('\\.max\\.js')) {
+	    		alert('babylon.max not detected. File rejected');
+	    		return;
+	    	}
+	    	var browser;
+	    	if (document.getElementById("firefox").checked) browser = FIRE_FOX;
+	    	if (document.getElementById("chrome" ).checked) browser = CHROME;
+	    	if (document.getElementById("edge"   ).checked) browser = EDGE;
+	    	
+			var discards = document.getElementById("discards");
+			discards.options.length = 0;
+	    	
+	    	for (var i = 0, len = files.length; i < len; i++) {
+	    		files[i][0] = false; // clean out boolean for additional runs
+    			switch(browser) {
+    			case FIRE_FOX:
+	     			var exp = new RegExp('"(' + files[i][2] + ')(\\.prototype|\\.\\w)', 'i');
+    				if (data.match(exp) ) {
+    					files[i][0] = true;
+    				}
+    				break;
+    			case CHROME:
+    			case EDGE:
+    				window.alert("Code from your PR goes here!");
+    				return;
+    			}
+	    		
+	    		// add onto the discard select when not found
+	    		if (!files[i][0]){
+	    			var option = document.createElement("option");
+	    			option.text = files[i][1];
+	    			discards.add(option);
+	    		}
+	    	}
+	    }
+	    
+	    function generate() {
+	    	// get all the ones from select
+			var discards = document.getElementById("discards");
+			var opt;
+			var asText = "";
+			for (var i = 0, len = discards.options.length; i < len; i++) {
+				opt = discards.options[i];
+                if (opt.selected) {	
+                	asText += opt.text;
+                }
+			}
+
+			var directory   = document.getElementById("directory"  ).value;
+			var filename    = document.getElementById("filename"   ).value;
+			var minFilename = document.getElementById("minFilename").value;
+			
+			if (directory.length === 0) directory = "../../dist/preview release";
+	    	var out = '';
+	    	out += '{\n';
+	    	out += '  "build": {\n';
+	    	out += '	    "filename": "' + filename + '",\n';
+	    	out += '	    "minFilename": "' + minFilename + '",\n';
+	    	out += '	    "outputDirectory":  "' + directory + '",\n';
+	    	out += '	    "srcOutputDirectory": "../../src/"\n';
+	    	out += '	  },\n';
+	    	out += '	  "core": {\n';
+	    	out += '	    "typescript": [\n';
+	    	out += '	      "../../src/**/*.ts",\n';
+	    	out += '	      "!../../src/**/*.d.ts"\n';
+	    	out += '	    ],\n';
+	    	out += '	    "files": [\n';
+	    		
+	    	var isFirst = true;
+		    for (var i = 0, len = files.length; i < len; i++) {
+		    	if (files[i][0] || asText.indexOf(files[i][1]) !== -1) {
+		    		if (!isFirst) {
+		    			out += ',';
+		    		}
+	    			isFirst = false;
+		    		out += '\n      ' + files[i][1];
+		    	}
+		    }
+		    out += '\n    ]\n';
+		    out += '  }\n';
+		    out += '}\n';
+		    
+            var blob = new Blob ( [ out ], { type : 'text/plain;charset=utf-8' } );
+
+            // turn blob into an object URL;
+            var objectUrl = (window.webkitURL || window.URL).createObjectURL(blob);
+
+            var link = window.document.createElement("a");
+            link.href = objectUrl;
+            link.download = "custom.config.json";
+            var click = document.createEvent("MouseEvents");
+            click.initEvent("click", true, false);
+            link.dispatchEvent(click);	            
+	    }
+
+	</script>
+</body>
+</html>

Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 12512 - 0
Tools/Npm/Oimo.js


Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 20676 - 0
Tools/Npm/babylon.canvas2d.js


Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 31 - 0
Tools/Npm/babylon.core.js


Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 43 - 0
Tools/Npm/babylon.js


Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 61376 - 0
Tools/Npm/babylon.max.js


Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 41 - 0
Tools/Npm/babylon.noworker.js


+ 1 - 0
Tools/Npm/getfiles.bat

@@ -5,5 +5,6 @@ xcopy /Y /F "../../dist/preview release/babylon.max.js"  .
 xcopy /Y /F "../../dist/preview release/babylon.noworker.js" . 
 xcopy /Y /F "../../dist/preview release/babylon.core.js" . 
 xcopy /Y /F "../../dist/preview release/canvas2D/babylon.canvas2d.js" . 
+xcopy /Y /F "../../dist/preview release/canvas2D/babylon.canvas2d.d.ts" . 
 xcopy /Y /F "../../dist/preview release/oimo.js" . 
 pause

+ 3 - 2
Tools/Npm/package.json

@@ -7,12 +7,12 @@
   ],
   "name": "babylonjs",
   "description": "Babylon.js is a JavaScript 3D engine based on webgl.",
-  "version": "2.5.0",
+  "version": "3.0.0-alpha",
   "repository": {
     "type": "git",
     "url": "https://github.com/BabylonJS/Babylon.js.git"
   },
-  "main": "babylon.js",
+  "main": "babylon.max.js",
   "files": [
     "babylon.d.ts",
     "babylon.module.d.ts",
@@ -21,6 +21,7 @@
     "babylon.noworker.js",
     "babylon.core.js",
     "babylon.canvas2d.js",
+    "babylon.canvas2d.d.ts",
     "Oimo.js",
     "package.json"
   ],

binární
assets/sounds/explosion.wav


binární
assets/sounds/jump.wav


binární
assets/textures/Ground.jpg


binární
assets/textures/babylonjs.mp4


binární
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;
         }

+ 79 - 13
canvas2D/src/Engine/babylon.fontTexture.ts

@@ -26,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;
         }
 
         /**
@@ -50,6 +51,13 @@
         }
 
         /**
+         * True if the font was drawn using multiplied alpha
+         */
+        public get isPremultipliedAlpha(): boolean {
+            return this._isPremultipliedAlpha;
+        }
+
+        /**
          * Get the Width (in pixel) of the Space character
          */
         public get spaceWidth(): number {
@@ -148,6 +156,7 @@
         protected _spaceWidth;
         protected _superSample: boolean;
         protected _signedDistanceField: boolean;
+        protected _isPremultipliedAlpha: boolean;
         protected _cachedFontId: string;
     }
 
@@ -174,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 = () => {
@@ -351,30 +361,30 @@
             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);
@@ -404,6 +414,8 @@
             this._sdfScale = 8;
             this._signedDistanceField = signedDistanceField;
             this._superSample = false;
+            this._isPremultipliedAlpha = !signedDistanceField;
+            this.name = `FontTexture ${font}`;
 
             // SDF will use super sample no matter what, the resolution is otherwise too poor to produce correct result
             if (superSample || signedDistanceField) {
@@ -478,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);
+            }
         }
 
         /**
@@ -508,7 +557,7 @@
             var textureSize = this.getSize();
 
             // we reached the end of the current line?
-            let width = Math.ceil(measure.width);
+            let width = Math.ceil(measure.width + 0.5);
             if (this._currentFreePosition.x + width + this._xMargin > textureSize.width) {
                 this._currentFreePosition.x = 0;
                 this._currentFreePosition.y += Math.ceil(this._lineHeightSuper + this._yMargin*2);
@@ -561,12 +610,27 @@
 
                 // Draw the character in the HTML canvas
                 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((curPosXMargin) / textureSize.width, (this._currentFreePosition.y + this._yMargin) / textureSize.height);
-            info.bottomRightUV = new Vector2((curPosXMargin + width) / textureSize.width, info.topLeftUV.y + ((this._lineHeightSuper + this._yMargin) / textureSize.height));
+            info.topLeftUV = new Vector2((curPosXMargin-0.5) / textureSize.width, (this._currentFreePosition.y-0.5 + this._yMargin) / textureSize.height);
+            info.bottomRightUV = new Vector2((curPosXMargin-0.5 + width) / textureSize.width, info.topLeftUV.y + (this._lineHeightSuper / textureSize.height));
             info.yOffset = info.xOffset = 0;
+            //console.log(`Char: ${char}, Offset: ${curPosX}, ${this._currentFreePosition.y + this._yMargin}, Size: ${width}, ${this._lineHeightSuper}, UV: ${info.topLeftUV}, ${info.bottomRightUV}`);
 
             if (this._signedDistanceField) {
                 let off = 1/textureSize.width;
@@ -765,12 +829,14 @@
             ctx.font = font;
             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;

+ 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[];

Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 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 {

Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 80 - 20
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);
 }

+ 0 - 0
canvas2D/src/shaders/lines2d.vertex.fx


Některé soubory nejsou zobrazeny, neboť je v těchto rozdílových datech změněno mnoho souborů