Browse Source

Merge branch 'master' into spriteIsVisible

Trevor Baron 7 years ago
parent
commit
145e4d878b
85 changed files with 36052 additions and 32798 deletions
  1. 15097 15007
      Playground/babylon.d.txt
  2. 111 1
      Playground/css/index.css
  3. BIN
      Playground/css/pattern_ban_1.png
  4. 12 20
      Playground/debug.html
  5. 892 0
      Playground/examples/list.json
  6. 12 20
      Playground/index-local.html
  7. 12 20
      Playground/index.html
  8. 12 20
      Playground/indexStable.html
  9. 136 22
      Playground/js/index.js
  10. 30 28
      Tools/DevLoader/BabylonLoader.js
  11. 40 1
      Tools/Gulp/config.json
  12. 5 3
      Tools/Gulp/gulpfile.js
  13. 87 31
      Tools/Publisher/index.js
  14. 31 0
      Viewer/assets/package.json
  15. 19 0
      Viewer/assets/readme.md
  16. 1 1
      Viewer/src/index.ts
  17. 2 2
      Viewer/src/initializer.ts
  18. 0 1
      Viewer/src/loader/plugins/applyMaterialConfig.ts
  19. 0 1
      Viewer/src/loader/plugins/extendedMaterialLoaderPlugin.ts
  20. 0 1
      Viewer/src/loader/plugins/msftLodLoaderPlugin.ts
  21. 1 1
      Viewer/src/loader/plugins/telemetryLoaderPlugin.ts
  22. 0 0
      Viewer/src/managers/telemetryManager.ts
  23. 29 19
      Viewer/src/viewer/defaultViewer.ts
  24. 1 1
      Viewer/src/viewer/viewer.ts
  25. 1 1
      Viewer/tsconfig.json
  26. 42 0
      Viewer/webpack.assets.config.js
  27. 1 2
      Viewer/webpack.gulp.config.js
  28. BIN
      assets/environments/environmentSpecular.env
  29. 16990 16904
      dist/preview release/babylon.d.ts
  30. 27 27
      dist/preview release/babylon.js
  31. 232 61
      dist/preview release/babylon.max.js
  32. 232 61
      dist/preview release/babylon.no-module.max.js
  33. 32 32
      dist/preview release/babylon.worker.js
  34. 232 61
      dist/preview release/es6.js
  35. 1 1
      dist/preview release/gltf2Interface/package.json
  36. 83 0
      dist/preview release/gui/babylon.gui.d.ts
  37. 311 4
      dist/preview release/gui/babylon.gui.js
  38. 4 4
      dist/preview release/gui/babylon.gui.min.js
  39. 83 0
      dist/preview release/gui/babylon.gui.module.d.ts
  40. 1 1
      dist/preview release/gui/package.json
  41. 5 5
      dist/preview release/inspector/babylon.inspector.bundle.js
  42. 23 8
      dist/preview release/inspector/babylon.inspector.css
  43. 0 1
      dist/preview release/inspector/babylon.inspector.d.ts
  44. 39 41
      dist/preview release/inspector/babylon.inspector.js
  45. 4 4
      dist/preview release/inspector/babylon.inspector.min.js
  46. 1 1
      dist/preview release/inspector/package.json
  47. 2 2
      dist/preview release/loaders/package.json
  48. 1 1
      dist/preview release/materialsLibrary/package.json
  49. 1 1
      dist/preview release/postProcessesLibrary/package.json
  50. 1 1
      dist/preview release/proceduralTexturesLibrary/package.json
  51. 2 2
      dist/preview release/serializers/package.json
  52. 1 1
      dist/preview release/viewer/babylon.viewer.d.ts
  53. 44 44
      dist/preview release/viewer/babylon.viewer.js
  54. 383 201
      dist/preview release/viewer/babylon.viewer.max.js
  55. 3 3
      dist/preview release/viewer/babylon.viewer.module.d.ts
  56. 11 0
      dist/preview release/viewer/package.json
  57. 9 3
      dist/preview release/what's new.md
  58. 3 3
      gui/src/2D/controls/container.ts
  59. 3 0
      gui/src/2D/controls/control.ts
  60. 350 0
      gui/src/2D/controls/grid.ts
  61. 1 1
      gui/src/3D/controls/control3D.ts
  62. 29 8
      inspector/sass/tabs/_toolsTab.scss
  63. 1 0
      inspector/src/Inspector.ts
  64. 41 43
      inspector/src/tabs/ToolsTab.ts
  65. 1 1
      package.json
  66. 1 1
      src/Engine/babylon.engine.ts
  67. 1 1
      src/Helpers/babylon.environmentHelper.ts
  68. 102 1
      src/Helpers/babylon.particleHelper.ts
  69. 7 0
      src/Helpers/babylon.photoDome.ts
  70. 7 0
      src/Helpers/babylon.videoDome.ts
  71. 4 0
      src/Materials/Textures/babylon.hdrCubeTexture.ts
  72. 5 1
      src/Mesh/babylon.mesh.ts
  73. 12 0
      src/Mesh/babylon.transformNode.ts
  74. 1 1
      src/Particles/EmitterTypes/babylon.IParticleEmitterType.ts
  75. 30 21
      src/Particles/EmitterTypes/babylon.coneParticleEmitter.ts
  76. 19 1
      src/Particles/babylon.IParticleSystem.ts
  77. 31 10
      src/Particles/babylon.gpuParticleSystem.ts
  78. 6 0
      src/Particles/babylon.particle.ts
  79. 49 14
      src/Particles/babylon.particleSystem.ts
  80. 1 1
      src/Particles/babylon.solidParticleSystem.ts
  81. 2 2
      src/Physics/Plugins/babylon.oimoJSPlugin.ts
  82. 2 2
      src/Shaders/gpuRenderParticles.vertex.fx
  83. 7 4
      src/Shaders/gpuUpdateParticles.vertex.fx
  84. 3 3
      src/Shaders/particles.vertex.fx
  85. 1 1
      src/Tools/babylon.environmentTextureTools.ts

File diff suppressed because it is too large
+ 15097 - 15007
Playground/babylon.d.txt


+ 111 - 1
Playground/css/index.css

@@ -64,7 +64,7 @@ body {
 }
 .wrapper {
     height: calc(100% - 40px - 30px); /* nvabar top and bottom*/
-    width: 100%;
+    width: calc(100%);
     display: -ms-flexbox;
     display: flex;
     -ms-flex-direction: row;
@@ -118,6 +118,116 @@ body {
     width:5px;
 }      
 
+#exampleList {
+    padding-top: 5px;
+
+    display: none;
+    position: absolute;
+    top: 40px;
+    right: 0;
+    width: 400px;
+    height: calc(100% - 75px);
+    overflow-y: auto;
+
+    border-right: 1px solid #efefef;
+}
+#exampleList #exampleBanner {
+    background-image: url("../css/pattern_ban_1.png");
+    background-repeat: repeat;
+    text-align: center;
+    padding: 10px 0;
+    margin-left: 2px;
+}
+#exampleList #exampleBanner h1 {
+    text-align: center;
+    font-weight: 700;
+    color: #00aeef;
+    font-size: 2em;
+    margin: .67em 0;
+}
+#exampleList .horizontalSeparator {
+    width: 80%;
+    height: 0;
+    display: block;
+    border-top: 1px solid #00aeef;
+    margin: 0 auto 20px auto;
+}
+#exampleList #filterBar {
+    width: 80%;
+    margin-left: 10%;
+}
+#exampleList #filterBarClear {
+    display: none;
+    height: 10px;
+    margin-left: -19px;
+    cursor: pointer;
+}
+#exampleList #noResultsContainer p {
+    width: 100%;
+    text-align: center;
+    font-weight: 300;
+}
+#exampleList .categoryContainer p {
+    margin-left: 5px;
+    font-size: 20px;
+    font-weight: 200;
+    word-wrap: break-word;
+}
+#exampleList .categoryContainer .itemLine {
+    cursor: pointer;
+    background-color: #ebebeb;
+    height: 120px;
+    overflow: hidden;
+    clear: both;
+    margin: 5px;
+    margin-bottom: 10px;
+}
+#exampleList .categoryContainer .itemLine img {
+    display: inline-block;
+    max-height: 100%;
+    max-width: 120px;
+    border: 0;
+}
+#exampleList .categoryContainer .itemLine .itemContent {
+    display: inline-block;
+    width: calc(100% - 125px);
+    height: 100%;
+    vertical-align: top;
+    padding: 5px;
+    box-sizing: border-box;
+}
+#exampleList .categoryContainer .itemLine .itemContent .itemContentLink {
+    height: 100%;
+}
+#exampleList .categoryContainer .itemLine .itemContent .itemContentLink h3 {
+    margin: 0;
+    font-size: 18px;
+    margin-bottom: 5px;
+    text-decoration: none;
+}
+#exampleList .categoryContainer .itemLine .itemContent .itemContentLink p {
+    margin: 0;
+    font-size: 15px;
+    margin-bottom: 3px;
+}
+#exampleList .categoryContainer .itemLine .itemContent .itemLineDocLink {
+    position: relative;
+    bottom: 20px;
+    font-size: 15px;
+    text-decoration: underline;
+    color: #00aeef;
+}
+#exampleList .categoryContainer .itemLine .itemContent .itemLinePGLink {
+    display: none;
+    position: relative;
+    float: right;
+    bottom: 20px;
+    text-align: right;
+    font-size: 15px;
+    text-decoration: underline;
+    color: #00aeef;
+}
+
 .wrapper #jsEditor {
     padding-top:5px;
     height: calc(100% - 10px);

BIN
Playground/css/pattern_ban_1.png


+ 12 - 20
Playground/debug.html

@@ -169,11 +169,7 @@
                 </div>
             </div>
             <div class="button select">
-                <span id="currentScript1600">Scenes</span>
-                <div class="toDisplayBig">
-                    <ul id="scriptsList1600">
-                    </ul>
-                </div>
+                <span class="examplesButton">Examples</span>
             </div>
         </div>
     </div>
@@ -263,11 +259,7 @@
 
         <div class="category right">
             <div class="button select">
-                <span id="currentScript1475">Scenes</span>
-                <div class="toDisplayBig">
-                    <ul id="scriptsList1475">
-                    </ul>
-                </div>
+                <span class="examplesButton">Examples</span>
             </div>
         </div>
     </div>
@@ -350,11 +342,7 @@
 
         <div class="category right">
             <div class="button select">
-                <span id="currentScript1030">Scenes</span>
-                <div class="toDisplayBig">
-                    <ul id="scriptsList1030">
-                    </ul>
-                </div>
+                <span class="examplesButton">Examples</span>
             </div>
         </div>
     </div>
@@ -434,11 +422,7 @@
 
         <div class="category right">
             <div class="button select">
-                <span id="currentScript750">Scenes</span>
-                <div class="toDisplayBig">
-                    <ul id="scriptsList750">
-                    </ul>
-                </div>
+                <span class="examplesButton">Examples</span>
             </div>
         </div>
     </div>
@@ -449,6 +433,14 @@
             <canvas touch-action="none" id="renderCanvas"></canvas>
         </div>
     </div>
+    <div id="exampleList">
+        <div id="exampleBanner">
+            <h1>Examples</h1>
+        </div>
+        <div class="horizontalSeparator"></div>
+        <input id="filterBar" type="text" placeholder="Filter examples...">
+        <img id="filterBarClear" src="http://d33wubrfki0l68.cloudfront.net/17ca450bae302631f4857cd8c3992234ec5dd9a7/057f9/img/ui/clear_button.png">
+    </div>
 
     <span class="label" id="fpsLabel">FPS</span>
 

+ 892 - 0
Playground/examples/list.json

