Browse Source

Merge branch 'master' of https://github.com/BabylonJS/Babylon.js into inspectorGizmos

Trevor Baron 6 years ago
parent
commit
14f0ca980e
48 changed files with 13684 additions and 13454 deletions
  1. 11971 11964
      Playground/babylon.d.txt
  2. 1326 1325
      dist/preview release/babylon.d.ts
  3. 1 1
      dist/preview release/babylon.js
  4. 26 8
      dist/preview release/babylon.max.js
  5. 26 8
      dist/preview release/babylon.no-module.max.js
  6. 1 1
      dist/preview release/babylon.worker.js
  7. 26 8
      dist/preview release/es6.js
  8. 1 1
      dist/preview release/glTF2Interface/package.json
  9. 2 2
      dist/preview release/gui/package.json
  10. 7 7
      dist/preview release/inspector/babylon.inspector.bundle.js
  11. 1 1
      dist/preview release/inspector/babylon.inspector.bundle.js.map
  12. 5 5
      dist/preview release/inspector/package.json
  13. 14 7
      dist/preview release/loaders/babylon.glTF2FileLoader.js
  14. 1 1
      dist/preview release/loaders/babylon.glTF2FileLoader.min.js
  15. 14 7
      dist/preview release/loaders/babylon.glTFFileLoader.js
  16. 1 1
      dist/preview release/loaders/babylon.glTFFileLoader.min.js
  17. 14 7
      dist/preview release/loaders/babylonjs.loaders.js
  18. 1 1
      dist/preview release/loaders/babylonjs.loaders.min.js
  19. 3 3
      dist/preview release/loaders/package.json
  20. 2 2
      dist/preview release/materialsLibrary/package.json
  21. 2 2
      dist/preview release/postProcessesLibrary/package.json
  22. 2 2
      dist/preview release/proceduralTexturesLibrary/package.json
  23. 3 3
      dist/preview release/serializers/package.json
  24. 1 1
      dist/preview release/viewer/babylon.viewer.js
  25. 2 2
      dist/preview release/viewer/babylon.viewer.max.js
  26. 1 0
      dist/preview release/what's new.md
  27. 1 1
      inspector/package.json
  28. 21 0
      inspector/src/components/actionTabs/actionTabs.scss
  29. 1 4
      inspector/src/components/actionTabs/lines/floatLineComponent.tsx
  30. 16 0
      inspector/src/components/actionTabs/lines/messageLineComponent.tsx
  31. 2 1
      inspector/src/components/actionTabs/tabs/propertyGrids/materials/commonMaterialPropertyGridComponent.tsx
  32. 38 8
      inspector/src/components/actionTabs/tabs/propertyGrids/materials/standardMaterialPropertyGridComponent.tsx
  33. 10 10
      inspector/src/components/actionTabs/tabs/propertyGrids/materials/texturePropertyGridComponent.tsx
  34. 3 3
      inspector/src/components/actionTabs/tabs/propertyGrids/meshes/axesViewerComponent.tsx
  35. 2 0
      inspector/src/components/actionTabs/tabs/propertyGrids/meshes/meshPropertyGridComponent.tsx
  36. 15 7
      inspector/src/components/actionTabs/tabs/tools/gltfComponent.tsx
  37. 2 2
      inspector/src/components/sceneExplorer/entities/transformNodeTreeItemComponent.tsx
  38. 37 11
      inspector/src/components/sceneExplorer/sceneExplorer.scss
  39. 39 16
      inspector/src/components/sceneExplorer/treeItemComponent.tsx
  40. 1 1
      inspector/src/components/sceneExplorer/treeItemSelectableComponent.tsx
  41. 16 9
      loaders/src/glTF/2.0/babylon.glTFLoader.ts
  42. 1 1
      package.json
  43. 1 0
      sandbox/index.css
  44. 4 1
      src/Engine/babylon.engine.ts
  45. 4 7
      src/Mesh/babylon.meshBuilder.ts
  46. 14 1
      src/Particles/babylon.baseParticleSystem.ts
  47. 1 1
      src/Particles/babylon.particleSystem.ts
  48. 1 0
      what's new.md

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


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


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


+ 26 - 8
dist/preview release/babylon.max.js

@@ -12945,7 +12945,7 @@ var BABYLON;
              * Returns the current version of the framework
              */
             get: function () {
-                return "4.0.0-alpha.7";
+                return "4.0.0-alpha.8";
             },
             enumerable: true,
             configurable: true
@@ -15789,6 +15789,7 @@ var BABYLON;
                         excludeLoaders.push(loader);
                         BABYLON.Tools.Warn(loader.constructor.name + " failed when trying to load " + texture.url + ", falling back to the next supported loader");
                         _this.createTexture(urlArg, noMipmap, invertY, scene, samplingMode, null, onError, buffer, texture, undefined, undefined, excludeLoaders);
+                        return;
                     }
                 }
                 if (!customFallback) {
@@ -15797,6 +15798,7 @@ var BABYLON;
                     }
                     if (BABYLON.Tools.UseFallbackTexture) {
                         _this.createTexture(BABYLON.Tools.fallbackTexture, noMipmap, invertY, scene, samplingMode, null, onError, buffer, texture);
+                        return;
                     }
                 }
                 if (onError) {
@@ -16953,6 +16955,7 @@ var BABYLON;
                     if (fallbackUrl) {
                         excludeLoaders.push(loader);
                         _this.createCubeTexture(fallbackUrl, scene, files, noMipmap, onLoad, onError, format, extension, createPolynomials, lodScale, lodOffset, texture, excludeLoaders);
+                        return;
                     }
                 }
                 if (onError && request) {
@@ -60818,6 +60821,23 @@ var BABYLON;
             this.id = name;
             this.name = name;
         }
+        Object.defineProperty(BaseParticleSystem.prototype, "noiseTexture", {
+            /**
+             * Gets or sets a texture used to add random noise to particle positions
+             */
+            get: function () {
+                return this._noiseTexture;
+            },
+            set: function (value) {
+                if (this._noiseTexture === value) {
+                    return;
+                }
+                this._noiseTexture = value;
+                this._reset();
+            },
+            enumerable: true,
+            configurable: true
+        });
         Object.defineProperty(BaseParticleSystem.prototype, "isAnimationSheetEnabled", {
             /**
              * Gets or sets whether an animation sprite sheet is enabled or not on the particle system
@@ -61451,7 +61471,7 @@ var BABYLON;
                     }
                     particle.position.addInPlace(_this._scaledDirection);
                     // Noise
-                    if (noiseTextureData && noiseTextureSize) {
+                    if (noiseTextureData && noiseTextureSize && particle._randomNoiseCoordinates1) {
                         var fetchedColorR = _this._fetchR(particle._randomNoiseCoordinates1.x, particle._randomNoiseCoordinates1.y, noiseTextureSize.width, noiseTextureSize.height, noiseTextureData);
                         var fetchedColorG = _this._fetchR(particle._randomNoiseCoordinates1.z, particle._randomNoiseCoordinates2.x, noiseTextureSize.width, noiseTextureSize.height, noiseTextureData);
                         var fetchedColorB = _this._fetchR(particle._randomNoiseCoordinates2.y, particle._randomNoiseCoordinates2.z, noiseTextureSize.width, noiseTextureSize.height, noiseTextureData);
@@ -70566,12 +70586,10 @@ var BABYLON;
             var vertexData = BABYLON.VertexData.CreatePlane(options);
             vertexData.applyToMesh(plane, options.updatable);
             if (options.sourcePlane) {
-                plane.translate(options.sourcePlane.normal, options.sourcePlane.d);
-                var product = Math.acos(BABYLON.Vector3.Dot(options.sourcePlane.normal, BABYLON.Axis.Z));
-                var vectorProduct = BABYLON.Vector3.Cross(BABYLON.Axis.Z, options.sourcePlane.normal);
-                if (vectorProduct.lengthSquared() > BABYLON.Epsilon) {
-                    plane.rotate(vectorProduct, product);
-                }
+                plane.translate(options.sourcePlane.normal, -options.sourcePlane.d);
+                var dot = BABYLON.Vector3.Dot(plane.position, options.sourcePlane.normal);
+                var flip = dot >= 0;
+                plane.lookAt(BABYLON.Vector3.Zero(), 0, flip ? Math.PI : 0, 0);
             }
             return plane;
         };

+ 26 - 8
dist/preview release/babylon.no-module.max.js

@@ -12912,7 +12912,7 @@ var BABYLON;
              * Returns the current version of the framework
              */
             get: function () {
-                return "4.0.0-alpha.7";
+                return "4.0.0-alpha.8";
             },
             enumerable: true,
             configurable: true
@@ -15756,6 +15756,7 @@ var BABYLON;
                         excludeLoaders.push(loader);
                         BABYLON.Tools.Warn(loader.constructor.name + " failed when trying to load " + texture.url + ", falling back to the next supported loader");
                         _this.createTexture(urlArg, noMipmap, invertY, scene, samplingMode, null, onError, buffer, texture, undefined, undefined, excludeLoaders);
+                        return;
                     }
                 }
                 if (!customFallback) {
@@ -15764,6 +15765,7 @@ var BABYLON;
                     }
                     if (BABYLON.Tools.UseFallbackTexture) {
                         _this.createTexture(BABYLON.Tools.fallbackTexture, noMipmap, invertY, scene, samplingMode, null, onError, buffer, texture);
+                        return;
                     }
                 }
                 if (onError) {
@@ -16920,6 +16922,7 @@ var BABYLON;
                     if (fallbackUrl) {
                         excludeLoaders.push(loader);
                         _this.createCubeTexture(fallbackUrl, scene, files, noMipmap, onLoad, onError, format, extension, createPolynomials, lodScale, lodOffset, texture, excludeLoaders);
+                        return;
                     }
                 }
                 if (onError && request) {
@@ -60785,6 +60788,23 @@ var BABYLON;
             this.id = name;
             this.name = name;
         }
