Kaynağa Gözat

Merge remote-tracking branch 'BabylonJS/master' into viewer-missing-configuration-params

Raanan Weber 7 yıl önce
ebeveyn
işleme
e862ff4dc5
71 değiştirilmiş dosya ile 27746 ekleme ve 26111 silme
  1. 7779 7586
      Playground/babylon.d.txt
  2. 1 1
      Playground/scripts/instanced bones.js
  3. 1 1
      Tools/Gulp/package.json
  4. 10715 10539
      dist/preview release/babylon.d.ts
  5. 53 53
      dist/preview release/babylon.js
  6. 354 101
      dist/preview release/babylon.max.js
  7. 54 54
      dist/preview release/babylon.worker.js
  8. 6867 6691
      dist/preview release/customConfigurations/minimalGLTFViewer/babylon.d.ts
  9. 54 54
      dist/preview release/customConfigurations/minimalGLTFViewer/babylon.js
  10. 355 100
      dist/preview release/customConfigurations/minimalGLTFViewer/babylon.max.js
  11. 355 100
      dist/preview release/customConfigurations/minimalGLTFViewer/es6.js
  12. 354 101
      dist/preview release/es6.js
  13. 22 0
      dist/preview release/gui/babylon.gui.d.ts
  14. 76 2
      dist/preview release/gui/babylon.gui.js
  15. 3 3
      dist/preview release/gui/babylon.gui.min.js
  16. 22 0
      dist/preview release/gui/babylon.gui.module.d.ts
  17. 4 4
      dist/preview release/inspector/babylon.inspector.bundle.js
  18. 4 4
      dist/preview release/inspector/babylon.inspector.min.js
  19. 2 2
      dist/preview release/loaders/babylon.glTF1FileLoader.min.js
  20. 1 0
      dist/preview release/loaders/babylon.glTF2FileLoader.js
  21. 2 2
      dist/preview release/loaders/babylon.glTF2FileLoader.min.js
  22. 1 0
      dist/preview release/loaders/babylon.glTFFileLoader.js
  23. 3 3
      dist/preview release/loaders/babylon.glTFFileLoader.min.js
  24. 1 1
      dist/preview release/loaders/babylon.objFileLoader.min.js
  25. 1 0
      dist/preview release/loaders/babylonjs.loaders.js
  26. 3 3
      dist/preview release/loaders/babylonjs.loaders.min.js
  27. 1 1
      dist/preview release/materialsLibrary/babylon.customMaterial.min.js
  28. 1 1
      dist/preview release/materialsLibrary/babylon.shadowOnlyMaterial.min.js
  29. 1 1
      dist/preview release/materialsLibrary/babylon.waterMaterial.min.js
  30. 3 3
      dist/preview release/materialsLibrary/babylonjs.materials.min.js
  31. 1 1
      dist/preview release/postProcessesLibrary/babylon.asciiArtPostProcess.min.js
  32. 1 1
      dist/preview release/postProcessesLibrary/babylon.digitalRainPostProcess.min.js
  33. 1 1
      dist/preview release/postProcessesLibrary/babylonjs.postProcess.min.js
  34. 1 1
      dist/preview release/serializers/babylon.glTF2Serializer.min.js
  35. 1 1
      dist/preview release/serializers/babylonjs.serializers.min.js
  36. 2 424
      dist/preview release/typedocValidationBaseline.json
  37. 66 66
      dist/preview release/viewer/babylon.viewer.js
  38. 6 2
      dist/preview release/what's new.md
  39. 6 0
      gui/src/advancedDynamicTexture.ts
  40. 1 0
      gui/src/controls/container.ts
  41. 18 2
      gui/src/controls/control.ts
  42. 49 0
      gui/src/controls/textBlock.ts
  43. 2 0
      loaders/src/glTF/2.0/babylon.glTFLoader.ts
  44. 0 28
      sandbox/index.js
  45. 1 1
      src/Animations/babylon.animatable.ts
  46. 1 1
      src/Audio/babylon.soundtrack.ts
  47. 40 33
      src/Engine/babylon.engine.ts
  48. 0 1
      src/Engine/babylon.nullEngine.ts
  49. 38 20
      src/Layer/babylon.glowLayer.ts
  50. 5 0
      src/Layer/babylon.highlightLayer.ts
  51. 2 2
      src/Loading/Plugins/babylon.babylonFileLoader.ts
  52. 17 10
      src/Materials/PBR/babylon.pbrBaseMaterial.ts
  53. 7 0
      src/Materials/PBR/babylon.pbrMaterial.ts
  54. 23 6
      src/Materials/babylon.effect.ts
  55. 16 0
      src/Materials/babylon.pushMaterial.ts
  56. 20 2
      src/Materials/babylon.standardMaterial.ts
  57. 17 0
      src/Math/babylon.math.ts
  58. 0 10
      src/Mesh/babylon.abstractMesh.ts
  59. 8 0
      src/Particles/babylon.particleSystem.ts
  60. 9 0
      src/Particles/babylon.solidParticle.ts
  61. 86 30
      src/Particles/babylon.solidParticleSystem.ts
  62. 5 0
      src/Shaders/ShadersInclude/bumpFragment.fx
  63. 4 0
      src/Shaders/ShadersInclude/bumpFragmentFunctions.fx
  64. 1 1
      src/Tools/babylon.assetsManager.ts
  65. 3 3
      src/Tools/babylon.promise.ts
  66. 162 29
      src/babylon.node.ts
  67. 3 1
      tests/nullEngine/app.js
  68. 5 5
      tests/nullEngine/package.json
  69. 19 17
      tests/unit/babylon/src/Loading/babylon.sceneLoader.tests.ts
  70. BIN
      tests/validation/ReferenceImages/local cubemaps.png
  71. 6 1
      tests/validation/config.json

Dosya farkı çok büyük olduğundan ihmal edildi
+ 7779 - 7586
Playground/babylon.d.txt


+ 1 - 1
Playground/scripts/instanced bones.js