@@ -0,0 +1,892 @@
+{
+    "examples": [
+        {
+            "title": "Animations",
+            "samples": [
+                {
+                    "title": "Bones 101",
+                    "doc": "https://doc.babylonjs.com/How_To/How_to_use_Bones_and_Skeletons",
+                    "icon": "icons/bones.jpg",
+                    "description": "Create complex animations by using skeletons and bones",
+                    "PGID": "#QY1WYT#0"
+                },                
+                {
+                    "title": "Animation blending",
+                    "doc": "https://doc.babylonjs.com/babylon101/Animations#animation-blending",
+                    "icon": "icons/animation_blending.jpg",
+                    "description": "Blend multiple animations together to move from on animation clip to another",
+                    "PGID": "#BCU1XR#0"
+                },
+                {
+                    "title": "Animation weights",
+                    "doc": "https://doc.babylonjs.com/babylon101/animations#animation-weights",
+                    "icon": "icons/animation_weight.jpg",
+                    "description": "Use weights to blend multiple animations together",
+                    "PGID": "#LL5BIQ#0"
+                },                
+                {
+                    "title": "Animation 101",
+                    "doc": "https://doc.babylonjs.com/babylon101/animations",
+                    "icon": "icons/animations.png", 
+                    "description": "How to add animations",
+                    "PGID": "#QYFDDP#1"
+                },
+                {
+                    "title": "Easing functions",
+                    "doc": "https://doc.babylonjs.com/babylon101/animations#easing-functions",
+                    "icon": "icons/easing_functions.png", 
+                    "description": "Create animations with different easing functions",
+                    "PGID": "#8ZNVGR#0"
+                },
+                {
+                    "title": "Instanced bones",
+                    "doc": "https://doc.babylonjs.com/how_to/how_to_use_bones_and_skeletons",
+                    "icon": "icons/instanced_bones.png", 
+                    "description": "Animated skeletons of people walking",
+                    "PGID": "#0K8EYN#0"
+                },
+                {
+                    "title": "Morph targets",
+                    "doc": "https://doc.babylonjs.com/how_to/how_to_use_morphtargets",
+                    "icon": "icons/morph_targets.jpg", 
+                    "description": "Morph a mesh between multiple targets",
+                    "PGID": "#2JDN66#0"
+                }                         
+            ]
+        },
+        {
+            "title": "Cameras",
+            "samples": [
+                {
+                    "title": "Cameras 101",
+                    "doc": "https://doc.babylonjs.com/babylon101/cameras",
+                    "icon": "icons/cameras.png", 
+                    "description": "Types of cameras in babylonjs",
+                    "PGID": "#1A3M5C#0"
+                },
+                {
+                    "title": "Device orientation camera",
+                    "doc": "https://doc.babylonjs.com/babylon101/cameras#device-orientation-camera",
+                    "icon": "icons/deviceOrientationCamera.jpg",
+                    "description": "Camera that reacts to events such as a mobile device being tilted forward or back",
+                    "PGID": "#12WBC#185"
+                }
+            ]
+        },
+        {
+            "title": "GUI",
+            "samples": [
+                {
+                    "title": "GUI",
+                    "doc": "https://doc.babylonjs.com/how_to/gui",
+                    "icon": "icons/gui.png", 
+                    "description": "Babylons graphical user interface provides sliders, buttons, etc.",
+                    "PGID": "#3VMTI9#0"
+                }
+            ]
+        },
+        {
+            "title": "Interactions & events",
+            "samples": [
+                {
+                    "title": "Picking",
+                    "doc": "https://doc.babylonjs.com/babylon101/picking_collisions",
+                    "icon": "icons/picking.png", 
+                    "description": "Use mouse or touch to pick meshes on the screen",
+                    "PGID": "#NU4F6Y#0"
+                },
+                {
+                    "title": "Actions",
+                    "doc": "https://doc.babylonjs.com/how_to/how_to_use_actions",
+                    "icon": "icons/actions.png", 
+                    "description": "Actions are a simple way to add interactions in your scenes",
+                    "PGID": "#J19GYK#0"
+                },
+                {
+                    "title": "Drag and drop",
+                    "doc": "https://doc.babylonjs.com/how_to/how_to_use_actions",
+                    "icon": "icons/drag_and_drop.png", 
+                    "description": "Move meshes around a scene with a mouse",
+                    "PGID": "#UZ23UH#0"
+                },
+                {
+                    "title": "Pointer events handling",
+                    "doc": "https://doc.babylonjs.com/how_to/how_to_use_actions",
+                    "icon": "icons/pointer_events_handling.png", 
+                    "description": "Handle pointer input",
+                    "PGID": "#C245A1#0"
+                }
+            ]
+        },
+        {
+            "title": "Lights",
+            "samples": [
+                {
+                    "title": "Light projected texture",
+                    "doc": "https://doc.babylonjs.com/babylon101/lights#projection-texture",
+                    "icon": "icons/projected_texture.jpg",
+                    "description": "Project a texture from a spot light",
+                    "PGID": "#CQNGRK#0"
+                }, 
+                {
+                    "title": "Lights 101",
+                    "doc": "https://doc.babylonjs.com/babylon101/lights",
+                    "icon": "icons/lights.png", 
+                    "description": "Add lights to a scene",
+                    "PGID": "#AQRDKW#0"
+                }, 
+                {
+                    "title": "Simultaneous lights",
+                    "doc": "https://doc.babylonjs.com/babylon101/lights",
+                    "icon": "icons/sim_lights.jpg", 
+                    "description": "Use multiple lights on a single mesh",
+                    "PGID": "#ZU5TKG#0"
+                },
+                {
+                    "title": "Point light",
+                    "doc": "https://doc.babylonjs.com/babylon101/lights#the-point-light",
+                    "icon": "icons/pointLight.jpg",
+                    "description": "Light emitting from a single point",
+                    "PGID": "#20OAV9#0"
+                },
+                {
+                    "title": "Directional light",
+                    "doc": "https://doc.babylonjs.com/babylon101/lights#the-directional-light",
+                    "icon": "icons/directionalLight.jpg",
+                    "description": "The light is emitted from everywhere in the specified direction, and has an infinite range",
+                    "PGID": "#20OAV9#1"
+                },
+                {
+                    "title": "Spot lgiht",
+                    "doc": "https://doc.babylonjs.com/babylon101/lights#the-spot-light",
+                    "icon": "icons/spotLight.jpg",
+                    "description": "Defines a cone of light pointing in a direction",
+                    "PGID": "#20OAV9#3"
+                },
+                {
+                    "title": "Hemispheric light",
+                    "doc": "https://doc.babylonjs.com/babylon101/lights#the-hemispheric-light",
+                    "icon": "icons/hemLight.jpg",
+                    "description": "Simulate an ambient environment light",
+                    "PGID": "#20OAV9#5"
+                }      
+            ]
+        },
+        {
+            "title": "Loaders",
+            "samples": [
+                {
+                    "title": "Cornell box",
+                    "doc": "https://doc.babylonjs.com/how_to/load_from_any_file_type",
+                    "icon": "icons/cornell.jpg",
+                    "description": "Load a glTF file and setup the environment",
+                    "PGID": "#J5E230#54"
+                },
+                {
+                    "title": "Import meshes",
+                    "doc": "https://doc.babylonjs.com/how_to/load_from_any_file_type",
+                    "icon": "icons/import_meshes.png", 
+                    "description": "Load a mesh from a file and add it to the scene",
+                    "PGID": "#UKNERM#0"
+                },
+                {
+                    "title": "Load glTF model",
+                    "doc": "https://doc.babylonjs.com/how_to/load_from_any_file_type",
+                    "icon": "icons/load_gltf.jpg", 
+                    "description": "Show how to easily load a glTF model",
+                    "PGID": "#PN1NNI#0"
+                },
+                {
+                    "title": "Assets manager",
+                    "doc": "http://localhost:8080/How_To/How_to_use_AssetsManager",
+                    "icon": "icons/assets_manager.jpg", 
+                    "description": "Use AssetsManager to load multiple assets in a centralized way",
+                    "PGID": "#Y7XMAR#0"
+                },
+                {
+                    "title": "Asset container",
+                    "doc": "https://doc.babylonjs.com/how_to/how_to_use_assetcontainer",
+                    "icon": "icons/assetContainer.jpg",
+                    "description": "To add and remove assets from a scene an AssetContainer can be used.",
+                    "PGID": "#17MXFZ#0"
+                }                 
+            ]
+        },         
+        {
+            "title": "Materials",
+            "samples": [   
+                {
+                    "title": "MultiMaterial",
+                    "doc": "https://doc.babylonjs.com/how_to/multi_materials",
+                    "icon": "icons/multi_material.jpg",
+                    "description": "Apply multiple materials to a single mesh using MultiMaterial class",
+                    "PGID": "#2Q4S2S#0"
+                },                   
+                {
+                    "title": "ShaderMaterial",
+                    "doc": "https://doc.babylonjs.com/how_to/shader_material",
+                    "icon": "icons/custom_shader.jpg",
+                    "description": "Use ShaderMaterial to create advanced effects",
+                    "PGID": "#ATDL99#0"
+                },                 
+                {
+                    "title": "X-ray material with Fresnel",
+                    "doc": "https://doc.babylonjs.com/how_to/how_to_use_fresnelparameters",
+                    "icon": "icons/xRayFresnel.jpg",
+                    "description": "Use fresnel parameters to simulate an x-ray effect",
+                    "PGID": "#GK7FK#0"
+                },                         
+                {
+                    "title": "Materials",
+                    "doc": "https://doc.babylonjs.com/babylon101/materials",
+                    "icon": "icons/materials.png", 
+                    "description": "Create and add materials to a mesh",
+                    "PGID": "#DXARSP#0"
+                },
+                {
+                    "title": "PBR",
+                    "doc": "https://doc.babylonjs.com/how_to/physically_based_rendering",
+                    "icon": "icons/pbr.png", 
+                    "description": "Physically based rendering materials",
+                    "PGID": "#8MGKWK#0"
+                },
+                {
+                    "title": "Glossiness and roughness",
+                    "doc": "https://doc.babylonjs.com/api/classes/babylon.standardmaterial",
+                    "icon": "icons/glossinessAndRoughness.jpg",
+                    "description": "Demonstration of glossiness and rouphness features of standard material",
+                    "PGID": "#RNBKQ#8"
+                },
+                {
+                    "title": "Cell Shading",
+                    "doc": "https://doc.babylonjs.com/extensions/cell",
+                    "icon": "icons/cell_shading.jpg", 
+                    "description": "Cell shading material",
+                    "PGID": "#0ZB1A3#1"
+                },
+                {
+                    "title": "Fur",
+                    "doc": "https://doc.babylonjs.com/extensions/fur",
+                    "icon": "icons/fur.jpg", 
+                    "description": "Fur material",
+                    "PGID": "#VABI8A#0"
+                },
+                {
+                    "title": "Fire",
+                    "doc": "https://doc.babylonjs.com/extensions/Fire",
+                    "icon": "icons/fire.jpg", 
+                    "description": "Fire material",
+                    "PGID": "#LR4YHT#0"
+                },
+                {
+                    "title": "Water",
+                    "doc": "https://doc.babylonjs.com/extensions/water",
+                    "icon": "icons/water.jpg", 
+                    "description": "Water material",
+                    "PGID": "#L76FB1#0"
+                }                      
+            ]
+        },         
+        {
+            "title": "Meshes",
+            "samples": [   
+                {
+                    "title": "Render lines",
+                    "doc": "http://localhost:8080/babylon101/Parametric_Shapes#lines",
+                    "icon": "icons/lines.jpg",
+                    "description": "Use LinesMesh to render lines in 3D",
+                    "PGID": "#SVZL1I#0"
+                },                 
+                {
+                    "title": "Displacement map (CPU)",
+                    "doc": "https://doc.babylonjs.com/api/classes/babylon.mesh.html#applydisplacementmap",
+                    "icon": "icons/displacement.jpg",
+                    "description": "Update mesh geometry using a displacement map (CPU)",
+                    "PGID": "#04JDPF#0"
+                },                   
+                {
+                    "title": "Constructive solid geometries",
+                    "doc": "https://doc.babylonjs.com/api/classes/babylon.csg.html",
+                    "icon": "icons/csg.jpg",
+                    "description": "Use boolean operations on meshes using CSG",
+                    "PGID": "#T6NP3F#0"
+                },                  
+                {
+                    "title": "Raycast on height map",
+                    "doc": "https://doc.babylonjs.com/babylon101/raycasts",
+                    "icon": "icons/heightMapRaycast.jpg",
+                    "description": "Raycast to find positions on a heightmap",
+                    "PGID": "#QM57B#0"
+                },                  
+                {
+                    "title": "Basic scene",
+                    "doc": "https://doc.babylonjs.com/features/scene",
+                    "icon": "icons/basic_scene.png", 
+                    "description": "Ball and plane",
+                    "PGID": "#TAZ2CB#0"
+                },
+                {
+                    "title": "Basic elements",
+                    "doc": "https://doc.babylonjs.com/how_to/set_shapes",
+                    "icon": "icons/basic_elements.png", 
+                    "description": "Ball, box, plane, line, etc",
+                    "PGID": "#A1210C#0"
+                },
+                {
+                    "title": "Rotation and scaling",
+                    "doc": "https://doc.babylonjs.com/how_to/rotate",
+                    "icon": "icons/rotation_and_scaling.png", 
+                    "description": "Position mesh layout in space",
+                    "PGID": "#CURCZC#0"
+                },
+                {
+                    "title": "Curved lines",
+                    "doc": "https://doc.babylonjs.com/how_to/how_to_use_path3d",
+                    "icon": "icons/path3D.jpg",
+                    "description": "Use Path3D to create a curved line",
+                    "PGID": "#7SQDY#1"
+                },
+                {
+                    "title": "Rotating mesh to look at a target",
+                    "doc": "https://doc.babylonjs.com/babylon101/position",
+                    "icon": "icons/meshLook.jpg",
+                    "description": "Make a mesh face towards where the pointer hit a plane",
+                    "PGID": "#23M0G6#1"
+                },        
+                {
+                    "title": "Height map",
+                    "doc": "https://doc.babylonjs.com/babylon101/height_map",
+                    "icon": "icons/height_map.png", 
+                    "description": "Use a height map to extrude a plane to create mountains",
+                    "PGID": "#95PXRY#0"
+                },        
+                {
+                    "title": "Extrude polygon",
+                    "doc": "https://doc.babylonjs.com/api/classes/babylon.meshbuilder#extrudepolygon",
+                    "icon": "icons/extrude_polygon.jpg", 
+                    "description": "Use MeshBuilder to generate geometry from extruded data",
+                    "PGID": "#TFLTJJ#0"
+                },        
+                {
+                    "title": "Polygon mesh",
+                    "doc": "https://doc.babylonjs.com/how_to/polygonmeshbuilder",
+                    "icon": "icons/polygon_mesh.jpg", 
+                    "description": "Use PolygonMeshBuilder to create meshes from polygon data",
+                    "PGID": "#0TQAQU#0"
+                },                     
+                {
+                    "title": "Look at",
+                    "doc": "https://doc.babylonjs.com/api/classes/babylon.abstractmesh#lookat",
+                    "icon": "icons/look_at.jpg", 
+                    "description": "Use lookAt() function to align meshes on a specific target",
+                    "PGID": "#N2K3ZN#0"
+                },        
+                {
+                    "title": "Ribbons",
+                    "doc": "https://doc.babylonjs.com/how_to/ribbon_tutorial",
+                    "icon": "icons/ribbons.jpg", 
+                    "description": "Use ribbons to create complex meshes",
+                    "PGID": "#29BR2V#1"
+                },        
+                {
+                    "title": "Decals",
+                    "doc": "https://doc.babylonjs.com/how_to/decals",
+                    "icon": "icons/decals.jpg", 
+                    "description": "Create decals to apply additional textures to a portion of a mesh",
+                    "PGID": "#EEUVTY#0"
+                }                                    
+            ]
+        },
+        {
+            "title": "Optimizations",
+            "samples": [
+                {
+                    "title": "Level of detail",
+                    "doc": "https://doc.babylonjs.com/how_to/how_to_use_lod",
+                    "icon": "icons/lod.jpg",
+                    "description": "Use various meshes based on distance to optimize rendering speed",
+                    "PGID": "#7HMHAU#0"
+                },
+                {
+                    "title": "Hardware instancing",
+                    "doc": "https://doc.babylonjs.com/how_to/how_to_use_instances",
+                    "icon": "icons/instances.jpg",
+                    "description": "Use hardware instancing to duplicate meshes at no cost",
+                    "PGID": "#YB006J#0"
+                },
+                {
+                    "title": "Octrees",
+                    "doc": "https://doc.babylonjs.com/how_to/optimizing_your_scene_with_octrees",
+                    "icon": "icons/octree.jpg",
+                    "description": "Use octrees to boost mesh selections when dealing with thousands of objects",
+                    "PGID": "#3YFJ5R#0"
+                }
+            ]
+        },        
+        {
+            "title": "Particles",
+            "samples": [
+                {
+                    "title": "Particles and mirrors",
+                    "doc": "https://doc.babylonjs.com/babylon101/particles",
+                    "icon": "icons/particle_mirror.jpg",
+                    "description": "Use particles with a mirror",
+                    "PGID": "#65MUMZ#1"
+                },                  
+                {
+                    "title": "Particles with custom shader",
+                    "doc": "https://doc.babylonjs.com/how_to/customise#custom-effects",
+                    "icon": "icons/custom_particles.jpg",
+                    "description": "Use custom shader to display CPU particles",
+                    "PGID": "#807QEP#0"
+                },                
+                {
+                    "title": "GPU particles",
+                    "doc": "https://doc.babylonjs.com/babylon101/particles#gpu-particles",
+                    "icon": "icons/gpu_particles.jpg",
+                    "description": "Use GPU only to create a massive number of particles",
+                    "PGID": "#PU4WYI#14"
+                },
+                {
+                    "title": "Particles 101",
+                    "doc": "https://doc.babylonjs.com/babylon101/particles",
+                    "icon": "icons/particles.png", 
+                    "description": "Create a particle system and attach it to a moving object",
+                    "PGID": "#EF9X5R#0"
+                },                           
+                {
+                    "title": "Low lying fog",
+                    "doc": "https://doc.babylonjs.com/babylon101/particles",
+                    "icon": "icons/lying_fog.jpg",
+                    "description": "Use particle to simulate volumetric fog",
+                    "PGID": "#BHNVUE#1"
+                },                           
+                {
+                    "title": "Particle editor",
+                    "doc": "https://doc.babylonjs.com/babylon101/particles",
+                    "icon": "icons/particle_editor.jpg",
+                    "description": "Online editor to play with particle parameters",
+                    "PGID": "#NNL67B#1"
+                },
+                {
+                    "title": "A lot of triangles with SPS",
+                    "doc": "https://doc.babylonjs.com/how_to/solid_particle_system",
+                    "icon": "icons/solidParticleSystem.jpg",
+                    "description": "Use solid particle system to create a colorful cube",
+                    "PGID": "#2FPT1A#5"
+                },
+                {
+                    "title": "Solid Particle System facet collision",
+                    "doc": "https://doc.babylonjs.com/how_to/solid_particle_system",
+                    "icon": "icons/facets.jpg", 
+                    "description": "Use SPS facets to simulate complex mesh collisions",
+                    "PGID": "#6UZDJ9#0"
+                },
+                {
+                    "title": "Solid Particle System collisions",
+                    "doc": "https://doc.babylonjs.com/how_to/solid_particle_system",
+                    "icon": "icons/sps_collisions.jpg", 
+                    "description": "Use basic geometry to simulate SPS collisions",
+                    "PGID": "#2V1C4Z#0"
+                },
+                {
+                    "title": "Solid Particle System and shadows",
+                    "doc": "https://doc.babylonjs.com/how_to/solid_particle_system",
+                    "icon": "icons/sps_shadows.jpg", 
+                    "description": "Animate SPS with realtime shadows",
+                    "PGID": "#ML2LR9#0"
+                }                        
+            ]
+        },        
+        {
+            "title": "Collisions & intersections",
+            "samples": [
+                {
+                    "title": "Collisions",
+                    "doc": "https://doc.babylonjs.com/babylon101/cameras,_mesh_collisions_and_gravity",
+                    "icon": "icons/collisions.png", 
+                    "description": "Handle basic collisions to avoid a camera going through a box",
+                    "PGID": "#U8MEB0#0"
+                },
+                {
+                    "title": "Intersections",
+                    "doc": "https://doc.babylonjs.com/babylon101/intersect_collisions_-_mesh",
+                    "icon": "icons/intersections.png", 
+                    "description": "Detect when meshes intersect each other",
+                    "PGID": "#KQV9SA#0"
+                }
+            ]
+        },              
+        {
+            "title": "Physics",
+            "samples": [
+                {
+                    "title": "Physics",
+                    "doc": "https://doc.babylonjs.com/how_to/using_the_physics_engine",
+                    "icon": "icons/physics.png", 
+                    "description": "How to use physic engines within Babylon",
+                    "PGID": "#7149G4#0"
+                },
+                {
+                    "title": "Cloth",
+                    "doc": "https://doc.babylonjs.com/how_to/using_the_physics_engine",
+                    "icon": "icons/cloth.jpg", 
+                    "description": "Use physic engine to simulate cloth",
+                    "PGID": "#7N1BRU#0"
+                }
+            ]
+        },                
+        {
+            "title": "Shadows",
+            "samples": [
+                {
+                    "title": "Contact hardening",
+                    "doc": "https://doc.babylonjs.com/babylon101/shadows#contact-hardening-shadow-webgl2-only",
+                    "icon": "icons/pcss.jpg",
+                    "description": "Shadows will get softer when they are further away from the object casting them",
+                    "PGID": "#EYEPRI#3"
+                },
+                {
+                    "title": "Self shadowing #1",
+                    "doc": "https://doc.babylonjs.com/babylon101/shadows#exponential-shadow-map",
+                    "icon": "icons/self_shadows1.jpg",
+                    "description": "Use shadow exponential mode to enable self shadowing on a rotating object",
+                    "PGID": "#F4XWU2#0"
+                },                
+                {
+                    "title": "Self shadowing #2",
+                    "doc": "https://doc.babylonjs.com/babylon101/shadows#close-exponential-shadow-map",
+                    "icon": "icons/self_shadows2.jpg",
+                    "description": "Use shadow close exponential mode to enable self shadowing on animated object",
+                    "PGID": "#4GAHX6#1"
+                },
+                {
+                    "title": "Shadows 101",
+                    "doc": "https://doc.babylonjs.com/babylon101/shadows",
+                    "icon": "icons/shadows.png", 
+                    "description": "Setup a scene with lights and meshes to cast different types of shadows",
+                    "PGID": "#IFYDRS#0"
+                },
+                {
+                    "title": "Shadow on transparent textures",
+                    "doc": "https://doc.babylonjs.com/babylon101/shadows",
+                    "icon": "icons/trasnparent_shadow.jpg",
+                    "description": "Create realistic shadows from a transparent texture",
+                    "PGID": "#2DT16W#2"
+                },
+                {
+                    "title": "Point light shadows",
+                    "doc": "https://doc.babylonjs.com/babylon101/shadows",
+                    "icon": "icons/point_shadows.jpg", 
+                    "description": "Use point light to cast shadows",
+                    "PGID": "#4MC650#0"
+                },
+                {
+                    "title": "Multi directional lights with soft shadows",
+                    "doc": "https://doc.babylonjs.com/babylon101/shadows",
+                    "icon": "icons/multi_shadows.jpg", 
+                    "description": "Use multiple directional lights to cast soft shadows",
+                    "PGID": "#KWS7KD#0"
+                },
+                {
+                    "title": "Different shadow filters",
+                    "doc": "https://doc.babylonjs.com/babylon101/shadows",
+                    "icon": "icons/shadow_filters.jpg", 
+                    "description": "Demonstrate different kind of shadows",
+                    "PGID": "#43T193#0"
+                }                                  
+            ]
+        },            
+        {            
+            "title": "Audio",
+            "samples": [
+                {
+                    "title": "Basic sounds",
+                    "doc": "https://doc.babylonjs.com/how_to/playing_sounds_and_music",
+                    "icon": "icons/basic_sounds.png", 
+                    "description": "Playing sounds with babylon",
+                    "PGID": "#DXAEUY#0"
+                },
+                {
+                    "title": "Sound on mesh",
+                    "doc": "https://doc.babylonjs.com/how_to/playing_sounds_and_music",
+                    "icon": "icons/sound_on_mesh.png", 
+                    "description": "Attach a sound to a mesh which will be modified by the objects position",
+                    "PGID": "#EDVU95#0"
+                },
+                {
+                    "title": "Audio analyzer #1",
+                    "doc": "https://doc.babylonjs.com/how_to/playing_sounds_and_music#using-the-analyser",
+                    "icon": "icons/analyzer.jpg", 
+                    "description": "Analyze audio frequencies in realtime",
+                    "PGID": "#TUR5GH#0"
+                },
+                {
+                    "title": "PBR with music analyzer #2",
+                    "doc": "https://doc.babylonjs.com/how_to/playing_sounds_and_music#using-the-analyser",
+                    "icon": "icons/musicAnalyzer.jpg",
+                    "description": "Visualize audio frequencies in realtime",
+                    "PGID": "#2JOSXE#21"
+                }
+            ]
+        },    
+        {
+            "title": "Special FX",
+            "samples": [
+                {
+                    "title": "Fog",
+                    "doc": "https://doc.babylonjs.com/babylon101/Environment#fog",
+                    "icon": "icons/fog.jpg",
+                    "description": "Simulate fog in your scene",
+                    "PGID": "#LR6389#0"
+                },                    
+                {
+                    "title": "Convolution post-process",
+                    "doc": "https://doc.babylonjs.com/api/classes/babylon.convolutionpostprocess",
+                    "icon": "icons/convolution.jpg",
+                    "description": "Apply emboss filter to the scene using the ConvolutionPostProcess",
+                    "PGID": "#B0RH9H#0"
+                },                  
+                {
+                    "title": "Lens flares",
+                    "doc": "https://doc.babylonjs.com/how_to/how_to_use_lens_flares",
+                    "icon": "icons/lens_flares.jpg",
+                    "description": "Simulate lens flares on the camera",
+                    "PGID": "#ZEB7H6#0"
+                },                 
+                {
+                    "title": "Glass wubble ball",
+                    "doc": "https://doc.babylonjs.com/api/classes/babylon.abstractmesh#getverticesdata",
+                    "icon": "icons/glassWubbleBall.jpg",
+                    "description": "Warped ball effect",
+                    "PGID": "#CXOLW#3"
+                },                
+                {
+                    "title": "Color curves",
+                    "doc": "https://doc.babylonjs.com/how_to/how_to_use_postprocesses#imageprocessing",
+                    "icon": "icons/color_curves.jpg",
+                    "description": "Apply color curves to your rendering",
+                    "PGID": "#HI65FJ#0"
+                },     
+                {
+                    "title": "Default rendering pipeline",
+                    "doc": "https://doc.babylonjs.com/how_to/using_default_rendering_pipeline",
+                    "icon": "icons/default_pipeline.jpg",
+                    "description": "Bloom, FXAA, sharpen, grain, vignette, chromatic aberration and DoF with one single object",
+                    "PGID": "#Y3C0HQ#146"
+                },                      
+                {
+                    "title": "Depth of field",
+                    "doc": "https://doc.babylonjs.com/how_to/using_default_rendering_pipeline#depth-of-field",
+                    "icon": "icons/dof.jpg",
+                    "description": "Apply depth of field effect",
+                    "PGID": "#8F5HYV#9"
+                },                           
+                {
+                    "title": "Glow layer",
+                    "doc": "https://doc.babylonjs.com/how_to/glow_layer",
+                    "icon": "icons/glow.jpg",
+                    "description": "Generates glow around emissive objects",
+                    "PGID": "#6ZVKE3#0"
+                },
+                {
+                    "title": "Sprites",
+                    "doc": "https://doc.babylonjs.com/babylon101/sprites",
+                    "icon": "icons/sprites.png", 
+                    "description": "Load and display sprites",
+                    "PGID": "#9RI8CG#0"
+                },
+                {
+                    "title": "Environment",
+                    "doc": "https://doc.babylonjs.com/babylon101/environment",
+                    "icon": "icons/environment.png", 
+                    "description": "Adding a skybox and fog",
+                    "PGID": "#7G0IQW#0"
+                },
+                {
+                    "title": "Fresnel",
+                    "doc": "https://doc.babylonjs.com/how_to/how_to_use_fresnelparameters",
+                    "icon": "icons/fresnel.png", 
+                    "description": "Renders spheres to simulate a fresnel lens",
+                    "PGID": "#AQZJ4C#0"
+                },
+                {
+                    "title": "SSAO rendering pipeline",
+                    "doc": "https://doc.babylonjs.com/how_to/using_the_ssao_rendering_pipeline",
+                    "icon": "icons/ssao_1.png", 
+                    "description": "Screen space ambient occlusion",
+                    "PGID": "#N96NXC#0"
+                },
+                {
+                    "title": "SSAO rendering pipeline (WebGL2)",
+                    "doc": "https://doc.babylonjs.com/api/classes/babylon.ssao2renderingpipeline",
+                    "icon": "icons/ssao_2.png", 
+                    "description": "Screen space ambient occlusion with WebGL2",
+                    "PGID": "#7D2QDD#0"
+                },
+                {
+                    "title": "Volumetric Light Scattering",
+                    "doc": "https://doc.babylonjs.com/how_to/using_the_volumetric_lightscattering_post-process",
+                    "icon": "icons/volumetric_light_scattering.png", 
+                    "description": "Simulates light scattering due to light hitting the atmosphere",
+                    "PGID": "#V2DAKC#0"
+                },
+                {
+                    "title": "Refraction and Reflection",
+                    "doc": "https://doc.babylonjs.com/how_to/how_to_use_fresnelparameters",
+                    "icon": "icons/refraction_and_reflection.png", 
+                    "description": "Simulate how light would reflect and refract with a sphere",
+                    "PGID": "#XH85A9#0"
+                },
+                {
+                    "title": "Portals",
+                    "doc": "https://doc.babylonjs.com/resources/shaderintro",
+                    "icon": "icons/portals.jpg",
+                    "description": "Portal effect created using custom shaders",
+                    "PGID": "#EEOWP#7"
+                },
+                {
+                    "title": "Warp speed !",
+                    "doc": "https://doc.babylonjs.com/how_to/shader_material",
+                    "icon": "icons/warpSpeed.jpg",
+                    "description": "Fly though stars using a custom shader texture",
+                    "PGID": "#1WBBW0#1"
+                },
+                {
+                    "title": "Hypnotizing infinite loader",
+                    "doc": "https://doc.babylonjs.com/babylon101/position",
+                    "icon": "icons/infiniteLoader.jpg",
+                    "description": "Visually apealing loading animation",
+                    "PGID": "#VUJG1#1"
+                },            
+                {
+                    "title": "Realtime refraction",
+                    "doc": "https://doc.babylonjs.com/how_to/how_to_use_reflection_probes",
+                    "icon": "icons/refraction.jpg", 
+                    "description": "use reflection probes to simulate realtime refraction",
+                    "PGID": "#RRYXWN#0"
+                },
+                {
+                    "title": "Realtime reflection",
+                    "doc": "https://doc.babylonjs.com/how_to/how_to_use_reflection_probes",
+                    "icon": "icons/reflection.jpg", 
+                    "description": "use reflection probes to simulate realtime reflection",
+                    "PGID": "#SF5RCN#0"
+                },                
+                {
+                    "title": "Motion blur",
+                    "doc": "https://doc.babylonjs.com/how_to/using_standard_rendering_pipeline#setting-up-the-motion-blur",
+                    "icon": "icons/motion_blur.jpg", 
+                    "description": "Use the standard rendering pipeline to simulate motion blur",
+                    "PGID": "#ZMAJZB#0"
+                },
+                {
+                    "title": "Highlight layer",
+                    "doc": "https://doc.babylonjs.com/how_to/highlight_layer",
+                    "icon": "icons/highlights.jpg", 
+                    "description": "Highlight a mesh",
+                    "PGID": "#7EESGZ#0"
+                },
+                {
+                    "title": "Lens effects",
+                    "doc": "https://doc.babylonjs.com/how_to/using_depth-of-field_and_other_lens_effects",
+                    "icon": "icons/lens_effect.jpg", 
+                    "description": "Create photographic effect with the LensRenderingPipeline",
+                    "PGID": "#B7JHWD#0"
+                }                           
+            ]
+        },
+        {
+            "title": "Textures",
+            "samples": [   
+                {
+                    "title": "Saving dynamic texture on disk",
+                    "doc": "https://doc.babylonjs.com/how_to/dynamictexture",
+                    "icon": "icons/savingDynamicTexture.jpg",
+                    "description": "Save a texture generated at runtime using DynamicTexture",
+                    "PGID": "#CA4SM#1"
+                },                
+                {
+                    "title": "360 videos",
+                    "doc": "https://doc.babylonjs.com/how_to/360videodome",
+                    "icon": "icons/360.jpg",
+                    "description": "Easily display and control 360 videos",
+                    "PGID": "#1E9JQ8#7"
+                },                
+                {
+                    "title": "ProceduralTexture",
+                    "doc": "https://doc.babylonjs.com/how_to/how_to_use_procedural_textures",
+                    "icon": "icons/procedural_texture.png", 
+                    "description": "Use procedual textures for wood, grass, marble, fire, etc.",
+                    "PGID": "#B2ZXG6#0"
+                },
+                {
+                    "title": "Local cubemaps",
+                    "doc": "https://doc.babylonjs.com/how_to/reflect#cubetexture",
+                    "icon": "icons/local_cubemap.jpg",
+                    "description": "Improve cubemaps with local mode",
+                    "PGID": "#RNASML#4"
+                },                 
+                {
+                    "title": "Starfield procedural texture",
+                    "doc": "https://doc.babylonjs.com/how_to/how_to_use_procedural_textures",
+                    "icon": "icons/starfield.jpg", 
+                    "description": "Use the starfield procedual texture to simulate space",
+                    "PGID": "#ZQWE4G#0"
+                },
+                {
+                    "title": "Equirectangular map as reflection texture",
+                    "doc": "https://doc.babylonjs.com/how_to/reflect",
+                    "icon": "icons/equMapOnReflectionTexture.jpg",
+                    "description": "Using Equirectangular maps as a reflection texture",
+                    "PGID": "#23IQHK#2"
+                },
+                {
+                    "title": "Mirrors",
+                    "doc": "https://doc.babylonjs.com/how_to/reflect",
+                    "icon": "icons/mirrors.jpg",
+                    "description": "Shows how to use mirrors in babylon",
+                    "PGID": "#2EP7UB#0"
+                },
+                {
+                    "title": "Custom render targets",
+                    "doc": "https://doc.babylonjs.com/api/classes/babylon.rendertargettexture",
+                    "icon": "icons/custom_rendertarget.jpg",
+                    "description": "Use render target textures to generate procedural data",
+                    "PGID": "#CJWDJR#0"
+                },
+                {
+                    "title": "Bump texture",
+                    "doc": "https://doc.babylonjs.com/how_to/more_materials#bump-map",
+                    "icon": "icons/bump.jpg",
+                    "description": "Use normal map to simulate bump",
+                    "PGID": "#RK0W5S#0"
+                }                              
+            ]
+        },
+        {
+            "title": "VR",
+            "samples": [
+                {
+                    "title": "WebVR",
+                    "doc": "https://doc.babylonjs.com/how_to/webvr_helper",
+                    "icon": "icons/webvr.png", 
+                    "description": "View a basic mesh and interact with a gui in WebVR",
+                    "PGID": "#TAFSN0#2"
+                } 
+            ]
+        },
+        {
+            "title": "Misc.",
+            "samples": [
+                {
+                    "title": "Charting",
+                    "doc": "https://doc.babylonjs.com/babylon101/",
+                    "icon": "icons/charting.jpg", 
+                    "description": "Creates a 3D charting presentation",
+                    "PGID": "#8PY6X5#1"
+                } 
+            ]
+        }         
+    ]
+}