+        Object.defineProperty(BaseParticleSystem.prototype, "noiseTexture", {
+            /**
+             * Gets or sets a texture used to add random noise to particle positions
+             */
+            get: function () {
+                return this._noiseTexture;
+            },
+            set: function (value) {
+                if (this._noiseTexture === value) {
+                    return;
+                }
+                this._noiseTexture = value;
+                this._reset();
+            },
+            enumerable: true,
+            configurable: true
+        });
         Object.defineProperty(BaseParticleSystem.prototype, "isAnimationSheetEnabled", {
             /**
              * Gets or sets whether an animation sprite sheet is enabled or not on the particle system
@@ -61418,7 +61438,7 @@ var BABYLON;
                     }
                     particle.position.addInPlace(_this._scaledDirection);
                     // Noise
-                    if (noiseTextureData && noiseTextureSize) {
+                    if (noiseTextureData && noiseTextureSize && particle._randomNoiseCoordinates1) {
                         var fetchedColorR = _this._fetchR(particle._randomNoiseCoordinates1.x, particle._randomNoiseCoordinates1.y, noiseTextureSize.width, noiseTextureSize.height, noiseTextureData);
                         var fetchedColorG = _this._fetchR(particle._randomNoiseCoordinates1.z, particle._randomNoiseCoordinates2.x, noiseTextureSize.width, noiseTextureSize.height, noiseTextureData);
                         var fetchedColorB = _this._fetchR(particle._randomNoiseCoordinates2.y, particle._randomNoiseCoordinates2.z, noiseTextureSize.width, noiseTextureSize.height, noiseTextureData);
@@ -70533,12 +70553,10 @@ var BABYLON;
             var vertexData = BABYLON.VertexData.CreatePlane(options);
             vertexData.applyToMesh(plane, options.updatable);
             if (options.sourcePlane) {
-                plane.translate(options.sourcePlane.normal, options.sourcePlane.d);
-                var product = Math.acos(BABYLON.Vector3.Dot(options.sourcePlane.normal, BABYLON.Axis.Z));
-                var vectorProduct = BABYLON.Vector3.Cross(BABYLON.Axis.Z, options.sourcePlane.normal);
-                if (vectorProduct.lengthSquared() > BABYLON.Epsilon) {
-                    plane.rotate(vectorProduct, product);
-                }
+                plane.translate(options.sourcePlane.normal, -options.sourcePlane.d);
+                var dot = BABYLON.Vector3.Dot(plane.position, options.sourcePlane.normal);
+                var flip = dot >= 0;
+                plane.lookAt(BABYLON.Vector3.Zero(), 0, flip ? Math.PI : 0, 0);
             }
             return plane;
         };

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


+ 26 - 8
dist/preview release/es6.js

@@ -12912,7 +12912,7 @@ var BABYLON;
              * Returns the current version of the framework
              */
             get: function () {
-                return "4.0.0-alpha.7";
+                return "4.0.0-alpha.8";
             },
             enumerable: true,
             configurable: true
@@ -15756,6 +15756,7 @@ var BABYLON;
                         excludeLoaders.push(loader);
                         BABYLON.Tools.Warn(loader.constructor.name + " failed when trying to load " + texture.url + ", falling back to the next supported loader");
                         _this.createTexture(urlArg, noMipmap, invertY, scene, samplingMode, null, onError, buffer, texture, undefined, undefined, excludeLoaders);
+                        return;
                     }
                 }
                 if (!customFallback) {
@@ -15764,6 +15765,7 @@ var BABYLON;
                     }
                     if (BABYLON.Tools.UseFallbackTexture) {
                         _this.createTexture(BABYLON.Tools.fallbackTexture, noMipmap, invertY, scene, samplingMode, null, onError, buffer, texture);
+                        return;
                     }
                 }
                 if (onError) {
@@ -16920,6 +16922,7 @@ var BABYLON;
                     if (fallbackUrl) {
                         excludeLoaders.push(loader);
                         _this.createCubeTexture(fallbackUrl, scene, files, noMipmap, onLoad, onError, format, extension, createPolynomials, lodScale, lodOffset, texture, excludeLoaders);
+                        return;
                     }
                 }
                 if (onError && request) {
@@ -60785,6 +60788,23 @@ var BABYLON;
             this.id = name;
             this.name = name;
         }