@@ -21,7 +21,7 @@ var createScene = function () {
 
 
     // Shadows
     // Shadows
     var shadowGenerator = new BABYLON.ShadowGenerator(1024, light);
     var shadowGenerator = new BABYLON.ShadowGenerator(1024, light);
-    shadowGenerator.useBlurVarianceShadowMap = true;
+    shadowGenerator.useBlurExponentialShadowMap = true;
 
 
     // Dude
     // Dude
     BABYLON.SceneLoader.ImportMesh("him", "scenes/Dude/", "Dude.babylon", scene, function (newMeshes2, particleSystems2, skeletons2) {
     BABYLON.SceneLoader.ImportMesh("him", "scenes/Dude/", "Dude.babylon", scene, function (newMeshes2, particleSystems2, skeletons2) {

+ 1 - 1
Tools/Gulp/package.json

@@ -57,7 +57,7 @@
         "through2": "~0.6.5",
         "through2": "~0.6.5",
         "ts-loader": "^2.3.7",
         "ts-loader": "^2.3.7",
         "typedoc": "^0.9.0",
         "typedoc": "^0.9.0",
-        "typescript": "^2.6.2",
+        "typescript": "~2.6.2",
         "webpack-stream": "^4.0.0"
         "webpack-stream": "^4.0.0"
     },
     },
     "scripts": {
     "scripts": {

Dosya farkı çok büyük olduğundan ihmal edildi
+ 10715 - 10539
dist/preview release/babylon.d.ts


Dosya farkı çok büyük olduğundan ihmal edildi
+ 53 - 53
dist/preview release/babylon.js


Dosya farkı çok büyük olduğundan ihmal edildi
+ 354 - 101
dist/preview release/babylon.max.js


Dosya farkı çok büyük olduğundan ihmal edildi
+ 54 - 54
dist/preview release/babylon.worker.js


Dosya farkı çok büyük olduğundan ihmal edildi
+ 6867 - 6691
dist/preview release/customConfigurations/minimalGLTFViewer/babylon.d.ts


Dosya farkı çok büyük olduğundan ihmal edildi
+ 54 - 54
dist/preview release/customConfigurations/minimalGLTFViewer/babylon.js


Dosya farkı çok büyük olduğundan ihmal edildi
+ 355 - 100
dist/preview release/customConfigurations/minimalGLTFViewer/babylon.max.js


Dosya farkı çok büyük olduğundan ihmal edildi
+ 355 - 100
dist/preview release/customConfigurations/minimalGLTFViewer/es6.js


Dosya farkı çok büyük olduğundan ihmal edildi
+ 354 - 101
dist/preview release/es6.js


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

@@ -163,6 +163,7 @@ declare module BABYLON.GUI {
         protected _horizontalAlignment: number;
         protected _horizontalAlignment: number;
         protected _verticalAlignment: number;
         protected _verticalAlignment: number;
         private _isDirty;
         private _isDirty;
+        _tempParentMeasure: Measure;
         protected _cachedParentMeasure: Measure;
         protected _cachedParentMeasure: Measure;
         private _paddingLeft;
         private _paddingLeft;
         private _paddingRight;
         private _paddingRight;
@@ -247,6 +248,8 @@ declare module BABYLON.GUI {
         readonly heightInPixels: number;
         readonly heightInPixels: number;
         fontFamily: string;
         fontFamily: string;
         fontStyle: string;
         fontStyle: string;
+        /** @ignore */
+        readonly _isFontSizeInPercentage: boolean;
         readonly fontSizeInPixels: number;
         readonly fontSizeInPixels: number;
         fontSize: string | number;
         fontSize: string | number;
         color: string;
         color: string;
@@ -274,6 +277,8 @@ declare module BABYLON.GUI {
         readonly centerY: number;
         readonly centerY: number;
         constructor(name?: string | undefined);
         constructor(name?: string | undefined);
         protected _getTypeName(): string;
         protected _getTypeName(): string;
+        /** @ignore */
+        _resetFontCache(): void;
         getLocalCoordinates(globalCoordinates: Vector2): Vector2;
         getLocalCoordinates(globalCoordinates: Vector2): Vector2;
         getLocalCoordinatesToRef(globalCoordinates: Vector2, result: Vector2): Control;
         getLocalCoordinatesToRef(globalCoordinates: Vector2, result: Vector2): Control;
         getParentLocalCoordinates(globalCoordinates: Vector2): Vector2;
         getParentLocalCoordinates(globalCoordinates: Vector2): Vector2;
@@ -543,6 +548,8 @@ declare module BABYLON.GUI {
         private _lines;
         private _lines;
         private _resizeToFit;
         private _resizeToFit;
         private _lineSpacing;
         private _lineSpacing;
+        private _outlineWidth;
+        private _outlineColor;
         /**
         /**
         * An event triggered after the text is changed
         * An event triggered after the text is changed
         * @type {BABYLON.Observable}
         * @type {BABYLON.Observable}
@@ -600,6 +607,20 @@ declare module BABYLON.GUI {
          */
          */
         lineSpacing: string | number;
         lineSpacing: string | number;
         /**
         /**
+         * Gets or sets outlineWidth of the text to display
+         */
+        /**
+         * Gets or sets outlineWidth of the text to display
+         */
+        outlineWidth: number;
+        /**
+         * Gets or sets outlineColor of the text to display
+         */
+        /**
+         * Gets or sets outlineColor of the text to display
+         */
+        outlineColor: string;
+        /**
          * Creates a new TextBlock object
          * Creates a new TextBlock object
          * @param name defines the name of the control
          * @param name defines the name of the control
          * @param text defines the text to display (emptry string by default)
          * @param text defines the text to display (emptry string by default)
@@ -613,6 +634,7 @@ declare module BABYLON.GUI {
         private _drawText(text, textWidth, y, context);
         private _drawText(text, textWidth, y, context);
         /** @ignore */
         /** @ignore */
         _draw(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
         _draw(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
+        protected _applyStates(context: CanvasRenderingContext2D): void;
         protected _additionalProcessing(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
         protected _additionalProcessing(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
         protected _parseLine(line: string | undefined, context: CanvasRenderingContext2D): object;
         protected _parseLine(line: string | undefined, context: CanvasRenderingContext2D): object;
         protected _parseLineWithTextWrapping(line: string | undefined, context: CanvasRenderingContext2D): object;
         protected _parseLineWithTextWrapping(line: string | undefined, context: CanvasRenderingContext2D): object;

+ 76 - 2
dist/preview release/gui/babylon.gui.js

@@ -203,6 +203,11 @@ var BABYLON;
             };
             };
             AdvancedDynamicTexture.prototype.markAsDirty = function () {
             AdvancedDynamicTexture.prototype.markAsDirty = function () {
                 this._isDirty = true;
                 this._isDirty = true;
+                this.executeOnAllControls(function (control) {
+                    if (control._isFontSizeInPercentage) {
+                        control._resetFontCache();
+                    }
+                });
             };
             };
             AdvancedDynamicTexture.prototype.addControl = function (control) {
             AdvancedDynamicTexture.prototype.addControl = function (control) {
                 this._rootContainer.addControl(control);
                 this._rootContainer.addControl(control);
@@ -826,6 +831,7 @@ var BABYLON;
                 this._horizontalAlignment = Control.HORIZONTAL_ALIGNMENT_CENTER;
                 this._horizontalAlignment = Control.HORIZONTAL_ALIGNMENT_CENTER;
                 this._verticalAlignment = Control.VERTICAL_ALIGNMENT_CENTER;
                 this._verticalAlignment = Control.VERTICAL_ALIGNMENT_CENTER;
                 this._isDirty = true;
                 this._isDirty = true;
+                this._tempParentMeasure = GUI.Measure.Empty();
                 this._cachedParentMeasure = GUI.Measure.Empty();
                 this._cachedParentMeasure = GUI.Measure.Empty();
                 this._paddingLeft = new GUI.ValueAndUnit(0);
                 this._paddingLeft = new GUI.ValueAndUnit(0);
                 this._paddingRight = new GUI.ValueAndUnit(0);
                 this._paddingRight = new GUI.ValueAndUnit(0);
@@ -1091,9 +1097,20 @@ var BABYLON;
                 enumerable: true,
                 enumerable: true,
                 configurable: true
                 configurable: true
             });
             });
+            Object.defineProperty(Control.prototype, "_isFontSizeInPercentage", {
+                /** @ignore */
+                get: function () {
+                    return this._fontSize.isPercentage;
+                },
+                enumerable: true,
+                configurable: true
+            });
             Object.defineProperty(Control.prototype, "fontSizeInPixels", {
             Object.defineProperty(Control.prototype, "fontSizeInPixels", {
                 get: function () {
                 get: function () {
-                    return this._fontSize.getValueInPixel(this._host, 100);
+                    if (this._fontSize.isPixel) {
+                        return this._fontSize.getValue(this._host);
+                    }
+                    return this._fontSize.getValueInPixel(this._host, this._tempParentMeasure.height || this._cachedParentMeasure.height);
                 },
                 },
                 enumerable: true,
                 enumerable: true,
                 configurable: true
                 configurable: true
@@ -1348,6 +1365,10 @@ var BABYLON;
             Control.prototype._getTypeName = function () {
             Control.prototype._getTypeName = function () {
                 return "Control";
                 return "Control";
             };
             };
+            /** @ignore */
+            Control.prototype._resetFontCache = function () {
+                this._fontSet = true;
+            };
             Control.prototype.getLocalCoordinates = function (globalCoordinates) {
             Control.prototype.getLocalCoordinates = function (globalCoordinates) {
                 var result = BABYLON.Vector2.Zero();
                 var result = BABYLON.Vector2.Zero();
                 this.getLocalCoordinatesToRef(globalCoordinates, result);
                 this.getLocalCoordinatesToRef(globalCoordinates, result);
@@ -1721,7 +1742,7 @@ var BABYLON;
                 if (!this._font && !this._fontSet) {
                 if (!this._font && !this._fontSet) {
                     return;
                     return;
                 }
                 }
-                this._font = this._fontStyle + " " + this._fontSize.getValue(this._host) + "px " + this._fontFamily;
+                this._font = this._fontStyle + " " + this.fontSizeInPixels + "px " + this._fontFamily;
                 this._fontOffset = Control._GetFontOffset(this._font);
                 this._fontOffset = Control._GetFontOffset(this._font);
             };
             };
             Control.prototype.dispose = function () {
             Control.prototype.dispose = function () {
@@ -2009,6 +2030,7 @@ var BABYLON;
                     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];
                         var child = _a[_i];
                         if (child.isVisible && !child.notRenderable) {
                         if (child.isVisible && !child.notRenderable) {
+                            child._tempParentMeasure.copyFrom(this._measureForChildren);
                             child._draw(this._measureForChildren, context);
                             child._draw(this._measureForChildren, context);
                             if (child.onAfterDrawObservable.hasObservers()) {
                             if (child.onAfterDrawObservable.hasObservers()) {
                                 child.onAfterDrawObservable.notifyObservers(child);
                                 child.onAfterDrawObservable.notifyObservers(child);
@@ -3241,6 +3263,8 @@ var BABYLON;
                 _this._textVerticalAlignment = GUI.Control.VERTICAL_ALIGNMENT_CENTER;
                 _this._textVerticalAlignment = GUI.Control.VERTICAL_ALIGNMENT_CENTER;
                 _this._resizeToFit = false;
                 _this._resizeToFit = false;
                 _this._lineSpacing = new GUI.ValueAndUnit(0);
                 _this._lineSpacing = new GUI.ValueAndUnit(0);
+                _this._outlineWidth = 0;
+                _this._outlineColor = "white";
                 /**
                 /**
                 * An event triggered after the text is changed
                 * An event triggered after the text is changed
                 * @type {BABYLON.Observable}
                 * @type {BABYLON.Observable}
@@ -3383,6 +3407,46 @@ var BABYLON;
                 enumerable: true,
                 enumerable: true,
                 configurable: true
                 configurable: true
             });
             });
+            Object.defineProperty(TextBlock.prototype, "outlineWidth", {
+                /**
+                 * Gets or sets outlineWidth of the text to display
+                 */
+                get: function () {
+                    return this._outlineWidth;
+                },
+                /**
+                 * Gets or sets outlineWidth of the text to display
+                 */
+                set: function (value) {
+                    if (this._outlineWidth === value) {
+                        return;
+                    }
+                    this._outlineWidth = value;
+                    this._markAsDirty();
+                },
+                enumerable: true,
+                configurable: true
+            });
+            Object.defineProperty(TextBlock.prototype, "outlineColor", {
+                /**
+                 * Gets or sets outlineColor of the text to display
+                 */
+                get: function () {
+                    return this._outlineColor;
+                },
+                /**
+                 * Gets or sets outlineColor of the text to display
+                 */
+                set: function (value) {
+                    if (this._outlineColor === value) {
+                        return;
+                    }
+                    this._outlineColor = value;
+                    this._markAsDirty();
+                },
+                enumerable: true,
+                configurable: true
+            });
             TextBlock.prototype._getTypeName = function () {
             TextBlock.prototype._getTypeName = function () {
                 return "TextBlock";
                 return "TextBlock";
             };
             };
@@ -3406,6 +3470,9 @@ var BABYLON;
                     context.shadowOffsetX = this.shadowOffsetX;
                     context.shadowOffsetX = this.shadowOffsetX;
                     context.shadowOffsetY = this.shadowOffsetY;
                     context.shadowOffsetY = this.shadowOffsetY;
                 }
                 }
+                if (this.outlineWidth) {
+                    context.strokeText(text, this._currentMeasure.left + x, y);
+                }
                 context.fillText(text, this._currentMeasure.left + x, y);
                 context.fillText(text, this._currentMeasure.left + x, y);
             };
             };
             /** @ignore */
             /** @ignore */
@@ -3418,6 +3485,13 @@ var BABYLON;
                 }
                 }
                 context.restore();
                 context.restore();
             };
             };
+            TextBlock.prototype._applyStates = function (context) {
+                _super.prototype._applyStates.call(this, context);
+                if (this.outlineWidth) {
+                    context.lineWidth = this.outlineWidth;
+                    context.strokeStyle = this.outlineColor;
+                }
+            };
             TextBlock.prototype._additionalProcessing = function (parentMeasure, context) {
             TextBlock.prototype._additionalProcessing = function (parentMeasure, context) {
                 this._lines = [];
                 this._lines = [];
                 var _lines = this.text.split("\n");
                 var _lines = this.text.split("\n");

Dosya farkı çok büyük olduğundan ihmal edildi
+ 3 - 3
dist/preview release/gui/babylon.gui.min.js


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

@@ -169,6 +169,7 @@ declare module BABYLON.GUI {
         protected _horizontalAlignment: number;
         protected _horizontalAlignment: number;
         protected _verticalAlignment: number;
         protected _verticalAlignment: number;
         private _isDirty;
         private _isDirty;
+        _tempParentMeasure: Measure;
         protected _cachedParentMeasure: Measure;
         protected _cachedParentMeasure: Measure;
         private _paddingLeft;
         private _paddingLeft;
         private _paddingRight;
         private _paddingRight;
@@ -253,6 +254,8 @@ declare module BABYLON.GUI {
         readonly heightInPixels: number;
         readonly heightInPixels: number;
         fontFamily: string;
         fontFamily: string;
         fontStyle: string;
         fontStyle: string;
+        /** @ignore */
+        readonly _isFontSizeInPercentage: boolean;
         readonly fontSizeInPixels: number;
         readonly fontSizeInPixels: number;
         fontSize: string | number;
         fontSize: string | number;
         color: string;
         color: string;
@@ -280,6 +283,8 @@ declare module BABYLON.GUI {
         readonly centerY: number;
         readonly centerY: number;
         constructor(name?: string | undefined);
         constructor(name?: string | undefined);
         protected _getTypeName(): string;
         protected _getTypeName(): string;
+        /** @ignore */
+        _resetFontCache(): void;
         getLocalCoordinates(globalCoordinates: Vector2): Vector2;
         getLocalCoordinates(globalCoordinates: Vector2): Vector2;
         getLocalCoordinatesToRef(globalCoordinates: Vector2, result: Vector2): Control;
         getLocalCoordinatesToRef(globalCoordinates: Vector2, result: Vector2): Control;
         getParentLocalCoordinates(globalCoordinates: Vector2): Vector2;
         getParentLocalCoordinates(globalCoordinates: Vector2): Vector2;
@@ -549,6 +554,8 @@ declare module BABYLON.GUI {
         private _lines;
         private _lines;
         private _resizeToFit;
         private _resizeToFit;
         private _lineSpacing;
         private _lineSpacing;
+        private _outlineWidth;
+        private _outlineColor;
         /**
         /**
         * An event triggered after the text is changed
         * An event triggered after the text is changed
         * @type {BABYLON.Observable}
         * @type {BABYLON.Observable}
@@ -606,6 +613,20 @@ declare module BABYLON.GUI {
          */
          */
         lineSpacing: string | number;
         lineSpacing: string | number;
         /**
         /**
+         * Gets or sets outlineWidth of the text to display
+         */
+        /**
+         * Gets or sets outlineWidth of the text to display
+         */
+        outlineWidth: number;
+        /**
+         * Gets or sets outlineColor of the text to display
+         */
+        /**
+         * Gets or sets outlineColor of the text to display
+         */
+        outlineColor: string;
+        /**
          * Creates a new TextBlock object
          * Creates a new TextBlock object
          * @param name defines the name of the control
          * @param name defines the name of the control
          * @param text defines the text to display (emptry string by default)
          * @param text defines the text to display (emptry string by default)
@@ -619,6 +640,7 @@ declare module BABYLON.GUI {
         private _drawText(text, textWidth, y, context);
         private _drawText(text, textWidth, y, context);
         /** @ignore */
         /** @ignore */
         _draw(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
         _draw(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
+        protected _applyStates(context: CanvasRenderingContext2D): void;
         protected _additionalProcessing(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
         protected _additionalProcessing(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
         protected _parseLine(line: string | undefined, context: CanvasRenderingContext2D): object;
         protected _parseLine(line: string | undefined, context: CanvasRenderingContext2D): object;
         protected _parseLineWithTextWrapping(line: string | undefined, context: CanvasRenderingContext2D): object;
         protected _parseLineWithTextWrapping(line: string | undefined, context: CanvasRenderingContext2D): object;

Dosya farkı çok büyük olduğundan ihmal edildi
+ 4 - 4
dist/preview release/inspector/babylon.inspector.bundle.js


Dosya farkı çok büyük olduğundan ihmal edildi
+ 4 - 4
dist/preview release/inspector/babylon.inspector.min.js


Dosya farkı çok büyük olduğundan ihmal edildi
+ 2 - 2
dist/preview release/loaders/babylon.glTF1FileLoader.min.js


+ 1 - 0
dist/preview release/loaders/babylon.glTF2FileLoader.js

@@ -841,6 +841,7 @@ var BABYLON;
                     var material = GLTFLoader._GetProperty(context + "/material", this._gltf.materials, primitive.material);
                     var material = GLTFLoader._GetProperty(context + "/material", this._gltf.materials, primitive.material);
                     promises.push(this._loadMaterialAsync("#/materials/" + material._index, material, babylonMesh));
                     promises.push(this._loadMaterialAsync("#/materials/" + material._index, material, babylonMesh));
                 }
                 }
+                this.onMeshLoadedObservable.notifyObservers(babylonMesh);
                 return Promise.all(promises).then(function () {
                 return Promise.all(promises).then(function () {
                     babylonMesh.setEnabled(true);
                     babylonMesh.setEnabled(true);
                 });
                 });

Dosya farkı çok büyük olduğundan ihmal edildi
+ 2 - 2
dist/preview release/loaders/babylon.glTF2FileLoader.min.js


+ 1 - 0
dist/preview release/loaders/babylon.glTFFileLoader.js

@@ -3017,6 +3017,7 @@ var BABYLON;
                     var material = GLTFLoader._GetProperty(context + "/material", this._gltf.materials, primitive.material);
                     var material = GLTFLoader._GetProperty(context + "/material", this._gltf.materials, primitive.material);
                     promises.push(this._loadMaterialAsync("#/materials/" + material._index, material, babylonMesh));
                     promises.push(this._loadMaterialAsync("#/materials/" + material._index, material, babylonMesh));
                 }
                 }
+                this.onMeshLoadedObservable.notifyObservers(babylonMesh);
                 return Promise.all(promises).then(function () {
                 return Promise.all(promises).then(function () {
                     babylonMesh.setEnabled(true);
                     babylonMesh.setEnabled(true);
                 });
                 });

Dosya farkı çok büyük olduğundan ihmal edildi
+ 3 - 3
dist/preview release/loaders/babylon.glTFFileLoader.min.js


Dosya farkı çok büyük olduğundan ihmal edildi
+ 1 - 1
dist/preview release/loaders/babylon.objFileLoader.min.js


+ 1 - 0
dist/preview release/loaders/babylonjs.loaders.js

@@ -3985,6 +3985,7 @@ var BABYLON;
                     var material = GLTFLoader._GetProperty(context + "/material", this._gltf.materials, primitive.material);
                     var material = GLTFLoader._GetProperty(context + "/material", this._gltf.materials, primitive.material);
                     promises.push(this._loadMaterialAsync("#/materials/" + material._index, material, babylonMesh));
                     promises.push(this._loadMaterialAsync("#/materials/" + material._index, material, babylonMesh));
                 }
                 }
+                this.onMeshLoadedObservable.notifyObservers(babylonMesh);
                 return Promise.all(promises).then(function () {
                 return Promise.all(promises).then(function () {
                     babylonMesh.setEnabled(true);
                     babylonMesh.setEnabled(true);
                 });
                 });

Dosya farkı çok büyük olduğundan ihmal edildi
+ 3 - 3
dist/preview release/loaders/babylonjs.loaders.min.js


Dosya farkı çok büyük olduğundan ihmal edildi
+ 1 - 1
dist/preview release/materialsLibrary/babylon.customMaterial.min.js


Dosya farkı çok büyük olduğundan ihmal edildi
+ 1 - 1
dist/preview release/materialsLibrary/babylon.shadowOnlyMaterial.min.js


Dosya farkı çok büyük olduğundan ihmal edildi
+ 1 - 1
dist/preview release/materialsLibrary/babylon.waterMaterial.min.js


Dosya farkı çok büyük olduğundan ihmal edildi
+ 3 - 3
dist/preview release/materialsLibrary/babylonjs.materials.min.js


Dosya farkı çok büyük olduğundan ihmal edildi
+ 1 - 1
dist/preview release/postProcessesLibrary/babylon.asciiArtPostProcess.min.js


Dosya farkı çok büyük olduğundan ihmal edildi
+ 1 - 1
dist/preview release/postProcessesLibrary/babylon.digitalRainPostProcess.min.js


Dosya farkı çok büyük olduğundan ihmal edildi
+ 1 - 1
dist/preview release/postProcessesLibrary/babylonjs.postProcess.min.js


Dosya farkı çok büyük olduğundan ihmal edildi
+ 1 - 1
dist/preview release/serializers/babylon.glTF2Serializer.min.js


Dosya farkı çok büyük olduğundan ihmal edildi
+ 1 - 1
dist/preview release/serializers/babylonjs.serializers.min.js


+ 2 - 424
dist/preview release/typedocValidationBaseline.json

@@ -1,7 +1,7 @@
 {
 {
-  "errors": 7341,
+  "errors": 7267,
   "babylon.typedoc.json": {
   "babylon.typedoc.json": {
-    "errors": 7341,
+    "errors": 7267,
     "AnimationKeyInterpolation": {
     "AnimationKeyInterpolation": {
       "Enumeration": {
       "Enumeration": {
         "Comments": {
         "Comments": {
@@ -334,11 +334,6 @@
             "MissingText": true
             "MissingText": true
           }
           }
         },
         },
-        "_isDisposed": {
-          "Comments": {
-            "MissingText": true
-          }
-        },
         "_lightSources": {
         "_lightSources": {
           "Comments": {
           "Comments": {
             "MissingText": true
             "MissingText": true
@@ -1195,11 +1190,6 @@
             }
             }
           }
           }
         },
         },
-        "isDisposed": {
-          "Comments": {
-            "MissingReturn": true
-          }
-        },
         "isInFrustum": {
         "isInFrustum": {
           "Comments": {
           "Comments": {
             "MissingReturn": true
             "MissingReturn": true
@@ -20141,418 +20131,6 @@
         }
         }
       }
       }
     },
     },
-    "Node": {
-      "Constructor": {
-        "new Node": {
-          "Comments": {
-            "MissingText": true,
-            "MissingReturn": true
-          },
-          "Parameter": {
-            "scene": {
-              "Comments": {
-                "MissingText": true
-              }
-            }
-          }
-        }
-      },
-      "Property": {
-        "_cache": {
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "_currentRenderId": {
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "_waitingParentId": {
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "animations": {
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "behaviors": {
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "doNotSerialize": {
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "id": {
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "metadata": {
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "name": {
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "onDispose": {
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "onReady": {
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "parent": {
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "state": {
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "uniqueId": {
-          "Comments": {
-            "MissingText": true
-          }
-        }
-      },
-      "Method": {
-        "_getDescendants": {
-          "Parameter": {
-            "predicate": {
-              "Comments": {
-                "MissingText": true
-              }
-            }
-          }
-        },
-        "_initCache": {
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "_isSynchronized": {
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "_markSyncedWithParent": {
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "_setReady": {
-          "Comments": {
-            "MissingText": true
-          },
-          "Parameter": {
-            "state": {
-              "Comments": {
-                "MissingText": true
-              }
-            }
-          }
-        },
-        "_updateCache": {
-          "Comments": {
-            "MissingText": true
-          },
-          "Parameter": {
-            "ignoreParentClass": {
-              "Comments": {
-                "MissingText": true
-              }
-            }
-          }
-        },
-        "addBehavior": {
-          "Comments": {
-            "MissingText": true
-          },
-          "Parameter": {
-            "behavior": {
-              "Comments": {
-                "MissingText": true
-              }
-            }
-          }
-        },
-        "computeWorldMatrix": {
-          "Comments": {
-            "MissingText": true
-          },
-          "Parameter": {
-            "force": {
-              "Comments": {
-                "MissingText": true
-              }
-            }
-          }
-        },
-        "createAnimationRange": {
-          "Comments": {
-            "MissingText": true
-          },
-          "Parameter": {
-            "name": {
-              "Comments": {
-                "MissingText": true
-              }
-            },
-            "from": {
-              "Comments": {
-                "MissingText": true
-              }
-            },
-            "to": {
-              "Comments": {
-                "MissingText": true
-              }
-            }
-          }
-        },
-        "deleteAnimationRange": {
-          "Comments": {
-            "MissingText": true
-          },
-          "Parameter": {
-            "name": {
-              "Comments": {
-                "MissingText": true
-              }
-            },
-            "deleteFrames": {
-              "Comments": {
-                "MissingText": true
-              }
-            }
-          }
-        },
-        "dispose": {
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "getAnimationByName": {
-          "Comments": {
-            "MissingText": true
-          },
-          "Parameter": {
-            "name": {
-              "Comments": {
-                "MissingText": true
-              }
-            }
-          }
-        },
-        "getAnimationRange": {
-          "Comments": {
-            "MissingText": true
-          },
-          "Parameter": {
-            "name": {
-              "Comments": {
-                "MissingText": true
-              }
-            }
-          }
-        },
-        "getBehaviorByName": {
-          "Comments": {
-            "MissingText": true
-          },
-          "Parameter": {
-            "name": {
-              "Comments": {
-                "MissingText": true
-              }
-            }
-          }
-        },
-        "getChildMeshes": {
-          "Comments": {
-            "MissingReturn": true
-          },
-          "Parameter": {
-            "directDescendantsOnly": {
-              "Comments": {
-                "MissingText": true
-              }
-            },
-            "predicate": {
-              "Comments": {
-                "MissingText": true
-              }
-            }
-          }
-        },
-        "getChildTransformNodes": {
-          "Comments": {
-            "MissingReturn": true
-          },
-          "Parameter": {
-            "directDescendantsOnly": {
-              "Comments": {
-                "MissingText": true
-              }
-            },
-            "predicate": {
-              "Comments": {
-                "MissingText": true
-              }
-            }
-          }
-        },
-        "getChildren": {
-          "Comments": {
-            "MissingReturn": true
-          },
-          "Parameter": {
-            "predicate": {
-              "Comments": {
-                "MissingText": true
-              }
-            }
-          }
-        },
-        "getClassName": {
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "getDescendants": {
-          "Parameter": {
-            "predicate": {
-              "Comments": {
-                "MissingText": true
-              }
-            }
-          }
-        },
-        "getEngine": {
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "getScene": {
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "getWorldMatrix": {
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "hasNewParent": {
-          "Comments": {
-            "MissingText": true
-          },
-          "Parameter": {
-            "update": {
-              "Comments": {
-                "MissingText": true
-              }
-            }
-          }
-        },
-        "isDescendantOf": {
-          "Comments": {
-            "MissingReturn": true
-          }
-        },
-        "isEnabled": {
-          "Parameter": {
-            "checkAncestors": {
-              "Comments": {
-                "MissingText": true
-              }
-            }
-          }
-        },
-        "isSynchronized": {
-          "Comments": {
-            "MissingText": true
-          },
-          "Parameter": {
-            "updateCache": {
-              "Comments": {
-                "MissingText": true
-              }
-            }
-          }
-        },
-        "isSynchronizedWithParent": {
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "removeBehavior": {
-          "Comments": {
-            "MissingText": true
-          },
-          "Parameter": {
-            "behavior": {
-              "Comments": {
-                "MissingText": true
-              }
-            }
-          }
-        },
-        "serializeAnimationRanges": {
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "updateCache": {
-          "Comments": {
-            "MissingText": true
-          },
-          "Parameter": {
-            "force": {
-              "Comments": {
-                "MissingText": true
-              }
-            }
-          }
-        },
-        "ParseAnimationRanges": {
-          "Comments": {
-            "MissingText": true
-          },
-          "Parameter": {
-            "node": {
-              "Comments": {
-                "MissingText": true
-              }
-            },
-            "parsedNode": {
-              "Comments": {
-                "MissingText": true
-              }
-            },
-            "scene": {
-              "Comments": {
-                "MissingText": true
-              }
-            }
-          }
-        }
-      }
-    },
     "NullEngineOptions": {
     "NullEngineOptions": {
       "Class": {
       "Class": {
         "Comments": {
         "Comments": {

Dosya farkı çok büyük olduğundan ihmal edildi
+ 66 - 66
dist/preview release/viewer/babylon.viewer.js


+ 6 - 2
dist/preview release/what's new.md

@@ -16,6 +16,7 @@
 ## Updates
 ## Updates
 
 
 - Tons of functions and classes received the code comments they deserved (All the community)
 - Tons of functions and classes received the code comments they deserved (All the community)
+- Added `particleSystem.reset()` to clear a particle system ([deltakosh](https://github.com/deltakosh))
 - Added support for all RGBA orders (BGR, RGB, etc..) for the DDS loader ([deltakosh](https://github.com/deltakosh))
 - Added support for all RGBA orders (BGR, RGB, etc..) for the DDS loader ([deltakosh](https://github.com/deltakosh))
 - Improved [SceneOptimizer](http://doc.babylonjs.com/how_to/how_to_use_sceneoptimizer) to provide better adaptability ([deltakosh](https://github.com/deltakosh))
 - Improved [SceneOptimizer](http://doc.babylonjs.com/how_to/how_to_use_sceneoptimizer) to provide better adaptability ([deltakosh](https://github.com/deltakosh))
 - Improved `scene.isReady()` function which now takes in account shadows and LOD ([deltakosh](https://github.com/deltakosh))
 - Improved `scene.isReady()` function which now takes in account shadows and LOD ([deltakosh](https://github.com/deltakosh))
@@ -26,7 +27,7 @@
   ([carloslanderas](https://github.com/carloslanderas))
   ([carloslanderas](https://github.com/carloslanderas))
 - VRHelper now has onBeforeCameraTeleport and onAfterCameraTeleport observables that will be notified before and after camera teleportation is triggered.
 - VRHelper now has onBeforeCameraTeleport and onAfterCameraTeleport observables that will be notified before and after camera teleportation is triggered.
   ([carloslanderas](https://github.com/carloslanderas))
   ([carloslanderas](https://github.com/carloslanderas))
-- VRHelper now has the public property teleportationEnabled to enable / disable camera teleportation. 
+- VRHelper now has the public property teleportationEnabled to enable / disable camera teleportation.
    ([carloslanderas](https://github.com/carloslanderas))
    ([carloslanderas](https://github.com/carloslanderas))
 - VRHelper now exposes onNewMeshPicked observable that will notify a PickingInfo object after meshSelectionPredicate evaluation
 - VRHelper now exposes onNewMeshPicked observable that will notify a PickingInfo object after meshSelectionPredicate evaluation
    ([carloslanderas](https://github.com/carloslanderas))
    ([carloslanderas](https://github.com/carloslanderas))
@@ -48,6 +49,7 @@
 - (Viewer) The viewer supports custom shaders in the configuration. ([RaananW](https://github.com/RaananW))
 - (Viewer) The viewer supports custom shaders in the configuration. ([RaananW](https://github.com/RaananW))
 - Documented PostProcessRenderEffect, DefaultRenderingPipeline, BlurPostProcess, DepthOfFieldEffect, PostProcess, PostProcessManager, Effect classes ([trevordev](https://github.com/trevordev))
 - Documented PostProcessRenderEffect, DefaultRenderingPipeline, BlurPostProcess, DepthOfFieldEffect, PostProcess, PostProcessManager, Effect classes ([trevordev](https://github.com/trevordev))
 - SPS internal storage of each solid particle rotation matrix ([jbousquie](https://github.com/jbousquie)) 
 - SPS internal storage of each solid particle rotation matrix ([jbousquie](https://github.com/jbousquie)) 
+- SPS particle parenting feature ([jbousquie](https://github.com/jbousquie))
 - (Viewer) Introducing the viewer labs - testing new features. ([RaananW](https://github.com/RaananW))
 - (Viewer) Introducing the viewer labs - testing new features. ([RaananW](https://github.com/RaananW))
 - AssetContainer Class and loading methods ([trevordev](https://github.com/trevordev))
 - AssetContainer Class and loading methods ([trevordev](https://github.com/trevordev))
 - KeepAssets class and AssetContainer.moveAllFromScene ([HoloLite](http://www.html5gamedevs.com/profile/28694-hololite/) [trevordev](https://github.com/trevordev))
 - KeepAssets class and AssetContainer.moveAllFromScene ([HoloLite](http://www.html5gamedevs.com/profile/28694-hololite/) [trevordev](https://github.com/trevordev))
@@ -63,6 +65,8 @@
 - Added promise-based async functions to the SceneLoader, Scene.whenReadyAsync, and material.forceCompilationAsync. ([bghgary](https://github.com/bghgary)]
 - Added promise-based async functions to the SceneLoader, Scene.whenReadyAsync, and material.forceCompilationAsync. ([bghgary](https://github.com/bghgary)]
 - Added checks to VertexData.merge to ensure data is valid before merging. ([bghgary](https://github.com/bghgary)]
 - Added checks to VertexData.merge to ensure data is valid before merging. ([bghgary](https://github.com/bghgary)]
 - Ability to set a mesh to customize the webVR gaze tracker ([trevordev](https://github.com/trevordev))
 - Ability to set a mesh to customize the webVR gaze tracker ([trevordev](https://github.com/trevordev))
+- Add stroke (outline) options on GUI text control ([SvenFrankson](https://github.com/SvenFrankson))
+- Add floating point texture support for RenderTargetCubeTexture ([PeapBoy](https://github.com/NicolasBuecher))
 
 
 ## Bug fixes
 ## Bug fixes
 
 
@@ -75,4 +79,4 @@
 
 
 - Removed the unused PostProcessRenderPass class and extended postProcessingRenderingEffect to support multiple PostProcesses ([trevordev](https://github.com/trevordev))
 - Removed the unused PostProcessRenderPass class and extended postProcessingRenderingEffect to support multiple PostProcesses ([trevordev](https://github.com/trevordev))
 - VertexData.merge no longer supports merging of data that do not have the same set of attributes. ([bghgary](https://github.com/bghgary)]
 - VertexData.merge no longer supports merging of data that do not have the same set of attributes. ([bghgary](https://github.com/bghgary)]
-- glTF 2.0 loader will now create a mesh for each primitive instead of merging the primitives together into one mesh. ([bghgary](https://github.com/bghgary)]
+- glTF 2.0 loader will now create a mesh for each primitive instead of merging the primitives together into one mesh. ([bghgary](https://github.com/bghgary)]

+ 6 - 0
gui/src/advancedDynamicTexture.ts

@@ -196,6 +196,12 @@ module BABYLON.GUI {
 
 
         public markAsDirty() {
         public markAsDirty() {
             this._isDirty = true;
             this._isDirty = true;
+
+            this.executeOnAllControls((control) => {
+                if (control._isFontSizeInPercentage) {
+                    control._resetFontCache();
+                }
+            });
         }
         }
 
 
         public addControl(control: Control): AdvancedDynamicTexture {
         public addControl(control: Control): AdvancedDynamicTexture {

+ 1 - 0
gui/src/controls/container.ts

@@ -159,6 +159,7 @@ module BABYLON.GUI {
                 this._clipForChildren(context);
                 this._clipForChildren(context);
                 for (var child of this._children) {
                 for (var child of this._children) {
                     if (child.isVisible && !child.notRenderable) {
                     if (child.isVisible && !child.notRenderable) {
+                        child._tempParentMeasure.copyFrom(this._measureForChildren);
                         child._draw(this._measureForChildren, context);
                         child._draw(this._measureForChildren, context);
 
 
                         if (child.onAfterDrawObservable.hasObservers()) {
                         if (child.onAfterDrawObservable.hasObservers()) {

+ 18 - 2
gui/src/controls/control.ts

@@ -20,6 +20,7 @@ module BABYLON.GUI {
         protected _horizontalAlignment = Control.HORIZONTAL_ALIGNMENT_CENTER;
         protected _horizontalAlignment = Control.HORIZONTAL_ALIGNMENT_CENTER;
         protected _verticalAlignment = Control.VERTICAL_ALIGNMENT_CENTER;
         protected _verticalAlignment = Control.VERTICAL_ALIGNMENT_CENTER;
         private _isDirty = true;
         private _isDirty = true;
+        public _tempParentMeasure = Measure.Empty();
         protected _cachedParentMeasure = Measure.Empty();
         protected _cachedParentMeasure = Measure.Empty();
         private _paddingLeft = new ValueAndUnit(0);
         private _paddingLeft = new ValueAndUnit(0);
         private _paddingRight = new ValueAndUnit(0);
         private _paddingRight = new ValueAndUnit(0);
@@ -277,8 +278,17 @@ module BABYLON.GUI {
             this._fontSet = true;
             this._fontSet = true;
         }
         }
 
 
+        /** @ignore */
+        public get _isFontSizeInPercentage(): boolean {
+            return this._fontSize.isPercentage;
+        }
+
         public get fontSizeInPixels(): number {
         public get fontSizeInPixels(): number {
-            return this._fontSize.getValueInPixel(this._host, 100);
+            if (this._fontSize.isPixel) {
+                return this._fontSize.getValue(this._host);
+            }
+
+            return this._fontSize.getValueInPixel(this._host, this._tempParentMeasure.height || this._cachedParentMeasure.height);
         }
         }
 
 
         public get fontSize(): string | number {
         public get fontSize(): string | number {
@@ -483,6 +493,11 @@ module BABYLON.GUI {
             return "Control";
             return "Control";
         }
         }
 
 
+        /** @ignore */
+        public _resetFontCache(): void {
+            this._fontSet = true;
+        }
+
         public getLocalCoordinates(globalCoordinates: Vector2): Vector2 {
         public getLocalCoordinates(globalCoordinates: Vector2): Vector2 {
             var result = Vector2.Zero();
             var result = Vector2.Zero();
 
 
@@ -948,12 +963,13 @@ module BABYLON.GUI {
             return false;
             return false;
         }
         }
 
 
+
         private _prepareFont() {
         private _prepareFont() {
             if (!this._font && !this._fontSet) {
             if (!this._font && !this._fontSet) {
                 return;
                 return;
             }
             }
 
 
-            this._font = this._fontStyle + " " + this._fontSize.getValue(this._host) + "px " + this._fontFamily;
+            this._font = this._fontStyle + " " + this.fontSizeInPixels + "px " + this._fontFamily;
 
 
             this._fontOffset = Control._GetFontOffset(this._font);
             this._fontOffset = Control._GetFontOffset(this._font);
         }
         }

+ 49 - 0
gui/src/controls/textBlock.ts

@@ -10,6 +10,8 @@ module BABYLON.GUI {
         private _lines: any[];
         private _lines: any[];
         private _resizeToFit: boolean = false;
         private _resizeToFit: boolean = false;
         private _lineSpacing: ValueAndUnit = new ValueAndUnit(0);
         private _lineSpacing: ValueAndUnit = new ValueAndUnit(0);
+        private _outlineWidth: number = 0;
+        private _outlineColor: string = "white";
         /**
         /**
         * An event triggered after the text is changed
         * An event triggered after the text is changed
         * @type {BABYLON.Observable}
         * @type {BABYLON.Observable}
@@ -141,6 +143,42 @@ module BABYLON.GUI {
         }
         }
 
 
         /**
         /**
+         * Gets or sets outlineWidth of the text to display
+         */
+        public get outlineWidth(): number {
+            return this._outlineWidth;
+        }
+
+        /**
+         * Gets or sets outlineWidth of the text to display
+         */
+        public set outlineWidth(value: number) {
+            if (this._outlineWidth === value) {
+                return;
+            }
+            this._outlineWidth = value;
+            this._markAsDirty();
+        }
+
+        /**
+         * Gets or sets outlineColor of the text to display
+         */
+        public get outlineColor(): string {
+            return this._outlineColor;
+        }
+
+        /**
+         * Gets or sets outlineColor of the text to display
+         */
+        public set outlineColor(value: string) {
+            if (this._outlineColor === value) {
+                return;
+            }
+            this._outlineColor = value;
+            this._markAsDirty();
+        }
+
+        /**
          * Creates a new TextBlock object
          * Creates a new TextBlock object
          * @param name defines the name of the control
          * @param name defines the name of the control
          * @param text defines the text to display (emptry string by default)
          * @param text defines the text to display (emptry string by default)
@@ -182,6 +220,9 @@ module BABYLON.GUI {
                 context.shadowOffsetY = this.shadowOffsetY;
                 context.shadowOffsetY = this.shadowOffsetY;
             }
             }
 
 
+            if (this.outlineWidth) {
+                context.strokeText(text, this._currentMeasure.left + x, y);
+            }
             context.fillText(text, this._currentMeasure.left + x, y);
             context.fillText(text, this._currentMeasure.left + x, y);
         }
         }
 
 
@@ -198,6 +239,14 @@ module BABYLON.GUI {
             context.restore();
             context.restore();
         }
         }
 
 
+        protected _applyStates(context: CanvasRenderingContext2D): void {
+            super._applyStates(context);
+            if (this.outlineWidth) {
+                context.lineWidth = this.outlineWidth;
+                context.strokeStyle = this.outlineColor;
+            }
+        }
+
         protected _additionalProcessing(parentMeasure: Measure, context: CanvasRenderingContext2D): void {
         protected _additionalProcessing(parentMeasure: Measure, context: CanvasRenderingContext2D): void {
             this._lines = [];
             this._lines = [];
             var _lines = this.text.split("\n");
             var _lines = this.text.split("\n");

+ 2 - 0
loaders/src/glTF/2.0/babylon.glTFLoader.ts

@@ -438,6 +438,8 @@ module BABYLON.GLTF2 {
                 promises.push(this._loadMaterialAsync("#/materials/" + material._index, material, babylonMesh));
                 promises.push(this._loadMaterialAsync("#/materials/" + material._index, material, babylonMesh));
             }
             }
 
 
+            this.onMeshLoadedObservable.notifyObservers(babylonMesh);
+
             return Promise.all(promises).then(() => {
             return Promise.all(promises).then(() => {
                 babylonMesh.setEnabled(true);
                 babylonMesh.setEnabled(true);
             });
             });

+ 0 - 28
sandbox/index.js

@@ -20,7 +20,6 @@ if (BABYLON.Engine.isSupported()) {
     var currentSkybox;
     var currentSkybox;
     var enableDebugLayer = false;
     var enableDebugLayer = false;
     var currentPluginName;
     var currentPluginName;
-    var toExecuteAfterSceneCreation;
 
 
     canvas.addEventListener("contextmenu", function (evt) {
     canvas.addEventListener("contextmenu", function (evt) {
         evt.preventDefault();
         evt.preventDefault();
@@ -129,10 +128,6 @@ if (BABYLON.Engine.isSupported()) {
             }
             }
         }
         }
 
 
-        if (toExecuteAfterSceneCreation) {
-            toExecuteAfterSceneCreation();
-        }
-
     };
     };
 
 
     var sceneError = function (sceneFile, babylonScene, message) {
     var sceneError = function (sceneFile, babylonScene, message) {
@@ -152,29 +147,6 @@ if (BABYLON.Engine.isSupported()) {
     };
     };
 
 
     filesInput = new BABYLON.FilesInput(engine, null, sceneLoaded, null, null, null, function () { BABYLON.Tools.ClearLogCache() }, null, sceneError);
     filesInput = new BABYLON.FilesInput(engine, null, sceneLoaded, null, null, null, function () { BABYLON.Tools.ClearLogCache() }, null, sceneError);
-    filesInput.onProcessFileCallback = (function (file, name, extension) {
-        if (extension === "dds") {
-            BABYLON.FilesInput.FilesToLoad[name] = file;
-            var loadTexture = () => {
-                if (currentPluginName === "gltf") { // currentPluginName is updated only once scene is loaded
-                    var newHdrTexture = BABYLON.CubeTexture.CreateFromPrefilteredData("file:" + file.correctName, currentScene);
-                    if (currentSkybox) {
-                        currentSkybox.dispose();
-                    }
-                    currentSkybox = currentScene.createDefaultSkybox(newHdrTexture, true, (currentScene.activeCamera.maxZ - currentScene.activeCamera.minZ) / 2, 0.3);
-                }
-            }
-            if (currentScene) {
-                loadTexture();
-            }
-            else {
-                // Postpone texture loading until scene is loaded
-                toExecuteAfterSceneCreation = loadTexture;
-            }
-            return false;
-        }
-        return true;
-    }).bind(this);
     filesInput.monitorElementForDragNDrop(canvas);
     filesInput.monitorElementForDragNDrop(canvas);
 
 
     window.addEventListener("keydown", function (evt) {
     window.addEventListener("keydown", function (evt) {

+ 1 - 1
src/Animations/babylon.animatable.ts

@@ -110,7 +110,7 @@
                 var fps = runtimeAnimations[0].animation.framePerSecond;
                 var fps = runtimeAnimations[0].animation.framePerSecond;
                 var currentFrame = runtimeAnimations[0].currentFrame;
                 var currentFrame = runtimeAnimations[0].currentFrame;
                 var adjustTime = frame - currentFrame;
                 var adjustTime = frame - currentFrame;
-                var delay = adjustTime * 1000 / fps;
+                var delay = adjustTime * 1000 / (fps * this.speedRatio);
                 if (this._localDelayOffset === null) {
                 if (this._localDelayOffset === null) {
                     this._localDelayOffset = 0;
                     this._localDelayOffset = 0;
                 }
                 }

+ 1 - 1
src/Audio/babylon.soundtrack.ts

@@ -35,7 +35,7 @@
         }
         }
 
 
         public dispose() {
         public dispose() {
-            if (Engine.audioEngine.canUseWebAudio) {
+            if (Engine.audioEngine && Engine.audioEngine.canUseWebAudio) {
                 if (this._connectedAnalyser) {
                 if (this._connectedAnalyser) {
                     this._connectedAnalyser.stopDebugCanvas();
                     this._connectedAnalyser.stopDebugCanvas();
                 }
                 }

+ 40 - 33
src/Engine/babylon.engine.ts

@@ -3987,37 +3987,35 @@
             this._gl.compressedTexImage2D(target, lod, internalFormat, width, height, 0, data);
             this._gl.compressedTexImage2D(target, lod, internalFormat, width, height, 0, data);
         }
         }
 
 
-        public createRenderTargetCubeTexture(size: number, options?: RenderTargetCreationOptions): InternalTexture {
-            var gl = this._gl;
-
-            var texture = new InternalTexture(this, InternalTexture.DATASOURCE_RENDERTARGET);
-
-            var generateMipMaps = true;
-            var generateDepthBuffer = true;
-            var generateStencilBuffer = false;
-
-            var samplingMode = Texture.TRILINEAR_SAMPLINGMODE;
-            if (options !== undefined) {
-                generateMipMaps = options.generateMipMaps === undefined ? true : options.generateMipMaps;
-                generateDepthBuffer = options.generateDepthBuffer === undefined ? true : options.generateDepthBuffer;
-                generateStencilBuffer = (generateDepthBuffer && options.generateStencilBuffer) ? true : false;
+        public createRenderTargetCubeTexture(size: number, options?: Partial<RenderTargetCreationOptions>): InternalTexture {
+            let fullOptions = {
+              generateMipMaps: true,
+              generateDepthBuffer: true,
+              generateStencilBuffer: false,
+              type: Engine.TEXTURETYPE_UNSIGNED_INT,
+              samplingMode: Texture.TRILINEAR_SAMPLINGMODE,
+              ...options
+            };
+            fullOptions.generateStencilBuffer = fullOptions.generateDepthBuffer && fullOptions.generateStencilBuffer;
 
 
-                if (options.samplingMode !== undefined) {
-                    samplingMode = options.samplingMode;
-                }
+            if (fullOptions.type === Engine.TEXTURETYPE_FLOAT && !this._caps.textureFloatLinearFiltering) {
+              // if floating point linear (gl.FLOAT) then force to NEAREST_SAMPLINGMODE
+              fullOptions.samplingMode = Texture.NEAREST_SAMPLINGMODE;
             }
             }
+            else if (fullOptions.type === Engine.TEXTURETYPE_HALF_FLOAT && !this._caps.textureHalfFloatLinearFiltering) {
+              // if floating point linear (HALF_FLOAT) then force to NEAREST_SAMPLINGMODE
+              fullOptions.samplingMode = Texture.NEAREST_SAMPLINGMODE;
+            }
+            var gl = this._gl
 
 
-            texture.isCube = true;
-            texture.generateMipMaps = generateMipMaps;
-            texture.samples = 1;
-            texture.samplingMode = samplingMode;
-
-            var filters = getSamplingParameters(samplingMode, generateMipMaps, gl);
-
+            var texture = new InternalTexture(this, InternalTexture.DATASOURCE_RENDERTARGET);
             this._bindTextureDirectly(gl.TEXTURE_CUBE_MAP, texture, true);
             this._bindTextureDirectly(gl.TEXTURE_CUBE_MAP, texture, true);
 
 
-            for (var face = 0; face < 6; face++) {
-                gl.texImage2D((gl.TEXTURE_CUBE_MAP_POSITIVE_X + face), 0, gl.RGBA, size, size, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
+            var filters = getSamplingParameters(fullOptions.samplingMode, fullOptions.generateMipMaps, gl);
+
+            if (fullOptions.type === Engine.TEXTURETYPE_FLOAT && !this._caps.textureFloat) {
+              fullOptions.type = Engine.TEXTURETYPE_UNSIGNED_INT;
+              Tools.Warn("Float textures are not supported. Cube render target forced to TEXTURETYPE_UNESIGNED_BYTE type");
             }
             }
 
 
             gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MAG_FILTER, filters.mag);
             gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MAG_FILTER, filters.mag);
@@ -4025,15 +4023,19 @@
             gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
             gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
             gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
             gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
 
 
+            for (var face = 0; face < 6; face++) {
+                gl.texImage2D((gl.TEXTURE_CUBE_MAP_POSITIVE_X + face), 0, this._getRGBABufferInternalSizedFormat(fullOptions.type), size, size, 0, gl.RGBA, this._getWebGLTextureType(fullOptions.type), null);
+            }
+
             // Create the framebuffer
             // Create the framebuffer
             var framebuffer = gl.createFramebuffer();
             var framebuffer = gl.createFramebuffer();
             this.bindUnboundFramebuffer(framebuffer);
             this.bindUnboundFramebuffer(framebuffer);
 
 
-            texture._depthStencilBuffer = this._setupFramebufferDepthAttachments(generateStencilBuffer, generateDepthBuffer, size, size);
+            texture._depthStencilBuffer = this._setupFramebufferDepthAttachments(fullOptions.generateStencilBuffer, fullOptions.generateDepthBuffer, size, size);
 
 
-            // Mipmaps
-            if (texture.generateMipMaps) {
-                gl.generateMipmap(gl.TEXTURE_CUBE_MAP);
+            // MipMaps
+            if (fullOptions.generateMipMaps) {
+              gl.generateMipmap(gl.TEXTURE_CUBE_MAP);
             }
             }
 
 
             // Unbind
             // Unbind
@@ -4045,8 +4047,13 @@
             texture.width = size;
             texture.width = size;
             texture.height = size;
             texture.height = size;
             texture.isReady = true;
             texture.isReady = true;
-
-            //this.resetTextureCache();
+            texture.isCube = true;
+            texture.samples = 1;
+            texture.generateMipMaps = fullOptions.generateMipMaps;
+            texture.samplingMode = fullOptions.samplingMode;
+            texture.type = fullOptions.type;
+            texture._generateDepthBuffer = fullOptions.generateDepthBuffer;
+            texture._generateStencilBuffer = fullOptions.generateStencilBuffer;
 
 
             this._internalTexturesCache.push(texture);
             this._internalTexturesCache.push(texture);
 
 
@@ -4814,7 +4821,7 @@
             if (this.disableTextureBindingOptimization) {
             if (this.disableTextureBindingOptimization) {
                 return -1;
                 return -1;
             }
             }
-            
+
             // Remove from bound list
             // Remove from bound list
             this._linkTrackers(internalTexture.previous, internalTexture.next);
             this._linkTrackers(internalTexture.previous, internalTexture.next);
 
 

+ 0 - 1
src/Engine/babylon.nullEngine.ts

@@ -265,7 +265,6 @@
 
 
                 this._stencilState.reset();
                 this._stencilState.reset();
                 this._depthCullingState.reset();
                 this._depthCullingState.reset();
-                this.setDepthFunctionToLessOrEqual();
                 this._alphaState.reset();
                 this._alphaState.reset();
             }
             }
 
 

+ 38 - 20
src/Layer/babylon.glowLayer.ts

@@ -101,6 +101,15 @@
         private _excludedMeshes: number[] = [];
         private _excludedMeshes: number[] = [];
 
 
         /**
         /**
+         * Callback used to let the user override the color selection on a per mesh basis
+         */
+        public customEmissiveColorSelector: (mesh: Mesh, subMesh: SubMesh, material: Material, result: Color4) => void;
+        /**
+         * Callback used to let the user override the texture selection on a per mesh basis
+         */
+        public customEmissiveTextureSelector: (mesh: Mesh, subMesh: SubMesh, material: Material) => Texture;
+
+        /**
          * Instantiates a new glow Layer and references it to the scene.
          * Instantiates a new glow Layer and references it to the scene.
          * @param name The name of the layer
          * @param name The name of the layer
          * @param scene The scene to use the layer in
          * @param scene The scene to use the layer in
@@ -310,29 +319,38 @@
          */
          */
         protected _setEmissiveTextureAndColor(mesh: Mesh, subMesh: SubMesh, material: Material): void {
         protected _setEmissiveTextureAndColor(mesh: Mesh, subMesh: SubMesh, material: Material): void {
             var textureLevel = 1.0;
             var textureLevel = 1.0;
-            if (material) {
-                this._emissiveTextureAndColor.texture = (<any>material).emissiveTexture;
-                if (this._emissiveTextureAndColor.texture) {
-                    textureLevel = this._emissiveTextureAndColor.texture.level;
+
+            if (this.customEmissiveTextureSelector) {
+                this._emissiveTextureAndColor.texture = this.customEmissiveTextureSelector(mesh, subMesh, material);
+            } else {
+                if (material) {
+                    this._emissiveTextureAndColor.texture = (<any>material).emissiveTexture;
+                    if (this._emissiveTextureAndColor.texture) {
+                        textureLevel = this._emissiveTextureAndColor.texture.level;
+                    }
+                }
+                else {
+                    this._emissiveTextureAndColor.texture = null;
                 }
                 }
-            }
-            else {
-                this._emissiveTextureAndColor.texture = null;
             }
             }
 
 
-            if ((<any>material).emissiveColor) {
-                this._emissiveTextureAndColor.color.set(
-                    (<any>material).emissiveColor.r * textureLevel,
-                    (<any>material).emissiveColor.g * textureLevel,
-                    (<any>material).emissiveColor .b * textureLevel,
-                    1.0);
-            }
-            else {
-                this._emissiveTextureAndColor.color.set(
-                    this.neutralColor.r,
-                    this.neutralColor.g,
-                    this.neutralColor.b,
-                    this.neutralColor.a);
+            if (this.customEmissiveColorSelector) {
+                this.customEmissiveColorSelector(mesh, subMesh, material, this._emissiveTextureAndColor.color);
+            } else {
+                if ((<any>material).emissiveColor) {
+                    this._emissiveTextureAndColor.color.set(
+                        (<any>material).emissiveColor.r * textureLevel,
+                        (<any>material).emissiveColor.g * textureLevel,
+                        (<any>material).emissiveColor .b * textureLevel,
+                        1.0);
+                }
+                else {
+                    this._emissiveTextureAndColor.color.set(
+                        this.neutralColor.r,
+                        this.neutralColor.g,
+                        this.neutralColor.b,
+                        this.neutralColor.a);
+                }
             }
             }
         }
         }
 
 

+ 5 - 0
src/Layer/babylon.highlightLayer.ts

@@ -230,6 +230,9 @@
                 mainTextureFixedSize: this._options.mainTextureFixedSize,
                 mainTextureFixedSize: this._options.mainTextureFixedSize,
                 mainTextureRatio: this._options.mainTextureRatio
                 mainTextureRatio: this._options.mainTextureRatio
             });
             });
+
+            // Do not render as long as no meshes have been added
+            this._shouldRender = false;
         }
         }
 
 
         /**
         /**
@@ -388,6 +391,7 @@
             var previousStencilOperationPass = engine.getStencilOperationPass();
             var previousStencilOperationPass = engine.getStencilOperationPass();
             var previousStencilOperationFail = engine.getStencilOperationFail();
             var previousStencilOperationFail = engine.getStencilOperationFail();
             var previousStencilOperationDepthFail = engine.getStencilOperationDepthFail();
             var previousStencilOperationDepthFail = engine.getStencilOperationDepthFail();
+            var previousStencilReference = engine.getStencilFunctionReference();
 
 
             // Stencil operations
             // Stencil operations
             engine.setStencilOperationPass(Engine.REPLACE);
             engine.setStencilOperationPass(Engine.REPLACE);
@@ -418,6 +422,7 @@
             engine.setStencilOperationPass(previousStencilOperationPass);
             engine.setStencilOperationPass(previousStencilOperationPass);
             engine.setStencilOperationFail(previousStencilOperationFail);
             engine.setStencilOperationFail(previousStencilOperationFail);
             engine.setStencilOperationDepthFail(previousStencilOperationDepthFail);
             engine.setStencilOperationDepthFail(previousStencilOperationDepthFail);
+            engine.setStencilFunctionReference(previousStencilReference);
         }
         }
 
 
         /**
         /**

+ 2 - 2
src/Loading/Plugins/babylon.babylonFileLoader.ts

@@ -644,7 +644,7 @@
                 }
                 }
                 scene.workerCollisions = !!parsedData.workerCollisions;
                 scene.workerCollisions = !!parsedData.workerCollisions;
 
 
-                var container = loadAssetContainer(scene, data, rootUrl, onerror, true);
+                var container = loadAssetContainer(scene, data, rootUrl, onError, true);
                 if (!container) {
                 if (!container) {
                     return false;
                     return false;
                 }
                 }
@@ -684,7 +684,7 @@
             return false;
             return false;
         },
         },
         loadAssetContainer: (scene: Scene, data: string, rootUrl: string, onError?: (message: string, exception?: any) => void): AssetContainer => {
         loadAssetContainer: (scene: Scene, data: string, rootUrl: string, onError?: (message: string, exception?: any) => void): AssetContainer => {
-            var container = loadAssetContainer(scene, data, rootUrl, onerror);
+            var container = loadAssetContainer(scene, data, rootUrl, onError);
             return container;
             return container;
         }
         }
     });
     });

+ 17 - 10
src/Materials/PBR/babylon.pbrBaseMaterial.ts

@@ -57,6 +57,7 @@
         public TANGENT = false;
         public TANGENT = false;
         public BUMP = false;
         public BUMP = false;
         public BUMPDIRECTUV = 0;
         public BUMPDIRECTUV = 0;
+        public OBJECTSPACE_NORMALMAP = false;
         public PARALLAX = false;
         public PARALLAX = false;
         public PARALLAXOCCLUSION = false;
         public PARALLAXOCCLUSION = false;
         public NORMALXYSCALE = true;
         public NORMALXYSCALE = true;
@@ -387,6 +388,11 @@
         protected _useRadianceOverAlpha = true;
         protected _useRadianceOverAlpha = true;
 
 
         /**
         /**
+         * Allows using an object space normal map (instead of tangent space).
+         */
+        protected _useObjectSpaceNormalMap = false;
+
+        /**
          * Allows using the bump map in parallax mode.
          * Allows using the bump map in parallax mode.
          */
          */
         protected _useParallax = false;
         protected _useParallax = false;
@@ -932,7 +938,7 @@
                 "vAlbedoInfos", "vAmbientInfos", "vOpacityInfos", "vReflectionInfos", "vReflectionPosition", "vReflectionSize", "vEmissiveInfos", "vReflectivityInfos", 
                 "vAlbedoInfos", "vAmbientInfos", "vOpacityInfos", "vReflectionInfos", "vReflectionPosition", "vReflectionSize", "vEmissiveInfos", "vReflectivityInfos", 
                 "vMicroSurfaceSamplerInfos", "vBumpInfos", "vLightmapInfos", "vRefractionInfos",
                 "vMicroSurfaceSamplerInfos", "vBumpInfos", "vLightmapInfos", "vRefractionInfos",
                 "mBones",
                 "mBones",
-                "vClipPlane", "albedoMatrix", "ambientMatrix", "opacityMatrix", "reflectionMatrix", "emissiveMatrix", "reflectivityMatrix", "microSurfaceSamplerMatrix", "bumpMatrix", "lightmapMatrix", "refractionMatrix",
+                "vClipPlane", "albedoMatrix", "ambientMatrix", "opacityMatrix", "reflectionMatrix", "emissiveMatrix", "reflectivityMatrix", "normalMatrix", "microSurfaceSamplerMatrix", "bumpMatrix", "lightmapMatrix", "refractionMatrix",
                 "vLightingIntensity",
                 "vLightingIntensity",
                 "logarithmicDepthConstant",
                 "logarithmicDepthConstant",
                 "vSphericalX", "vSphericalY", "vSphericalZ",
                 "vSphericalX", "vSphericalY", "vSphericalZ",
@@ -1139,9 +1145,11 @@
                         else {
                         else {
                             defines.PARALLAX = false;
                             defines.PARALLAX = false;
                         }
                         }
+                        
+                        defines.OBJECTSPACE_NORMALMAP = this._useObjectSpaceNormalMap;
                     } else {
                     } else {
                         defines.BUMP = false;
                         defines.BUMP = false;
-                    }
+                    }                
 
 
                     var refractionTexture = this._getRefractionTexture();
                     var refractionTexture = this._getRefractionTexture();
                     if (refractionTexture && StandardMaterial.RefractionTextureEnabled) {
                     if (refractionTexture && StandardMaterial.RefractionTextureEnabled) {
@@ -1299,14 +1307,6 @@
         }
         }
 
 
         /**
         /**
-         * Binds to the world matrix.
-         * @param world - The world matrix.
-         */
-        public bindOnlyWorldMatrix(world: Matrix): void {
-            this._activeEffect.setMatrix("world", world);
-        }
-
-        /**
          * Binds the submesh data.
          * Binds the submesh data.
          * @param world - The world matrix.
          * @param world - The world matrix.
          * @param mesh - The BJS mesh.
          * @param mesh - The BJS mesh.
@@ -1331,6 +1331,13 @@
             // Matrices
             // Matrices
             this.bindOnlyWorldMatrix(world);
             this.bindOnlyWorldMatrix(world);
 
 
+            // Normal Matrix
+            if (defines.OBJECTSPACE_NORMALMAP)
+            {
+                world.toNormalMatrix(this._normalMatrix);
+                this.bindOnlyNormalMatrix(this._normalMatrix);                
+            }
+
             let mustRebind = this._mustRebind(scene, effect, mesh.visibility);
             let mustRebind = this._mustRebind(scene, effect, mesh.visibility);
 
 
             // Bones
             // Bones

+ 7 - 0
src/Materials/PBR/babylon.pbrMaterial.ts

@@ -358,6 +358,13 @@
         public useRadianceOverAlpha = true;
         public useRadianceOverAlpha = true;
 
 
         /**
         /**
+         * Allows using an object space normal map (instead of tangent space).
+         */
+        @serialize()
+        @expandToProperty("_markAllSubMeshesAsTexturesDirty")
+        public useObjectSpaceNormalMap = false;
+        
+        /**
          * Allows using the bump map in parallax mode.
          * Allows using the bump map in parallax mode.
          */
          */
         @serialize()
         @serialize()

+ 23 - 6
src/Materials/babylon.effect.ts

@@ -64,22 +64,39 @@
 
 
         /**
         /**
          * Removes the defines that shoould be removed when falling back.
          * Removes the defines that shoould be removed when falling back.
-         * @param currentDefines The current define statements for the shader.
+         * @param currentDefines defines the current define statements for the shader.
+         * @param effect defines the current effect we try to compile
          * @returns The resulting defines with defines of the current rank removed.
          * @returns The resulting defines with defines of the current rank removed.
          */
          */
-        public reduce(currentDefines: string): string {
+        public reduce(currentDefines: string, effect: Effect): string {
             // First we try to switch to CPU skinning
             // First we try to switch to CPU skinning
-            if (this._mesh && this._mesh.computeBonesUsingShaders && this._mesh.numBoneInfluencers > 0) {
+            if (this._mesh && this._mesh.computeBonesUsingShaders && this._mesh.numBoneInfluencers > 0 && this._mesh.material) {
                 this._mesh.computeBonesUsingShaders = false;
                 this._mesh.computeBonesUsingShaders = false;
                 currentDefines = currentDefines.replace("#define NUM_BONE_INFLUENCERS " + this._mesh.numBoneInfluencers, "#define NUM_BONE_INFLUENCERS 0");
                 currentDefines = currentDefines.replace("#define NUM_BONE_INFLUENCERS " + this._mesh.numBoneInfluencers, "#define NUM_BONE_INFLUENCERS 0");
-                Tools.Log("Falling back to CPU skinning for " + this._mesh.name);
 
 
                 var scene = this._mesh.getScene();
                 var scene = this._mesh.getScene();
                 for (var index = 0; index < scene.meshes.length; index++) {
                 for (var index = 0; index < scene.meshes.length; index++) {
                     var otherMesh = scene.meshes[index];
                     var otherMesh = scene.meshes[index];
 
 
-                    if (otherMesh.material === this._mesh.material && otherMesh.computeBonesUsingShaders && otherMesh.numBoneInfluencers > 0) {
+                    if (!otherMesh.material) {
+                        continue;
+                    }
+
+                    if (!otherMesh.computeBonesUsingShaders || otherMesh.numBoneInfluencers === 0) {
+                        continue;
+                    }
+
+                    if (otherMesh.material.getEffect() === effect) {
                         otherMesh.computeBonesUsingShaders = false;
                         otherMesh.computeBonesUsingShaders = false;
+                    } else {
+                        for (var subMesh of otherMesh.subMeshes) {
+                            let subMeshEffect = subMesh.effect;
+
+                            if (subMeshEffect === effect) {
+                                otherMesh.computeBonesUsingShaders = false;
+                                break;
+                            }
+                        }
                     }
                     }
                 }
                 }
             }
             }
@@ -808,7 +825,7 @@
 
 
                 if (fallbacks && fallbacks.isMoreFallbacks) {
                 if (fallbacks && fallbacks.isMoreFallbacks) {
                     Tools.Error("Trying next fallback.");
                     Tools.Error("Trying next fallback.");
-                    this.defines = fallbacks.reduce(this.defines);
+                    this.defines = fallbacks.reduce(this.defines, this);
                     this._prepareEffect();
                     this._prepareEffect();
                 } else { // Sorry we did everything we can
                 } else { // Sorry we did everything we can
 
 

+ 16 - 0
src/Materials/babylon.pushMaterial.ts

@@ -3,6 +3,8 @@
 
 
         protected _activeEffect: Effect;
         protected _activeEffect: Effect;
 
 
+        protected _normalMatrix : Matrix = new Matrix();
+
         constructor(name: string, scene: Scene) {
         constructor(name: string, scene: Scene) {
             super(name, scene);
             super(name, scene);
             this.storeEffectOnSubMeshes = true;
             this.storeEffectOnSubMeshes = true;
@@ -24,10 +26,24 @@
             return this.isReadyForSubMesh(mesh, mesh.subMeshes[0], useInstances);
             return this.isReadyForSubMesh(mesh, mesh.subMeshes[0], useInstances);
         }
         }
 
 
+         /**
+         * Binds the given world matrix to the active effect
+         * 
+         * @param world the matrix to bind
+         */
         public bindOnlyWorldMatrix(world: Matrix): void {
         public bindOnlyWorldMatrix(world: Matrix): void {
             this._activeEffect.setMatrix("world", world);
             this._activeEffect.setMatrix("world", world);
         }
         }
 
 
+        /**
+         * Binds the given normal matrix to the active effect
+         * 
+         * @param normalMatrix the matrix to bind
+         */
+        public bindOnlyNormalMatrix(normalMatrix: Matrix): void {                        
+            this._activeEffect.setMatrix("normalMatrix", normalMatrix);
+        }
+
         public bind(world: Matrix, mesh?: Mesh): void {
         public bind(world: Matrix, mesh?: Mesh): void {
             if (!mesh) {
             if (!mesh) {
                 return;
                 return;

+ 20 - 2
src/Materials/babylon.standardMaterial.ts

@@ -48,6 +48,7 @@ module BABYLON {
         public REFLECTIONFRESNELFROMSPECULAR = false;
         public REFLECTIONFRESNELFROMSPECULAR = false;
         public LIGHTMAP = false;
         public LIGHTMAP = false;
         public LIGHTMAPDIRECTUV = 0;
         public LIGHTMAPDIRECTUV = 0;
+        public OBJECTSPACE_NORMALMAP = false;
         public USELIGHTMAPASSHADOWMAP = false;
         public USELIGHTMAPASSHADOWMAP = false;
         public REFLECTIONMAP_3D = false;
         public REFLECTIONMAP_3D = false;
         public REFLECTIONMAP_SPHERICAL = false;
         public REFLECTIONMAP_SPHERICAL = false;
@@ -198,6 +199,14 @@ module BABYLON {
         @expandToProperty("_markAllSubMeshesAsLightsDirty")
         @expandToProperty("_markAllSubMeshesAsLightsDirty")
         public disableLighting: boolean;
         public disableLighting: boolean;
 
 
+        @serialize("useObjectSpaceNormalMap")
+        private _useObjectSpaceNormalMap = false;
+        /**
+         * Allows using an object space normal map (instead of tangent space).
+         */
+        @expandToProperty("_markAllSubMeshesAsTexturesDirty")
+        public useObjectSpaceNormalMap: boolean;
+
         @serialize("useParallax")
         @serialize("useParallax")
         private _useParallax = false;
         private _useParallax = false;
         @expandToProperty("_markAllSubMeshesAsTexturesDirty")
         @expandToProperty("_markAllSubMeshesAsTexturesDirty")
@@ -667,6 +676,8 @@ module BABYLON {
                             defines.PARALLAX = this._useParallax;
                             defines.PARALLAX = this._useParallax;
                             defines.PARALLAXOCCLUSION = this._useParallaxOcclusion;
                             defines.PARALLAXOCCLUSION = this._useParallaxOcclusion;
                         }
                         }
+
+                        defines.OBJECTSPACE_NORMALMAP = this._useObjectSpaceNormalMap;
                     } else {
                     } else {
                         defines.BUMP = false;
                         defines.BUMP = false;
                     }
                     }
@@ -849,7 +860,7 @@ module BABYLON {
                     "vFogInfos", "vFogColor", "pointSize",
                     "vFogInfos", "vFogColor", "pointSize",
                     "vDiffuseInfos", "vAmbientInfos", "vOpacityInfos", "vReflectionInfos", "vEmissiveInfos", "vSpecularInfos", "vBumpInfos", "vLightmapInfos", "vRefractionInfos",
                     "vDiffuseInfos", "vAmbientInfos", "vOpacityInfos", "vReflectionInfos", "vEmissiveInfos", "vSpecularInfos", "vBumpInfos", "vLightmapInfos", "vRefractionInfos",
                     "mBones",
                     "mBones",
-                    "vClipPlane", "diffuseMatrix", "ambientMatrix", "opacityMatrix", "reflectionMatrix", "emissiveMatrix", "specularMatrix", "bumpMatrix", "lightmapMatrix", "refractionMatrix",
+                    "vClipPlane", "diffuseMatrix", "ambientMatrix", "opacityMatrix", "reflectionMatrix", "emissiveMatrix", "specularMatrix", "bumpMatrix", "normalMatrix", "lightmapMatrix", "refractionMatrix",
                     "diffuseLeftColor", "diffuseRightColor", "opacityParts", "reflectionLeftColor", "reflectionRightColor", "emissiveLeftColor", "emissiveRightColor", "refractionLeftColor", "refractionRightColor",
                     "diffuseLeftColor", "diffuseRightColor", "opacityParts", "reflectionLeftColor", "reflectionRightColor", "emissiveLeftColor", "emissiveRightColor", "refractionLeftColor", "refractionRightColor",
                     "vReflectionPosition", "vReflectionSize",
                     "vReflectionPosition", "vReflectionSize",
                     "logarithmicDepthConstant", "vTangentSpaceParams"
                     "logarithmicDepthConstant", "vTangentSpaceParams"
@@ -973,6 +984,13 @@ module BABYLON {
             // Matrices        
             // Matrices        
             this.bindOnlyWorldMatrix(world);
             this.bindOnlyWorldMatrix(world);
 
 
+            // Normal Matrix
+            if (defines.OBJECTSPACE_NORMALMAP)
+            {
+                world.toNormalMatrix(this._normalMatrix);
+                this.bindOnlyNormalMatrix(this._normalMatrix);               
+            }
+
             let mustRebind = this._mustRebind(scene, effect, mesh.visibility);
             let mustRebind = this._mustRebind(scene, effect, mesh.visibility);
 
 
             // Bones
             // Bones
@@ -1160,7 +1178,7 @@ module BABYLON {
                 // View
                 // View
                 if (scene.fogEnabled && mesh.applyFog && scene.fogMode !== Scene.FOGMODE_NONE || this._reflectionTexture || this._refractionTexture) {
                 if (scene.fogEnabled && mesh.applyFog && scene.fogMode !== Scene.FOGMODE_NONE || this._reflectionTexture || this._refractionTexture) {
                     this.bindView(effect);
                     this.bindView(effect);
-                }
+                }              
 
 
                 // Fog
                 // Fog
                 MaterialHelper.BindFogParameters(scene, mesh, effect);
                 MaterialHelper.BindFogParameters(scene, mesh, effect);

+ 17 - 0
src/Math/babylon.math.ts

@@ -3894,6 +3894,22 @@
 
 
             return true;
             return true;
         }
         }
+
+        /**
+         * Writes to the given matrix a normal matrix, computed from this one (using values from identity matrix for fourth row and column).  
+         * @param ref matrix to store the result
+         */
+        public toNormalMatrix(ref : Matrix): void {            
+            this.invertToRef(ref)
+            ref.transpose();
+            var m = ref.m;
+            Matrix.FromValuesToRef(
+                m[0], m[1], m[2],  0,
+                m[4], m[5], m[6],  0,
+                m[8], m[9], m[10], 0,
+                0,    0,    0,     1, ref);
+        }
+
         /**
         /**
          * Returns a new Matrix as the extracted rotation matrix from the current one.  
          * Returns a new Matrix as the extracted rotation matrix from the current one.  
          */
          */
@@ -3902,6 +3918,7 @@
             this.getRotationMatrixToRef(result);
             this.getRotationMatrixToRef(result);
             return result;
             return result;
         }
         }
+       
         /**
         /**
          * Extracts the rotation matrix from the current one and sets it as the passed "result".  
          * Extracts the rotation matrix from the current one and sets it as the passed "result".  
          * Returns the current Matrix.  
          * Returns the current Matrix.  

+ 0 - 10
src/Mesh/babylon.abstractMesh.ts

@@ -412,7 +412,6 @@
         public _masterMesh: Nullable<AbstractMesh>;
         public _masterMesh: Nullable<AbstractMesh>;
 
 
         public _boundingInfo: Nullable<BoundingInfo>;
         public _boundingInfo: Nullable<BoundingInfo>;
-        public _isDisposed = false;
         public _renderId = 0;
         public _renderId = 0;
 
 
         public subMeshes: SubMesh[];
         public subMeshes: SubMesh[];
@@ -467,13 +466,6 @@
         }
         }
 
 
         /**
         /**
-         * Boolean : true if the mesh has been disposed.  
-         */
-        public isDisposed(): boolean {
-            return this._isDisposed;
-        }
-
-        /**
          * Returns the string "AbstractMesh"
          * Returns the string "AbstractMesh"
          */
          */
         public getClassName(): string {
         public getClassName(): string {
@@ -1456,8 +1448,6 @@
             this.onCollideObservable.clear();
             this.onCollideObservable.clear();
             this.onCollisionPositionChangeObservable.clear();
             this.onCollisionPositionChangeObservable.clear();
 
 
-            this._isDisposed = true;
-
             super.dispose(doNotRecurse);
             super.dispose(doNotRecurse);
         }
         }
 
 

+ 8 - 0
src/Particles/babylon.particleSystem.ts

@@ -494,6 +494,14 @@
         }
         }
 
 
         /**
         /**
+         * Remove all active particles
+         */
+        public reset(): void {
+            this._stockParticles = [];
+            this._particles = [];
+        }
+
+        /**
          * @ignore (for internal use only)
          * @ignore (for internal use only)
          */
          */
         public _appendParticleVertex(index: number, particle: Particle, offsetX: number, offsetY: number): void {
         public _appendParticleVertex(index: number, particle: Particle, offsetX: number, offsetY: number): void {

+ 9 - 0
src/Particles/babylon.solidParticle.ts

@@ -94,6 +94,15 @@ module BABYLON {
          * Last computed particle rotation matrix
          * Last computed particle rotation matrix
          */
          */
         public _rotationMatrix: number[] = [1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0];
         public _rotationMatrix: number[] = [1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0];
+        /**
+         * Parent particle Id, if any.
+         * Default null.
+         */
+        public parentId: Nullable<number> = null;
+        /**
+         * Internal global position in the SPS.
+         */
+        public _globalPosition: Vector3 = Vector3.Zero();
 
 
         /**
         /**
          * Creates a Solid Particle object.
          * Creates a Solid Particle object.

+ 86 - 30
src/Particles/babylon.solidParticleSystem.ts

@@ -134,6 +134,9 @@
                 };
                 };
             private _needs32Bits: boolean = false;
             private _needs32Bits: boolean = false;
             private _pivotBackTranslation: Vector3 = Vector3.Zero();
             private _pivotBackTranslation: Vector3 = Vector3.Zero();
+            private _scaledPivot: Vector3 = Vector3.Zero();
+            private _particleHasParent: boolean = false;
+            private _parent: SolidParticle;
 
 
             /**
             /**
              * Creates a SPS (Solid Particle System) object.
              * Creates a SPS (Solid Particle System) object.
@@ -399,12 +402,16 @@
                     this._quaternionRotationYPR();
                     this._quaternionRotationYPR();
                 }
                 }
                 this._quaternionToRotationMatrix();
                 this._quaternionToRotationMatrix();
+
+                this._scaledPivot.x = this._copy.pivot.x * this._copy.scaling.x;
+                this._scaledPivot.y = this._copy.pivot.y * this._copy.scaling.y;
+                this._scaledPivot.z = this._copy.pivot.z * this._copy.scaling.z;
                 
                 
                 if (this._copy.translateFromPivot) {
                 if (this._copy.translateFromPivot) {
                     this._pivotBackTranslation.copyFromFloats(0.0, 0.0, 0.0);
                     this._pivotBackTranslation.copyFromFloats(0.0, 0.0, 0.0);
                 }
                 }
                 else {
                 else {
-                    this._pivotBackTranslation.copyFrom(this._copy.pivot);
+                    this._pivotBackTranslation.copyFrom(this._scaledPivot);
                 }
                 }
     
     
                 for (i = 0; i < shape.length; i++) {
                 for (i = 0; i < shape.length; i++) {
@@ -420,9 +427,9 @@
                     this._vertex.y *= this._copy.scaling.y;
                     this._vertex.y *= this._copy.scaling.y;
                     this._vertex.z *= this._copy.scaling.z;
                     this._vertex.z *= this._copy.scaling.z;
 
 
-                    this._vertex.x -= this._copy.pivot.x;
-                    this._vertex.y -= this._copy.pivot.y;
-                    this._vertex.z -= this._copy.pivot.z;
+                    this._vertex.x -= this._scaledPivot.x;
+                    this._vertex.y -= this._scaledPivot.y;
+                    this._vertex.z -= this._scaledPivot.z;
     
     
                     Vector3.TransformCoordinatesToRef(this._vertex, this._rotMatrix, this._rotated);
                     Vector3.TransformCoordinatesToRef(this._vertex, this._rotMatrix, this._rotated);
 
 
@@ -582,11 +589,15 @@
                 }
                 }
                 this._quaternionToRotationMatrix();
                 this._quaternionToRotationMatrix();
 
 
+                this._scaledPivot.x = this._particle.pivot.x * this._particle.scaling.x;
+                this._scaledPivot.y = this._particle.pivot.y * this._particle.scaling.y;
+                this._scaledPivot.z = this._particle.pivot.z * this._particle.scaling.z;
+
                 if (this._copy.translateFromPivot) {
                 if (this._copy.translateFromPivot) {
                     this._pivotBackTranslation.copyFromFloats(0.0, 0.0, 0.0);
                     this._pivotBackTranslation.copyFromFloats(0.0, 0.0, 0.0);
                 }
                 }
                 else {
                 else {
-                    this._pivotBackTranslation.copyFrom(this._copy.pivot);
+                    this._pivotBackTranslation.copyFrom(this._scaledPivot);
                 }
                 }
     
     
                 this._shape = particle._model._shape;
                 this._shape = particle._model._shape;
@@ -603,9 +614,9 @@
                     this._vertex.y *= this._copy.scaling.y;
                     this._vertex.y *= this._copy.scaling.y;
                     this._vertex.z *= this._copy.scaling.z;
                     this._vertex.z *= this._copy.scaling.z;
 
 
-                    this._vertex.x -= this._copy.pivot.x;
-                    this._vertex.y -= this._copy.pivot.y;
-                    this._vertex.z -= this._copy.pivot.z;
+                    this._vertex.x -= this._scaledPivot.x;
+                    this._vertex.y -= this._scaledPivot.y;
+                    this._vertex.z -= this._scaledPivot.z;
     
     
                     Vector3.TransformCoordinatesToRef(this._vertex, this._rotMatrix, this._rotated);
                     Vector3.TransformCoordinatesToRef(this._vertex, this._rotMatrix, this._rotated);
                     this._rotated.addInPlace(this._pivotBackTranslation);
                     this._rotated.addInPlace(this._pivotBackTranslation);
@@ -624,6 +635,15 @@
                 particle.scaling.x = 1.0;
                 particle.scaling.x = 1.0;
                 particle.scaling.y = 1.0;
                 particle.scaling.y = 1.0;
                 particle.scaling.z = 1.0;
                 particle.scaling.z = 1.0;
+                particle.uvs.x = 0.0;
+                particle.uvs.y = 0.0;
+                particle.uvs.z = 1.0;
+                particle.uvs.w = 1.0;
+                particle.pivot.x = 0.0;
+                particle.pivot.y = 0.0;
+                particle.pivot.z = 0.0;
+                particle.translateFromPivot = false;
+                particle.parentId = null;
             }
             }
 
 
             /**
             /**
@@ -751,7 +771,12 @@
     
     
                     if (this._particle.isVisible) {
                     if (this._particle.isVisible) {
                         this._particle._stillInvisible = false; // un-mark permanent invisibility
                         this._particle._stillInvisible = false; // un-mark permanent invisibility
-    
+                        this._particleHasParent = (this._particle.parentId !== null);
+
+                        this._scaledPivot.x = this._particle.pivot.x * this._particle.scaling.x;
+                        this._scaledPivot.y = this._particle.pivot.y * this._particle.scaling.y;
+                        this._scaledPivot.z = this._particle.pivot.z * this._particle.scaling.z;
+
                         // particle rotation matrix
                         // particle rotation matrix
                         if (this.billboard) {
                         if (this.billboard) {
                             this._particle.rotation.x = 0.0;
                             this._particle.rotation.x = 0.0;
@@ -767,15 +792,46 @@
                                 this._quaternionRotationYPR();
                                 this._quaternionRotationYPR();
                             }
                             }
                             this._quaternionToRotationMatrix();
                             this._quaternionToRotationMatrix();
-                            this._particle._rotationMatrix[0] = this._rotMatrix.m[0];
-                            this._particle._rotationMatrix[1] = this._rotMatrix.m[1];
-                            this._particle._rotationMatrix[2] = this._rotMatrix.m[2];
-                            this._particle._rotationMatrix[3] = this._rotMatrix.m[4];
-                            this._particle._rotationMatrix[4] = this._rotMatrix.m[5];
-                            this._particle._rotationMatrix[5] = this._rotMatrix.m[6];
-                            this._particle._rotationMatrix[6] = this._rotMatrix.m[8];
-                            this._particle._rotationMatrix[7] = this._rotMatrix.m[9];
-                            this._particle._rotationMatrix[8] = this._rotMatrix.m[10];
+                        }
+
+                        if (this._particleHasParent) {
+                            this._parent = this.particles[this._particle.parentId!];
+                            this._rotated.x = this._particle.position.x * this._parent._rotationMatrix[0] + this._particle.position.y * this._parent._rotationMatrix[3] + this._particle.position.z * this._parent._rotationMatrix[6];
+                            this._rotated.y = this._particle.position.x * this._parent._rotationMatrix[1] + this._particle.position.y * this._parent._rotationMatrix[4] + this._particle.position.z * this._parent._rotationMatrix[7];
+                            this._rotated.z = this._particle.position.x * this._parent._rotationMatrix[2] + this._particle.position.y * this._parent._rotationMatrix[5] + this._particle.position.z * this._parent._rotationMatrix[8];
+
+                            this._particle._globalPosition.x = this._parent._globalPosition.x + this._rotated.x;
+                            this._particle._globalPosition.y = this._parent._globalPosition.y + this._rotated.y;
+                            this._particle._globalPosition.z = this._parent._globalPosition.z + this._rotated.z;
+
+                            if (this._computeParticleRotation || this.billboard) {
+                                this._particle._rotationMatrix[0] = this._rotMatrix.m[0] * this._parent._rotationMatrix[0] + this._rotMatrix.m[1] * this._parent._rotationMatrix[3] + this._rotMatrix.m[2] * this._parent._rotationMatrix[6];
+                                this._particle._rotationMatrix[1] = this._rotMatrix.m[0] * this._parent._rotationMatrix[1] + this._rotMatrix.m[1] * this._parent._rotationMatrix[4] + this._rotMatrix.m[2] * this._parent._rotationMatrix[7];
+                                this._particle._rotationMatrix[2] = this._rotMatrix.m[0] * this._parent._rotationMatrix[2] + this._rotMatrix.m[1] * this._parent._rotationMatrix[5] + this._rotMatrix.m[2] * this._parent._rotationMatrix[8];
+                                this._particle._rotationMatrix[3] = this._rotMatrix.m[4] * this._parent._rotationMatrix[0] + this._rotMatrix.m[5] * this._parent._rotationMatrix[3] + this._rotMatrix.m[6] * this._parent._rotationMatrix[6];
+                                this._particle._rotationMatrix[4] = this._rotMatrix.m[4] * this._parent._rotationMatrix[1] + this._rotMatrix.m[5] * this._parent._rotationMatrix[4] + this._rotMatrix.m[6] * this._parent._rotationMatrix[7];
+                                this._particle._rotationMatrix[5] = this._rotMatrix.m[4] * this._parent._rotationMatrix[2] + this._rotMatrix.m[5] * this._parent._rotationMatrix[5] + this._rotMatrix.m[6] * this._parent._rotationMatrix[8];
+                                this._particle._rotationMatrix[6] = this._rotMatrix.m[8] * this._parent._rotationMatrix[0] + this._rotMatrix.m[9] * this._parent._rotationMatrix[3] + this._rotMatrix.m[10] * this._parent._rotationMatrix[6];
+                                this._particle._rotationMatrix[7] = this._rotMatrix.m[8] * this._parent._rotationMatrix[1] + this._rotMatrix.m[9] * this._parent._rotationMatrix[4] + this._rotMatrix.m[10] * this._parent._rotationMatrix[7];
+                                this._particle._rotationMatrix[8] = this._rotMatrix.m[8] * this._parent._rotationMatrix[2] + this._rotMatrix.m[9] * this._parent._rotationMatrix[5] + this._rotMatrix.m[10] * this._parent._rotationMatrix[8];
+                            }
+                        }
+                        else {
+                            this._particle._globalPosition.x = this._particle.position.x;
+                            this._particle._globalPosition.y = this._particle.position.y;
+                            this._particle._globalPosition.z = this._particle.position.z;
+
+                            if (this._computeParticleRotation || this.billboard) {
+                                this._particle._rotationMatrix[0] = this._rotMatrix.m[0];
+                                this._particle._rotationMatrix[1] = this._rotMatrix.m[1];
+                                this._particle._rotationMatrix[2] = this._rotMatrix.m[2];
+                                this._particle._rotationMatrix[3] = this._rotMatrix.m[4];
+                                this._particle._rotationMatrix[4] = this._rotMatrix.m[5];
+                                this._particle._rotationMatrix[5] = this._rotMatrix.m[6];
+                                this._particle._rotationMatrix[6] = this._rotMatrix.m[8];
+                                this._particle._rotationMatrix[7] = this._rotMatrix.m[9];
+                                this._particle._rotationMatrix[8] = this._rotMatrix.m[10];
+                            }
                         }
                         }
        
        
                         if (this._particle.translateFromPivot) {
                         if (this._particle.translateFromPivot) {
@@ -784,9 +840,9 @@
                             this._pivotBackTranslation.z = 0.0;
                             this._pivotBackTranslation.z = 0.0;
                         }
                         }
                         else {
                         else {
-                            this._pivotBackTranslation.x = this._particle.pivot.x;
-                            this._pivotBackTranslation.y = this._particle.pivot.y;
-                            this._pivotBackTranslation.z = this._particle.pivot.z;
+                            this._pivotBackTranslation.x = this._scaledPivot.x;
+                            this._pivotBackTranslation.y = this._scaledPivot.y;
+                            this._pivotBackTranslation.z = this._scaledPivot.z;
                         }
                         }
                         // particle vertex loop
                         // particle vertex loop
                         for (pt = 0; pt < this._shape.length; pt++) {
                         for (pt = 0; pt < this._shape.length; pt++) {
@@ -807,9 +863,9 @@
                             this._vertex.y *= this._particle.scaling.y;
                             this._vertex.y *= this._particle.scaling.y;
                             this._vertex.z *= this._particle.scaling.z;
                             this._vertex.z *= this._particle.scaling.z;
 
 
-                            this._vertex.x -= this._particle.pivot.x;
-                            this._vertex.y -= this._particle.pivot.y;
-                            this._vertex.z -= this._particle.pivot.z;
+                            this._vertex.x -= this._scaledPivot.x;
+                            this._vertex.y -= this._scaledPivot.y;
+                            this._vertex.z -= this._scaledPivot.z;
     
     
                             this._rotated.x = this._vertex.x * this._particle._rotationMatrix[0] + this._vertex.y * this._particle._rotationMatrix[3] + this._vertex.z * this._particle._rotationMatrix[6];
                             this._rotated.x = this._vertex.x * this._particle._rotationMatrix[0] + this._vertex.y * this._particle._rotationMatrix[3] + this._vertex.z * this._particle._rotationMatrix[6];
                             this._rotated.y = this._vertex.x * this._particle._rotationMatrix[1] + this._vertex.y * this._particle._rotationMatrix[4] + this._vertex.z * this._particle._rotationMatrix[7];
                             this._rotated.y = this._vertex.x * this._particle._rotationMatrix[1] + this._vertex.y * this._particle._rotationMatrix[4] + this._vertex.z * this._particle._rotationMatrix[7];
@@ -819,9 +875,9 @@
                             this._rotated.y += this._pivotBackTranslation.y;
                             this._rotated.y += this._pivotBackTranslation.y;
                             this._rotated.z += this._pivotBackTranslation.z;
                             this._rotated.z += this._pivotBackTranslation.z;
 
 
-                            this._positions32[idx] = this._particle.position.x + this._cam_axisX.x * this._rotated.x + this._cam_axisY.x * this._rotated.y + this._cam_axisZ.x * this._rotated.z;
-                            this._positions32[idx + 1] = this._particle.position.y + this._cam_axisX.y * this._rotated.x + this._cam_axisY.y * this._rotated.y + this._cam_axisZ.y * this._rotated.z;
-                            this._positions32[idx + 2] = this._particle.position.z + this._cam_axisX.z * this._rotated.x + this._cam_axisY.z * this._rotated.y + this._cam_axisZ.z * this._rotated.z;
+                            this._positions32[idx] = this._particle._globalPosition.x + this._cam_axisX.x * this._rotated.x + this._cam_axisY.x * this._rotated.y + this._cam_axisZ.x * this._rotated.z;
+                            this._positions32[idx + 1] = this._particle._globalPosition.y + this._cam_axisX.y * this._rotated.x + this._cam_axisY.y * this._rotated.y + this._cam_axisZ.y * this._rotated.z;
+                            this._positions32[idx + 2] = this._particle._globalPosition.z + this._cam_axisX.z * this._rotated.x + this._cam_axisY.z * this._rotated.y + this._cam_axisZ.z * this._rotated.z;
     
     
                             if (this._computeBoundingBox) {
                             if (this._computeBoundingBox) {
                                 if (this._positions32[idx] < this._minimum.x) {
                                 if (this._positions32[idx] < this._minimum.x) {
@@ -926,9 +982,9 @@
                         this._maxBbox.x = this._particle._modelBoundingInfo.maximum.x * this._particle.scaling.x;
                         this._maxBbox.x = this._particle._modelBoundingInfo.maximum.x * this._particle.scaling.x;
                         this._maxBbox.y = this._particle._modelBoundingInfo.maximum.y * this._particle.scaling.y;
                         this._maxBbox.y = this._particle._modelBoundingInfo.maximum.y * this._particle.scaling.y;
                         this._maxBbox.z = this._particle._modelBoundingInfo.maximum.z * this._particle.scaling.z;
                         this._maxBbox.z = this._particle._modelBoundingInfo.maximum.z * this._particle.scaling.z;
-                        bSphere.center.x = this._particle.position.x + (this._minBbox.x + this._maxBbox.x) * 0.5;
-                        bSphere.center.y = this._particle.position.y + (this._minBbox.y + this._maxBbox.y) * 0.5;
-                        bSphere.center.z = this._particle.position.z + (this._minBbox.z + this._maxBbox.z) * 0.5;
+                        bSphere.center.x = this._particle._globalPosition.x + (this._minBbox.x + this._maxBbox.x) * 0.5;
+                        bSphere.center.y = this._particle._globalPosition.y + (this._minBbox.y + this._maxBbox.y) * 0.5;
+                        bSphere.center.z = this._particle._globalPosition.z + (this._minBbox.z + this._maxBbox.z) * 0.5;
                         bSphere.radius = this._bSphereRadiusFactor * 0.5 * Math.sqrt((this._maxBbox.x - this._minBbox.x) * (this._maxBbox.x - this._minBbox.x) + (this._maxBbox.y - this._minBbox.y) * (this._maxBbox.y - this._minBbox.y) + (this._maxBbox.z - this._minBbox.z) * (this._maxBbox.z - this._minBbox.z));
                         bSphere.radius = this._bSphereRadiusFactor * 0.5 * Math.sqrt((this._maxBbox.x - this._minBbox.x) * (this._maxBbox.x - this._minBbox.x) + (this._maxBbox.y - this._minBbox.y) * (this._maxBbox.y - this._minBbox.y) + (this._maxBbox.z - this._minBbox.z) * (this._maxBbox.z - this._minBbox.z));
                         bSphere._update(this.mesh._worldMatrix);
                         bSphere._update(this.mesh._worldMatrix);
                     }
                     }

+ 5 - 0
src/Shaders/ShadersInclude/bumpFragment.fx

@@ -25,5 +25,10 @@
 #endif
 #endif
 
 
 #ifdef BUMP
 #ifdef BUMP
+#ifdef OBJECTSPACE_NORMALMAP
+	normalW = normalize(texture2D(bumpSampler, vBumpUV).xyz  * 2.0 - 1.0);
+	normalW = normalize(mat3(normalMatrix) * normalW);	
+#else
 	normalW = perturbNormal(TBN, vBumpUV + uvOffset);
 	normalW = perturbNormal(TBN, vBumpUV + uvOffset);
+#endif
 #endif
 #endif

+ 4 - 0
src/Shaders/ShadersInclude/bumpFragmentFunctions.fx

@@ -11,6 +11,10 @@
 	varying mat3 vTBN;
 	varying mat3 vTBN;
 #endif
 #endif
 
 
+#ifdef OBJECTSPACE_NORMALMAP
+uniform mat4 normalMatrix;
+#endif
+
 	// Thanks to http://www.thetenthplanet.de/archives/1180
 	// Thanks to http://www.thetenthplanet.de/archives/1180
 	mat3 cotangent_frame(vec3 normal, vec3 p, vec2 uv)
 	mat3 cotangent_frame(vec3 normal, vec3 p, vec2 uv)
 	{
 	{

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

@@ -311,7 +311,7 @@ module BABYLON {
             scene._loadFile(this.url, (data) => {
             scene._loadFile(this.url, (data) => {
                 this.text = data as string;
                 this.text = data as string;
                 onSuccess();
                 onSuccess();
-            }, undefined, false, true, (request, exception) => {
+            }, undefined, false, false, (request, exception) => {
                 if (request) {
                 if (request) {
                     onError(request.status + " " + request.statusText, exception);
                     onError(request.status + " " + request.statusText, exception);
                 }
                 }

+ 3 - 3
src/Tools/babylon.promise.ts

@@ -122,17 +122,17 @@ module BABYLON {
 
 
                 return returnedValue;
                 return returnedValue;
             } catch (e) {
             } catch (e) {
-                this._reject(e);
+                this._reject(e, true);
             }
             }
 
 
             return null;
             return null;
         }
         }
 
 
-        private _reject(reason: any): void {
+        private _reject(reason: any, onLocalThrow = false): void {
             this._state = PromiseStates.Rejected;
             this._state = PromiseStates.Rejected;
             this._reason = reason;
             this._reason = reason;
 
 
-            if (this._onRejected) {
+            if (this._onRejected && !onLocalThrow) {
                 try {
                 try {
                     this._onRejected(reason);
                     this._onRejected(reason);
                     this._rejectWasConsumed = true;
                     this._rejectWasConsumed = true;

+ 162 - 29
src/babylon.node.ts

@@ -4,41 +4,82 @@
      * Node is the basic class for all scene objects (Mesh, Light Camera).
      * Node is the basic class for all scene objects (Mesh, Light Camera).
      */
      */
     export class Node {
     export class Node {
+        /**
+         * Gets or sets the name of the node
+         */
         @serialize()
         @serialize()
         public name: string;
         public name: string;
 
 
+        /**
+         * Gets or sets the id of the node
+         */
         @serialize()
         @serialize()
         public id: string;
         public id: string;
 
 
+        /**
+         * Gets or sets the unique id of the node
+         */
         @serialize()
         @serialize()
         public uniqueId: number;
         public uniqueId: number;
 
 
+        /**
+         * Gets or sets a string used to store user defined state for the node
+         */
         @serialize()
         @serialize()
         public state = "";
         public state = "";
 
 
+        /**
+         * Gets or sets an object used to store user defined information for the node
+         */
         @serialize()
         @serialize()
         public metadata: any = null;
         public metadata: any = null;
 
 
+        /**
+         * Gets or sets a boolean used to define if the node must be serialized
+         */
         public doNotSerialize = false;
         public doNotSerialize = false;
+        
+        /** @ignore */
+        public _isDisposed = false;        
 
 
+        /**
+         * Gets a list of {BABYLON.Animation} associated with the node
+         */
         public animations = new Array<Animation>();
         public animations = new Array<Animation>();
         private _ranges: { [name: string]: Nullable<AnimationRange> } = {};
         private _ranges: { [name: string]: Nullable<AnimationRange> } = {};
 
 
+        /**
+         * Callback raised when the node is ready to be used
+         */
         public onReady: (node: Node) => void;
         public onReady: (node: Node) => void;
 
 
         private _isEnabled = true;
         private _isEnabled = true;
         private _isReady = true;
         private _isReady = true;
+        /** @ignore */
         public _currentRenderId = -1;
         public _currentRenderId = -1;
         private _parentRenderId = -1;
         private _parentRenderId = -1;
 
 
+        /** @ignore */
         public _waitingParentId: Nullable<string>;
         public _waitingParentId: Nullable<string>;
 
 
         private _scene: Scene;
         private _scene: Scene;
+        /** @ignore */
         public _cache: any;
         public _cache: any;
 
 
         private _parentNode: Nullable<Node>;
         private _parentNode: Nullable<Node>;
         private _children: Node[];
         private _children: Node[];
 
 
+        /**
+         * Gets a boolean indicating if the node has been disposed
+         * @returns true if the node was disposed
+         */
+        public isDisposed(): boolean {
+            return this._isDisposed;
+        }        
+
+        /**
+         * Gets or sets the parent of the node
+         */
         public set parent(parent: Nullable<Node>) {
         public set parent(parent: Nullable<Node>) {
             if (this._parentNode === parent) {
             if (this._parentNode === parent) {
                 return;
                 return;
@@ -68,17 +109,24 @@
             return this._parentNode;
             return this._parentNode;
         }
         }
 
 
+        /**
+         * Gets a string idenfifying the name of the class
+         * @returns "Node" string
+         */
         public getClassName(): string {
         public getClassName(): string {
             return "Node";
             return "Node";
         }
         }
 
 
         /**
         /**
-        * An event triggered when the mesh is disposed.
+        * An event triggered when the mesh is disposed
         * @type {BABYLON.Observable}
         * @type {BABYLON.Observable}
         */
         */
         public onDisposeObservable = new Observable<Node>();
         public onDisposeObservable = new Observable<Node>();
 
 
         private _onDisposeObserver: Nullable<Observer<Node>>;
         private _onDisposeObserver: Nullable<Observer<Node>>;
+        /**
+         * Sets a callback that will be raised when the node will be disposed
+         */
         public set onDispose(callback: () => void) {
         public set onDispose(callback: () => void) {
             if (this._onDisposeObserver) {
             if (this._onDisposeObserver) {
                 this.onDisposeObservable.remove(this._onDisposeObserver);
                 this.onDisposeObservable.remove(this._onDisposeObserver);
@@ -87,7 +135,7 @@
         }
         }
 
 
         /**
         /**
-         * @constructor
+         * Creates a new Node
          * @param {string} name - the name and id to be given to this node
          * @param {string} name - the name and id to be given to this node
          * @param {BABYLON.Scene} the scene this node will be added to
          * @param {BABYLON.Scene} the scene this node will be added to
          */
          */
@@ -99,10 +147,18 @@
             this._initCache();
             this._initCache();
         }
         }
 
 
+        /**
+         * Gets the scene of the node
+         * @returns a {BABYLON.Scene}
+         */
         public getScene(): Scene {
         public getScene(): Scene {
             return this._scene;
             return this._scene;
         }
         }
 
 
+        /**
+         * Gets the engine of the node
+         * @returns a {BABYLON.Engine}
+         */
         public getEngine(): Engine {
         public getEngine(): Engine {
             return this._scene.getEngine();
             return this._scene.getEngine();
         }
         }
@@ -110,6 +166,12 @@
         // Behaviors
         // Behaviors
         private _behaviors = new Array<Behavior<Node>>();
         private _behaviors = new Array<Behavior<Node>>();
 
 
+        /**
+         * Attach a behavior to the node
+         * @see http://doc.babylonjs.com/features/behaviour
+         * @param behavior defines the behavior to attach
+         * @returns the current Node
+         */
         public addBehavior(behavior: Behavior<Node>): Node {
         public addBehavior(behavior: Behavior<Node>): Node {
             var index = this._behaviors.indexOf(behavior);
             var index = this._behaviors.indexOf(behavior);
 
 
@@ -135,6 +197,12 @@
             return this;
             return this;
         }
         }
 
 
+        /**
+         * Remove an attached behavior
+         * @see http://doc.babylonjs.com/features/behaviour
+         * @param behavior defines the behavior to attach
+         * @returns the current Node
+         */
         public removeBehavior(behavior: Behavior<Node>): Node {
         public removeBehavior(behavior: Behavior<Node>): Node {
             var index = this._behaviors.indexOf(behavior);
             var index = this._behaviors.indexOf(behavior);
 
 
@@ -148,10 +216,20 @@
             return this;
             return this;
         }
         }
 
 
+        /**
+         * Gets the list of attached behaviors
+         * @see http://doc.babylonjs.com/features/behaviour
+         */
         public get behaviors(): Behavior<Node>[] {
         public get behaviors(): Behavior<Node>[] {
             return this._behaviors;
             return this._behaviors;
         }
         }
 
 
+        /**
+         * Gets an attached behavior by name
+         * @param name defines the name of the behavior to look for
+         * @see http://doc.babylonjs.com/features/behaviour
+         * @returns null if behavior was not found else the requested behavior
+         */
         public getBehaviorByName(name: string): Nullable<Behavior<Node>> {
         public getBehaviorByName(name: string): Nullable<Behavior<Node>> {
             for (var behavior of this._behaviors) {
             for (var behavior of this._behaviors) {
                 if (behavior.name === name) {
                 if (behavior.name === name) {
@@ -162,18 +240,23 @@
             return null;
             return null;
         }
         }
 
 
-        // override it in derived class
+        /**
+         * Returns the world matrix of the node
+         * @returns a matrix containing the node's world matrix
+         */
         public getWorldMatrix(): Matrix {
         public getWorldMatrix(): Matrix {
             return Matrix.Identity();
             return Matrix.Identity();
         }
         }
 
 
         // override it in derived class if you add new variables to the cache
         // override it in derived class if you add new variables to the cache
         // and call the parent class method
         // and call the parent class method
+        /** @ignore */
         public _initCache() {
         public _initCache() {
             this._cache = {};
             this._cache = {};
             this._cache.parent = undefined;
             this._cache.parent = undefined;
         }
         }
 
 
+        /** @ignore */
         public updateCache(force?: boolean): void {
         public updateCache(force?: boolean): void {
             if (!force && this.isSynchronized())
             if (!force && this.isSynchronized())
                 return;
                 return;
@@ -185,20 +268,24 @@
 
 
         // override it in derived class if you add new variables to the cache
         // override it in derived class if you add new variables to the cache
         // and call the parent class method if !ignoreParentClass
         // and call the parent class method if !ignoreParentClass
+        /** @ignore */
         public _updateCache(ignoreParentClass?: boolean): void {
         public _updateCache(ignoreParentClass?: boolean): void {
         }
         }
 
 
         // override it in derived class if you add new variables to the cache
         // override it in derived class if you add new variables to the cache
+        /** @ignore */
         public _isSynchronized(): boolean {
         public _isSynchronized(): boolean {
             return true;
             return true;
         }
         }
 
 
+        /** @ignore */
         public _markSyncedWithParent() {
         public _markSyncedWithParent() {
             if (this.parent) {
             if (this.parent) {
                 this._parentRenderId = this.parent._currentRenderId;
                 this._parentRenderId = this.parent._currentRenderId;
             }
             }
         }
         }
 
 
+        /** @ignore */
         public isSynchronizedWithParent(): boolean {
         public isSynchronizedWithParent(): boolean {
             if (!this.parent) {
             if (!this.parent) {
                 return true;
                 return true;
@@ -211,6 +298,7 @@
             return this.parent.isSynchronized();
             return this.parent.isSynchronized();
         }
         }
 
 
+        /** @ignore */
         public isSynchronized(updateCache?: boolean): boolean {
         public isSynchronized(updateCache?: boolean): boolean {
             var check = this.hasNewParent();
             var check = this.hasNewParent();
 
 
@@ -224,6 +312,7 @@
             return !check;
             return !check;
         }
         }
 
 
+        /** @ignore */
         public hasNewParent(update?: boolean): boolean {
         public hasNewParent(update?: boolean): boolean {
             if (this._cache.parent === this.parent)
             if (this._cache.parent === this.parent)
                 return false;
                 return false;
@@ -236,17 +325,17 @@
 
 
         /**
         /**
          * Is this node ready to be used/rendered
          * Is this node ready to be used/rendered
-         * @return {boolean} is it ready
+         * @return true if the node is ready
          */
          */
         public isReady(): boolean {
         public isReady(): boolean {
             return this._isReady;
             return this._isReady;
         }
         }
 
 
         /**
         /**
-         * Is this node enabled. 
-         * If the node has a parent, all ancestors will be checked and false will be returned if any are false (not enabled), otherwise will return true.
-         * @param {boolean} [checkAncestors=true] - Indicates if this method should check the ancestors. The default is to check the ancestors. If set to false, the method will return the value of this node without checking ancestors.
-         * @return {boolean} whether this node (and its parent) is enabled.
+         * Is this node enabled?
+         * If the node has a parent, all ancestors will be checked and false will be returned if any are false (not enabled), otherwise will return true
+         * @param checkAncestors indicates if this method should check the ancestors. The default is to check the ancestors. If set to false, the method will return the value of this node without checking ancestors
+         * @return whether this node (and its parent) is enabled
          * @see setEnabled
          * @see setEnabled
          */
          */
         public isEnabled(checkAncestors: boolean = true): boolean {
         public isEnabled(checkAncestors: boolean = true): boolean {
@@ -266,8 +355,8 @@
         }
         }
 
 
         /**
         /**
-         * Set the enabled state of this node.
-         * @param {boolean} value - the new enabled state
+         * Set the enabled state of this node
+         * @param value defines the new enabled state
          * @see isEnabled
          * @see isEnabled
          */
          */
         public setEnabled(value: boolean): void {
         public setEnabled(value: boolean): void {
@@ -275,10 +364,11 @@
         }
         }
 
 
         /**
         /**
-         * Is this node a descendant of the given node.
-         * The function will iterate up the hierarchy until the ancestor was found or no more parents defined.
-         * @param {BABYLON.Node} ancestor - The parent node to inspect
+         * Is this node a descendant of the given node?
+         * The function will iterate up the hierarchy until the ancestor was found or no more parents defined
+         * @param ancestor defines the parent node to inspect
          * @see parent
          * @see parent
+         * @returns a boolean indicating if this node is a descendant of the given node
          */
          */
         public isDescendantOf(ancestor: Node): boolean {
         public isDescendantOf(ancestor: Node): boolean {
             if (this.parent) {
             if (this.parent) {
@@ -291,12 +381,7 @@
             return false;
             return false;
         }
         }
 
 
-        /**
-         * Evaluate the list of children and determine if they should be considered as descendants considering the given criterias
-         * @param {BABYLON.Node[]} results the result array containing the nodes matching the given criterias
-         * @param {boolean} directDescendantsOnly if true only direct descendants of 'this' will be considered, if false direct and also indirect (children of children, an so on in a recursive manner) descendants of 'this' will be considered.
-         * @param predicate: an optional predicate that will be called on every evaluated children, the predicate must return true for a given child to be part of the result, otherwise it will be ignored.
-         */
+        /** @ignore */
         public _getDescendants(results: Node[], directDescendantsOnly: boolean = false, predicate?: (node: Node) => boolean): void {
         public _getDescendants(results: Node[], directDescendantsOnly: boolean = false, predicate?: (node: Node) => boolean): void {
             if (!this._children) {
             if (!this._children) {
                 return;
                 return;
@@ -316,10 +401,10 @@
         }
         }
 
 
         /**
         /**
-         * Will return all nodes that have this node as ascendant.
-         * @param {boolean} directDescendantsOnly if true only direct descendants of 'this' will be considered, if false direct and also indirect (children of children, an so on in a recursive manner) descendants of 'this' will be considered.
-         * @param predicate: an optional predicate that will be called on every evaluated children, the predicate must return true for a given child to be part of the result, otherwise it will be ignored.
-         * @return {BABYLON.Node[]} all children nodes of all types.
+         * Will return all nodes that have this node as ascendant
+         * @param directDescendantsOnly defines if true only direct descendants of 'this' will be considered, if false direct and also indirect (children of children, an so on in a recursive manner) descendants of 'this' will be considered
+         * @param predicate defines an optional predicate that will be called on every evaluated child, the predicate must return true for a given child to be part of the result, otherwise it will be ignored
+         * @return all children nodes of all types
          */
          */
         public getDescendants(directDescendantsOnly?: boolean, predicate?: (node: Node) => boolean): Node[] {
         public getDescendants(directDescendantsOnly?: boolean, predicate?: (node: Node) => boolean): Node[] {
             var results = new Array<Node>();
             var results = new Array<Node>();
@@ -330,7 +415,10 @@
         }
         }
 
 
         /**
         /**
-         * Get all child-meshes of this node.
+         * Get all child-meshes of this node
+         * @param directDescendantsOnly defines if true only direct descendants of 'this' will be considered, if false direct and also indirect (children of children, an so on in a recursive manner) descendants of 'this' will be considered
+         * @param predicate defines an optional predicate that will be called on every evaluated child, the predicate must return true for a given child to be part of the result, otherwise it will be ignored
+         * @returns an array of {BABYLON.AbstractMesh}
          */
          */
         public getChildMeshes(directDescendantsOnly?: boolean, predicate?: (node: Node) => boolean): AbstractMesh[] {
         public getChildMeshes(directDescendantsOnly?: boolean, predicate?: (node: Node) => boolean): AbstractMesh[] {
             var results: Array<AbstractMesh> = [];
             var results: Array<AbstractMesh> = [];
@@ -341,7 +429,10 @@
         }
         }
 
 
         /**
         /**
-         * Get all child-transformNodes of this node.
+         * Get all child-transformNodes of this node
+         * @param directDescendantsOnly defines if true only direct descendants of 'this' will be considered, if false direct and also indirect (children of children, an so on in a recursive manner) descendants of 'this' will be considered
+         * @param predicate defines an optional predicate that will be called on every evaluated child, the predicate must return true for a given child to be part of the result, otherwise it will be ignored
+         * @returns an array of {BABYLON.TransformNode}
          */
          */
         public getChildTransformNodes(directDescendantsOnly?: boolean, predicate?: (node: Node) => boolean): TransformNode[] {
         public getChildTransformNodes(directDescendantsOnly?: boolean, predicate?: (node: Node) => boolean): TransformNode[] {
             var results: Array<TransformNode> = [];
             var results: Array<TransformNode> = [];
@@ -352,12 +443,15 @@
         }
         }
 
 
         /**
         /**
-         * Get all direct children of this node.
-        */
+         * Get all direct children of this node
+         * @param predicate defines an optional predicate that will be called on every evaluated child, the predicate must return true for a given child to be part of the result, otherwise it will be ignored
+         * @returns an array of {BABYLON.Node}
+         */
         public getChildren(predicate?: (node: Node) => boolean): Node[] {
         public getChildren(predicate?: (node: Node) => boolean): Node[] {
             return this.getDescendants(true, predicate);
             return this.getDescendants(true, predicate);
         }
         }
 
 
+        /** @ignore */
         public _setReady(state: boolean): void {
         public _setReady(state: boolean): void {
             if (state === this._isReady) {
             if (state === this._isReady) {
                 return;
                 return;
@@ -374,6 +468,11 @@
             }
             }
         }
         }
 
 
+        /**
+         * Get an animation by name
+         * @param name defines the name of the animation to look for
+         * @returns null if not found else the requested animation
+         */
         public getAnimationByName(name: string): Nullable<Animation> {
         public getAnimationByName(name: string): Nullable<Animation> {
             for (var i = 0; i < this.animations.length; i++) {
             for (var i = 0; i < this.animations.length; i++) {
                 var animation = this.animations[i];
                 var animation = this.animations[i];
@@ -386,6 +485,12 @@
             return null;
             return null;
         }
         }
 
 
+        /**
+         * Creates an animation range for this node
+         * @param name defines the name of the range
+         * @param from defines the starting key
+         * @param to defines the end key
+         */
         public createAnimationRange(name: string, from: number, to: number): void {
         public createAnimationRange(name: string, from: number, to: number): void {
             // check name not already in use
             // check name not already in use
             if (!this._ranges[name]) {
             if (!this._ranges[name]) {
@@ -398,6 +503,11 @@
             }
             }
         }
         }
 
 
+        /**
+         * Delete a specific animation range
+         * @param name defines the name of the range to delete
+         * @param deleteFrames defines if animation frames from the range must be deleted as well
+         */
         public deleteAnimationRange(name: string, deleteFrames = true): void {
         public deleteAnimationRange(name: string, deleteFrames = true): void {
             for (var i = 0, nAnimations = this.animations.length; i < nAnimations; i++) {
             for (var i = 0, nAnimations = this.animations.length; i < nAnimations; i++) {
                 if (this.animations[i]) {
                 if (this.animations[i]) {
@@ -407,6 +517,11 @@
             this._ranges[name] = null; // said much faster than 'delete this._range[name]' 
             this._ranges[name] = null; // said much faster than 'delete this._range[name]' 
         }
         }
 
 
+        /**
+         * Get an animation range by name
+         * @param name defines the name of the animation range to look for
+         * @returns null if not found else the requested animation range
+         */
         public getAnimationRange(name: string): Nullable<AnimationRange> {
         public getAnimationRange(name: string): Nullable<AnimationRange> {
             return this._ranges[name];
             return this._ranges[name];
         }
         }
@@ -417,7 +532,7 @@
          * @param loop defines if the animation should loop (false by default)
          * @param loop defines if the animation should loop (false by default)
          * @param speedRatio defines the speed factor in which to run the animation (1 by default)
          * @param speedRatio defines the speed factor in which to run the animation (1 by default)
          * @param onAnimationEnd defines a function to be executed when the animation ended (undefined by default)
          * @param onAnimationEnd defines a function to be executed when the animation ended (undefined by default)
-         * @returns the {BABYLON.Animatable} object created for this animation. If range does not exist, it will return null
+         * @returns the object created for this animation. If range does not exist, it will return null
          */
          */
         public beginAnimation(name: string, loop?: boolean, speedRatio?: number, onAnimationEnd?: () => void): Nullable<Animatable> {
         public beginAnimation(name: string, loop?: boolean, speedRatio?: number, onAnimationEnd?: () => void): Nullable<Animatable> {
             var range = this.getAnimationRange(name);
             var range = this.getAnimationRange(name);
@@ -429,6 +544,10 @@
             return this._scene.beginAnimation(this, range.from, range.to, loop, speedRatio, onAnimationEnd);
             return this._scene.beginAnimation(this, range.from, range.to, loop, speedRatio, onAnimationEnd);
         }
         }
 
 
+        /**
+         * Serialize animation ranges into a JSON compatible object
+         * @returns serialization object
+         */
         public serializeAnimationRanges(): any {
         public serializeAnimationRanges(): any {
             var serializationRanges = [];
             var serializationRanges = [];
             for (var name in this._ranges) {
             for (var name in this._ranges) {
@@ -445,11 +564,18 @@
             return serializationRanges;
             return serializationRanges;
         }
         }
 
 
-        // override it in derived class
+        /**
+         * Computes the world matrix of the node
+         * @param force defines if the cache version should be invalidated forcing the world matrix to be created from scratch
+         * @returns the world matrix
+         */
         public computeWorldMatrix(force?: boolean): Matrix {
         public computeWorldMatrix(force?: boolean): Matrix {
             return Matrix.Identity();
             return Matrix.Identity();
         }
         }
 
 
+        /**
+         * Releases all associated resources
+         */
         public dispose(): void {
         public dispose(): void {
             this.parent = null;
             this.parent = null;
 
 
@@ -463,8 +589,15 @@
             }
             }
 
 
             this._behaviors = [];
             this._behaviors = [];
+            this._isDisposed = true;            
         }
         }
 
 
+        /**
+         * Parse animation range data from a serialization object and store them into a given node
+         * @param node defines where to store the animation ranges
+         * @param parsedNode defines the serialization object to read data from
+         * @param scene defines the hosting scene
+         */
         public static ParseAnimationRanges(node: Node, parsedNode: any, scene: Scene): void {
         public static ParseAnimationRanges(node: Node, parsedNode: any, scene: Scene): void {
             if (parsedNode.ranges) {
             if (parsedNode.ranges) {
                 for (var index = 0; index < parsedNode.ranges.length; index++) {
                 for (var index = 0; index < parsedNode.ranges.length; index++) {

+ 3 - 1
tests/nullEngine/app.js

@@ -129,6 +129,8 @@ var engine = new BABYLON.NullEngine();
 //     scene.render();
 //     scene.render();
 // })
 // })
 
 
+new BABYLON.Scene(engine).dispose()
+
 BABYLON.SceneLoader.Load("https://playground.babylonjs.com/scenes/", "skull.babylon", engine, (scene) => {
 BABYLON.SceneLoader.Load("https://playground.babylonjs.com/scenes/", "skull.babylon", engine, (scene) => {
     console.log('scene loaded!');
     console.log('scene loaded!');
     for (var index = 0; index < scene.meshes.length; index++) {
     for (var index = 0; index < scene.meshes.length; index++) {
@@ -139,4 +141,4 @@ BABYLON.SceneLoader.Load("https://playground.babylonjs.com/scenes/", "skull.baby
      //   scene.render();
      //   scene.render();
     //});
     //});
   
   
-  }, progress => {}, (scene, err) => console.error('error:', err));
+  }, progress => {}, (scene, err) => console.error('error:', err));

+ 5 - 5
tests/nullEngine/package.json

@@ -1,5 +1,5 @@
-{
-  "devDependencies": {
-    "xhr2": "^0.1.4"
-  }
-}
+{
+  "devDependencies": {
+    "xhr2": "^0.1.4"
+  }
+}

+ 19 - 17
tests/unit/babylon/src/Loading/babylon.sceneLoader.tests.ts

@@ -39,19 +39,25 @@ describe('Babylon Scene Loader', function () {
     describe('#glTF', () => {
     describe('#glTF', () => {
         it('Load BoomBox', () => {
         it('Load BoomBox', () => {
             const scene = new BABYLON.Scene(subject);
             const scene = new BABYLON.Scene(subject);
-            return BABYLON.SceneLoader.AppendAsync("/Playground/scenes/BoomBox/", "BoomBox.gltf", scene);
+            return BABYLON.SceneLoader.AppendAsync("/Playground/scenes/BoomBox/", "BoomBox.gltf", scene).then(scene => {
+                expect(scene.meshes.length, "scene.meshes.length").to.equal(3);
+                expect(scene.materials.length, "scene.materials.length").to.equal(1);
+            });
         });
         });
 
 
         it('Load BoomBox GLB', () => {
         it('Load BoomBox GLB', () => {
             const scene = new BABYLON.Scene(subject);
             const scene = new BABYLON.Scene(subject);
-            return BABYLON.SceneLoader.AppendAsync("/Playground/scenes/", "BoomBox.glb", scene);
+            return BABYLON.SceneLoader.AppendAsync("/Playground/scenes/", "BoomBox.glb", scene).then(scene => {
+                expect(scene.meshes.length, "scene.meshes.length").to.equal(3);
+                expect(scene.materials.length, "scene.materials.length").to.equal(1);
+            });
         });
         });
 
 
         it('Load BoomBox with callbacks', () => {
         it('Load BoomBox with callbacks', () => {
             let parsedCount = 0;
             let parsedCount = 0;
-            let primaryMeshLoadCount = 0;
-            let primaryMaterialLoadCount = 0;
-            let textureLoadCounts: { [name: string]: number } = {};
+            let meshCount = 0;
+            let materialCount = 0;
+            let textureCounts: { [name: string]: number } = {};
             let ready = false;
             let ready = false;
 
 
             const deferred = new BABYLON.Deferred();
             const deferred = new BABYLON.Deferred();
@@ -61,18 +67,14 @@ describe('Babylon Scene Loader', function () {
                 };
                 };
 
 
                 loader.onMeshLoaded = mesh => {
                 loader.onMeshLoaded = mesh => {
-                    if (mesh.name === "BoomBox") {
-                        primaryMeshLoadCount++;
-                    }
+                    meshCount++;
                 };
                 };
                 loader.onMaterialLoaded = material => {
                 loader.onMaterialLoaded = material => {
-                    if (material.name === "BoomBox_Mat") {
-                        primaryMaterialLoadCount++;
-                    }
+                    materialCount++;
                 };
                 };
                 loader.onTextureLoaded = texture => {
                 loader.onTextureLoaded = texture => {
-                    textureLoadCounts[texture.name] = textureLoadCounts[texture.name] || 0;
-                    textureLoadCounts[texture.name]++;
+                    textureCounts[texture.name] = textureCounts[texture.name] || 0;
+                    textureCounts[texture.name]++;
                 };
                 };
 
 
                 loader.onComplete = () => {
                 loader.onComplete = () => {
@@ -91,8 +93,8 @@ describe('Babylon Scene Loader', function () {
                 ready = true;
                 ready = true;
 
 
                 expect(parsedCount, "parsedCount").to.equal(1);
                 expect(parsedCount, "parsedCount").to.equal(1);
-                expect(primaryMeshLoadCount, "primaryMeshLoadCount").to.equal(1);
-                expect(primaryMaterialLoadCount, "primaryMaterialLoadCount").to.equal(1);
+                expect(meshCount, "meshCount").to.equal(scene.meshes.length);
+                expect(materialCount, "materialCount").to.equal(scene.materials.length);
 
 
                 const expectedTextureLoadCounts = {
                 const expectedTextureLoadCounts = {
                     "baseColor": 1,
                     "baseColor": 1,
@@ -100,9 +102,9 @@ describe('Babylon Scene Loader', function () {
                     "normal": 1,
                     "normal": 1,
                     "emissive": 1
                     "emissive": 1
                 };
                 };
-                expect(Object.keys(textureLoadCounts), "Object.keys(textureLoadCounts)").to.have.lengthOf(Object.keys(expectedTextureLoadCounts).length);
+                expect(Object.keys(textureCounts), "Object.keys(textureCounts)").to.have.lengthOf(Object.keys(expectedTextureLoadCounts).length);
                 for (const textureName in expectedTextureLoadCounts) {
                 for (const textureName in expectedTextureLoadCounts) {
-                    expect(textureLoadCounts, "textureLoadCounts").to.have.property(textureName, expectedTextureLoadCounts[textureName]);
+                    expect(textureCounts, "textureCounts").to.have.property(textureName, expectedTextureLoadCounts[textureName]);
                 }
                 }
             });
             });
 
 

BIN
tests/validation/ReferenceImages/local cubemaps.png


+ 6 - 1
tests/validation/config.json

@@ -303,7 +303,7 @@
     },
     },
     {
     {
       "title": "PBR",
       "title": "PBR",
-      "playgroundId": "#LCA0Q4",
+      "playgroundId": "#LCA0Q4#0",
       "referenceImage": "pbr.png"
       "referenceImage": "pbr.png"
     },
     },
     {
     {
@@ -370,6 +370,11 @@
       "title": "GlowLayer",
       "title": "GlowLayer",
       "playgroundId": "#LRFB2D#1",
       "playgroundId": "#LRFB2D#1",
       "referenceImage": "GlowLayer.png"
       "referenceImage": "GlowLayer.png"
+    },
+    {
+      "title": "Local cubemaps",
+      "playgroundId": "#RNASML#4",
+      "referenceImage": "local cubemaps.png"
     }
     }
   ]
   ]
 }
 }