+ 12 - 20
Playground/index-local.html

@@ -112,11 +112,7 @@
                     </div>
                 </div>
                 <div class="button select">
-                    <span id="currentScript1600">Scenes</span>
-                    <div class="toDisplayBig">
-                        <ul id="scriptsList1600">
-                        </ul>
-                    </div>
+                    <span class="examplesButton">Examples</span>
                 </div>
             </div>
         </div>
@@ -205,11 +201,7 @@
 
             <div class="category right">
                 <div class="button select">
-                    <span id="currentScript1475">Scenes</span>
-                    <div class="toDisplayBig">
-                        <ul id="scriptsList1475">
-                        </ul>
-                    </div>
+                    <span class="examplesButton">Examples</span>
                 </div>
             </div>
         </div>
@@ -292,11 +284,7 @@
 
             <div class="category right">
                 <div class="button select">
-                    <span id="currentScript1030">Scenes</span>
-                    <div class="toDisplayBig">
-                        <ul id="scriptsList1030">
-                        </ul>
-                    </div>
+                    <span class="examplesButton">Examples</span>
                 </div>
             </div>
         </div>
@@ -376,11 +364,7 @@
 
             <div class="category right">
                 <div class="button select">
-                    <span id="currentScript750">Scenes</span>
-                    <div class="toDisplayBig">
-                        <ul id="scriptsList750">
-                        </ul>
-                    </div>
+                    <span class="examplesButton">Examples</span>
                 </div>
             </div>
         </div>
@@ -391,6 +375,14 @@
                 <canvas touch-action="none" id="renderCanvas"></canvas>
             </div>
         </div>
+        <div id="exampleList">
+            <div id="exampleBanner">
+                <h1>Examples</h1>
+            </div>
+            <div class="horizontalSeparator"></div>
+            <input id="filterBar" type="text" placeholder="Filter examples...">
+            <img id="filterBarClear" src="http://d33wubrfki0l68.cloudfront.net/17ca450bae302631f4857cd8c3992234ec5dd9a7/057f9/img/ui/clear_button.png">
+        </div>
 
         <span class="label" id="fpsLabel">FPS</span>
 

+ 12 - 20
Playground/index.html

@@ -147,11 +147,7 @@
                     </div>
                 </div>
                 <div class="button select">
-                    <span id="currentScript1600">Scenes</span>
-                    <div class="toDisplayBig">
-                        <ul id="scriptsList1600">
-                        </ul>
-                    </div>
+                    <span class="examplesButton">Examples</span>
                 </div>
             </div>
         </div>
@@ -240,11 +236,7 @@
 
             <div class="category right">
                 <div class="button select">
-                    <span id="currentScript1475">Scenes</span>
-                    <div class="toDisplayBig">
-                        <ul id="scriptsList1475">
-                        </ul>
-                    </div>
+                    <span class="examplesButton">Examples</span>
                 </div>
             </div>
         </div>
@@ -327,11 +319,7 @@
 
             <div class="category right">
                 <div class="button select">
-                    <span id="currentScript1030">Scenes</span>
-                    <div class="toDisplayBig">
-                        <ul id="scriptsList1030">
-                        </ul>
-                    </div>
+                    <span class="examplesButton">Examples</span>
                 </div>
             </div>
         </div>
@@ -411,11 +399,7 @@
 
             <div class="category right">
                 <div class="button select">
-                    <span id="currentScript750">Scenes</span>
-                    <div class="toDisplayBig">
-                        <ul id="scriptsList750">
-                        </ul>
-                    </div>
+                    <span id="currentScript750">Examples</span>
                 </div>
             </div>
         </div>
@@ -426,6 +410,14 @@
                 <canvas touch-action="none" id="renderCanvas"></canvas>
             </div>
         </div>
+        <div id="exampleList">
+            <div id="exampleBanner">
+                <h1>Examples</h1>
+            </div>
+            <div class="horizontalSeparator"></div>
+            <input id="filterBar" type="text" placeholder="Filter examples...">
+            <img id="filterBarClear" src="http://d33wubrfki0l68.cloudfront.net/17ca450bae302631f4857cd8c3992234ec5dd9a7/057f9/img/ui/clear_button.png">
+        </div>
 
         <span class="label" id="fpsLabel">FPS</span>
 

+ 12 - 20
Playground/indexStable.html

@@ -138,11 +138,7 @@
                     </div>
                 </div>
                 <div class="button select">
-                    <span id="currentScript1600">Scenes</span>
-                    <div class="toDisplayBig">
-                        <ul id="scriptsList1600">
-                        </ul>
-                    </div>
+                    <span class="examplesButton">Examples</span>
                 </div>
             </div>
         </div>
@@ -231,11 +227,7 @@
 
             <div class="category right">
                 <div class="button select">
-                    <span id="currentScript1475">Scenes</span>
-                    <div class="toDisplayBig">
-                        <ul id="scriptsList1475">
-                        </ul>
-                    </div>
+                    <span class="examplesButton">Examples</span>
                 </div>
             </div>
         </div>
@@ -318,11 +310,7 @@
 
             <div class="category right">
                 <div class="button select">
-                    <span id="currentScript1030">Scenes</span>
-                    <div class="toDisplayBig">
-                        <ul id="scriptsList1030">
-                        </ul>
-                    </div>
+                    <span class="examplesButton">Examples</span>
                 </div>
             </div>
         </div>
@@ -402,11 +390,7 @@
 
             <div class="category right">
                 <div class="button select">
-                    <span id="currentScript750">Scenes</span>
-                    <div class="toDisplayBig">
-                        <ul id="scriptsList750">
-                        </ul>
-                    </div>
+                    <span class="examplesButton">Examples</span>
                 </div>
             </div>
         </div>
@@ -417,6 +401,14 @@
                 <canvas touch-action="none" id="renderCanvas"></canvas>
             </div>
         </div>
+        <div id="exampleList">
+            <div id="exampleBanner">
+                <h1>Examples</h1>
+            </div>
+            <div class="horizontalSeparator"></div>
+            <input id="filterBar" type="text" placeholder="Filter examples...">
+            <img id="filterBarClear" src="http://d33wubrfki0l68.cloudfront.net/17ca450bae302631f4857cd8c3992234ec5dd9a7/057f9/img/ui/clear_button.png">
+        </div>
 
         <span class="label" id="fpsLabel">FPS</span>
 

+ 136 - 22
Playground/js/index.js

@@ -56,6 +56,66 @@
         '.navbarBottom .links .link'];
 
     var run = function () {
+
+        // #region - Examples playgrounds
+        var examplesButton = document.getElementsByClassName("examplesButton");
+        var isExamplesDisplayed = false;
+        for(var i = 0; i < examplesButton.length; i++) {
+           examplesButton[i].parentElement.onclick = function () {
+            isExamplesDisplayed = !isExamplesDisplayed;
+            if (isExamplesDisplayed) {
+                document.getElementById("exampleList").style.display = "block";
+                document.getElementsByClassName("wrapper")[0].style.width = "calc(100% - 400px)";
+            }
+            else {
+                document.getElementById("exampleList").style.display = "none";
+                document.getElementsByClassName("wrapper")[0].style.width = "100%";
+            }
+        } 
+        }
+        
+
+        var filterBarClear = document.getElementById("filterBarClear");
+        var filterBar = document.getElementById("filterBar");
+        var filter = function () {
+            var filterText = filterBar.value.toLowerCase();
+            if (filterText == "") filterBarClear.style.display = "none";
+            else filterBarClear.style.display = "inline-block";
+
+            var lines = document.getElementsByClassName("itemLine");
+            for (var lineIndex = 0; lineIndex < lines.length; lineIndex++) {
+                var line = lines[lineIndex];
+                if (line.innerText.toLowerCase().indexOf(filterText) > -1) {
+                    line.style.display = "";
+                } else {
+                    line.style.display = "none";
+                }
+            }
+
+            var categories = document.getElementsByClassName("categoryContainer");
+            var displayCount = categories.length;
+
+            for (var categoryIndex = 0; categoryIndex < categories.length; categoryIndex++) {
+                var category = categories[categoryIndex];
+                category.style.display = "block";
+                if (category.clientHeight < 25) {
+                    category.style.display = "none";
+                    displayCount--;
+                }
+            }
+
+            if (displayCount == 0) document.getElementById("noResultsContainer").style.display = "block";
+            else document.getElementById("noResultsContainer").style.display = "none";
+        }
+        filterBar.oninput = function () {
+            filter();
+        }
+        filterBarClear.onclick = function () {
+            filterBar.value = "";
+            filter();
+        }
+        // #endregion
+
         var blockEditorChange = false;
 
         var markDirty = function () {
@@ -63,11 +123,9 @@
                 return;
             }
 
-
-            setToMultipleID("currentScript", "innerHTML", "Custom");
+            // setToMultipleID("currentScript", "innerHTML", "Custom");
             setToMultipleID("safemodeToggle", "addClass", "checked");
             setToMultipleID("minimapToggle", "addClass", "checked");
-
             setToMultipleID('safemodeToggle', 'innerHTML', 'Safe mode <i class="fa fa-check-square" aria-hidden="true"></i>');
         }
 
@@ -107,7 +165,7 @@
                         blockEditorChange = false;
                         compileAndRun();
 
-                        setToMultipleID("currentScript", "innerHTML", title);
+                        // setToMultipleID("currentScript", "innerHTML", title);
 
                         currentSnippetToken = null;
                     }