+        Object.defineProperty(BaseParticleSystem.prototype, "noiseTexture", {
+            /**
+             * Gets or sets a texture used to add random noise to particle positions
+             */
+            get: function () {
+                return this._noiseTexture;
+            },
+            set: function (value) {
+                if (this._noiseTexture === value) {
+                    return;
+                }
+                this._noiseTexture = value;
+                this._reset();
+            },
+            enumerable: true,
+            configurable: true
+        });
         Object.defineProperty(BaseParticleSystem.prototype, "isAnimationSheetEnabled", {
             /**
              * Gets or sets whether an animation sprite sheet is enabled or not on the particle system
@@ -61418,7 +61438,7 @@ var BABYLON;
                     }
                     particle.position.addInPlace(_this._scaledDirection);
                     // Noise
-                    if (noiseTextureData && noiseTextureSize) {
+                    if (noiseTextureData && noiseTextureSize && particle._randomNoiseCoordinates1) {
                         var fetchedColorR = _this._fetchR(particle._randomNoiseCoordinates1.x, particle._randomNoiseCoordinates1.y, noiseTextureSize.width, noiseTextureSize.height, noiseTextureData);
                         var fetchedColorG = _this._fetchR(particle._randomNoiseCoordinates1.z, particle._randomNoiseCoordinates2.x, noiseTextureSize.width, noiseTextureSize.height, noiseTextureData);
                         var fetchedColorB = _this._fetchR(particle._randomNoiseCoordinates2.y, particle._randomNoiseCoordinates2.z, noiseTextureSize.width, noiseTextureSize.height, noiseTextureData);
@@ -70533,12 +70553,10 @@ var BABYLON;
             var vertexData = BABYLON.VertexData.CreatePlane(options);
             vertexData.applyToMesh(plane, options.updatable);
             if (options.sourcePlane) {
-                plane.translate(options.sourcePlane.normal, options.sourcePlane.d);
-                var product = Math.acos(BABYLON.Vector3.Dot(options.sourcePlane.normal, BABYLON.Axis.Z));
-                var vectorProduct = BABYLON.Vector3.Cross(BABYLON.Axis.Z, options.sourcePlane.normal);
-                if (vectorProduct.lengthSquared() > BABYLON.Epsilon) {
-                    plane.rotate(vectorProduct, product);
-                }
+                plane.translate(options.sourcePlane.normal, -options.sourcePlane.d);
+                var dot = BABYLON.Vector3.Dot(plane.position, options.sourcePlane.normal);
+                var flip = dot >= 0;
+                plane.lookAt(BABYLON.Vector3.Zero(), 0, flip ? Math.PI : 0, 0);
             }
             return plane;
         };

+ 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": "4.0.0-alpha.7",
+    "version": "4.0.0-alpha.8",
     "repository": {
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"

+ 2 - 2
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": "4.0.0-alpha.7",
+    "version": "4.0.0-alpha.8",
     "repository": {
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"
@@ -27,7 +27,7 @@
     ],
     "license": "Apache-2.0",
     "dependencies": {
-        "babylonjs": "4.0.0-alpha.7"
+        "babylonjs": "4.0.0-alpha.8"
     },
     "engines": {
         "node": "*"

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


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


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

@@ -4,7 +4,7 @@
     },
     "name": "babylonjs-inspector",
     "description": "The Babylon.js inspector.",
-    "version": "4.0.0-alpha.7",
+    "version": "4.0.0-alpha.8",
     "repository": {
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"
@@ -28,10 +28,10 @@
     ],
     "license": "Apache-2.0",
     "dependencies": {
-        "babylonjs": "4.0.0-alpha.7",
-        "babylonjs-gui": "4.0.0-alpha.7",
-        "babylonjs-loaders": "4.0.0-alpha.7",
-        "babylonjs-serializers": "4.0.0-alpha.7"
+        "babylonjs": "4.0.0-alpha.8",
+        "babylonjs-gui": "4.0.0-alpha.8",
+        "babylonjs-loaders": "4.0.0-alpha.8",
+        "babylonjs-serializers": "4.0.0-alpha.8"
     },
     "engines": {
         "node": "*"

+ 14 - 7
dist/preview release/loaders/babylon.glTF2FileLoader.js

@@ -2220,8 +2220,14 @@ var BABYLON;
                 this.logOpen(context + " " + (texture.name || ""));
                 var sampler = (texture.sampler == undefined ? GLTFLoader._DefaultSampler : ArrayItem.Get(context + "/sampler", this.gltf.samplers, texture.sampler));
                 var samplerData = this._loadSampler("/samplers/" + sampler.index, sampler);
+                var image = ArrayItem.Get(context + "/source", this.gltf.images, texture.source);
+                var textureURL = null;
+                if (image.uri && !BABYLON.Tools.IsBase64(image.uri) && this.babylonScene.getEngine().textureFormatInUse) {
+                    // If an image uri and a texture format is set like (eg. KTX) load from url instead of blob to support texture format and fallback
+                    textureURL = this._uniqueRootUrl + image.uri;
+                }
                 var deferred = new BABYLON.Deferred();
-                var babylonTexture = new BABYLON.Texture(null, this.babylonScene, samplerData.noMipMaps, false, samplerData.samplingMode, function () {
+                var babylonTexture = new BABYLON.Texture(textureURL, this.babylonScene, samplerData.noMipMaps, false, samplerData.samplingMode, function () {
                     if (!_this._disposed) {
                         deferred.resolve();
                     }
@@ -2231,14 +2237,15 @@ var BABYLON;
                     }
                 });
                 promises.push(deferred.promise);
+                if (!textureURL) {
+                    promises.push(this.loadImageAsync("/images/" + image.index, image).then(function (data) {
+                        var name = image.uri || _this._fileName + "#image" + image.index;
+                        var dataUrl = "data:" + _this._uniqueRootUrl + name;
+                        babylonTexture.updateURL(dataUrl, new Blob([data], { type: image.mimeType }));
+                    }));
+                }
                 babylonTexture.wrapU = samplerData.wrapU;
                 babylonTexture.wrapV = samplerData.wrapV;
-                var image = ArrayItem.Get(context + "/source", this.gltf.images, texture.source);
-                promises.push(this.loadImageAsync("/images/" + image.index, image).then(function (data) {
-                    var name = image.uri || _this._fileName + "#image" + image.index;
-                    var dataUrl = "data:" + _this._uniqueRootUrl + name;
-                    babylonTexture.updateURL(dataUrl, new Blob([data], { type: image.mimeType }));
-                }));
                 assign(babylonTexture);
                 this.logClose();
                 return Promise.all(promises).then(function () {

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


+ 14 - 7
dist/preview release/loaders/babylon.glTFFileLoader.js

@@ -4428,8 +4428,14 @@ var BABYLON;
                 this.logOpen(context + " " + (texture.name || ""));
                 var sampler = (texture.sampler == undefined ? GLTFLoader._DefaultSampler : ArrayItem.Get(context + "/sampler", this.gltf.samplers, texture.sampler));
                 var samplerData = this._loadSampler("/samplers/" + sampler.index, sampler);
+                var image = ArrayItem.Get(context + "/source", this.gltf.images, texture.source);
+                var textureURL = null;
+                if (image.uri && !BABYLON.Tools.IsBase64(image.uri) && this.babylonScene.getEngine().textureFormatInUse) {
+                    // If an image uri and a texture format is set like (eg. KTX) load from url instead of blob to support texture format and fallback
+                    textureURL = this._uniqueRootUrl + image.uri;
+                }
                 var deferred = new BABYLON.Deferred();
-                var babylonTexture = new BABYLON.Texture(null, this.babylonScene, samplerData.noMipMaps, false, samplerData.samplingMode, function () {
+                var babylonTexture = new BABYLON.Texture(textureURL, this.babylonScene, samplerData.noMipMaps, false, samplerData.samplingMode, function () {
                     if (!_this._disposed) {
                         deferred.resolve();
                     }
@@ -4439,14 +4445,15 @@ var BABYLON;
                     }
                 });
                 promises.push(deferred.promise);
+                if (!textureURL) {
+                    promises.push(this.loadImageAsync("/images/" + image.index, image).then(function (data) {
+                        var name = image.uri || _this._fileName + "#image" + image.index;
+                        var dataUrl = "data:" + _this._uniqueRootUrl + name;
+                        babylonTexture.updateURL(dataUrl, new Blob([data], { type: image.mimeType }));
+                    }));
+                }
                 babylonTexture.wrapU = samplerData.wrapU;
                 babylonTexture.wrapV = samplerData.wrapV;
-                var image = ArrayItem.Get(context + "/source", this.gltf.images, texture.source);
-                promises.push(this.loadImageAsync("/images/" + image.index, image).then(function (data) {
-                    var name = image.uri || _this._fileName + "#image" + image.index;
-                    var dataUrl = "data:" + _this._uniqueRootUrl + name;
-                    babylonTexture.updateURL(dataUrl, new Blob([data], { type: image.mimeType }));
-                }));
                 assign(babylonTexture);
                 this.logClose();
                 return Promise.all(promises).then(function () {

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


+ 14 - 7
dist/preview release/loaders/babylonjs.loaders.js

@@ -5490,8 +5490,14 @@ var BABYLON;
                 this.logOpen(context + " " + (texture.name || ""));
                 var sampler = (texture.sampler == undefined ? GLTFLoader._DefaultSampler : ArrayItem.Get(context + "/sampler", this.gltf.samplers, texture.sampler));
                 var samplerData = this._loadSampler("/samplers/" + sampler.index, sampler);
+                var image = ArrayItem.Get(context + "/source", this.gltf.images, texture.source);
+                var textureURL = null;
+                if (image.uri && !BABYLON.Tools.IsBase64(image.uri) && this.babylonScene.getEngine().textureFormatInUse) {
+                    // If an image uri and a texture format is set like (eg. KTX) load from url instead of blob to support texture format and fallback
+                    textureURL = this._uniqueRootUrl + image.uri;
+                }
                 var deferred = new BABYLON.Deferred();
-                var babylonTexture = new BABYLON.Texture(null, this.babylonScene, samplerData.noMipMaps, false, samplerData.samplingMode, function () {
+                var babylonTexture = new BABYLON.Texture(textureURL, this.babylonScene, samplerData.noMipMaps, false, samplerData.samplingMode, function () {
                     if (!_this._disposed) {
                         deferred.resolve();
                     }
@@ -5501,14 +5507,15 @@ var BABYLON;
                     }
                 });
                 promises.push(deferred.promise);
+                if (!textureURL) {
+                    promises.push(this.loadImageAsync("/images/" + image.index, image).then(function (data) {
+                        var name = image.uri || _this._fileName + "#image" + image.index;
+                        var dataUrl = "data:" + _this._uniqueRootUrl + name;
+                        babylonTexture.updateURL(dataUrl, new Blob([data], { type: image.mimeType }));
+                    }));
+                }
                 babylonTexture.wrapU = samplerData.wrapU;
                 babylonTexture.wrapV = samplerData.wrapV;
-                var image = ArrayItem.Get(context + "/source", this.gltf.images, texture.source);
-                promises.push(this.loadImageAsync("/images/" + image.index, image).then(function (data) {
-                    var name = image.uri || _this._fileName + "#image" + image.index;
-                    var dataUrl = "data:" + _this._uniqueRootUrl + name;
-                    babylonTexture.updateURL(dataUrl, new Blob([data], { type: image.mimeType }));
-                }));
                 assign(babylonTexture);
                 this.logClose();
                 return Promise.all(promises).then(function () {

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


+ 3 - 3
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": "4.0.0-alpha.7",
+    "version": "4.0.0-alpha.8",
     "repository": {
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"
@@ -27,8 +27,8 @@
     ],
     "license": "Apache-2.0",
     "dependencies": {
-        "babylonjs-gltf2interface": "4.0.0-alpha.7",
-        "babylonjs": "4.0.0-alpha.7"
+        "babylonjs-gltf2interface": "4.0.0-alpha.8",
+        "babylonjs": "4.0.0-alpha.8"
     },
     "engines": {
         "node": "*"

+ 2 - 2
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": "4.0.0-alpha.7",
+    "version": "4.0.0-alpha.8",
     "repository": {
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"
@@ -27,7 +27,7 @@
     ],
     "license": "Apache-2.0",
     "dependencies": {
-        "babylonjs": "4.0.0-alpha.7"
+        "babylonjs": "4.0.0-alpha.8"
     },
     "engines": {
         "node": "*"

+ 2 - 2
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": "4.0.0-alpha.7",
+    "version": "4.0.0-alpha.8",
     "repository": {
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"
@@ -27,7 +27,7 @@
     ],
     "license": "Apache-2.0",
     "dependencies": {
-        "babylonjs": "4.0.0-alpha.7"
+        "babylonjs": "4.0.0-alpha.8"
     },
     "engines": {
         "node": "*"

+ 2 - 2
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": "4.0.0-alpha.7",
+    "version": "4.0.0-alpha.8",
     "repository": {
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"
@@ -27,7 +27,7 @@
     ],
     "license": "Apache-2.0",
     "dependencies": {
-        "babylonjs": "4.0.0-alpha.7"
+        "babylonjs": "4.0.0-alpha.8"
     },
     "engines": {
         "node": "*"

+ 3 - 3
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": "4.0.0-alpha.7",
+    "version": "4.0.0-alpha.8",
     "repository": {
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"
@@ -27,8 +27,8 @@
     ],
     "license": "Apache-2.0",
     "dependencies": {
-        "babylonjs": "4.0.0-alpha.7",
-        "babylonjs-gltf2interface": "4.0.0-alpha.7"
+        "babylonjs": "4.0.0-alpha.8",
+        "babylonjs-gltf2interface": "4.0.0-alpha.8"
     },
     "engines": {
         "node": "*"

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


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


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

@@ -71,6 +71,7 @@
 - Added support for mesh instancing for improved performance when multiple nodes point to the same mesh ([bghgary](https://github.com/bghgary))
 - Create `TransformNode` objects instead of `Mesh` objects for glTF nodes without geometry ([bghgary](https://github.com/bghgary))
 - Added glTF JSON pointers to metadata of nodes, materials, and textures ([bghgary](https://github.com/bghgary))
+- Load KTX textures in the gltf2 loader when textureFormat is set on engine ([TrevorDev](https://github.com/TrevorDev))
 
 ### glTF Serializer
 

+ 1 - 1
inspector/package.json

@@ -50,4 +50,4 @@
         "webpack-cli": "~3.1.2",
         "webpack-stream": "5.0.0"
     }
-}
+}

+ 21 - 0
inspector/src/components/actionTabs/actionTabs.scss

@@ -171,6 +171,26 @@
                     opacity: 0.6;
                 }
 
+                .iconMessageLine {
+                    padding-left: 5px;
+                    height: 30px;
+                    display: grid;
+                    grid-template-columns: 30px 1fr;
+
+                    .icon {
+                        grid-column: 1;
+                        display: grid;
+                        align-items: center;
+                        justify-items: center;
+                    }
+
+                    .value {
+                        grid-column: 2;
+                        display: flex;
+                        align-items: center;
+                    }
+                }
+
                 .textLine {
                     padding-left: 5px;
                     height: 30px;
@@ -563,6 +583,7 @@
                         width: 256px;
                         margin-top: 5px;
                         margin-bottom: 5px;
+                        border: 2px solid rgba(255, 255, 255, 0.4);
                     }
                 }
 

+ 1 - 4
inspector/src/components/actionTabs/lines/floatLineComponent.tsx

@@ -6,7 +6,6 @@ interface IFloatLineComponentProps {
     label: string,
     target: any,
     propertyName: string,
-    step?: number,
     onPropertyChangedObservable?: Observable<PropertyChangedEvent>,
     additionalClass?: string
 }
@@ -71,15 +70,13 @@ export class FloatLineComponent extends React.Component<IFloatLineComponentProps
     }
 
     render() {
-
-        const step = this.props.step !== undefined ? this.props.step : 0.1;
         return (
             <div className={this.props.additionalClass ? this.props.additionalClass + " floatLine" : "floatLine"}>
                 <div className="label">
                     {this.props.label}
                 </div>
                 <div className="value">
-                    <input className="numeric-input" value={this.state.value} onChange={evt => this.updateValue(evt.target.value)} step={step} />
+                    <input className="numeric-input" value={this.state.value} onChange={evt => this.updateValue(evt.target.value)} />
                 </div>
             </div>
         );

+ 16 - 0
inspector/src/components/actionTabs/lines/messageLineComponent.tsx

@@ -1,8 +1,11 @@
 import * as React from "react";
+import { IconProp } from "@fortawesome/fontawesome-svg-core";
+import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
 
 interface IMessageLineComponentProps {
     text: string,
     color?: string,
+    icon?: IconProp
 }
 
 export class MessageLineComponent extends React.Component<IMessageLineComponentProps> {
@@ -11,6 +14,19 @@ export class MessageLineComponent extends React.Component<IMessageLineComponentP
     }
 
     render() {
+        if (this.props.icon) {
+            return (
+                <div className="iconMessageLine">
+                    <div className="icon" style={{ color: this.props.color ? this.props.color : "" }}>
+                        <FontAwesomeIcon icon={this.props.icon}/>
+                    </div>
+                    <div className="value" title={this.props.text}>
+                        {this.props.text}
+                    </div>
+                </div>
+            );
+        }
+
         return (
             <div className="messageLine">
                 <div className="value" title={this.props.text} style={{ color: this.props.color ? this.props.color : "" }}>

+ 2 - 1
inspector/src/components/actionTabs/tabs/propertyGrids/materials/commonMaterialPropertyGridComponent.tsx

@@ -58,13 +58,14 @@ export class CommonMaterialPropertyGridComponent extends React.Component<ICommon
                     <SliderLineComponent label="Point size" target={material} propertyName="pointSize" minimum={0} maximum={100} step={0.1} onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                     <SliderLineComponent label="Z-offset" target={material} propertyName="zOffset" minimum={-10} maximum={10} step={0.1} onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                 </LineContainerComponent>
-                <LineContainerComponent title="TRANSPARENCY">
+                <LineContainerComponent title="TRANSPARENCY">                
                     <SliderLineComponent label="Alpha" target={material} propertyName="alpha" minimum={0} maximum={1} step={0.01} onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                     {
                         (material as any).transparencyMode !== undefined &&
                         <OptionsLineComponent label="Transparency mode" options={transparencyModeOptions} target={material} propertyName="transparencyMode" onPropertyChangedObservable={this.props.onPropertyChangedObservable} onSelect={value => this.setState({ transparencyMode: value })} />
                     }
                     <OptionsLineComponent label="Alpha mode" options={alphaModeOptions} target={material} propertyName="alphaMode" onPropertyChangedObservable={this.props.onPropertyChangedObservable} onSelect={value => this.setState({ alphaMode: value })} />
+                    <CheckBoxLineComponent label="Separate culling pass" target={material} propertyName="separateCullingPass" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                 </LineContainerComponent>
             </div>
         );

+ 38 - 8
inspector/src/components/actionTabs/tabs/propertyGrids/materials/standardMaterialPropertyGridComponent.tsx

@@ -30,19 +30,11 @@ export class StandardMaterialPropertyGridComponent extends React.Component<IStan
         return (
             <LineContainerComponent title="TEXTURES">
                 <TextureLinkLineComponent label="Diffuse" texture={material.diffuseTexture} material={material} onSelectionChangedObservable={this.props.onSelectionChangedObservable} onDebugSelectionChangeObservable={onDebugSelectionChangeObservable} />
-                {
-                    material.diffuseTexture &&
-                    <SliderLineComponent label="Diffuse level" target={material.diffuseTexture} propertyName="level" minimum={0} maximum={2} step={0.01} onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
-                }
                 <TextureLinkLineComponent label="Specular" texture={material.specularTexture} material={material} onSelectionChangedObservable={this.props.onSelectionChangedObservable} onDebugSelectionChangeObservable={onDebugSelectionChangeObservable} />
                 <TextureLinkLineComponent label="Reflection" texture={material.reflectionTexture} material={material} onSelectionChangedObservable={this.props.onSelectionChangedObservable} onDebugSelectionChangeObservable={onDebugSelectionChangeObservable} />
                 <TextureLinkLineComponent label="Refraction" texture={material.refractionTexture} material={material} onSelectionChangedObservable={this.props.onSelectionChangedObservable} onDebugSelectionChangeObservable={onDebugSelectionChangeObservable} />
                 <TextureLinkLineComponent label="Emissive" texture={material.emissiveTexture} material={material} onSelectionChangedObservable={this.props.onSelectionChangedObservable} onDebugSelectionChangeObservable={onDebugSelectionChangeObservable} />
                 <TextureLinkLineComponent label="Bump" texture={material.bumpTexture} material={material} onSelectionChangedObservable={this.props.onSelectionChangedObservable} onDebugSelectionChangeObservable={onDebugSelectionChangeObservable} />
-                {
-                    material.bumpTexture &&
-                    <SliderLineComponent label="Bump level" target={material.bumpTexture} propertyName="level" minimum={0} maximum={2} step={0.01} onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
-                }
                 <TextureLinkLineComponent label="Opacity" texture={material.opacityTexture} material={material} onSelectionChangedObservable={this.props.onSelectionChangedObservable} onDebugSelectionChangeObservable={onDebugSelectionChangeObservable} />
                 <TextureLinkLineComponent label="Ambient" texture={material.ambientTexture} material={material} onSelectionChangedObservable={this.props.onSelectionChangedObservable} onDebugSelectionChangeObservable={onDebugSelectionChangeObservable} />
                 <TextureLinkLineComponent label="Lightmap" texture={material.lightmapTexture} material={material} onSelectionChangedObservable={this.props.onSelectionChangedObservable} onDebugSelectionChangeObservable={onDebugSelectionChangeObservable} />
@@ -64,6 +56,44 @@ export class StandardMaterialPropertyGridComponent extends React.Component<IStan
                     <Color3LineComponent label="Emissive" target={material} propertyName="emissiveColor" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                     <Color3LineComponent label="Ambient" target={material} propertyName="ambientColor" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                 </LineContainerComponent>
+                <LineContainerComponent title="LEVELS" closed={true}>
+                    {
+                        material.diffuseTexture &&
+                        <SliderLineComponent label="Diffuse level" target={material.diffuseTexture} propertyName="level" minimum={0} maximum={2} step={0.01} onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                    }
+                    {
+                        material.specularTexture &&
+                        <SliderLineComponent label="Specular level" target={material.specularTexture} propertyName="level" minimum={0} maximum={2} step={0.01} onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                    }
+                    {
+                        material.reflectionTexture &&
+                        <SliderLineComponent label="Reflection level" target={material.reflectionTexture} propertyName="level" minimum={0} maximum={2} step={0.01} onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                    }
+                    {
+                        material.refractionTexture &&
+                        <SliderLineComponent label="Refraction level" target={material.refractionTexture} propertyName="level" minimum={0} maximum={2} step={0.01} onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                    }
+                    {
+                        material.emissiveTexture &&
+                        <SliderLineComponent label="Emissive level" target={material.emissiveTexture} propertyName="level" minimum={0} maximum={2} step={0.01} onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                    }
+                    {
+                        material.bumpTexture &&
+                        <SliderLineComponent label="Bump level" target={material.bumpTexture} propertyName="level" minimum={0} maximum={2} step={0.01} onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                    }
+                    {
+                        material.opacityTexture &&
+                        <SliderLineComponent label="Opacity level" target={material.opacityTexture} propertyName="level" minimum={0} maximum={2} step={0.01} onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                    }
+                    {
+                        material.ambientTexture &&
+                        <SliderLineComponent label="Ambient level" target={material.ambientTexture} propertyName="level" minimum={0} maximum={2} step={0.01} onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                    }
+                    {
+                        material.lightmapTexture &&
+                        <SliderLineComponent label="Lightmap level" target={material.lightmapTexture} propertyName="level" minimum={0} maximum={2} step={0.01} onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                    }
+                </LineContainerComponent>
             </div>
         );
     }

+ 10 - 10
inspector/src/components/actionTabs/tabs/propertyGrids/materials/texturePropertyGridComponent.tsx

@@ -50,22 +50,22 @@ export class TexturePropertyGridComponent extends React.Component<ITextureProper
                 {
                     adtTexture &&
                     <LineContainerComponent title="ADVANCED TEXTURE PROPERTIES">
-                        <SliderLineComponent label="Render scale" minimum={0.1} maximum={5} target={adtTexture} propertyName="renderScale" step={0.1} onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                        <SliderLineComponent label="Render scale" minimum={0.1} maximum={5} step={0.1} target={adtTexture} propertyName="renderScale" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                         <CheckBoxLineComponent label="Premultiply alpha" target={adtTexture} propertyName="premulAlpha" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
-                        <FloatLineComponent label="Ideal width" target={adtTexture} propertyName="idealWidth" step={0.1} onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
-                        <FloatLineComponent label="Ideal height" target={adtTexture} propertyName="idealHeight" step={0.1} onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                        <FloatLineComponent label="Ideal width" target={adtTexture} propertyName="idealWidth" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                        <FloatLineComponent label="Ideal height" target={adtTexture} propertyName="idealHeight" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                         <CheckBoxLineComponent label="Use smallest ideal" target={adtTexture} propertyName="useSmallestIdeal" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                         <CheckBoxLineComponent label="Render at ideal size" target={adtTexture} propertyName="renderAtIdealSize" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                     </LineContainerComponent>
                 }
                 <LineContainerComponent title="TRANSFORM">
-                    <FloatLineComponent label="U offset" target={texture} propertyName="uOffset" step={0.1} onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
-                    <FloatLineComponent label="V offset" target={texture} propertyName="vOffset" step={0.1} onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
-                    <FloatLineComponent label="V scale" target={texture} propertyName="uScale" step={0.1} onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
-                    <FloatLineComponent label="V scale" target={texture} propertyName="vScale" step={0.1} onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
-                    <FloatLineComponent label="U angle" target={texture} propertyName="uAng" step={0.1} onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
-                    <FloatLineComponent label="V angle" target={texture} propertyName="vAng" step={0.1} onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
-                    <FloatLineComponent label="W angle" target={texture} propertyName="wAng" step={0.1} onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                    <FloatLineComponent label="U offset" target={texture} propertyName="uOffset" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                    <FloatLineComponent label="V offset" target={texture} propertyName="vOffset" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                    <FloatLineComponent label="V scale" target={texture} propertyName="uScale" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                    <FloatLineComponent label="V scale" target={texture} propertyName="vScale" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                    <FloatLineComponent label="U angle" target={texture} propertyName="uAng" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                    <FloatLineComponent label="V angle" target={texture} propertyName="vAng" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                    <FloatLineComponent label="W angle" target={texture} propertyName="wAng" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                     <CheckBoxLineComponent label="Clamp U" isSelected={() => texture.wrapU === BABYLON.Texture.CLAMP_ADDRESSMODE} onSelect={(value) => texture.wrapU = value ? BABYLON.Texture.CLAMP_ADDRESSMODE : BABYLON.Texture.WRAP_ADDRESSMODE} />
                     <CheckBoxLineComponent label="Clamp V" isSelected={() => texture.wrapV === BABYLON.Texture.CLAMP_ADDRESSMODE} onSelect={(value) => texture.wrapV = value ? BABYLON.Texture.CLAMP_ADDRESSMODE : BABYLON.Texture.WRAP_ADDRESSMODE} />
                 </LineContainerComponent>

+ 3 - 3
inspector/src/components/actionTabs/tabs/propertyGrids/meshes/axesViewerComponent.tsx

@@ -40,9 +40,9 @@ export class AxesViewerComponent extends React.Component<IAxisViewerComponentPro
         const y = new BABYLON.Vector3(0, 1, 0);
         const z = new BABYLON.Vector3(0, 0, 1);
 
-        viewer.xAxisMesh.metadata = { hidden: true };
-        viewer.yAxisMesh.metadata = { hidden: true };
-        viewer.zAxisMesh.metadata = { hidden: true };
+        viewer.xAxisMesh!.metadata = { hidden: true };
+        viewer.yAxisMesh!.metadata = { hidden: true };
+        viewer.zAxisMesh!.metadata = { hidden: true };
 
         node.metadata.onBeforeRenderObserver = scene.onBeforeRenderObservable.add(() => {
             let matrix = node.getWorldMatrix();

+ 2 - 0
inspector/src/components/actionTabs/tabs/propertyGrids/meshes/meshPropertyGridComponent.tsx

@@ -8,6 +8,7 @@ import { Vector3LineComponent } from "../../../lines/vector3LineComponent";
 import { SliderLineComponent } from "../../../lines/sliderLineComponent";
 import { QuaternionLineComponent } from "../../../lines/quaternionLineComponent";
 import { AxesViewerComponent } from "./axesViewerComponent";
+import { FloatLineComponent } from "../../../lines/floatLineComponent";
 
 interface IMeshPropertyGridComponentProps {
     mesh: Mesh,
@@ -145,6 +146,7 @@ export class MeshPropertyGridComponent extends React.Component<IMeshPropertyGrid
                 </LineContainerComponent>
                 <LineContainerComponent title="DISPLAY" closed={true}>
                     <SliderLineComponent label="Visibility" target={mesh} propertyName="visibility" minimum={0} maximum={1} step={0.01} onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                    <FloatLineComponent label="Alpha index" target={mesh} propertyName="alphaIndex" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                     <CheckBoxLineComponent label="Receive shadows" target={mesh} propertyName="receiveShadows" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                     {
                         mesh.isVerticesDataPresent(BABYLON.VertexBuffer.ColorKind) &&

+ 15 - 7
inspector/src/components/actionTabs/tabs/tools/gltfComponent.tsx

@@ -6,7 +6,7 @@ import { GlobalState } from "../../../globalState";
 import { FloatLineComponent } from "../../lines/floatLineComponent";
 import { OptionsLineComponent } from "../../lines/optionsLineComponent";
 import { MessageLineComponent } from "../../lines/messageLineComponent";
-import { BooleanLineComponent } from "../../lines/booleanLineComponent";
+import { faCheck, faTimesCircle } from "@fortawesome/free-solid-svg-icons";
 import { TextLineComponent } from "../../lines/textLineComponent";
 
 interface IGLTFComponentProps {
@@ -65,7 +65,7 @@ export class GLTFComponent extends React.Component<IGLTFComponentProps> {
             return `${count} ${singularForm}s`;
         }
 
-        return `No ${singularForm}`;
+        return `${singularForm}`;
     }
 
     renderValidation() {
@@ -74,10 +74,18 @@ export class GLTFComponent extends React.Component<IGLTFComponentProps> {
 
         return (
             <LineContainerComponent title="GLTF VALIDATION" closed={!issues.numErrors && !issues.numWarnings}>
-                <BooleanLineComponent label={this.prepareText("error", issues.numErrors)} value={issues.numErrors === 0} />
-                <BooleanLineComponent label={this.prepareText("warning", issues.numWarnings)} value={issues.numWarnings === 0} />
-                <BooleanLineComponent label={this.prepareText("info", issues.numInfos)} value={issues.numInfos === 0} />
-                <BooleanLineComponent label={this.prepareText("hint", issues.numHints)} value={issues.numHints === 0} />
+                {
+                    issues.numErrors !== 0 &&
+                    <MessageLineComponent text="Your file has some validation issues" icon={faTimesCircle} color="Red"/>
+                }
+                {
+                    issues.numErrors === 0 &&
+                    <MessageLineComponent text="Your file is a valid glTF file" icon={faCheck} color="Green"/>
+                }
+                <TextLineComponent label="Errors" value={issues.numErrors.toString()} />
+                <TextLineComponent label="Warnings" value={issues.numWarnings.toString()} />
+                <TextLineComponent label="Infos" value={issues.numInfos.toString()} />
+                <TextLineComponent label="Hints" value={issues.numHints.toString()} />
                 <TextLineComponent label="More details" value="Click here" onLink={() => this.openValidationDetails()} />
             </LineContainerComponent>
         )
@@ -114,7 +122,7 @@ export class GLTFComponent extends React.Component<IGLTFComponentProps> {
                 </LineContainerComponent>
                 <LineContainerComponent title="GLTF EXTENSIONS" closed={true}>
                     <CheckBoxLineComponent label="MSFT_lod" isSelected={() => extensionStates["MSFT_lod"].enabled} onSelect={value => extensionStates["MSFT_lod"].enabled = value} />
-                    <FloatLineComponent label="Maximum LODs" target={extensionStates["MSFT_lod"]} propertyName="maxLODsToLoad" step={1} additionalClass="gltf-extension-property" />
+                    <FloatLineComponent label="Maximum LODs" target={extensionStates["MSFT_lod"]} propertyName="maxLODsToLoad" additionalClass="gltf-extension-property" />
                     <CheckBoxLineComponent label="MSFT_minecraftMesh" isSelected={() => extensionStates["MSFT_minecraftMesh"].enabled} onSelect={value => extensionStates["MSFT_minecraftMesh"].enabled = value} />
                     <CheckBoxLineComponent label="MSFT_sRGBFactors" isSelected={() => extensionStates["MSFT_sRGBFactors"].enabled} onSelect={value => extensionStates["MSFT_sRGBFactors"].enabled = value} />
                     <CheckBoxLineComponent label="MSFT_audio_emitter" isSelected={() => extensionStates["MSFT_audio_emitter"].enabled} onSelect={value => extensionStates["MSFT_audio_emitter"].enabled = value} />

+ 2 - 2
inspector/src/components/sceneExplorer/entities/transformNodeTreeItemComponent.tsx

@@ -1,5 +1,5 @@
 import { TransformNode, IExplorerExtensibilityGroup } from "babylonjs";
-import { faCube } from '@fortawesome/free-solid-svg-icons';
+import { faCodeBranch } from '@fortawesome/free-solid-svg-icons';
 import { TreeItemLabelComponent } from "../treeItemLabelComponent";
 import { ExtensionsComponent } from "../extensionsComponent";
 import * as React from "react";
@@ -20,7 +20,7 @@ export class TransformNodeItemComponent extends React.Component<ITransformNodeIt
         const transformNode = this.props.transformNode;
         return (
             <div className="transformNodeTools">
-                <TreeItemLabelComponent label={transformNode.name} onClick={() => this.props.onClick()} icon={faCube} color="cornflowerblue" />
+                <TreeItemLabelComponent label={transformNode.name} onClick={() => this.props.onClick()} icon={faCodeBranch} color="cornflowerblue" />
                 {
                     <ExtensionsComponent target={transformNode} extensibilityGroups={this.props.extensibilityGroups} />
                 }

+ 37 - 11
inspector/src/components/sceneExplorer/sceneExplorer.scss

@@ -121,22 +121,48 @@
         -ms-user-select: none;    
         user-select: none;    
         
-        align-self: center;                
-        display: flex;
-        align-items: center;
+        align-self: center;     
+        display: grid;
+        align-items: center;           
 
         &:hover {
             background: #444444;
         }
-        
-        .arrow {
-            margin-left: 0px;
-            color: white;
-            cursor: pointer;
-            display: inline-block;
-            margin-right: 6px;
-            opacity: 0.5;
+
+        .expandableHeader {
+            display: grid;
+            grid-template-columns: 1fr 20px;
+
+            .text {
+                grid-column: 1;
+                display: grid;
+                grid-template-columns: 20px 1fr;
+
+                .arrow {
+                    grid-column: 1;
+                    margin-left: 0px;
+                    color: white;
+                    cursor: pointer;
+                    display: inline-block;
+                    margin-right: 6px;
+                    opacity: 0.5;
+                }
+
+                .text-value {
+                    grid-column: 2;
+                    display: flex;
+                    align-items: center;
+                }
+            }
+
+            .expandAll {                
+                opacity: 0.5;
+                grid-column: 2;
+                margin-right: 5px;  
+            }
         }
+        
+
     }
 
     .icon {

+ 39 - 16
inspector/src/components/sceneExplorer/treeItemComponent.tsx

@@ -1,14 +1,15 @@
 import * as React from "react";
 import { Nullable, Observable, IExplorerExtensibilityGroup } from "babylonjs";
 import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-import { faPlus, faMinus, faBan } from '@fortawesome/free-solid-svg-icons';
+import { faPlus, faMinus, faBan, faExpandArrowsAlt, faCompress } from '@fortawesome/free-solid-svg-icons';
 import { TreeItemSelectableComponent } from "./treeItemSelectableComponent";
 import { Tools } from "../../tools";
 
 interface ITreeItemExpandableHeaderComponentProps {
     isExpanded: boolean,
     label: string,
-    onClick: () => void
+    onClick: () => void,
+    onExpandAll: (expand: boolean) => void
 }
 
 class TreeItemExpandableHeaderComponent extends React.Component<ITreeItemExpandableHeaderComponentProps> {
@@ -16,14 +17,27 @@ class TreeItemExpandableHeaderComponent extends React.Component<ITreeItemExpanda
         super(props);
     }
 
+    expandAll() {
+        this.props.onExpandAll(!this.props.isExpanded);
+    }
+
     render() {
         const chevron = this.props.isExpanded ? <FontAwesomeIcon icon={faMinus} /> : <FontAwesomeIcon icon={faPlus} />
+        const expandAll = this.props.isExpanded ? <FontAwesomeIcon icon={faCompress} /> : <FontAwesomeIcon icon={faExpandArrowsAlt} />
 
         return (
-            <div>
-                <span className="arrow icon" onClick={() => this.props.onClick()}>
-                    {chevron}
-                </span> {this.props.label}
+            <div className="expandableHeader">
+                <div className="text">
+                    <div className="arrow icon" onClick={() => this.props.onClick()}>
+                        {chevron}
+                    </div> 
+                    <div className="text-value">
+                        {this.props.label}
+                    </div>
+                </div>
+                <div className="expandAll icon" onClick={() => this.expandAll()} title={this.props.isExpanded ? "Collapse all" : "Expand all"}>
+                    {expandAll}
+                </div>
             </div>
         )
     }
@@ -40,10 +54,15 @@ class TreeItemRootHeaderComponent extends React.Component<ITreeItemRootHeaderCom
 
     render() {
         return (
-            <div>
-                <span className="arrow icon">
-                    <FontAwesomeIcon icon={faBan} />
-                </span> {this.props.label}
+            <div className="expandableHeader">
+                <div className="text">
+                    <div className="arrow icon">
+                        <FontAwesomeIcon icon={faBan} />
+                    </div>
+                    <div className="text-value">
+                        {this.props.label}
+                    </div>
+                </div>
             </div>
         )
     }
@@ -61,15 +80,15 @@ export interface ITreeItemComponentProps {
 }
 
 
-export class TreeItemComponent extends React.Component<ITreeItemComponentProps, { isExpanded: boolean }> {
+export class TreeItemComponent extends React.Component<ITreeItemComponentProps, { isExpanded: boolean, mustExpand: boolean }> {
     constructor(props: ITreeItemComponentProps) {
         super(props);
 
-        this.state = { isExpanded: false };
+        this.state = { isExpanded: false, mustExpand: false };
     }
 
     switchExpandedState(): void {
-        this.setState({ isExpanded: !this.state.isExpanded });
+        this.setState({ isExpanded: !this.state.isExpanded, mustExpand: false });
     }
 
     shouldComponentUpdate(nextProps: ITreeItemComponentProps, nextState: { isExpanded: boolean }) {
@@ -93,6 +112,10 @@ export class TreeItemComponent extends React.Component<ITreeItemComponentProps,
         return true;
     }
 
+    expandAll(expand: boolean) {
+        this.setState({isExpanded: expand, mustExpand: expand});
+    }
+
     render() {
         const items = this.props.items;
 
@@ -121,7 +144,7 @@ export class TreeItemComponent extends React.Component<ITreeItemComponentProps,
         if (!this.state.isExpanded) {
             return (
                 <div className="groupContainer" style={marginStyle}>
-                    <TreeItemExpandableHeaderComponent isExpanded={false} label={this.props.label} onClick={() => this.switchExpandedState()} />
+                    <TreeItemExpandableHeaderComponent isExpanded={false} label={this.props.label} onClick={() => this.switchExpandedState()} onExpandAll={expand => this.expandAll(expand)} />
                 </div >
             )
         }
@@ -131,12 +154,12 @@ export class TreeItemComponent extends React.Component<ITreeItemComponentProps,
         return (
             <div>
                 <div className="groupContainer" style={marginStyle}>
-                    <TreeItemExpandableHeaderComponent isExpanded={this.state.isExpanded} label={this.props.label} onClick={() => this.switchExpandedState()} />
+                    <TreeItemExpandableHeaderComponent isExpanded={this.state.isExpanded} label={this.props.label} onClick={() => this.switchExpandedState()} onExpandAll={expand => this.expandAll(expand)} />
                 </div>
                 {
                     sortedItems.map(item => {
                         return (
-                            <TreeItemSelectableComponent extensibilityGroups={this.props.extensibilityGroups} key={item.uniqueId} offset={this.props.offset + 2} selectedEntity={this.props.selectedEntity} entity={item} onSelectionChangedObservable={this.props.onSelectionChangedObservable} filter={this.props.filter} />
+                            <TreeItemSelectableComponent mustExpand={this.state.mustExpand} extensibilityGroups={this.props.extensibilityGroups} key={item.uniqueId} offset={this.props.offset + 1} selectedEntity={this.props.selectedEntity} entity={item} onSelectionChangedObservable={this.props.onSelectionChangedObservable} filter={this.props.filter} />
                         );
                     })
                 }

+ 1 - 1
inspector/src/components/sceneExplorer/treeItemSelectableComponent.tsx

@@ -92,7 +92,7 @@ export class TreeItemSelectableComponent extends React.Component<ITreeItemSelect
             children.map(item => {
 
                 return (
-                    <TreeItemSelectableComponent extensibilityGroups={this.props.extensibilityGroups} selectedEntity={this.props.selectedEntity} key={item.uniqueId} offset={this.props.offset + 2} entity={item} onSelectionChangedObservable={this.props.onSelectionChangedObservable} filter={this.props.filter} />
+                    <TreeItemSelectableComponent mustExpand={this.props.mustExpand} extensibilityGroups={this.props.extensibilityGroups} selectedEntity={this.props.selectedEntity} key={item.uniqueId} offset={this.props.offset + 2} entity={item} onSelectionChangedObservable={this.props.onSelectionChangedObservable} filter={this.props.filter} />
                 );
             })
         )

+ 16 - 9
loaders/src/glTF/2.0/babylon.glTFLoader.ts

@@ -1713,8 +1713,15 @@ module BABYLON.GLTF2 {
             const sampler = (texture.sampler == undefined ? GLTFLoader._DefaultSampler : ArrayItem.Get(`${context}/sampler`, this.gltf.samplers, texture.sampler));
             const samplerData = this._loadSampler(`/samplers/${sampler.index}`, sampler);
 
+            const image = ArrayItem.Get(`${context}/source`, this.gltf.images, texture.source);
+            let textureURL: Nullable<string> = null;
+            if (image.uri && !Tools.IsBase64(image.uri) && this.babylonScene.getEngine().textureFormatInUse) {
+                // If an image uri and a texture format is set like (eg. KTX) load from url instead of blob to support texture format and fallback
+                textureURL = this._uniqueRootUrl + image.uri;
+            }
+
             const deferred = new Deferred<void>();
-            const babylonTexture = new Texture(null, this.babylonScene, samplerData.noMipMaps, false, samplerData.samplingMode, () => {
+            const babylonTexture = new Texture(textureURL, this.babylonScene, samplerData.noMipMaps, false, samplerData.samplingMode, () => {
                 if (!this._disposed) {
                     deferred.resolve();
                 }
@@ -1725,16 +1732,16 @@ module BABYLON.GLTF2 {
             });
             promises.push(deferred.promise);
 
+            if (!textureURL) {
+                promises.push(this.loadImageAsync(`/images/${image.index}`, image).then((data) => {
+                    const name = image.uri || `${this._fileName}#image${image.index}`;
+                    const dataUrl = `data:${this._uniqueRootUrl}${name}`;
+                    babylonTexture.updateURL(dataUrl, new Blob([data], { type: image.mimeType }));
+                }));
+            }
+
             babylonTexture.wrapU = samplerData.wrapU;
             babylonTexture.wrapV = samplerData.wrapV;
-
-            const image = ArrayItem.Get(`${context}/source`, this.gltf.images, texture.source);
-            promises.push(this.loadImageAsync(`/images/${image.index}`, image).then((data) => {
-                const name = image.uri || `${this._fileName}#image${image.index}`;
-                const dataUrl = `data:${this._uniqueRootUrl}${name}`;
-                babylonTexture.updateURL(dataUrl, new Blob([data], { type: image.mimeType }));
-            }));
-
             assign(babylonTexture);
 
             this.logClose();

+ 1 - 1
package.json

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

+ 1 - 0
sandbox/index.css

@@ -189,6 +189,7 @@ a {
     color: white;
     width: calc(100% - 168px);
     min-height: 30px;
+    font-size: 14px;
 }
 
 .row {

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

@@ -481,7 +481,7 @@ module BABYLON {
          * Returns the current version of the framework
          */
         public static get Version(): string {
-            return "4.0.0-alpha.7";
+            return "4.0.0-alpha.8";
         }
 
         /**
@@ -4307,6 +4307,7 @@ module BABYLON {
                         excludeLoaders.push(loader);
                         Tools.Warn((loader.constructor as any).name + " failed when trying to load " + texture.url + ", falling back to the next supported loader");
                         this.createTexture(urlArg, noMipmap, invertY, scene, samplingMode, null, onError, buffer, texture, undefined, undefined, excludeLoaders);
+                        return;
                     }
                 }
 
@@ -4316,6 +4317,7 @@ module BABYLON {
                     }
                     if (Tools.UseFallbackTexture) {
                         this.createTexture(Tools.fallbackTexture, noMipmap, invertY, scene, samplingMode, null, onError, buffer, texture);
+                        return;
                     }
                 }
 
@@ -5716,6 +5718,7 @@ module BABYLON {
                     if (fallbackUrl) {
                         excludeLoaders.push(loader);
                         this.createCubeTexture(fallbackUrl, scene, files, noMipmap, onLoad, onError, format, extension, createPolynomials, lodScale, lodOffset, texture, excludeLoaders);
+                        return;
                     }
                 }
 

+ 4 - 7
src/Mesh/babylon.meshBuilder.ts

@@ -694,14 +694,11 @@ module BABYLON {
             vertexData.applyToMesh(plane, options.updatable);
 
             if (options.sourcePlane) {
-                plane.translate(options.sourcePlane.normal, options.sourcePlane.d);
+                plane.translate(options.sourcePlane.normal, -options.sourcePlane.d);
 
-                var product = Math.acos(Vector3.Dot(options.sourcePlane.normal, Axis.Z));
-                var vectorProduct = Vector3.Cross(Axis.Z, options.sourcePlane.normal);
-
-                if (vectorProduct.lengthSquared() > Epsilon) {
-                    plane.rotate(vectorProduct, product);
-                }
+                const dot = BABYLON.Vector3.Dot(plane.position, options.sourcePlane.normal);
+                const flip = dot >= 0;
+                plane.lookAt(BABYLON.Vector3.Zero(), 0, flip ? Math.PI : 0, 0);
             }
 
             return plane;

+ 14 - 1
src/Particles/babylon.baseParticleSystem.ts

@@ -163,10 +163,23 @@ module BABYLON {
          */
         public preventAutoStart: boolean = false;
 
+        private _noiseTexture: Nullable<ProceduralTexture>;
+
         /**
          * Gets or sets a texture used to add random noise to particle positions
          */
-        public noiseTexture: Nullable<ProceduralTexture>;
+        public get noiseTexture(): Nullable<ProceduralTexture> {
+            return this._noiseTexture;
+        }
+
+        public set noiseTexture(value : Nullable<ProceduralTexture>) {
+            if (this._noiseTexture === value) {
+                return;
+            }
+
+            this._noiseTexture = value;
+            this._reset();
+        }
 
         /** Gets or sets the strength to apply to the noise value (default is (10, 10, 10)) */
         public noiseStrength = new Vector3(10, 10, 10);

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

@@ -308,7 +308,7 @@ module BABYLON {
                     particle.position.addInPlace(this._scaledDirection);
 
                     // Noise
-                    if (noiseTextureData && noiseTextureSize) {
+                    if (noiseTextureData && noiseTextureSize && particle._randomNoiseCoordinates1) {
                         let fetchedColorR = this._fetchR(particle._randomNoiseCoordinates1.x, particle._randomNoiseCoordinates1.y, noiseTextureSize.width, noiseTextureSize.height, noiseTextureData);
                         let fetchedColorG = this._fetchR(particle._randomNoiseCoordinates1.z, particle._randomNoiseCoordinates2.x, noiseTextureSize.width, noiseTextureSize.height, noiseTextureData);
                         let fetchedColorB = this._fetchR(particle._randomNoiseCoordinates2.y, particle._randomNoiseCoordinates2.z, noiseTextureSize.width, noiseTextureSize.height, noiseTextureData);

+ 1 - 0
what's new.md

@@ -204,6 +204,7 @@
 - Spring Joint could not be removed ([TrevorDev](https://github.com/TrevorDev))
 - Sometimes duplicate controller models are loaded in VR ([TrevorDev](https://github.com/TrevorDev))
 - Particle emit rate and start size over time do not reset on every particle system start ([TrevorDev](https://github.com/TrevorDev))
+- Fix position and rotation of plane mesh created by MeshBuilder.CreatePlane when specifying a source plane ([sable](https://github.com/thscott))
 
 ### Core Engine