@@ -133,33 +191,89 @@
         var loadScriptsList = function () {
             var xhr = new XMLHttpRequest();
 
-            xhr.open('GET', 'scripts/scripts.txt', true);
+            xhr.open('GET', 'examples/list.json', true);
 
             xhr.onreadystatechange = function () {
                 if (xhr.readyState === 4) {
                     if (xhr.status === 200) {
-                        scripts = xhr.responseText.split("\n");
+                        scripts = JSON.parse(xhr.response)["examples"];
+
+                        function sortScriptsList(a, b) {
+                            if (a.title < b.title) return -1;
+                            else return 1;
+                            return 0;
+                        }
+                        scripts.sort(sortScriptsList);
+
+                        var exampleList = document.getElementById("exampleList");
+
+                        for (var i = 0; i < scripts.length; i++) {
+                            scripts[i].samples.sort(sortScriptsList);
+
+                            var exampleCategory = document.createElement("div");
+                            exampleCategory.classList.add("categoryContainer");
+
+                            var exampleCategoryTitle = document.createElement("p");
+                            exampleCategoryTitle.innerText = scripts[i].title;
+                            exampleCategory.appendChild(exampleCategoryTitle);
 
-                        for (var i = 0; i < multipleSize.length; i++) {
-                            var ul = document.getElementById("scriptsList" + multipleSize[i]);
+                            for (var ii = 0; ii < scripts[i].samples.length; ii++) {
+                                var example = document.createElement("div");
+                                example.classList.add("itemLine");
+                                example.id = ii;
 
-                            var index;
-                            for (index = 0; index < scripts.length; index++) {
-                                var option = document.createElement("li");
-                                var a = document.createElement("a");
-                                a.href = "#";
-                                a.innerHTML = (index + 1) + " - " + scripts[index];
-                                a.scriptLinkIndex = index + 1;
-                                //a.onclick = onScriptClick;
-                                option.scriptLinkIndex = index + 1;
-                                option.onclick = onScriptClick;
+                                var exampleImg = document.createElement("img");
+                                exampleImg.src = scripts[i].samples[ii].icon.replace("icons", "http://doc.babylonjs.com/examples/icons");
+                                exampleImg.setAttribute("onClick", "document.getElementById('PGLink_" + scripts[i].samples[ii].PGID + "').click();");
 
-                                option.appendChild(a);
+                                var exampleContent = document.createElement("div");
+                                exampleContent.classList.add("itemContent");
+                                exampleContent.setAttribute("onClick", "document.getElementById('PGLink_" + scripts[i].samples[ii].PGID + "').click();");
 
-                                ul.appendChild(option);
+                                var exampleContentLink = document.createElement("div");
+                                exampleContentLink.classList.add("itemContentLink");
+
+                                var exampleTitle = document.createElement("h3");
+                                exampleTitle.classList.add("exampleCategoryTitle");
+                                exampleTitle.innerText = scripts[i].samples[ii].title;
+                                var exampleDescr = document.createElement("div");
+                                exampleDescr.classList.add("itemLineChild");
+                                exampleDescr.innerText = scripts[i].samples[ii].description;
+
+                                var exampleDocLink = document.createElement("a");
+                                exampleDocLink.classList.add("itemLineDocLink");
+                                exampleDocLink.innerText = "Documentation";
+                                exampleDocLink.href = scripts[i].samples[ii].doc;
+                                exampleDocLink.target = "_blank";
+
+                                var examplePGLink = document.createElement("a");
+                                examplePGLink.id = "PGLink_" + scripts[i].samples[ii].PGID;
+                                examplePGLink.classList.add("itemLinePGLink");
+                                examplePGLink.innerText = "Display";
+                                examplePGLink.href = scripts[i].samples[ii].PGID;
+
+                                exampleContentLink.appendChild(exampleTitle);
+                                exampleContentLink.appendChild(exampleDescr);
+                                exampleContent.appendChild(exampleContentLink);
+                                exampleContent.appendChild(exampleDocLink);
+                                exampleContent.appendChild(examplePGLink);
+
+                                example.appendChild(exampleImg);
+                                example.appendChild(exampleContent);
+
+                                exampleCategory.appendChild(example);
                             }
+
+                            exampleList.appendChild(exampleCategory);
                         }
 
+                        var noResultContainer = document.createElement("div");
+                        noResultContainer.id = "noResultsContainer";
+                        noResultContainer.classList.add("categoryContainer");
+                        noResultContainer.style.display = "none";
+                        noResultContainer.innerHTML = "<p id='noResults'>No results found.</p>";
+                        exampleList.appendChild(noResultContainer);
+
                         if (!location.hash) {
                             // Query string
                             var queryString = window.location.search;
@@ -932,7 +1046,7 @@
                                     blockEditorChange = false;
                                     compileAndRun();
 
-                                    setToMultipleID("currentScript", "innerHTML", "Custom");
+                                    // setToMultipleID("currentScript", "innerHTML", "Custom");
                                 } else if (firstTime) {
                                     location.href = location.href.replace(location.hash, "");
                                     if (scripts) {
@@ -1026,4 +1140,4 @@
         }
     };
     xhr.send(null);
-})();
+})();

+ 30 - 28
Tools/DevLoader/BabylonLoader.js

@@ -2,8 +2,8 @@
 
 var BABYLONDEVTOOLS;
 (function (BABYLONDEVTOOLS) {
-    
-    var getJson = function(url, callback, errorCallback) {
+
+    var getJson = function (url, callback, errorCallback) {
         var xhr = new XMLHttpRequest();
         xhr.open('GET', url);
         xhr.onload = function () {
@@ -12,8 +12,8 @@ var BABYLONDEVTOOLS;
                 callback(data)
             } else {
                 errorCallback({
-                status: this.status,
-                statusText: xhr.statusText
+                    status: this.status,
+                    statusText: xhr.statusText
                 });
             }
         };
@@ -39,19 +39,19 @@ var BABYLONDEVTOOLS;
             dependencies = [];
             callback = null;
             min = (document.location.href.toLowerCase().indexOf('dist=min') > 0);
-            useDist = (min || useDist || document.location.href.toLowerCase().indexOf('dist=true') > 0);            
+            useDist = (min || useDist || document.location.href.toLowerCase().indexOf('dist=true') > 0);
             babylonJSPath = '';
         }
 
-        Loader.prototype.debugShortcut = function(engine) {
+        Loader.prototype.debugShortcut = function (engine) {
             // Add inspector shortcut
             var map = {};
-            var onkey = function(e){
+            var onkey = function (e) {
                 e = e || event; // to deal with IE
                 map[e.keyCode] = e.type == 'keydown';
-                if(map[17] && map[16] && map[18] && map[73]) {
+                if (map[17] && map[16] && map[18] && map[73]) {
                     if (engine.scenes && engine.scenes.length > 0) {
-                        for (var i = 0; i < engine.scenes.length; i ++) {
+                        for (var i = 0; i < engine.scenes.length; i++) {
                             if (engine.scenes[0].debugLayer.isVisible()) {
                                 engine.scenes[0].debugLayer.hide();
                             }
@@ -91,7 +91,7 @@ var BABYLONDEVTOOLS;
             return this;
         }
 
-        Loader.prototype.useDist = function() {
+        Loader.prototype.useDist = function () {
             useDist = true;
             return this;
         }
@@ -99,22 +99,22 @@ var BABYLONDEVTOOLS;
         Loader.prototype.dequeue = function () {
             if (queue.length == 0) {
                 console.log('Scripts loaded');
-                BABYLON.Engine.ShadersRepository = "/src/Shaders/"; 
-                if (callback) {                    
+                BABYLON.Engine.ShadersRepository = "/src/Shaders/";
+                if (callback) {
                     callback();
                 }
-                return;                
+                return;
             }
 
             var url = queue.shift();
-            
+
             var head = document.getElementsByTagName('head')[0];
             var script = document.createElement('script');
             script.type = 'text/javascript';
             script.src = url;
 
             var self = this;
-            script.onload = function() {
+            script.onload = function () {
                 self.dequeue();
             };
             head.appendChild(script);
@@ -135,7 +135,7 @@ var BABYLONDEVTOOLS;
         }
 
         Loader.prototype.loadScripts = function (urls) {
-            for (var i = 0; i< urls.length; i++) {
+            for (var i = 0; i < urls.length; i++) {
                 this.loadScript(urls[i]);
             }
         }
@@ -147,7 +147,7 @@ var BABYLONDEVTOOLS;
                     var file = library.files[i];
                     if (file.indexOf('lib.d.ts') > 0) {
                         continue;
-                    } 
+                    }
 
                     file = file.replace('.ts', '.js');
                     file = file.replace('../', '');
@@ -169,39 +169,41 @@ var BABYLONDEVTOOLS;
             }
             else if (min) {
                 if (library.webpack) {
-                    this.loadScript(babylonJSPath + '/dist/preview release' + module.build.distOutputDirectory + library.output.replace('.js', '.bundle.js'));
+                    if (module.build.distOutputDirectory)
+                        this.loadScript(babylonJSPath + '/dist/preview release' + module.build.distOutputDirectory + library.output.replace('.js', '.bundle.js'));
                 }
                 else {
                     this.loadScript(babylonJSPath + '/dist/preview release' + module.build.distOutputDirectory + library.output.replace('.js', '.min.js'));
                 }
             }
             else {
-                this.loadScript(babylonJSPath + '/dist/preview release' + module.build.distOutputDirectory + library.output);
+                if (module.build.distOutputDirectory)
+                    this.loadScript(babylonJSPath + '/dist/preview release' + module.build.distOutputDirectory + library.output);
             }
 
             if (!min && library.sassFiles && library.sassFiles.length > 0) {
                 var cssFile = library.output.replace('.js', '.css');
-                cssFile = babylonJSPath + '/dist/preview release' +  module.build.distOutputDirectory + cssFile;
+                cssFile = babylonJSPath + '/dist/preview release' + module.build.distOutputDirectory + cssFile;
                 this.loadCss(cssFile);
             }
         }
 
         Loader.prototype.loadModule = function (module) {
-            for (var i = 0; i< module.libraries.length; i++) {
+            for (var i = 0; i < module.libraries.length; i++) {
                 this.loadLibrary(module.libraries[i], module);
             }
         }
 
-        Loader.prototype.processDependency = function(settings, dependency, filesToLoad) {
+        Loader.prototype.processDependency = function (settings, dependency, filesToLoad) {
             if (dependency.dependUpon) {
-                for (var i = 0; i < dependency.dependUpon.length; i++ ) {
+                for (var i = 0; i < dependency.dependUpon.length; i++) {
                     var dependencyName = dependency.dependUpon[i];
                     var parent = settings.workloads[dependencyName];
                     this.processDependency(settings, parent, filesToLoad);
                 }
             }
 
-            for (var i = 0; i< dependency.files.length; i++) {
+            for (var i = 0; i < dependency.files.length; i++) {
                 var file = dependency.files[i];
 
                 if (filesToLoad.indexOf(file) === -1) {
@@ -240,7 +242,7 @@ var BABYLONDEVTOOLS;
 
             // Modules
             if (loadModules) {
-                for (var i = 0; i< settings.modules.length; i++) {
+                for (var i = 0; i < settings.modules.length; i++) {
                     if (settings.modules[i] === "viewer") {
                         continue;
                     }
@@ -255,7 +257,7 @@ var BABYLONDEVTOOLS;
                 callback = newCallback;
             }
             getJson('/Tools/Gulp/config.json',
-                function(data) {
+                function (data) {
                     if (!min) {
                         self.loadScript('/dist/preview release/split.js');
                     }
@@ -267,14 +269,14 @@ var BABYLONDEVTOOLS;
 
                     self.dequeue();
                 },
-                function(reason) { 
+                function (reason) {
                     console.error(reason);
                 }
             );
         };
 
         return Loader;
-    }());    
+    }());
 
     var loader = new Loader();
     BABYLONDEVTOOLS.Loader = loader;

+ 40 - 1
Tools/Gulp/config.json

@@ -1263,7 +1263,8 @@
         "serializers",
         "inspector",
         "gui",
-        "viewer"
+        "viewer",
+        "viewer-assets"
     ],
     "materialsLibrary": {
         "libraries": [
@@ -1719,6 +1720,7 @@
                     "../../gui/src/2D/controls/inputText.ts",
                     "../../gui/src/2D/controls/virtualKeyboard.ts",
                     "../../gui/src/2D/controls/multiLine.ts",
+                    "../../gui/src/2D/controls/grid.ts",                    
                     "../../gui/src/3D/gui3DManager.ts",
                     "../../gui/src/3D/materials/fluentMaterial.ts",
                     "../../gui/src/3D/vector3WithInfo.ts",
@@ -1853,6 +1855,7 @@
                 "name": "babylonjs-viewer",
                 "main": "../../Viewer/dist/build/src/index.d.ts",
                 "out": "../../../../dist/preview release/viewer/babylon.viewer.module.d.ts",
+                "legacyDeclaration": true,
                 "prependText": "/// <reference path=\"./babylon.d.ts\"/>\n/// <reference path=\"./babylon.glTF2Interface.d.ts\"/>\n/// <reference path=\"./babylonjs.loaders.d.ts\"/>\ndeclare module \"babylonjs-loaders\"{ export=BABYLON;}\n"
             },
             "outputs": [
@@ -1888,5 +1891,41 @@
                 }
             ]
         }
+    },
+    "viewer-assets": {
+        "libraries": [
+            {
+                "files": [],
+                "noBundleInName": true,
+                "output": "babylon.viewer.assets.js",
+                "webpack": "../../Viewer/webpack.assets.config.js",
+                "bundle": "true",
+                "moduleDeclaration": {
+                    "name": "BabylonViewerAssets",
+                    "module": "babylonjs-viewer-assets"
+                },
+                "babylonIncluded": true
+            }
+        ],
+        "build": {
+            "srcOutputDirectory": "../../Viewer/",
+            "dtsBundle": {
+                "name": "babylonjs-viewer-assets",
+                "baseDir": "../../Viewer/dist/build/src/assets/",
+                "main": "../../Viewer/dist/build/src/assets/index.d.ts",
+                "out": "../../../build/assets/babylon.viewer.assets.module.d.ts"
+            },
+            "outputs": [
+                {
+                    "destination": [
+                        {
+                            "filename": "babylon.viewer.assets.js",
+                            "outputDirectory": "/../../Viewer/dist/build/assets/"
+                        }
+                    ],
+                    "minified": true
+                }
+            ]
+        }
     }
 }

+ 5 - 3
Tools/Gulp/gulpfile.js

@@ -469,10 +469,12 @@ var buildExternalLibrary = function (library, settings, watch) {
                         let fileLocation = path.join(path.dirname(settings.build.dtsBundle.main), settings.build.dtsBundle.out);
                         fs.readFile(fileLocation, function (err, data) {
                             if (err) throw err;
-                            data = settings.build.dtsBundle.prependText + '\n' + data.toString();
+                            data = (settings.build.dtsBundle.prependText || "") + '\n' + data.toString();
                             fs.writeFile(fileLocation, data);
-                            var newData = processViewerDeclaration(data);
-                            fs.writeFile(fileLocation.replace('.module', ''), newData);
+                            if (settings.build.dtsBundle.legacyDeclaration) {
+                                var newData = processViewerDeclaration(data);
+                                fs.writeFile(fileLocation.replace('.module', ''), newData);
+                            }
                         });
                     });
                 }

+ 87 - 31
Tools/Publisher/index.js

@@ -1,6 +1,7 @@
 let prompt = require('prompt');
 let shelljs = require('shelljs');
 let fs = require('fs-extra');
+let path = require('path');
 
 let basePath = '../../dist/preview release';
 
@@ -46,7 +47,20 @@ let packages = [
     },
     {
         name: 'viewer',
-        path: basePath + '/viewer/'
+        path: basePath + '/../../Viewer/',
+        required: [
+            basePath + '/viewer/readme.md',
+            basePath + '/viewer/package.json',
+            basePath + '/viewer/babylon.viewer.js'
+        ]
+    },
+    {
+        name: 'viewer-assets',
+        path: basePath + '/../../Viewer/dist/build/assets/',
+        required: [
+            basePath + '/../../Viewer/assets/readme.md',
+            basePath + '/../../Viewer/assets/package.json',
+        ]
     }
 ];
 
@@ -71,7 +85,16 @@ function processPackages(version) {
     packages.forEach((package) => {
         if (package.name === "core") {
             processCore(package, version);
+        } else if (package.name === "viewer") {
+            processViewer(package, version);
         } else {
+
+            if (package.required) {
+                package.required.forEach(file => {
+                    fs.copySync(file, package.path + '/' + path.basename(file));
+                });
+            }
+
             let packageJson = require(package.path + 'package.json');
             packageJson.version = version;
             if (packageJson.dependencies) {
@@ -83,14 +106,8 @@ function processPackages(version) {
             }
             if (packageJson.peerDependencies) packageJson.peerDependencies.babylonjs = minimumDependency;
             fs.writeFileSync(package.path + 'package.json', JSON.stringify(packageJson, null, 4));
-            console.log('Publishing ' + package.name + " from " + package.path);
-            let tagDef = "";
-            // check for alpha or beta
-            if (version.indexOf('alpha') !== -1 || version.indexOf('beta') !== -1) {
-                tagDef = '--tag preview';
-            }
-            //publish the respected package
-            shelljs.exec('npm publish \"' + package.path + "\"" + ' ' + tagDef);
+
+            publish(version, package.name, package.path);
         }
 
     });
@@ -153,18 +170,6 @@ function processCore(package, version) {
         }
     ];
 
-    // remove the modules for now
-    /*fs.readdirSync(basePath + '/modules/').forEach(object => {
-        console.log(object);
-        if (fs.statSync(basePath + '/modules/' + object).isDirectory) {
-            files.push({
-                path: basePath + '/modules/' + object,
-                objectName: object,
-                isDir: true
-            });
-        }
-    })*/
-
     //copy them to the package path
     files.forEach(file => {
         fs.copySync(file.path, basePath + '/package/' + file.objectName);
@@ -189,16 +194,7 @@ function processCore(package, version) {
 
     fs.writeFileSync(basePath + '/package/' + 'package.json', JSON.stringify(packageJson, null, 4));
 
-    console.log('Publishing ' + package.name + " from " + basePath + '/package/');
-
-    let tagDef = "";
-    // check for alpha or beta
-    if (version.indexOf('alpha') !== -1 || version.indexOf('beta') !== -1) {
-        tagDef = '--tag preview';
-    }
-
-    //publish the respected package
-    shelljs.exec('npm publish \"' + basePath + '/package/' + "\"" + ' ' + tagDef);
+    publish(version, package.name, basePath + '/package/');
 
     // remove package directory
     fs.removeSync(basePath + '/package/');
@@ -217,3 +213,63 @@ function processCore(package, version) {
     fs.writeFileSync(package.path + 'package.json', JSON.stringify(packageJson, null, 4));
 }
 
+function processViewer(package, version) {
+
+    let buildPath = package.path + "dist/build/src/";
+    let projectPath = '../../Viewer';
+
+    if (package.required) {
+        package.required.forEach(file => {
+
+            fs.copySync(file, buildPath + '/' + path.basename(file));
+        });
+    }
+    // the viewer needs to be built using tsc on the viewer's main repository
+
+    // build the viewer
+    console.log("executing " + 'tsc -p ' + projectPath);
+    shelljs.exec('tsc -p ' + projectPath);
+
+    let packageJson = require(buildPath + '/package.json');
+
+    let files = getFiles(buildPath).map(f => f.replace(buildPath + "/", "")).filter(f => f.indexOf("assets/") === -1);
+
+    packageJson.files = files;
+    packageJson.version = version;
+    packageJson.module = "index.js";
+    packageJson.main = "babylon.viewer.js";
+    packageJson.typings = "index.d.ts";
+
+    fs.writeFileSync(buildPath + '/package.json', JSON.stringify(packageJson, null, 4));
+
+    publish(version, package.name, buildPath);
+
+}
+
+function publish(version, packageName, basePath) {
+    console.log('Publishing ' + packageName + " from " + basePath);
+
+    let tagDef = "";
+    // check for alpha or beta
+    if (version.indexOf('alpha') !== -1 || version.indexOf('beta') !== -1) {
+        tagDef = '--tag preview';
+    }
+
+    //publish the respected package
+    console.log("executing " + 'npm publish \"' + basePath + "\"" + ' ' + tagDef);
+    shelljs.exec('npm publish \"' + basePath + "\"" + ' ' + tagDef);
+}
+
+function getFiles(dir, files_) {
+    files_ = files_ || [];
+    var files = fs.readdirSync(dir);
+    for (var i in files) {
+        var name = dir + '/' + files[i];
+        if (fs.statSync(name).isDirectory()) {
+            getFiles(name, files_);
+        } else {
+            files_.push(name);
+        }
+    }
+    return files_;
+}

+ 31 - 0
Viewer/assets/package.json

@@ -0,0 +1,31 @@
+{
+    "author": {
+        "name": "Raanan Weber"
+    },
+    "name": "babylonjs-viewer-assets",
+    "description": "Compiled resources for the Babylon viewer.",
+    "version": "3.3.0-alpha.3",
+    "repository": {
+        "type": "git",
+        "url": "https://github.com/BabylonJS/Babylon.js.git"
+    },
+    "main": "babylon.viewer.assets.js",
+    "files": [
+        "babylon.viewer.assets.js",
+        "babylon.viewer.assets.module.d.ts",
+        "readme.md",
+        "package.json"
+    ],
+    "typings": "babylon.viewer.assets.module.d.ts",
+    "keywords": [
+        "3D",
+        "javascript",
+        "html5",
+        "webgl",
+        "viewer"
+    ],
+    "license": "Apache-2.0",
+    "engines": {
+        "node": "*"
+    }
+}

+ 19 - 0
Viewer/assets/readme.md

@@ -0,0 +1,19 @@
+# Babylon.js Viewer Assets
+
+Babylon's viewer assets package contains all needed binsry assets neeed for the proper operation of the viewer's templating system.
+
+This packes is only needed when intalling the viewer's npm package and is installed  and used automatically.
+
+For basic and advanced viewer usage instructions please read the doc at https://doc.babylonjs.com/extensions/the_babylon_viewer
+
+The source code can be found at https://github.com/BabylonJS/Babylon.js/tree/master/Viewer
+
+## Overriding the package
+
+To override the package when (for example) using webpack, define the package `babylonjs-viewer-assets` in "externals":
+
+```javascript
+externals: {
+    "babylonjs-viewer-assets": true
+}
+```

+ 1 - 1
Viewer/src/index.ts

@@ -3,7 +3,7 @@ import { viewerGlobals } from './configuration/globals';
 import { viewerManager } from './viewer/viewerManager';
 import { DefaultViewer } from './viewer/defaultViewer';
 import { AbstractViewer } from './viewer/viewer';
-import { telemetryManager } from './telemetryManager';
+import { telemetryManager } from './managers/telemetryManager';
 import { ModelLoader } from './loader/modelLoader';
 import { ViewerModel, ModelState } from './model/viewerModel';
 import { AnimationPlayMode, AnimationState } from './model/modelAnimation';

+ 2 - 2
Viewer/src/initializer.ts

@@ -1,6 +1,6 @@
 import { DefaultViewer } from './viewer/defaultViewer';
 import { mapperManager } from './configuration/mappers';
-import { viewerGlobals, disableInit } from './';
+import { viewerGlobals } from './configuration/globals';
 
 
 /**
@@ -11,7 +11,7 @@ export function initListeners() {
     document.addEventListener("DOMContentLoaded", init);
     function init(event) {
         document.removeEventListener("DOMContentLoaded", init);
-        if (viewerGlobals.disableInit || disableInit) return;
+        if (viewerGlobals.disableInit) return;
         InitTags();
     }
 }

+ 0 - 1
Viewer/src/loader/plugins/applyMaterialConfig.ts

@@ -1,5 +1,4 @@
 import { ILoaderPlugin } from "./loaderPlugin";
-import { telemetryManager } from "../../telemetryManager";
 import { ViewerModel } from "../../model/viewerModel";
 import { Tools, ISceneLoaderPlugin, ISceneLoaderPluginAsync, Material } from "babylonjs";
 import { IGLTFLoaderData, GLTF2 } from "babylonjs-loaders";

+ 0 - 1
Viewer/src/loader/plugins/extendedMaterialLoaderPlugin.ts

@@ -1,5 +1,4 @@
 import { ILoaderPlugin } from "./loaderPlugin";
-import { telemetryManager } from "../../telemetryManager";
 import { ViewerModel } from "../../model/viewerModel";
 import { Color3, Texture, BaseTexture, Tools, ISceneLoaderPlugin, ISceneLoaderPluginAsync, Material, PBRMaterial, Engine } from "babylonjs";
 

+ 0 - 1
Viewer/src/loader/plugins/msftLodLoaderPlugin.ts

@@ -1,5 +1,4 @@
 import { ILoaderPlugin } from "./loaderPlugin";
-import { telemetryManager } from "../../telemetryManager";
 import { ViewerModel } from "../../model/viewerModel";
 import { Tools, ISceneLoaderPlugin, ISceneLoaderPluginAsync } from "babylonjs";
 import { IGLTFLoaderExtension, GLTF2 } from "babylonjs-loaders";

+ 1 - 1
Viewer/src/loader/plugins/telemetryLoaderPlugin.ts

@@ -1,5 +1,5 @@
 import { ILoaderPlugin } from "./loaderPlugin";
-import { telemetryManager } from "../../telemetryManager";
+import { telemetryManager } from "../../managers/telemetryManager";
 import { ViewerModel } from "../../model/viewerModel";
 import { Tools, ISceneLoaderPlugin, ISceneLoaderPluginAsync } from "babylonjs";
 

Viewer/src/telemetryManager.ts → Viewer/src/managers/telemetryManager.ts


+ 29 - 19
Viewer/src/viewer/defaultViewer.ts

@@ -26,6 +26,9 @@ export class DefaultViewer extends AbstractViewer {
         super(containerElement, initialConfiguration);
 
         this.onModelLoadedObservable.add(this._onModelLoaded);
+        this.onModelRemovedObservable.add(() => {
+            this._configureTemplate();
+        })
 
         this.onEngineInitObservable.add(() => {
             this.sceneManager.onLightsConfiguredObservable.add((data) => {
@@ -294,32 +297,39 @@ export class DefaultViewer extends AbstractViewer {
      * It is mainly responsible to changing the title and subtitle etc'.
      * @param model the model to be used to configure the templates by
      */
-    protected _configureTemplate(model: ViewerModel) {
+    protected _configureTemplate(model?: ViewerModel) {
         let navbar = this.templateManager.getTemplate('navBar');
         if (!navbar) return;
 
-        let newParams: any = {};
-
-        let animationNames = model.getAnimationNames();
-        if (animationNames.length >= 1) {
-            this._isAnimationPaused = (model.configuration.animation && !model.configuration.animation.autoStart) || !model.configuration.animation;
-            this._animationList = animationNames;
-            newParams.animations = this._animationList;
-            newParams.paused = this._isAnimationPaused;
-            let animationIndex = 0;
-            if (model.configuration.animation && typeof model.configuration.animation.autoStart === 'string') {
-                animationIndex = animationNames.indexOf(model.configuration.animation.autoStart);
-                if (animationIndex === -1) {
-                    animationIndex = 0;
+        let newParams: any = navbar.configuration.params || {};
+
+        if (!model) {
+            newParams.animations = null;
+        } else {
+
+            let animationNames = model.getAnimationNames();
+            newParams.animations = animationNames;
+            if (animationNames.length) {
+                this._isAnimationPaused = (model.configuration.animation && !model.configuration.animation.autoStart) || !model.configuration.animation;
+                this._animationList = animationNames;
+                newParams.paused = this._isAnimationPaused;
+                let animationIndex = 0;
+                if (model.configuration.animation && typeof model.configuration.animation.autoStart === 'string') {
+                    animationIndex = animationNames.indexOf(model.configuration.animation.autoStart);
+                    if (animationIndex === -1) {
+                        animationIndex = 0;
+                    }
                 }
+                this._updateAnimationType(animationNames[animationIndex], newParams);
+            } else {
+                newParams.animations = null;
             }
-            this._updateAnimationType(animationNames[animationIndex], newParams);
-        }
 
-        if (model.configuration.thumbnail) {
-            newParams.logoImage = model.configuration.thumbnail
+            if (model.configuration.thumbnail) {
+                newParams.logoImage = model.configuration.thumbnail
+            }
         }
-        navbar.updateParams(newParams);
+        navbar.updateParams(newParams, false);
     }
 
     /**

+ 1 - 1
Viewer/src/viewer/viewer.ts

@@ -10,7 +10,7 @@ import { ModelLoader } from '../loader/modelLoader';
 import { CameraBehavior } from '../interfaces';
 import { viewerGlobals } from '../configuration/globals';
 import { extendClassWithConfig } from '../helper';
-import { telemetryManager } from '../telemetryManager';
+import { telemetryManager } from '../managers/telemetryManager';
 import { deepmerge } from '../helper/';
 import { ObservablesManager } from '../managers/observablesManager';
 import { ConfigurationContainer } from '../configuration/configurationContainer';

+ 1 - 1
Viewer/tsconfig.json

@@ -1,7 +1,7 @@
 {
     "compilerOptions": {
         "target": "es2015",
-        "module": "es2015",
+        "module": "commonjs",
         "declaration": true,
         "experimentalDecorators": true,
         "emitDecoratorMetadata": true,

+ 42 - 0
Viewer/webpack.assets.config.js

@@ -0,0 +1,42 @@
+module.exports = {
+    entry: [
+        __dirname + '/src/assets/index.ts'
+    ],
+    output: {
+        libraryTarget: 'var',
+        library: 'BabylonViewerAssets',
+        umdNamedDefine: true
+    },
+    resolve: {
+        extensions: ['.ts']
+    },
+    module: {
+        loaders: [{
+            test: /\.tsx?$/,
+            use: {
+                loader: 'ts-loader',
+                options: {
+                    configFile: 'tsconfig-gulp.json'
+                }
+            },
+            exclude: /node_modules/
+        },
+        {
+            test: /\.(html)$/,
+            use: {
+                loader: 'html-loader',
+                options: {
+                    minimize: true
+                }
+            }
+        },
+        {
+            test: /\.(jpe?g|png|ttf|eot|svg?)(\?[a-z0-9=&.]+)?$/,
+            use: 'base64-image-loader?limit=1000&name=[name].[ext]'
+        },
+        {
+            test: /\.(woff|ttf|eot|svg)(\?v=[0-9]\.[0-9]\.[0-9])?$/,
+            loader: 'base64-font-loader'
+        }]
+    }
+}

+ 1 - 2
Viewer/webpack.gulp.config.js

@@ -2,8 +2,7 @@ module.exports = {
     //context: __dirname,
     entry: [
         __dirname + '/src/index.ts'
-    ]
-    ,
+    ],
     output: {
         libraryTarget: 'var',
         library: 'BabylonViewer',

BIN
assets/environments/environmentSpecular.env


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


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


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


File diff suppressed because it is too large
+ 232 - 61
dist/preview release/babylon.no-module.max.js


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


File diff suppressed because it is too large
+ 232 - 61
dist/preview release/es6.js


+ 1 - 1
dist/preview release/gltf2Interface/package.json

@@ -1,7 +1,7 @@
 {
     "name": "babylonjs-gltf2interface",
     "description": "A typescript declaration of babylon's gltf2 inteface.",
-    "version": "3.3.0-alpha.4",
+    "version": "3.3.0-alpha.6",
     "repository": {
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"

+ 83 - 0
dist/preview release/gui/babylon.gui.d.ts

@@ -607,6 +607,8 @@ declare module BABYLON.GUI {
         private _enterCount;
         private _doNotRender;
         private _downPointerIds;
+        /** @hidden */
+        _tag: any;
         /** Gets or sets a boolean indicating if the control can be hit with pointer events */
         isHitTestVisible: boolean;
         /** Gets or sets a boolean indicating if the control can block pointer events */
@@ -1867,6 +1869,87 @@ declare module BABYLON.GUI {
 
 declare module BABYLON.GUI {
     /**
+     * Class used to create a 2D grid container
+     */
+    class Grid extends Container {
+        name: string | undefined;
+        private _rowDefinitions;
+        private _columnDefinitions;
+        private _cells;
+        private _childControls;
+        /** Gets the list of children */
+        readonly children: Control[];
+        /**
+         * Adds a new row to the grid
+         * @param height defines the height of the row (either in pixel or a value between 0 and 1)
+         * @param isPixel defines if the height is expressed in pixel (or in percentage)
+         * @returns the current grid
+         */
+        addRowDefinition(height: number, isPixel?: boolean): Grid;
+        /**
+         * Adds a new column to the grid
+         * @param width defines the width of the column (either in pixel or a value between 0 and 1)
+         * @param isPixel defines if the width is expressed in pixel (or in percentage)
+         * @returns the current grid
+         */
+        addColumnDefinition(width: number, isPixel?: boolean): Grid;
+        /**
+         * Update a row definition
+         * @param index defines the index of the row to update
+         * @param height defines the height of the row (either in pixel or a value between 0 and 1)
+         * @param isPixel defines if the weight is expressed in pixel (or in percentage)
+         * @returns the current grid
+         */
+        setRowDefinition(index: number, height: number, isPixel?: boolean): Grid;
+        /**
+         * Update a column definition
+         * @param index defines the index of the column to update
+         * @param width defines the width of the column (either in pixel or a value between 0 and 1)
+         * @param isPixel defines if the width is expressed in pixel (or in percentage)
+         * @returns the current grid
+         */
+        setColumnDefinition(index: number, width: number, isPixel?: boolean): Grid;
+        private _removeCell(cell, key);
+        private _offsetCell(previousKey, key);
+        /**
+         * Remove a column definition at specified index
+         * @param index defines the index of the column to remove
+         * @returns the current grid
+         */
+        removeColumnDefinition(index: number): Grid;
+        /**
+         * Remove a row definition at specified index
+         * @param index defines the index of the row to remove
+         * @returns the current grid
+         */
+        removeRowDefinition(index: number): Grid;
+        /**
+         * Adds a new control to the current grid
+         * @param control defines the control to add
+         * @param row defines the row where to add the control (0 by default)
+         * @param column defines the column where to add the control (0 by default)
+         * @returns the current grid
+         */
+        addControl(control: Control, row?: number, column?: number): Grid;
+        /**
+         * Removes a control from the current container
+         * @param control defines the control to remove
+         * @returns the current container
+         */
+        removeControl(control: Control): Container;
+        /**
+         * Creates a new Grid
+         * @param name defines control name
+         */
+        constructor(name?: string | undefined);
+        protected _getTypeName(): string;
+        protected _additionalProcessing(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
+    }
+}
+
+
+declare module BABYLON.GUI {
+    /**
      * Class used to manage 3D user interface
      * @see http://doc.babylonjs.com/how_to/gui3d
      */

+ 311 - 4
dist/preview release/gui/babylon.gui.js

@@ -2888,7 +2888,7 @@ var BABYLON;
              * @returns the child control if found
              */
             Container.prototype.getChildByName = function (name) {
-                for (var _i = 0, _a = this._children; _i < _a.length; _i++) {
+                for (var _i = 0, _a = this.children; _i < _a.length; _i++) {
                     var child = _a[_i];
                     if (child.name === name) {
                         return child;
@@ -2903,7 +2903,7 @@ var BABYLON;
              * @returns the child control if found
              */
             Container.prototype.getChildByType = function (name, type) {
-                for (var _i = 0, _a = this._children; _i < _a.length; _i++) {
+                for (var _i = 0, _a = this.children; _i < _a.length; _i++) {
                     var child = _a[_i];
                     if (child.typeName === type) {
                         return child;
@@ -2917,7 +2917,7 @@ var BABYLON;
              * @returns true if the control is in child list
              */
             Container.prototype.containsControl = function (control) {
-                return this._children.indexOf(control) !== -1;
+                return this.children.indexOf(control) !== -1;
             };
             /**
              * Adds a new control to the current container
@@ -6477,6 +6477,313 @@ var BABYLON;
     })(GUI = BABYLON.GUI || (BABYLON.GUI = {}));
 })(BABYLON || (BABYLON = {}));
 
+/// <reference path="../../../../dist/preview release/babylon.d.ts"/>
+
+var BABYLON;
+(function (BABYLON) {
+    var GUI;
+    (function (GUI) {
+        /**
+         * Class used to create a 2D grid container
+         */
+        var Grid = /** @class */ (function (_super) {
+            __extends(Grid, _super);
+            /**
+             * Creates a new Grid
+             * @param name defines control name
+             */
+            function Grid(name) {
+                var _this = _super.call(this, name) || this;
+                _this.name = name;
+                _this._rowDefinitions = new Array();
+                _this._columnDefinitions = new Array();
+                _this._cells = {};
+                _this._childControls = new Array();
+                return _this;
+            }
+            Object.defineProperty(Grid.prototype, "children", {
+                /** Gets the list of children */
+                get: function () {
+                    return this._childControls;
+                },
+                enumerable: true,
+                configurable: true
+            });
+            /**
+             * Adds a new row to the grid
+             * @param height defines the height of the row (either in pixel or a value between 0 and 1)
+             * @param isPixel defines if the height is expressed in pixel (or in percentage)
+             * @returns the current grid
+             */
+            Grid.prototype.addRowDefinition = function (height, isPixel) {
+                if (isPixel === void 0) { isPixel = false; }
+                this._rowDefinitions.push(new GUI.ValueAndUnit(height, isPixel ? GUI.ValueAndUnit.UNITMODE_PIXEL : GUI.ValueAndUnit.UNITMODE_PERCENTAGE));
+                this._markAsDirty();
+                return this;
+            };
+            /**
+             * Adds a new column to the grid
+             * @param width defines the width of the column (either in pixel or a value between 0 and 1)
+             * @param isPixel defines if the width is expressed in pixel (or in percentage)
+             * @returns the current grid
+             */
+            Grid.prototype.addColumnDefinition = function (width, isPixel) {
+                if (isPixel === void 0) { isPixel = false; }
+                this._columnDefinitions.push(new GUI.ValueAndUnit(width, isPixel ? GUI.ValueAndUnit.UNITMODE_PIXEL : GUI.ValueAndUnit.UNITMODE_PERCENTAGE));
+                this._markAsDirty();
+                return this;
+            };
+            /**
+             * Update a row definition
+             * @param index defines the index of the row to update
+             * @param height defines the height of the row (either in pixel or a value between 0 and 1)
+             * @param isPixel defines if the weight is expressed in pixel (or in percentage)
+             * @returns the current grid
+             */
+            Grid.prototype.setRowDefinition = function (index, height, isPixel) {
+                if (isPixel === void 0) { isPixel = false; }
+                if (index < 0 || index >= this._rowDefinitions.length) {
+                    return this;
+                }
+                this._rowDefinitions[index] = new GUI.ValueAndUnit(height, isPixel ? GUI.ValueAndUnit.UNITMODE_PIXEL : GUI.ValueAndUnit.UNITMODE_PERCENTAGE);
+                this._markAsDirty();
+                return this;
+            };
+            /**
+             * Update a column definition
+             * @param index defines the index of the column to update
+             * @param width defines the width of the column (either in pixel or a value between 0 and 1)
+             * @param isPixel defines if the width is expressed in pixel (or in percentage)
+             * @returns the current grid
+             */
+            Grid.prototype.setColumnDefinition = function (index, width, isPixel) {
+                if (isPixel === void 0) { isPixel = false; }
+                if (index < 0 || index >= this._columnDefinitions.length) {
+                    return this;
+                }
+                this._columnDefinitions[index] = new GUI.ValueAndUnit(width, isPixel ? GUI.ValueAndUnit.UNITMODE_PIXEL : GUI.ValueAndUnit.UNITMODE_PERCENTAGE);
+                this._markAsDirty();
+                return this;
+            };
+            Grid.prototype._removeCell = function (cell, key) {
+                if (!cell) {
+                    return;
+                }
+                _super.prototype.removeControl.call(this, cell);
+                for (var _i = 0, _a = cell.children; _i < _a.length; _i++) {
+                    var control = _a[_i];
+                    var childIndex = this._childControls.indexOf(control);
+                    if (childIndex !== -1) {
+                        this._childControls.splice(childIndex, 1);
+                    }
+                }
+                delete this._cells[key];
+            };
+            Grid.prototype._offsetCell = function (previousKey, key) {
+                if (!this._cells[key]) {
+                    return;
+                }
+                this._cells[previousKey] = this._cells[key];
+                for (var _i = 0, _a = this._cells[previousKey].children; _i < _a.length; _i++) {
+                    var control = _a[_i];
+                    control._tag = previousKey;
+                }
+                delete this._cells[key];
+            };
+            /**
+             * Remove a column definition at specified index
+             * @param index defines the index of the column to remove
+             * @returns the current grid
+             */
+            Grid.prototype.removeColumnDefinition = function (index) {
+                if (index < 0 || index >= this._columnDefinitions.length) {
+                    return this;
+                }
+                for (var x = 0; x < this._rowDefinitions.length; x++) {
+                    var key = x + ":" + index;
+                    var cell = this._cells[key];
+                    this._removeCell(cell, key);
+                }
+                for (var x = 0; x < this._rowDefinitions.length; x++) {
+                    for (var y = index + 1; y < this._columnDefinitions.length; y++) {
+                        var previousKey = x + ":" + (y - 1);
+                        var key = x + ":" + y;
+                        this._offsetCell(previousKey, key);
+                    }
+                }
+                this._columnDefinitions.splice(index, 1);
+                this._markAsDirty();
+                return this;
+            };
+            /**
+             * Remove a row definition at specified index
+             * @param index defines the index of the row to remove
+             * @returns the current grid
+             */
+            Grid.prototype.removeRowDefinition = function (index) {
+                if (index < 0 || index >= this._rowDefinitions.length) {
+                    return this;
+                }
+                for (var y = 0; y < this._columnDefinitions.length; y++) {
+                    var key = index + ":" + y;
+                    var cell = this._cells[key];
+                    this._removeCell(cell, key);
+                }
+                for (var y = 0; y < this._columnDefinitions.length; y++) {
+                    for (var x = index + 1; x < this._rowDefinitions.length; x++) {
+                        var previousKey = x - 1 + ":" + y;
+                        var key = x + ":" + y;
+                        this._offsetCell(previousKey, key);
+                    }
+                }
+                this._rowDefinitions.splice(index, 1);
+                this._markAsDirty();
+                return this;
+            };
+            /**
+             * Adds a new control to the current grid
+             * @param control defines the control to add
+             * @param row defines the row where to add the control (0 by default)
+             * @param column defines the column where to add the control (0 by default)
+             * @returns the current grid
+             */
+            Grid.prototype.addControl = function (control, row, column) {
+                if (row === void 0) { row = 0; }
+                if (column === void 0) { column = 0; }
+                if (this._rowDefinitions.length === 0) {
+                    // Add default row definition
+                    this.addRowDefinition(1, false);
+                }
+                if (this._columnDefinitions.length === 0) {
+                    // Add default column definition
+                    this.addColumnDefinition(1, false);
+                }
+                var x = Math.min(row, this._rowDefinitions.length - 1);
+                var y = Math.min(column, this._columnDefinitions.length - 1);
+                var key = x + ":" + y;
+                var goodContainer = this._cells[key];
+                if (!goodContainer) {
+                    goodContainer = new GUI.Container(key);
+                    this._cells[key] = goodContainer;
+                    goodContainer.horizontalAlignment = GUI.Control.HORIZONTAL_ALIGNMENT_LEFT;
+                    goodContainer.verticalAlignment = GUI.Control.VERTICAL_ALIGNMENT_TOP;
+                    _super.prototype.addControl.call(this, goodContainer);
+                }
+                goodContainer.addControl(control);
+                this._childControls.push(control);
+                control._tag = key;
+                this._markAsDirty();
+                return this;
+            };
+            /**
+             * Removes a control from the current container
+             * @param control defines the control to remove
+             * @returns the current container
+             */
+            Grid.prototype.removeControl = function (control) {
+                var index = this._childControls.indexOf(control);
+                if (index !== -1) {
+                    this._childControls.splice(index, 1);
+                }
+                var cell = this._cells[control._tag];
+                if (cell) {
+                    cell.removeControl(control);
+                }
+                this._markAsDirty();
+                return this;
+            };
+            Grid.prototype._getTypeName = function () {
+                return "Grid";
+            };
+            Grid.prototype._additionalProcessing = function (parentMeasure, context) {
+                var widths = [];
+                var heights = [];
+                var lefts = [];
+                var tops = [];
+                var availableWidth = this._currentMeasure.width;
+                var globalWidthPercentage = 0;
+                var availableHeight = this._currentMeasure.height;
+                var globalHeightPercentage = 0;
+                // Heights
+                var index = 0;
+                for (var _i = 0, _a = this._rowDefinitions; _i < _a.length; _i++) {
+                    var value = _a[_i];
+                    if (value.isPixel) {
+                        var height = value.getValue(this._host);
+                        availableHeight -= height;
+                        heights[index] = height;
+                    }
+                    else {
+                        globalHeightPercentage += value.internalValue;
+                    }
+                    index++;
+                }
+                var top = 0;
+                index = 0;
+                for (var _b = 0, _c = this._rowDefinitions; _b < _c.length; _b++) {
+                    var value = _c[_b];
+                    tops.push(top);
+                    if (!value.isPixel) {
+                        var height = (value.internalValue / globalHeightPercentage) * availableHeight;
+                        top += height;
+                        heights[index] = height;
+                    }
+                    else {
+                        top += value.getValue(this._host);
+                    }
+                    index++;
+                }
+                // Widths
+                index = 0;
+                for (var _d = 0, _e = this._columnDefinitions; _d < _e.length; _d++) {
+                    var value = _e[_d];
+                    if (value.isPixel) {
+                        var width = value.getValue(this._host);
+                        availableWidth -= width;
+                        widths[index] = width;
+                    }
+                    else {
+                        globalWidthPercentage += value.internalValue;
+                    }
+                    index++;
+                }
+                var left = 0;
+                index = 0;
+                for (var _f = 0, _g = this._columnDefinitions; _f < _g.length; _f++) {
+                    var value = _g[_f];
+                    lefts.push(left);
+                    if (!value.isPixel) {
+                        var width = (value.internalValue / globalWidthPercentage) * availableWidth;
+                        left += width;
+                        widths[index] = width;
+                    }
+                    else {
+                        left += value.getValue(this._host);
+                    }
+                    index++;
+                }
+                // Setting child sizes
+                for (var key in this._cells) {
+                    if (!this._cells.hasOwnProperty(key)) {
+                        continue;
+                    }
+                    var split = key.split(":");
+                    var x = parseInt(split[0]);
+                    var y = parseInt(split[1]);
+                    var cell = this._cells[key];
+                    cell.left = lefts[y] + "px";
+                    cell.top = tops[x] + "px";
+                    cell.width = widths[y] + "px";
+                    cell.height = heights[x] + "px";
+                }
+                _super.prototype._additionalProcessing.call(this, parentMeasure, context);
+            };
+            return Grid;
+        }(GUI.Container));
+        GUI.Grid = Grid;
+    })(GUI = BABYLON.GUI || (BABYLON.GUI = {}));
+})(BABYLON || (BABYLON = {}));
+
 /// <reference path="../../../dist/preview release/babylon.d.ts"/>
 var BABYLON;
 (function (BABYLON) {
@@ -7125,7 +7432,7 @@ var BABYLON;
                     this._isVisible = value;
                     var mesh = this.mesh;
                     if (mesh) {
-                        mesh.isVisible = value;
+                        mesh.setEnabled(value);
                     }
                 },
                 enumerable: true,

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


+ 83 - 0
dist/preview release/gui/babylon.gui.module.d.ts

@@ -612,6 +612,8 @@ declare module BABYLON.GUI {
         private _enterCount;
         private _doNotRender;
         private _downPointerIds;
+        /** @hidden */
+        _tag: any;
         /** Gets or sets a boolean indicating if the control can be hit with pointer events */
         isHitTestVisible: boolean;
         /** Gets or sets a boolean indicating if the control can block pointer events */
@@ -1872,6 +1874,87 @@ declare module BABYLON.GUI {
 
 declare module BABYLON.GUI {
     /**
+     * Class used to create a 2D grid container
+     */
+    class Grid extends Container {
+        name: string | undefined;
+        private _rowDefinitions;
+        private _columnDefinitions;
+        private _cells;
+        private _childControls;
+        /** Gets the list of children */
+        readonly children: Control[];
+        /**
+         * Adds a new row to the grid
+         * @param height defines the height of the row (either in pixel or a value between 0 and 1)
+         * @param isPixel defines if the height is expressed in pixel (or in percentage)
+         * @returns the current grid
+         */
+        addRowDefinition(height: number, isPixel?: boolean): Grid;
+        /**
+         * Adds a new column to the grid
+         * @param width defines the width of the column (either in pixel or a value between 0 and 1)
+         * @param isPixel defines if the width is expressed in pixel (or in percentage)
+         * @returns the current grid
+         */
+        addColumnDefinition(width: number, isPixel?: boolean): Grid;
+        /**
+         * Update a row definition
+         * @param index defines the index of the row to update
+         * @param height defines the height of the row (either in pixel or a value between 0 and 1)
+         * @param isPixel defines if the weight is expressed in pixel (or in percentage)
+         * @returns the current grid
+         */
+        setRowDefinition(index: number, height: number, isPixel?: boolean): Grid;
+        /**
+         * Update a column definition
+         * @param index defines the index of the column to update
+         * @param width defines the width of the column (either in pixel or a value between 0 and 1)
+         * @param isPixel defines if the width is expressed in pixel (or in percentage)
+         * @returns the current grid
+         */
+        setColumnDefinition(index: number, width: number, isPixel?: boolean): Grid;
+        private _removeCell(cell, key);
+        private _offsetCell(previousKey, key);
+        /**
+         * Remove a column definition at specified index
+         * @param index defines the index of the column to remove
+         * @returns the current grid
+         */
+        removeColumnDefinition(index: number): Grid;
+        /**
+         * Remove a row definition at specified index
+         * @param index defines the index of the row to remove
+         * @returns the current grid
+         */
+        removeRowDefinition(index: number): Grid;
+        /**
+         * Adds a new control to the current grid
+         * @param control defines the control to add
+         * @param row defines the row where to add the control (0 by default)
+         * @param column defines the column where to add the control (0 by default)
+         * @returns the current grid
+         */
+        addControl(control: Control, row?: number, column?: number): Grid;
+        /**
+         * Removes a control from the current container
+         * @param control defines the control to remove
+         * @returns the current container
+         */
+        removeControl(control: Control): Container;
+        /**
+         * Creates a new Grid
+         * @param name defines control name
+         */
+        constructor(name?: string | undefined);
+        protected _getTypeName(): string;
+        protected _additionalProcessing(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
+    }
+}
+
+
+declare module BABYLON.GUI {
+    /**
      * Class used to manage 3D user interface
      * @see http://doc.babylonjs.com/how_to/gui3d
      */

+ 1 - 1
dist/preview release/gui/package.json

@@ -4,7 +4,7 @@
     },
     "name": "babylonjs-gui",
     "description": "The Babylon.js GUI library is an extension you can use to generate interactive user interface. It is build on top of the DynamicTexture.",
-    "version": "3.3.0-alpha.4",
+    "version": "3.3.0-alpha.6",
     "repository": {
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"

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


+ 23 - 8
dist/preview release/inspector/babylon.inspector.css

@@ -308,15 +308,13 @@
     border-bottom: 1px solid #5db0d7;
     box-sizing: border-box; }
   .insp-wrapper .tab-panel .tool-label, .insp-wrapper .tab-panel .tool-label-line, .insp-wrapper .tab-panel .tool-label-error {
-    display: inline-block;
-    width: 75%;
-    padding: 2px;
     background-color: #2c2c2c;
-    border-bottom: 1px solid #242424;
-    border-top: 1px solid #242424;
-    height: 30px;
-    line-height: 30px;
-    box-sizing: border-box; }
+    border: none;
+    outline: none;
+    font-family: "Inconsolata", sans-serif;
+    color: #b3b3b3;
+    padding: 5px;
+    margin: 0px 6px 0px 0; }
   .insp-wrapper .tab-panel .tool-label-line {
     width: 100%; }
   .insp-wrapper .tab-panel .tool-label-error {
@@ -336,6 +334,23 @@
   .insp-wrapper .tab-panel .tool-infos {
     width: 100%;
     padding: 4px; }
+  .insp-wrapper .tab-panel .tool-input {
+    background-color: #2c2c2c;
+    border: none;
+    outline: none;
+    font-family: "Inconsolata", sans-serif;
+    color: #ccc;
+    padding: 5px 10px;
+    margin: 0px 6px 0px 0;
+    width: 100%;
+    border-top: 1px solid #242424;
+    border-bottom: 1px solid #242424;
+    text-align: left; }
+    .insp-wrapper .tab-panel .tool-input:hover {
+      background-color: #383838;
+      cursor: pointer; }
+    .insp-wrapper .tab-panel .tool-input:active {
+      background-color: #454545; }
   .insp-wrapper .property-type {
     color: #5db0d7; }
   .insp-wrapper .property-name, .insp-wrapper .insp-details .base-row .prop-name, .insp-wrapper .insp-details .row .prop-name, .insp-wrapper .insp-details .header-row .prop-name {

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

@@ -1056,7 +1056,6 @@ declare module INSPECTOR {
         private _inspector;
         private _scene;
         constructor(tabbar: TabBar, insp: Inspector);
-        private _createToolLabel(content, parent);
         dispose(): void;
     }
 }

+ 39 - 41
dist/preview release/inspector/babylon.inspector.js

@@ -304,6 +304,7 @@ var INSPECTOR;
             // Create popup
             var popup = window.open('', 'Babylon.js INSPECTOR', 'toolbar=no,resizable=yes,menubar=no,width=750,height=1000');
             if (!popup) {
+                alert("Please update your browser to open the Babylon.js inspector in an external view.");
                 return;
             }
             popup.document.title = "Babylon.js INSPECTOR";
@@ -4268,16 +4269,16 @@ var INSPECTOR;
             title.appendChild(versionSpan);
             // Environment block
             title = INSPECTOR.Helpers.CreateDiv('tool-title2', _this._panel);
-            title.textContent = "Environment";
+            title.textContent = "Environment Texture (.dds, .env)";
             {
-                var elemLabel = _this._createToolLabel("Load Environment Texture (.dds, .env) ", _this._panel);
-                elemLabel.className = "tool-label-line";
                 var errorElemm_1 = INSPECTOR.Inspector.DOCUMENT.createElement('div');
                 errorElemm_1.className = "tool-label-error";
                 errorElemm_1.style.display = "none";
+                var elemValue = INSPECTOR.Helpers.CreateDiv(null, _this._panel);
                 var inputElement = INSPECTOR.Inspector.DOCUMENT.createElement('input');
-                inputElement.className = "tool-label-line";
+                inputElement.className = "tool-input";
                 inputElement.type = "file";
+                inputElement.accept = ".dds, .env";
                 inputElement.onchange = function (event) {
                     var files = event.target.files;
                     var file = null;
@@ -4315,46 +4316,48 @@ var INSPECTOR;
                         }
                     }, undefined, true);
                 };
-                _this._panel.appendChild(inputElement);
-                _this._createToolLabel("Compress to .env", _this._panel);
-                var elemValue = INSPECTOR.Helpers.CreateDiv('tool-value', _this._panel);
-                inputElement = INSPECTOR.Inspector.DOCUMENT.createElement('input');
-                inputElement.value = "Save";
-                inputElement.type = "button";
-                inputElement.onclick = function () {
-                    if (!_this._scene.environmentTexture) {
-                        errorElemm_1.style.display = "block";
-                        errorElemm_1.textContent = "You must load an environment texture first.";
-                        return;
-                    }
-                    if (_this._scene.activeCamera) {
-                        BABYLON.EnvironmentTextureTools.CreateEnvTextureAsync(_this._scene.environmentTexture)
-                            .then(function (buffer) {
-                            var blob = new Blob([buffer], { type: "octet/stream" });
-                            BABYLON.Tools.Download(blob, "environment.env");
-                            errorElemm_1.style.display = "none";
-                        })
-                            .catch(function (error) {
-                            errorElemm_1.style.display = "block";
-                            errorElemm_1.textContent = error;
-                        });
-                    }
-                    else {
-                        errorElemm_1.style.display = "block";
-                        errorElemm_1.textContent = "An active camera is required.";
-                    }
-                };
                 elemValue.appendChild(inputElement);
+                if (!_this._scene.getEngine().premultipliedAlpha) {
+                    elemValue = INSPECTOR.Helpers.CreateDiv(null, _this._panel);
+                    inputElement = INSPECTOR.Inspector.DOCUMENT.createElement('input');
+                    inputElement.value = "Compress current texture to .env";
+                    inputElement.className = "tool-input";
+                    inputElement.type = "button";
+                    inputElement.onclick = function () {
+                        if (!_this._scene.environmentTexture) {
+                            errorElemm_1.style.display = "block";
+                            errorElemm_1.textContent = "You must load an environment texture first.";
+                            return;
+                        }
+                        if (_this._scene.activeCamera) {
+                            BABYLON.EnvironmentTextureTools.CreateEnvTextureAsync(_this._scene.environmentTexture)
+                                .then(function (buffer) {
+                                var blob = new Blob([buffer], { type: "octet/stream" });
+                                BABYLON.Tools.Download(blob, "environment.env");
+                                errorElemm_1.style.display = "none";
+                            })
+                                .catch(function (error) {
+                                errorElemm_1.style.display = "block";
+                                errorElemm_1.textContent = error;
+                            });
+                        }
+                        else {
+                            errorElemm_1.style.display = "block";
+                            errorElemm_1.textContent = "An active camera is required.";
+                        }
+                    };
+                    elemValue.appendChild(inputElement);
+                }
                 _this._panel.appendChild(errorElemm_1);
             }
             title = INSPECTOR.Helpers.CreateDiv('tool-title2', _this._panel);
             title.textContent = "Capture";
             {
-                _this._createToolLabel("Screenshot", _this._panel);
-                var elemValue = INSPECTOR.Helpers.CreateDiv('tool-value', _this._panel);
+                var elemValue = INSPECTOR.Helpers.CreateDiv(null, _this._panel);
                 var inputElement = INSPECTOR.Inspector.DOCUMENT.createElement('input');
-                inputElement.value = "Capture";
+                inputElement.value = "Take Screenshot";
                 inputElement.type = "button";
+                inputElement.className = "tool-input";
                 inputElement.onclick = function () {
                     if (_this._scene.activeCamera) {
                         BABYLON.Tools.CreateScreenshot(_this._scene.getEngine(), _this._scene.activeCamera, { precision: 0.5 });
@@ -4364,11 +4367,6 @@ var INSPECTOR;
             }
             return _this;
         }
-        ToolsTab.prototype._createToolLabel = function (content, parent) {
-            var elem = INSPECTOR.Helpers.CreateDiv('tool-label', parent);
-            elem.textContent = content;
-            return elem;
-        };
         ToolsTab.prototype.dispose = function () {
             // Nothing to dispose
         };

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


+ 1 - 1
dist/preview release/inspector/package.json

@@ -4,7 +4,7 @@
     },
     "name": "babylonjs-inspector",
     "description": "The Babylon.js inspector.",
-    "version": "3.3.0-alpha.4",
+    "version": "3.3.0-alpha.6",
     "repository": {
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"

+ 2 - 2
dist/preview release/loaders/package.json

@@ -4,7 +4,7 @@
     },
     "name": "babylonjs-loaders",
     "description": "The Babylon.js file loaders library is an extension you can use to load different 3D file types into a Babylon scene.",
-    "version": "3.3.0-alpha.4",
+    "version": "3.3.0-alpha.6",
     "repository": {
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"
@@ -27,7 +27,7 @@
     ],
     "license": "Apache-2.0",
     "dependencies": {
-        "babylonjs-gltf2interface": "3.3.0-alpha.4"
+        "babylonjs-gltf2interface": "3.3.0-alpha.6"
     },
     "peerDependencies": {
         "babylonjs": ">=3.2.0-alpha"

+ 1 - 1
dist/preview release/materialsLibrary/package.json

@@ -4,7 +4,7 @@
     },
     "name": "babylonjs-materials",
     "description": "The Babylon.js materials library is a collection of advanced materials to be used in a Babylon.js scene.",
-    "version": "3.3.0-alpha.4",
+    "version": "3.3.0-alpha.6",
     "repository": {
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"

+ 1 - 1
dist/preview release/postProcessesLibrary/package.json

@@ -4,7 +4,7 @@
     },
     "name": "babylonjs-post-process",
     "description": "The Babylon.js materials library is a collection of advanced materials to be used in a Babylon.js scene.",
-    "version": "3.3.0-alpha.4",
+    "version": "3.3.0-alpha.6",
     "repository": {
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"

+ 1 - 1
dist/preview release/proceduralTexturesLibrary/package.json

@@ -4,7 +4,7 @@
     },
     "name": "babylonjs-procedural-textures",
     "description": "The Babylon.js materials library is a collection of advanced materials to be used in a Babylon.js scene.",
-    "version": "3.3.0-alpha.4",
+    "version": "3.3.0-alpha.6",
     "repository": {
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"

+ 2 - 2
dist/preview release/serializers/package.json

@@ -4,7 +4,7 @@
     },
     "name": "babylonjs-serializers",
     "description": "The Babylon.js serializers library is an extension you can use to serialize Babylon scenes.",
-    "version": "3.3.0-alpha.4",
+    "version": "3.3.0-alpha.6",
     "repository": {
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"
@@ -27,7 +27,7 @@
     ],
     "license": "Apache-2.0",
     "dependencies": {
-        "babylonjs-gltf2interface": "3.3.0-alpha.4"
+        "babylonjs-gltf2interface": "3.3.0-alpha.6"
     },
     "peerDependencies": {
         "babylonjs": ">=3.2.0-alpha"

+ 1 - 1
dist/preview release/viewer/babylon.viewer.d.ts

@@ -181,7 +181,7 @@ declare module BabylonViewer {
                 * It is mainly responsible to changing the title and subtitle etc'.
                 * @param model the model to be used to configure the templates by
                 */
-            protected _configureTemplate(model: ViewerModel): void;
+            protected _configureTemplate(model?: ViewerModel): void;
             /**
                 * This will load a new model to the default viewer
                 * overriding the AbstractViewer's loadModel.

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


File diff suppressed because it is too large
+ 383 - 201
dist/preview release/viewer/babylon.viewer.max.js


+ 3 - 3
dist/preview release/viewer/babylon.viewer.module.d.ts

@@ -14,7 +14,7 @@ declare module 'babylonjs-viewer' {
     import { viewerManager } from 'babylonjs-viewer/viewer/viewerManager';
     import { DefaultViewer } from 'babylonjs-viewer/viewer/defaultViewer';
     import { AbstractViewer } from 'babylonjs-viewer/viewer/viewer';
-    import { telemetryManager } from 'babylonjs-viewer/telemetryManager';
+    import { telemetryManager } from 'babylonjs-viewer/managers/telemetryManager';
     import { ModelLoader } from 'babylonjs-viewer/loader/modelLoader';
     import { ViewerModel, ModelState } from 'babylonjs-viewer/model/viewerModel';
     import { AnimationPlayMode, AnimationState } from 'babylonjs-viewer/model/modelAnimation';
@@ -181,7 +181,7 @@ declare module 'babylonjs-viewer/viewer/defaultViewer' {
                 * It is mainly responsible to changing the title and subtitle etc'.
                 * @param model the model to be used to configure the templates by
                 */
-            protected _configureTemplate(model: ViewerModel): void;
+            protected _configureTemplate(model?: ViewerModel): void;
             /**
                 * This will load a new model to the default viewer
                 * overriding the AbstractViewer's loadModel.
@@ -458,7 +458,7 @@ declare module 'babylonjs-viewer/viewer/viewer' {
     }
 }
 
-declare module 'babylonjs-viewer/telemetryManager' {
+declare module 'babylonjs-viewer/managers/telemetryManager' {
     import { Engine, Observable } from "babylonjs";
     /**
         * The data structure of a telemetry event.

+ 11 - 0
dist/preview release/viewer/package.json

@@ -31,5 +31,16 @@
     "license": "Apache-2.0",
     "engines": {
         "node": "*"
+    },
+    "dependencies": {
+        "deepmerge": "~2.1.1",
+        "handlebars": "~4.0.11",
+        "pepjs": "~0.4.3"
+    },
+    "peerDependencies": {
+        "babylonjs": ">3.3.0-alpha",
+        "babylonjs-loaders": ">3.3.0-alpha",
+        "babylonjs-gltf2interface": ">3.3.0-alpha",
+        "babylonjs-viewer-assets": ">3.3.0-alpha"
     }
 }

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

@@ -6,16 +6,18 @@
 - Added new `MixMaterial` to the Materials Library allowing to mix up to 8 textures ([julien-moreau](https://github.com/julien-moreau))
 - Added new `PhotoDome` object to display 360 photos. [Demo](https://www.babylonjs-playground.com/#14KRGG#0) ([SzeyinLee](https://github.com/SzeyinLee))
 - New GUI 3D controls toolset. [Complete doc + demos](http://doc.babylonjs.com/how_to/gui3d) ([Deltakosh](https://github.com/deltakosh))
-- Added Environmnent Texture Tools to reduce the size of the usual .DDS file ([sebavan](http://www.github.com/sebavan))
+- Added [Environmnent Texture Tools](https://doc.babylonjs.com/how_to/physically_based_rendering#creating-a-compressed-environment-texture) to reduce the size of the usual .DDS file ([sebavan](http://www.github.com/sebavan))
+- New GUI control: the [Grid](http://doc.babylonjs.com/how_to/gui#grid) ([Deltakosh](https://github.com/deltakosh))
 
 ## Updates
 
 - All NPM packages have `latest`and `preview` streams [#3055](https://github.com/BabylonJS/Babylon.js/issues/3055) ([RaananW](https://github.com/RaananW))
+- Added New Tools Tab in the inspector (env texture and screenshot tools so far) ([sebavan](http://www.github.com/sebavan))
 
 ### Core Engine
 
 - Added new `Animatable.waitAsync` function to use Promises with animations. Demo [Here](https://www.babylonjs-playground.com/#HZBCXR) ([Deltakosh](https://github.com/deltakosh))
-- Added the choice of [forming a closed loop](http://doc.babylonjs.com/how_to/how_to_use_curve3#catmull-rom-spline) to the catamull-rom-spline curve3 ([johnk](https://github.com/babylonjsguide))
+- Added the choice of [forming a closed loop](http://doc.babylonjs.com/how_to/how_to_use_curve3#catmull-rom-spline) to the catmull-rom-spline curve3 ([johnk](https://github.com/babylonjsguide))
 - Added support for specifying the center of rotation to textures ([bghgary](http://www.github.com/bghgary))
 - Added webVR support for Oculus Go ([TrevorDev](https://github.com/TrevorDev))
 - Added ability to not generate polynomials harmonics upon prefiltered texture creation ([sebavan](http://www.github.com/sebavan))
@@ -29,6 +31,7 @@
 - Added a new `mesh.ignoreNonUniformScaling` to turn off non uniform scaling compensation ([Deltakosh](https://github.com/deltakosh))
 - AssetsManager tasks will only run when their state is INIT. It is now possible to remove a task from the assets manager ([RaananW](https://github.com/RaananW))
 - Sprite isVisible field ([TrevorDev](https://github.com/TrevorDev))
+- Added support for `minScaleX`, `minScaleY`, `maxScaleX`, `maxScaleY` for particles ([Deltakosh](https://github.com/deltakosh))
 
 ### glTF Loader
 
@@ -44,7 +47,7 @@
 - Shadows will only render while models are entering the scene or animating ([RaananW](https://github.com/RaananW))
 - Support for model drag and drop onto the canvas ([RaananW](https://github.com/RaananW))
 - New lab feature - global light rotation [#4347](https://github.com/BabylonJS/Babylon.js/issues/4347) ([RaananW](https://github.com/RaananW))
-- New package - babylonjs-viewer-assets, to separate the binary assets and the code of the viewer ([RaananW](https://github.com/RaananW))
+- New NPM package - babylonjs-viewer-assets, to separate the binary assets and the code of the viewer ([RaananW](https://github.com/RaananW))
 
 ### Documentation
 
@@ -66,6 +69,8 @@
 - Fixed a bug with setting `unlit` on `PBRMaterial` after the material is ready (Wrong dirty flags) ([bghgary](http://www.github.com/bghgary))
 - Fixed `HighlightLayer` support on browsers not supporting HalfFloat ([sebavan](http://www.github.com/sebavan))
 - Fixed support for R and RG texture formats ([sebavan](http://www.github.com/sebavan))
+- Fixed `updatable` parameter setting in the SPS ([jerome](https://github.com/jbousquie))
+- Angular and linear velocity were using the wrong method to copy values to the physics engine ([RaananW](https://github.com/RaananW))
 
 ### Viewer
 
@@ -76,6 +81,7 @@
 - Model configuration was not extended correctly if loaded more than one model ([RaananW](https://github.com/RaananW))
 - It wasn't possible to disable camera behavior(s) using configuration  [#4348](https://github.com/BabylonJS/Babylon.js/issues/4348) ([RaananW](https://github.com/RaananW))
 - Animation blending was always set to true, ignoring configuration [#4412](https://github.com/BabylonJS/Babylon.js/issues/4412) ([RaananW](https://github.com/RaananW))
+- Animation navbar now updates correctly when a new model is loaded [#4441](https://github.com/BabylonJS/Babylon.js/issues/4441) ([RaananW](https://github.com/RaananW))
 
 ## Breaking changes
 

+ 3 - 3
gui/src/2D/controls/container.ts

@@ -92,7 +92,7 @@ module BABYLON.GUI {
          * @returns the child control if found
          */
         public getChildByName(name: string): Nullable<Control> {
-            for (var child of this._children) {
+            for (var child of this.children) {
                 if (child.name === name) {
                     return child;
                 }
@@ -108,7 +108,7 @@ module BABYLON.GUI {
          * @returns the child control if found
          */        
         public getChildByType(name: string, type: string): Nullable<Control> {
-            for (var child of this._children) {
+            for (var child of this.children) {
                 if (child.typeName === type) {
                     return child;
                 }
@@ -123,7 +123,7 @@ module BABYLON.GUI {
          * @returns true if the control is in child list
          */
         public containsControl(control: Control): boolean {
-            return this._children.indexOf(control) !== -1;
+            return this.children.indexOf(control) !== -1;
         }
 
         /**

+ 3 - 0
gui/src/2D/controls/control.ts

@@ -72,6 +72,9 @@ module BABYLON.GUI {
         private _doNotRender = false;
         private _downPointerIds:{[id:number] : boolean} = {};
 
+        /** @hidden */
+        public _tag: any;
+
         /** Gets or sets a boolean indicating if the control can be hit with pointer events */
         public isHitTestVisible = true;
         /** Gets or sets a boolean indicating if the control can block pointer events */

+ 350 - 0
gui/src/2D/controls/grid.ts

@@ -0,0 +1,350 @@
+/// <reference path="../../../../dist/preview release/babylon.d.ts"/>
+
+module BABYLON.GUI {
+    /**
+     * Class used to create a 2D grid container
+     */
+    export class Grid extends Container {
+        private _rowDefinitions = new Array<ValueAndUnit>();
+        private _columnDefinitions = new Array<ValueAndUnit>();
+        private _cells: {[key: string]:Container} = {};
+        private _childControls = new Array<Control>();
+
+        /** Gets the list of children */
+        public get children(): Control[] {
+            return this._childControls;
+        }             
+
+        /**
+         * Adds a new row to the grid
+         * @param height defines the height of the row (either in pixel or a value between 0 and 1)
+         * @param isPixel defines if the height is expressed in pixel (or in percentage)
+         * @returns the current grid
+         */
+        public addRowDefinition(height: number, isPixel = false): Grid {
+            this._rowDefinitions.push(new ValueAndUnit(height, isPixel ? ValueAndUnit.UNITMODE_PIXEL : ValueAndUnit.UNITMODE_PERCENTAGE));
+
+            this._markAsDirty();
+
+            return this;
+        }
+
+        /**
+         * Adds a new column to the grid
+         * @param width defines the width of the column (either in pixel or a value between 0 and 1)
+         * @param isPixel defines if the width is expressed in pixel (or in percentage)
+         * @returns the current grid
+         */
+        public addColumnDefinition(width: number, isPixel = false): Grid {
+            this._columnDefinitions.push(new ValueAndUnit(width, isPixel ? ValueAndUnit.UNITMODE_PIXEL : ValueAndUnit.UNITMODE_PERCENTAGE));
+            
+            this._markAsDirty();
+
+            return this;
+        }     
+
+        /**
+         * Update a row definition
+         * @param index defines the index of the row to update
+         * @param height defines the height of the row (either in pixel or a value between 0 and 1)
+         * @param isPixel defines if the weight is expressed in pixel (or in percentage)
+         * @returns the current grid
+         */
+        public setRowDefinition(index: number, height: number, isPixel = false): Grid {
+            if (index < 0 || index >= this._rowDefinitions.length) {
+                return this;
+            }
+
+            this._rowDefinitions[index] = new ValueAndUnit(height,isPixel ? ValueAndUnit.UNITMODE_PIXEL : ValueAndUnit.UNITMODE_PERCENTAGE);
+
+            this._markAsDirty();
+
+            return this;
+        }
+
+        /**
+         * Update a column definition
+         * @param index defines the index of the column to update
+         * @param width defines the width of the column (either in pixel or a value between 0 and 1)
+         * @param isPixel defines if the width is expressed in pixel (or in percentage)
+         * @returns the current grid
+         */
+        public setColumnDefinition(index: number, width: number, isPixel = false): Grid {
+            if (index < 0 || index >= this._columnDefinitions.length) {
+                return this;
+            }
+
+            this._columnDefinitions[index] = new ValueAndUnit(width, isPixel ? ValueAndUnit.UNITMODE_PIXEL : ValueAndUnit.UNITMODE_PERCENTAGE);
+
+            this._markAsDirty();
+
+            return this;
+        }        
+
+        private _removeCell(cell: Container, key: string) {
+            if (!cell) {
+                return;
+            }
+
+            super.removeControl(cell);
+
+            for (var control of cell.children) {
+                let childIndex = this._childControls.indexOf(control);
+
+                if (childIndex !== -1) {
+                    this._childControls.splice(childIndex, 1);
+                }
+            }
+
+            delete this._cells[key];
+        }
+
+        private _offsetCell(previousKey: string, key: string) {
+            if (!this._cells[key]) {
+                return;
+            }
+
+            this._cells[previousKey] = this._cells[key];
+
+            for (var control of this._cells[previousKey].children) {
+                control._tag = previousKey;
+            } 
+
+            delete this._cells[key];
+        }
+
+        /**
+         * Remove a column definition at specified index
+         * @param index defines the index of the column to remove
+         * @returns the current grid
+         */
+        public removeColumnDefinition(index: number): Grid {
+            if (index < 0 || index >= this._columnDefinitions.length) {
+                return this;
+            }
+
+            for (var x = 0; x < this._rowDefinitions.length; x++) {
+                let key = `${x}:${index}`;
+                let cell = this._cells[key];
+
+                this._removeCell(cell, key);
+            }
+
+            for (var x = 0; x < this._rowDefinitions.length; x++) {
+                for (var y = index + 1; y < this._columnDefinitions.length; y++) {
+                    let previousKey = `${x}:${y - 1}`;
+                    let key = `${x}:${y}`;
+
+                    this._offsetCell(previousKey, key);
+                }
+            }
+            
+            this._columnDefinitions.splice(index, 1);
+
+            this._markAsDirty();
+
+            return this;
+        }
+
+        /**
+         * Remove a row definition at specified index
+         * @param index defines the index of the row to remove
+         * @returns the current grid
+         */
+        public removeRowDefinition(index: number): Grid {
+            if (index < 0 || index >= this._rowDefinitions.length) {
+                return this;
+            }
+
+            for (var y = 0; y < this._columnDefinitions.length; y++) {
+                let key = `${index}:${y}`;
+                let cell = this._cells[key];
+
+                this._removeCell(cell, key);
+            }
+
+            for (var y = 0; y < this._columnDefinitions.length; y++) {
+                for (var x = index + 1; x < this._rowDefinitions.length; x++) {
+                    let previousKey = `${x - 1}:${y}`;
+                    let key = `${x}:${y}`;
+
+                    this._offsetCell(previousKey, key);
+                }
+            }
+            
+            this._rowDefinitions.splice(index, 1);
+
+            this._markAsDirty();
+
+            return this;
+        }
+
+        /**
+         * Adds a new control to the current grid
+         * @param control defines the control to add
+         * @param row defines the row where to add the control (0 by default)
+         * @param column defines the column where to add the control (0 by default)
+         * @returns the current grid
+         */
+        public addControl(control: Control, row: number = 0, column: number = 0): Grid {
+            if (this._rowDefinitions.length === 0) {
+                // Add default row definition
+                this.addRowDefinition(1, false);
+            }
+
+            if (this._columnDefinitions.length === 0) {
+                // Add default column definition
+                this.addColumnDefinition(1, false);
+            }
+
+            let x = Math.min(row, this._rowDefinitions.length - 1);
+            let y = Math.min(column, this._columnDefinitions.length - 1);
+            let key = `${x}:${y}`;
+            let goodContainer = this._cells[key];
+
+            if (!goodContainer) {
+                goodContainer = new Container(key);
+                this._cells[key] = goodContainer;
+                goodContainer.horizontalAlignment = Control.HORIZONTAL_ALIGNMENT_LEFT;
+                goodContainer.verticalAlignment = Control.VERTICAL_ALIGNMENT_TOP;
+                super.addControl(goodContainer);
+            }
+
+            goodContainer.addControl(control);
+            this._childControls.push(control);
+            control._tag = key;
+
+            this._markAsDirty();            
+
+            return this;
+        }
+
+        /**
+         * Removes a control from the current container
+         * @param control defines the control to remove
+         * @returns the current container
+         */        
+        public removeControl(control: Control): Container {
+            var index = this._childControls.indexOf(control);
+
+            if (index !== -1) {
+                this._childControls.splice(index, 1);
+            }
+
+            let cell = this._cells[control._tag];
+
+            if (cell) {
+                cell.removeControl(control);
+            }
+
+            this._markAsDirty();
+            return this;
+        }        
+
+        /**
+         * Creates a new Grid
+         * @param name defines control name
+         */
+        constructor(public name?: string) {
+            super(name);
+        }
+
+        protected _getTypeName(): string {
+            return "Grid";
+        }   
+
+        protected _additionalProcessing(parentMeasure: Measure, context: CanvasRenderingContext2D): void {
+            let widths = [];
+            let heights = [];
+            let lefts = [];
+            let tops = [];
+
+            let availableWidth = this._currentMeasure.width;
+            let globalWidthPercentage = 0;
+            let availableHeight = this._currentMeasure.height;
+            let globalHeightPercentage = 0;
+
+            // Heights
+            let index = 0;
+            for (var value of this._rowDefinitions) {
+                if (value.isPixel) {
+                    let height = value.getValue(this._host);
+                    availableHeight -= height;
+                    heights[index] = height;
+                } else {
+                    globalHeightPercentage += value.internalValue;
+                }
+                index++;
+            }
+
+            let top = 0;
+            index = 0;
+            for (var value of this._rowDefinitions) {
+                tops.push(top);
+
+                if (!value.isPixel) {
+                    let height = (value.internalValue / globalHeightPercentage) * availableHeight;
+                    top += height;
+                    heights[index] = height;
+                } else {
+                    top += value.getValue(this._host);
+                }
+                index++;
+            }
+
+            // Widths
+            index = 0;
+            for (var value of this._columnDefinitions) {
+                if (value.isPixel) {
+                    let width = value.getValue(this._host);
+                    availableWidth -= width;
+                    widths[index] = width;
+                } else {
+                    globalWidthPercentage += value.internalValue;
+                }
+                index++;
+            }
+
+            let left = 0;
+            index = 0;
+            for (var value of this._columnDefinitions) {
+                lefts.push(left);
+                if (!value.isPixel) {
+                    let width = (value.internalValue / globalWidthPercentage) * availableWidth;
+                    left += width;
+                    widths[index] = width;
+                }  else {
+                    left += value.getValue(this._host);
+                }
+                index++;
+            }       
+            
+            // Setting child sizes
+            for (var key in this._cells) {
+                if (!this._cells.hasOwnProperty(key)) {
+                    continue;
+                }
+                let split = key.split(":");
+                let x = parseInt(split[0]);
+                let y = parseInt(split[1]);
+                let cell = this._cells[key];
+
+                cell.left = lefts[y] + "px";
+                cell.top = tops[x] + "px";
+                cell.width = widths[y] + "px";
+                cell.height = heights[x] + "px";
+            }
+
+            super._additionalProcessing(parentMeasure, context);
+        }
+
+        /** Releases associated resources */
+        public dispose() {
+            super.dispose();
+
+            for (var control of this._childControls) {
+                control.dispose();
+            }
+        }
+    }
+}

+ 1 - 1
gui/src/3D/controls/control3D.ts

@@ -179,7 +179,7 @@ module BABYLON.GUI {
 
             let mesh = this.mesh;
             if (mesh) {
-                mesh.isVisible = value;
+                mesh.setEnabled(value);
             }
         }
 

+ 29 - 8
inspector/sass/tabs/_toolsTab.scss

@@ -17,15 +17,13 @@
     }
 
     .tool-label {
-        display         : inline-block;
-        width           : 75%;
-        padding         : 2px;
         background-color: $background-lighter;
-        border-bottom   : 1px solid $background;
-        border-top      : 1px solid $background;
-        height          : 30px;
-        line-height     : 30px;
-        box-sizing      : border-box;
+        border          : none;
+        outline         : none;
+        font-family     : $font;
+        color           : darken($color, 10%);
+        padding         : 5px;
+        margin          : 0px 6px 0px 0;
     }
 
     .tool-label-line {
@@ -56,4 +54,27 @@
         width           : 100%;
         padding         : 4px;
     }
+
+    .tool-input {
+        background-color: $background-lighter;
+        border          : none;
+        outline         : none;
+        font-family     : $font;
+        color           : $color;
+        padding         : 5px 10px;
+        margin          : 0px 6px 0px 0;
+        width           : 100%;
+        border-top      : 1px solid $background;
+        border-bottom   : 1px solid $background;
+        text-align: left;
+
+        &:hover {
+            background-color:$background-lighter2;
+            cursor: pointer;
+        }
+
+        &:active {
+            background-color:$background-lighter3;
+        }
+    }
 }

+ 1 - 0
inspector/src/Inspector.ts

@@ -372,6 +372,7 @@ module INSPECTOR {
             // Create popup
             let popup = window.open('', 'Babylon.js INSPECTOR', 'toolbar=no,resizable=yes,menubar=no,width=750,height=1000');
             if (!popup) {
+                alert("Please update your browser to open the Babylon.js inspector in an external view.");
                 return;
             }
             popup.document.title = "Babylon.js INSPECTOR";

+ 41 - 43
inspector/src/tabs/ToolsTab.ts

@@ -24,18 +24,18 @@ module INSPECTOR {
 
             // Environment block
             title = Helpers.CreateDiv('tool-title2', this._panel);
-            title.textContent = "Environment";
+            title.textContent = "Environment Texture (.dds, .env)";
             {
-                let elemLabel = this._createToolLabel("Load Environment Texture (.dds, .env) ", this._panel);
-                elemLabel.className = "tool-label-line";
-
                 let errorElemm = Inspector.DOCUMENT.createElement('div');
                 errorElemm.className = "tool-label-error";
                 errorElemm.style.display = "none";
 
+                let elemValue = Helpers.CreateDiv(null, this._panel);
+
                 let inputElement = Inspector.DOCUMENT.createElement('input');
-                inputElement.className = "tool-label-line";
+                inputElement.className = "tool-input";
                 inputElement.type = "file";
+                inputElement.accept =".dds, .env";
                 inputElement.onchange = (event: any) => {
                     var files: File[] = event.target.files;
                     let file: BABYLON.Nullable<File> = null;
@@ -81,37 +81,40 @@ module INSPECTOR {
                         }
                     }, undefined, true);
                 };
-                this._panel.appendChild(inputElement);
+                elemValue.appendChild(inputElement);
 
-                this._createToolLabel("Compress to .env", this._panel);
-                let elemValue = Helpers.CreateDiv('tool-value', this._panel);
-                inputElement = Inspector.DOCUMENT.createElement('input');
-                inputElement.value = "Save";
-                inputElement.type = "button";
-                inputElement.onclick = () => {
-                    if (!this._scene.environmentTexture) {
-                        errorElemm.style.display = "block";
-                        errorElemm.textContent = "You must load an environment texture first.";
-                        return;
-                    }
-                    if (this._scene.activeCamera) {
-                        BABYLON.EnvironmentTextureTools.CreateEnvTextureAsync(<BABYLON.CubeTexture>this._scene.environmentTexture)
-                        .then((buffer: ArrayBuffer) => {
-                            var blob = new Blob([buffer], {type: "octet/stream"});
-                            BABYLON.Tools.Download(blob, "environment.env");
-                            errorElemm.style.display = "none";
-                        })
-                        .catch((error: any) => {
+                if (!this._scene.getEngine().premultipliedAlpha) {
+                    elemValue = Helpers.CreateDiv(null, this._panel);
+
+                    inputElement = Inspector.DOCUMENT.createElement('input');
+                    inputElement.value = "Compress current texture to .env";
+                    inputElement.className = "tool-input";
+                    inputElement.type = "button";
+                    inputElement.onclick = () => {
+                        if (!this._scene.environmentTexture) {
                             errorElemm.style.display = "block";
-                            errorElemm.textContent = error;
-                        });
-                    }
-                    else {
-                        errorElemm.style.display = "block";
-                        errorElemm.textContent = "An active camera is required.";
-                    }
-                };
-                elemValue.appendChild(inputElement);
+                            errorElemm.textContent = "You must load an environment texture first.";
+                            return;
+                        }
+                        if (this._scene.activeCamera) {
+                            BABYLON.EnvironmentTextureTools.CreateEnvTextureAsync(<BABYLON.CubeTexture>this._scene.environmentTexture)
+                            .then((buffer: ArrayBuffer) => {
+                                var blob = new Blob([buffer], {type: "octet/stream"});
+                                BABYLON.Tools.Download(blob, "environment.env");
+                                errorElemm.style.display = "none";
+                            })
+                            .catch((error: any) => {
+                                errorElemm.style.display = "block";
+                                errorElemm.textContent = error;
+                            });
+                        }
+                        else {
+                            errorElemm.style.display = "block";
+                            errorElemm.textContent = "An active camera is required.";
+                        }
+                    };
+                    elemValue.appendChild(inputElement);
+                }
                 
                 this._panel.appendChild(errorElemm);
             }
@@ -119,11 +122,12 @@ module INSPECTOR {
             title = Helpers.CreateDiv('tool-title2', this._panel);
             title.textContent = "Capture";
             {
-                this._createToolLabel("Screenshot", this._panel);
-                let elemValue = Helpers.CreateDiv('tool-value', this._panel);
+                let elemValue = Helpers.CreateDiv(null, this._panel);
+
                 let inputElement = Inspector.DOCUMENT.createElement('input');
-                inputElement.value = "Capture";
+                inputElement.value = "Take Screenshot";
                 inputElement.type = "button";
+                inputElement.className = "tool-input";
                 inputElement.onclick = () => {
                     if (this._scene.activeCamera) {
                         BABYLON.Tools.CreateScreenshot(this._scene.getEngine(), this._scene.activeCamera, {precision: 0.5});
@@ -133,12 +137,6 @@ module INSPECTOR {
             }
         }
 
-        private _createToolLabel(content: string, parent: HTMLElement): HTMLElement {
-            let elem = Helpers.CreateDiv('tool-label', parent);
-            elem.textContent = content;
-            return elem;
-        }
-
         public dispose() {
             // Nothing to dispose
         }

+ 1 - 1
package.json

@@ -9,7 +9,7 @@
     ],
     "name": "babylonjs",
     "description": "Babylon.js is a JavaScript 3D engine based on webgl.",
-    "version": "3.3.0-alpha.4",
+    "version": "3.3.0-alpha.6",
     "repository": {
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"

+ 1 - 1
src/Engine/babylon.engine.ts

@@ -710,7 +710,7 @@
          * Returns the current version of the framework
          */
         public static get Version(): string {
-            return "3.3.0-alpha.4";
+            return "3.3.0-alpha.6";
         }
 
         // Updatable statics so stick with vars here

+ 1 - 1
src/Helpers/babylon.environmentHelper.ts

@@ -186,7 +186,7 @@ module BABYLON {
         /**
          * Default environment texture URL.
          */
-        private static _environmentTextureCDNUrl = "https://assets.babylonjs.com/environments/environmentSpecular.dds";
+        private static _environmentTextureCDNUrl = "https://assets.babylonjs.com/environments/environmentSpecular.env";
 
         /**
          * Creates the default options for the helper.

+ 102 - 1
src/Helpers/babylon.particleHelper.ts

@@ -48,6 +48,22 @@ module BABYLON {
          */
         maxSize: number;
         /**
+         * Minimum scale of each particle on X axis
+         */
+        minScaleX: number;
+        /**
+         * Maximum scale of each particle on X axis
+         */
+        maxScaleX: number;       
+        /**
+         * Minimum scale of each particle on Y axis
+         */
+        minScaleY: number;
+        /**
+         * Maximum scale of each particle on Y axis
+         */
+        maxScaleY: number;           
+        /**
          * Minimum lifetime for each particle
          */
         minLifeTime: number;
@@ -170,7 +186,9 @@ module BABYLON {
          */
         public static UpdateSystem(system: ParticleSystem, data: IParticleSystemData, scene: Scene): void {
             // Texture of each particle
-            system.particleTexture = new Texture(`${ParticleHelper._baseAssetsUrl}/textures/${data.textureFile}`, scene);
+            if (data.textureFile) {
+                system.particleTexture = new Texture(`${ParticleHelper._baseAssetsUrl}/textures/${data.textureFile}`, scene);
+            }
 
             // Colors of all particles
             system.color1 = new Color4(data.color1.r, data.color1.g, data.color1.b, data.color1.a);
@@ -181,6 +199,12 @@ module BABYLON {
             system.minSize = data.minSize;
             system.maxSize = data.maxSize;
 
+            system.minScaleX = data.minScaleX;
+            system.maxScaleX = data.maxScaleX;    
+            
+            system.minScaleY = data.minScaleY;
+            system.maxScaleY = data.maxScaleY;              
+
             // Life time of each particle (random between...
             system.minLifeTime = data.minLifeTime;
             system.maxLifeTime = data.maxLifeTime;
@@ -243,6 +267,83 @@ module BABYLON {
                     break;
             }
         }
+
+        /**
+         * Static function used to export a particle system to a IParticleSystemData variable.
+         * Please note that texture file name is not exported and must be added manually
+         * @param system defines the particle system to export
+         */
+        public static ExportSystem(system: ParticleSystem): IParticleSystemData {
+            var outData: any = {};
+
+            // Colors of all particles
+            outData.color1 = { r: system.color1.r, g: system.color1.g, b: system.color1.b, a: system.color1.a };
+            outData.color2 = { r: system.color2.r, g: system.color2.g, b: system.color2.b, a: system.color2.a };
+            outData.colorDead = { r: system.colorDead.r, g: system.colorDead.g, b: system.colorDead.b, a: system.colorDead.a };
+
+            // Size of each particle (random between...
+            outData.minSize = system.minSize;
+            outData.maxSize = system.maxSize;
+
+            outData.minScaleX = system.minScaleX;
+            outData.maxScaleX = system.maxScaleX;     
+            
+            outData.minScaleY = system.minScaleY;
+            outData.maxScaleY = system.maxScaleY;             
+
+            // Life time of each particle (random between...
+            outData.minLifeTime = system.minLifeTime;
+            outData.maxLifeTime = system.maxLifeTime;
+
+            // Emission rate
+            outData.emitRate = system.emitRate;
+
+            // Blend mode : BLENDMODE_ONEONE, or BLENDMODE_STANDARD
+            outData.blendMode = system.blendMode;
+
+            // Set the gravity of all particles
+            outData.gravity = {x: system.gravity.x, y: system.gravity.y, z: system.gravity.z};
+
+            // Angular speed, in radians
+            outData.minAngularSpeed = system.minAngularSpeed;
+            outData.maxAngularSpeed = system.maxAngularSpeed;
+
+            // Speed
+            outData.minEmitPower = system.minEmitPower;
+            outData.maxEmitPower = system.maxEmitPower;
+            outData.updateSpeed = system.updateSpeed;
+
+            
+            switch (system.particleEmitterType.getClassName()) {
+                case "BoxEmitter":
+                    outData.emitterType = "box";
+                    outData.direction1 = {x: system.direction1.x, y: system.direction1.y, z: system.direction1.z };
+                    outData.direction2 = {x: system.direction2.x, y: system.direction2.y, z: system.direction2.z };
+                    outData.minEmitBox = {x: system.minEmitBox.x, y: system.minEmitBox.y, z: system.minEmitBox.z };
+                    outData.maxEmitBox = {x: system.maxEmitBox.x, y: system.maxEmitBox.y, z: system.maxEmitBox.z };
+                    break;
+                case "SphereParticleEmitter":
+                    outData.emitterType = "sphere";
+                    outData.radius = (system.particleEmitterType as SphereParticleEmitter).radius;
+                    break;
+                case "SphereDirectedParticleEmitter":
+                    outData.emitterType = "directed_sphere";
+                    var sphereDirectedParticleEmitter = system.particleEmitterType as SphereDirectedParticleEmitter;
+                    outData.radius = sphereDirectedParticleEmitter.radius;
+                    outData.direction1 = {x: sphereDirectedParticleEmitter.direction1.x, y: sphereDirectedParticleEmitter.direction1.y, z: sphereDirectedParticleEmitter.direction1.z };
+                    outData.direction2 = {x: sphereDirectedParticleEmitter.direction2.x, y: sphereDirectedParticleEmitter.direction2.y, z: sphereDirectedParticleEmitter.direction2.z };                
+                    break;
+                case "ConeEmitter":
+                    outData.emitterType = "cone";
+                    outData.radius = (system.particleEmitterType as ConeParticleEmitter).radius;
+                    outData.angle = (system.particleEmitterType as ConeParticleEmitter).angle;
+                    break;
+                default:
+                    break;
+            }
+
+            return outData;
+        }
     }
 
 }

+ 7 - 0
src/Helpers/babylon.photoDome.ts

@@ -13,6 +13,13 @@ module BABYLON {
         protected _photoTexture: Texture;
 
         /**
+         * Gets the texture being displayed on the sphere
+         */
+        public get photoTexture(): Texture {
+            return this._photoTexture;
+        }        
+
+        /**
          * The skybox material
          */
         protected _material: BackgroundMaterial;

+ 7 - 0
src/Helpers/babylon.videoDome.ts

@@ -13,6 +13,13 @@ module BABYLON {
         protected _videoTexture: VideoTexture;
 
         /**
+         * Gets the video texture being displayed on the sphere
+         */
+        public get videoTexture(): VideoTexture {
+            return this._videoTexture;
+        }
+
+        /**
          * The skybox material
          */
         protected _material: BackgroundMaterial;

+ 4 - 0
src/Materials/Textures/babylon.hdrCubeTexture.ts

@@ -137,6 +137,10 @@ module BABYLON {
          */
         private loadTexture() {
             var callback = (buffer: ArrayBuffer): Nullable<ArrayBufferView[]> => {
+
+                this.lodGenerationOffset = 0.0;
+                this.lodGenerationScale = 0.8;
+
                 let scene = this.getScene();
 
                 if (!scene) {

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

@@ -2621,7 +2621,11 @@
                             instance.animations.push(Animation.Parse(parsedAnimation));
                         }
                         Node.ParseAnimationRanges(instance, parsedMesh, scene);
-                    }
+
+                        if (parsedMesh.autoAnimate) {
+                            scene.beginAnimation(instance, parsedMesh.autoAnimateFrom, parsedMesh.autoAnimateTo, parsedMesh.autoAnimateLoop, parsedMesh.autoAnimateSpeed || 1.0);
+                        }                            
+                }
                 }
             }
 

+ 12 - 0
src/Mesh/babylon.transformNode.ts

@@ -25,6 +25,18 @@ module BABYLON {
         protected _isDirty = false;
         private _transformToBoneReferal: Nullable<TransformNode>;
 
+        /**
+        * Set the billboard mode. Default is 0.
+        *
+        * | Value | Type | Description |
+        * | --- | --- | --- |
+        * | 0 | BILLBOARDMODE_NONE |  |
+        * | 1 | BILLBOARDMODE_X |  |
+        * | 2 | BILLBOARDMODE_Y |  |
+        * | 4 | BILLBOARDMODE_Z |  |
+        * | 7 | BILLBOARDMODE_ALL |  |
+        *
+        */
         @serialize()
         public billboardMode = TransformNode.BILLBOARDMODE_NONE;
 

+ 1 - 1
src/Particles/EmitterTypes/babylon.IParticleEmitterType.ts

@@ -51,7 +51,7 @@ module BABYLON {
          */        
         serialize(): any;
 
- /**
+        /**
          * Parse properties from a JSON object
          * @param serializationObject defines the JSON object
          */

+ 30 - 21
src/Particles/EmitterTypes/babylon.coneParticleEmitter.ts

@@ -6,22 +6,36 @@ module BABYLON {
      */
     export class ConeParticleEmitter implements IParticleEmitterType {
         private _radius: number;
+        private _angle: number;
         private _height: number;
 
         /**
-         * Gets the radius of the emission cone.
+         * Gets or sets the radius of the emission cone
          */
         public get radius(): number {
             return this._radius;
         }
 
-        /**
-         * Sets the radius of the emission cone.
-         */
         public set radius(value: number) {
             this._radius = value;
-            if (this.angle !== 0) {
-                this._height = value / Math.tan(this.angle / 2);
+            this._buildHeight();
+        }
+
+        /**
+         * Gets or sets the angle of the emission cone
+         */
+        public get angle(): number {
+            return this._angle;
+        }
+
+        public set angle(value: number) {
+            this._angle = value;
+            this._buildHeight();
+        }        
+
+        private _buildHeight() {
+            if (this._angle !== 0) {
+                this._height =  this._radius / Math.tan(this._angle / 2);
             }
             else {
                 this._height = 1;
@@ -32,17 +46,12 @@ module BABYLON {
          * Creates a new instance ConeParticleEmitter
          * @param radius the radius of the emission cone (1 by default)
          * @param angles the cone base angle (PI by default)
-         * @param directionRandomizer defines how much to randomize the particle direction [0-1]
+         * @param directionRandomizer defines how much to randomize the particle direction [0-1] (default is 0)
          */
-        constructor(radius = 1, 
-            /**
-             * The radius of the emission cone.
-             */
-            public angle = Math.PI, 
-            /**
-             * The cone base angle.
-             */
+        constructor(radius = 1, angle = Math.PI, 
+            /** defines how much to randomize the particle direction [0-1] (default is 0) */
             public directionRandomizer = 0) {
+            this.angle = angle;
             this.radius = radius;
         }
 
@@ -54,7 +63,7 @@ module BABYLON {
          * @param particle is the particle we are computed the direction for
          */
         public startDirectionFunction(emitPower: number, worldMatrix: Matrix, directionToUpdate: Vector3, particle: Particle): void {
-            if (this.angle === 0) {
+            if (this._angle === 0) {
                 Vector3.TransformNormalFromFloatsToRef(0, emitPower, 0, worldMatrix, directionToUpdate);
             }
             else {
@@ -98,7 +107,7 @@ module BABYLON {
          * @returns the new emitter
          */
         public clone(): ConeParticleEmitter {
-            let newOne = new ConeParticleEmitter(this.radius, this.angle, this.directionRandomizer);
+            let newOne = new ConeParticleEmitter(this._radius, this._angle, this.directionRandomizer);
 
             Tools.DeepCopy(this, newOne);
 
@@ -110,8 +119,8 @@ module BABYLON {
          * @param effect defines the update shader
          */        
         public applyToShader(effect: Effect): void {
-            effect.setFloat("radius", this.radius);
-            effect.setFloat("coneAngle", this.angle);
+            effect.setFloat("radius", this._radius);
+            effect.setFloat("coneAngle", this._angle);
             effect.setFloat("height", this._height);
             effect.setFloat("directionRandomizer", this.directionRandomizer);
         }
@@ -140,8 +149,8 @@ module BABYLON {
             var serializationObject: any = {};
 
             serializationObject.type = this.getClassName();
-            serializationObject.radius  = this.radius;
-            serializationObject.angle  = this.angle;
+            serializationObject.radius  = this._radius;
+            serializationObject.angle  = this._angle;
             serializationObject.directionRandomizer  = this.directionRandomizer;
 
             return serializationObject;

+ 19 - 1
src/Particles/babylon.IParticleSystem.ts

@@ -62,7 +62,25 @@ module BABYLON {
         /**
          * Maximum Size of emitting particles.
          */
-        maxSize: number;        
+        maxSize: number;     
+        
+        /**
+         * Minimum scale of emitting particles on X axis.
+         */
+        minScaleX: number;
+        /**
+         * Maximum scale of emitting particles on X axis.
+         */
+        maxScaleX: number;        
+
+        /**
+         * Minimum scale of emitting particles on Y axis.
+         */
+        minScaleY: number;
+        /**
+         * Maximum scale of emitting particles on Y axis.
+         */
+        maxScaleY: number;             
         
         /**
          * Random color of each particle after it has been emitted, between color1 and color2 vectors.

+ 31 - 10
src/Particles/babylon.gpuParticleSystem.ts

@@ -57,7 +57,7 @@
 
         private _randomTexture: RawTexture;
 
-        private readonly _attributesStrideSize = 16;
+        private readonly _attributesStrideSize = 18;
         private _updateEffectOptions: EffectCreationOptions;
 
         private _randomTextureSize: number;
@@ -119,7 +119,25 @@
         /**
          * Maximum Size of emitting particles.
          */
-        public maxSize = 1;        
+        public maxSize = 1;  
+        
+        /**
+         * Minimum scale of emitting particles on X axis.
+         */
+        public minScaleX = 1;
+        /**
+         * Maximum scale of emitting particles on X axis.
+         */
+        public maxScaleX = 1;        
+
+        /**
+         * Minimum scale of emitting particles on Y axis.
+         */
+        public minScaleY = 1;
+        /**
+         * Maximum scale of emitting particles on Y axis.
+         */
+        public maxScaleY = 1;           
         
         /**
          * Random color of each particle after it has been emitted, between color1 and color2 vectors.
@@ -356,7 +374,7 @@
 
             this._updateEffectOptions = {
                 attributes: ["position", "age", "life", "seed", "size", "color", "direction", "angle"],
-                uniformsNames: ["currentCount", "timeDelta", "generalRandoms", "emitterWM", "lifeTime", "color1", "color2", "sizeRange", "gravity", "emitPower",
+                uniformsNames: ["currentCount", "timeDelta", "generalRandoms", "emitterWM", "lifeTime", "color1", "color2", "sizeRange", "scaleRange","gravity", "emitPower",
                                 "direction1", "direction2", "minEmitBox", "maxEmitBox", "radius", "directionRandomizer", "height", "coneAngle", "stopFactor", 
                                 "angleRange"],
                 uniformBuffersNames: [],
@@ -393,10 +411,10 @@
             updateVertexBuffers["age"] = source.createVertexBuffer("age", 3, 1);
             updateVertexBuffers["life"] = source.createVertexBuffer("life", 4, 1);
             updateVertexBuffers["seed"] = source.createVertexBuffer("seed", 5, 1);
-            updateVertexBuffers["size"] = source.createVertexBuffer("size", 6, 1);
-            updateVertexBuffers["color"] = source.createVertexBuffer("color", 7, 4);
-            updateVertexBuffers["direction"] = source.createVertexBuffer("direction", 11, 3);
-            updateVertexBuffers["angle"] = source.createVertexBuffer("angle", 14, 2);
+            updateVertexBuffers["size"] = source.createVertexBuffer("size", 6, 3);
+            updateVertexBuffers["color"] = source.createVertexBuffer("color", 9, 4);
+            updateVertexBuffers["direction"] = source.createVertexBuffer("direction", 13, 3);
+            updateVertexBuffers["angle"] = source.createVertexBuffer("angle", 16, 2);
            
             let vao = this._engine.recordVertexArrayObject(updateVertexBuffers, null, this._updateEffect);
             this._engine.bindArrayBuffer(null);
@@ -409,9 +427,9 @@
             renderVertexBuffers["position"] = source.createVertexBuffer("position", 0, 3, this._attributesStrideSize, true);
             renderVertexBuffers["age"] = source.createVertexBuffer("age", 3, 1, this._attributesStrideSize, true);
             renderVertexBuffers["life"] = source.createVertexBuffer("life", 4, 1, this._attributesStrideSize, true);
-            renderVertexBuffers["size"] = source.createVertexBuffer("size", 6, 1, this._attributesStrideSize, true);           
-            renderVertexBuffers["color"] = source.createVertexBuffer("color", 7, 4, this._attributesStrideSize, true);
-            renderVertexBuffers["angle"] = source.createVertexBuffer("angle", 14, 2, this._attributesStrideSize, true);
+            renderVertexBuffers["size"] = source.createVertexBuffer("size", 6, 3, this._attributesStrideSize, true);           
+            renderVertexBuffers["color"] = source.createVertexBuffer("color", 9, 4, this._attributesStrideSize, true);
+            renderVertexBuffers["angle"] = source.createVertexBuffer("angle", 16, 2, this._attributesStrideSize, true);
 
             renderVertexBuffers["offset"] = spriteSource.createVertexBuffer("offset", 0, 2);
             renderVertexBuffers["uv"] = spriteSource.createVertexBuffer("uv", 2, 2);
@@ -444,6 +462,8 @@
 
               // Size
               data.push(0.0);
+              data.push(0.0);
+              data.push(0.0);
 
               // color
               data.push(0.0);
@@ -571,6 +591,7 @@
             this._updateEffect.setDirectColor4("color1", this.color1);
             this._updateEffect.setDirectColor4("color2", this.color2);
             this._updateEffect.setFloat2("sizeRange", this.minSize, this.maxSize);
+            this._updateEffect.setFloat4("scaleRange", this.minScaleX, this.maxScaleX, this.minScaleY, this.maxScaleY);
             this._updateEffect.setFloat2("angleRange", this.minAngularSpeed, this.maxAngularSpeed);
             this._updateEffect.setVector3("gravity", this.gravity);
 

+ 6 - 0
src/Particles/babylon.particle.ts

@@ -41,6 +41,11 @@
         public size = 0;
 
         /**
+         * The current scale of the particle.
+         */
+        public scale = new Vector2(1, 1);        
+
+        /**
          * The current angle of the particle.
          */
         public angle = 0;
@@ -134,6 +139,7 @@
             other.lifeTime = this.lifeTime;
             other.age = this.age;
             other.size = this.size;
+            other.scale.copyFrom(this.scale);
             other.angle = this.angle;
             other.angularSpeed = this.angularSpeed;
             other.particleSystem = this.particleSystem;

+ 49 - 14
src/Particles/babylon.particleSystem.ts

@@ -93,6 +93,24 @@
         public maxSize = 1;
 
         /**
+         * Minimum scale of emitting particles on X axis.
+         */
+        public minScaleX = 1;
+        /**
+         * Maximum scale of emitting particles on X axis.
+         */
+        public maxScaleX = 1;        
+
+        /**
+         * Minimum scale of emitting particles on Y axis.
+         */
+        public minScaleY = 1;
+        /**
+         * Maximum scale of emitting particles on Y axis.
+         */
+        public maxScaleY = 1;           
+
+        /**
          * Minimum angular speed of emitting particles (Z-axis rotation for each particle).
          */
         public minAngularSpeed = 0;
@@ -330,7 +348,7 @@
         private _stopped = false;
         private _actualFrame = 0;
         private _scaledUpdateSpeed: number;
-        private _vertexBufferSize = 11;
+        private _vertexBufferSize = 12;
         private _isAnimationSheetEnabled: boolean;
 
         // end of sheet animation
@@ -382,7 +400,7 @@
             this._epsilon = epsilon;
             this._isAnimationSheetEnabled = isAnimationSheetEnabled;
             if (isAnimationSheetEnabled) {
-                this._vertexBufferSize = 12;
+                this._vertexBufferSize = 13;
             }
 
             this._scene = scene || Engine.LastCreatedScene;
@@ -393,22 +411,24 @@
 
             this._createIndexBuffer();
 
-            // 11 floats per particle (x, y, z, r, g, b, a, angle, size, offsetX, offsetY) + 1 filler
+            // 13 floats per particle (x, y, z, r, g, b, a, angle, scaleX, scaleY, offsetX, offsetY) + 1 filler
             this._vertexData = new Float32Array(capacity * this._vertexBufferSize * 4);
             this._vertexBuffer = new Buffer(scene.getEngine(), this._vertexData, true, this._vertexBufferSize);
 
             var positions = this._vertexBuffer.createVertexBuffer(VertexBuffer.PositionKind, 0, 3);
             var colors = this._vertexBuffer.createVertexBuffer(VertexBuffer.ColorKind, 3, 4);
-            var options = this._vertexBuffer.createVertexBuffer("options", 7, 4);
+            var options = this._vertexBuffer.createVertexBuffer("options", 7, 3);
+            var size = this._vertexBuffer.createVertexBuffer("size", 10, 2);
 
             if (this._isAnimationSheetEnabled) {
-                var cellIndexBuffer = this._vertexBuffer.createVertexBuffer("cellIndex", 11, 1);
+                var cellIndexBuffer = this._vertexBuffer.createVertexBuffer("cellIndex", 12, 1);
                 this._vertexBuffers["cellIndex"] = cellIndexBuffer;
             }
 
             this._vertexBuffers[VertexBuffer.PositionKind] = positions;
             this._vertexBuffers[VertexBuffer.ColorKind] = colors;
             this._vertexBuffers["options"] = options;
+            this._vertexBuffers["size"] = size;
 
             // Default emitter type
             this.particleEmitterType = new BoxParticleEmitter();
@@ -534,9 +554,10 @@
             this._vertexData[offset + 5] = particle.color.b;
             this._vertexData[offset + 6] = particle.color.a;
             this._vertexData[offset + 7] = particle.angle;
-            this._vertexData[offset + 8] = particle.size;
-            this._vertexData[offset + 9] = offsetX;
-            this._vertexData[offset + 10] = offsetY;
+            this._vertexData[offset + 8] = offsetX;
+            this._vertexData[offset + 9] = offsetY;   
+            this._vertexData[offset + 10] = particle.scale.x * particle.size;
+            this._vertexData[offset + 11] = particle.scale.y * particle.size;      
         }
 
         /**
@@ -562,10 +583,11 @@
             this._vertexData[offset + 5] = particle.color.b;
             this._vertexData[offset + 6] = particle.color.a;
             this._vertexData[offset + 7] = particle.angle;
-            this._vertexData[offset + 8] = particle.size;
-            this._vertexData[offset + 9] = offsetX;
-            this._vertexData[offset + 10] = offsetY;
-            this._vertexData[offset + 11] = particle.cellIndex;
+            this._vertexData[offset + 8] = offsetX;
+            this._vertexData[offset + 9] = offsetY;   
+            this._vertexData[offset + 10] = particle.scale.x * particle.size;
+            this._vertexData[offset + 11] = particle.scale.y * particle.size;
+            this._vertexData[offset + 12] = particle.cellIndex;
         }
 
         // start of sub system methods
@@ -677,6 +699,7 @@
                 particle.lifeTime = Scalar.RandomRange(this.minLifeTime, this.maxLifeTime);
 
                 particle.size = Scalar.RandomRange(this.minSize, this.maxSize);
+                particle.scale.copyFromFloats(Scalar.RandomRange(this.minScaleX, this.maxScaleX), Scalar.RandomRange(this.minScaleY, this.maxScaleY));
                 particle.angularSpeed = Scalar.RandomRange(this.minAngularSpeed, this.maxAngularSpeed);
 
                 var step = Scalar.RandomRange(0, 1.0);
@@ -712,11 +735,11 @@
                 var effectCreationOption: any;
 
                 if (this._isAnimationSheetEnabled) {
-                    attributesNamesOrOptions = [VertexBuffer.PositionKind, VertexBuffer.ColorKind, "options", "cellIndex"];
+                    attributesNamesOrOptions = [VertexBuffer.PositionKind, VertexBuffer.ColorKind, "options", "size", "cellIndex"];
                     effectCreationOption = ["invView", "view", "projection", "particlesInfos", "vClipPlane", "textureMask"];
                 }
                 else {
-                    attributesNamesOrOptions = [VertexBuffer.PositionKind, VertexBuffer.ColorKind, "options"];
+                    attributesNamesOrOptions = [VertexBuffer.PositionKind, VertexBuffer.ColorKind, "options", "size", ];
                     effectCreationOption = ["invView", "view", "projection", "vClipPlane", "textureMask"]
                 }
 
@@ -1074,6 +1097,10 @@
             serializationObject.maxAngularSpeed = this.maxAngularSpeed;
             serializationObject.minSize = this.minSize;
             serializationObject.maxSize = this.maxSize;
+            serializationObject.minScaleX = this.minScaleX;
+            serializationObject.maxScaleX = this.maxScaleX;
+            serializationObject.minScaleY = this.minScaleY;
+            serializationObject.maxScaleY = this.maxScaleY;            
             serializationObject.minEmitPower = this.minEmitPower;
             serializationObject.maxEmitPower = this.maxEmitPower;
             serializationObject.minLifeTime = this.minLifeTime;
@@ -1169,6 +1196,14 @@
             particleSystem.maxAngularSpeed = parsedParticleSystem.maxAngularSpeed;
             particleSystem.minSize = parsedParticleSystem.minSize;
             particleSystem.maxSize = parsedParticleSystem.maxSize;
+
+            if (parsedParticleSystem.minScaleX) {
+                particleSystem.minScaleX = parsedParticleSystem.minScaleX;
+                particleSystem.maxScaleX = parsedParticleSystem.maxScaleX;                
+                particleSystem.minScaleY = parsedParticleSystem.minScaleY;
+                particleSystem.maxScaleY = parsedParticleSystem.maxScaleY;                
+            }
+
             particleSystem.minLifeTime = parsedParticleSystem.minLifeTime;
             particleSystem.maxLifeTime = parsedParticleSystem.maxLifeTime;
             particleSystem.minEmitPower = parsedParticleSystem.minEmitPower;

+ 1 - 1
src/Particles/babylon.solidParticleSystem.ts

@@ -159,7 +159,7 @@
                 this._particlesIntersect = options ? <boolean>options.particleIntersection : false;
                 this._bSphereOnly= options ? <boolean>options.boundingSphereOnly : false;
                 this._bSphereRadiusFactor = (options && options.bSphereRadiusFactor) ? options.bSphereRadiusFactor : 1.0;
-                if (options && options.updatable) {
+                if (options && options.updatable !== undefined) {
                     this._updatable = options.updatable;
                 } else {
                     this._updatable = true;

+ 2 - 2
src/Physics/Plugins/babylon.oimoJSPlugin.ts

@@ -351,11 +351,11 @@ module BABYLON {
         }*/
 
         public setLinearVelocity(impostor: PhysicsImpostor, velocity: Vector3) {
-            impostor.physicsBody.linearVelocity.init(velocity.x, velocity.y, velocity.z);
+            impostor.physicsBody.linearVelocity.copy(velocity);
         }
 
         public setAngularVelocity(impostor: PhysicsImpostor, velocity: Vector3) {
-            impostor.physicsBody.angularVelocity.init(velocity.x, velocity.y, velocity.z);
+            impostor.physicsBody.angularVelocity.copy(velocity);
         }
 
         public getLinearVelocity(impostor: PhysicsImpostor): Nullable<Vector3> {

+ 2 - 2
src/Shaders/gpuRenderParticles.vertex.fx

@@ -8,7 +8,7 @@ uniform mat4 projection;
 in vec3 position;
 in float age;
 in float life;
-in float size;
+in vec3 size;
 in vec4 color;
 in vec2 offset;
 in vec2 uv;
@@ -29,7 +29,7 @@ void main() {
   float ratio = age / life;
   vColor = color * vec4(1.0 - ratio) + colorDead * vec4(ratio);
 
-  vec2 cornerPos = offset * size;
+  vec2 cornerPos = offset * size.yz * size.x;
 
   // Rotate
 	vec4 rotatedCorner;

+ 7 - 4
src/Shaders/gpuUpdateParticles.vertex.fx

@@ -10,6 +10,7 @@ uniform mat4 emitterWM;
 uniform vec2 lifeTime;
 uniform vec2 emitPower;
 uniform vec2 sizeRange;
+uniform vec4 scaleRange;
 uniform vec4 color1;
 uniform vec4 color2;
 uniform vec3 gravity;
@@ -45,7 +46,7 @@ in vec3 position;
 in float age;
 in float life;
 in float seed;
-in float size;
+in vec3 size;
 in vec4 color;
 in vec3 direction;
 in vec2 angle;
@@ -55,7 +56,7 @@ out vec3 outPosition;
 out float outAge;
 out float outLife;
 out float outSeed;
-out float outSize;
+out vec3 outSize;
 out vec4 outColor;
 out vec3 outDirection;
 out vec2 outAngle;
@@ -77,7 +78,7 @@ void main() {
       outLife = life;
       outSeed = seed;
       outColor = vec4(0.,0.,0.,0.);
-      outSize = 0.;
+      outSize = vec3(0., 0., 0.);
       outDirection = direction;
       outAngle = angle;
       return;
@@ -96,7 +97,9 @@ void main() {
     outSeed = seed;
 
     // Size
-    outSize = sizeRange.x + (sizeRange.y - sizeRange.x) * randoms.g;
+    outSize.x = sizeRange.x + (sizeRange.y - sizeRange.x) * randoms.g;
+    outSize.y = scaleRange.x + (scaleRange.y - scaleRange.x) * randoms.b;
+    outSize.z = scaleRange.z + (scaleRange.w - scaleRange.z) * randoms.a;
 
     // Color
     outColor = color1 + (color2 - color1) * randoms.b;

+ 3 - 3
src/Shaders/particles.vertex.fx

@@ -1,7 +1,8 @@
 // Attributes
 attribute vec3 position;
 attribute vec4 color;
-attribute vec4 options;
+attribute vec3 options;
+attribute vec2 size;
 attribute float cellIndex;
 
 // Uniforms
@@ -22,9 +23,8 @@ varying float fClipDistance;
 void main(void) {	
 	vec3 viewPos = (view * vec4(position, 1.0)).xyz; 
 	vec2 cornerPos;
-	float size = options.y;
 	float angle = options.x;
-	vec2 offset = options.zw;
+	vec2 offset = options.yz;
 	
 	cornerPos = vec2(offset.x - 0.5, offset.y  - 0.5) * size;
 

+ 1 - 1
src/Tools/babylon.environmentTextureTools.ts

@@ -146,7 +146,7 @@ module BABYLON {
 
             let engine = internalTexture.getEngine();
             if (engine && engine.premultipliedAlpha) {
-                return Promise.reject("Env texture can only be created when the engine is created with the premultipliedAlpha option.");
+                return Promise.reject("Env texture can only be created when the engine is created with the premultipliedAlpha option set to false.");
             }
 
             let canvas = engine.getRenderingCanvas();