Explorar el Código

Merge pull request #2964 from BabylonJS/master

Nightly
David Catuhe hace 8 años
padre
commit
ebc3caa0be
Se han modificado 48 ficheros con 32769 adiciones y 32234 borrados
  1. 3687 3670
      dist/preview release/babylon.d.ts
  2. 43 43
      dist/preview release/babylon.js
  3. 456 393
      dist/preview release/babylon.max.js
  4. 3687 3670
      dist/preview release/babylon.module.d.ts
  5. 43 43
      dist/preview release/babylon.worker.js
  6. 11630 11613
      dist/preview release/customConfigurations/minimalGLTFViewer/babylon.d.ts
  7. 44 44
      dist/preview release/customConfigurations/minimalGLTFViewer/babylon.js
  8. 621 514
      dist/preview release/customConfigurations/minimalGLTFViewer/babylon.max.js
  9. 11630 11613
      dist/preview release/customConfigurations/minimalGLTFViewer/babylon.module.d.ts
  10. 20 19
      dist/preview release/gui/babylon.gui.d.ts
  11. 59 56
      dist/preview release/gui/babylon.gui.js
  12. 3 3
      dist/preview release/gui/babylon.gui.min.js
  13. 20 19
      dist/preview release/gui/babylon.gui.module.d.ts
  14. 7 4
      dist/preview release/loaders/babylon.glTF2FileLoader.d.ts
  15. 153 107
      dist/preview release/loaders/babylon.glTF2FileLoader.js
  16. 2 2
      dist/preview release/loaders/babylon.glTF2FileLoader.min.js
  17. 7 4
      dist/preview release/loaders/babylon.glTFFileLoader.d.ts
  18. 154 108
      dist/preview release/loaders/babylon.glTFFileLoader.js
  19. 3 3
      dist/preview release/loaders/babylon.glTFFileLoader.min.js
  20. 153 107
      dist/preview release/loaders/babylonjs.loaders.js
  21. 3 3
      dist/preview release/loaders/babylonjs.loaders.min.js
  22. 7 4
      dist/preview release/loaders/babylonjs.loaders.module.d.ts
  23. 2 1
      dist/preview release/materialsLibrary/babylon.customMaterial.js
  24. 1 1
      dist/preview release/materialsLibrary/babylon.customMaterial.min.js
  25. 2 1
      dist/preview release/materialsLibrary/babylonjs.materials.js
  26. 1 1
      dist/preview release/materialsLibrary/babylonjs.materials.min.js
  27. 3 3
      gui/src/advancedDynamicTexture.ts
  28. 8 8
      gui/src/controls/button.ts
  29. 2 2
      gui/src/controls/checkbox.ts
  30. 6 6
      gui/src/controls/colorpicker.ts
  31. 4 0
      gui/src/controls/container.ts
  32. 32 27
      gui/src/controls/control.ts
  33. 4 4
      gui/src/controls/inputText.ts
  34. 2 2
      gui/src/controls/radioButton.ts
  35. 7 5
      gui/src/controls/slider.ts
  36. 143 99
      loaders/src/glTF/2.0/babylon.glTFLoader.ts
  37. 4 0
      loaders/src/glTF/2.0/babylon.glTFLoaderInterfaces.ts
  38. 0 6
      loaders/src/glTF/2.0/babylon.glTFLoaderUtils.ts
  39. 1 1
      materialsLibrary/src/custom/babylon.customMaterial.ts
  40. 1 1
      src/Cameras/VR/babylon.vrExperienceHelper.ts
  41. 38 13
      src/Engine/babylon.engine.ts
  42. 3 1
      src/Engine/babylon.nullEngine.ts
  43. 0 4
      src/Materials/Textures/babylon.renderTargetTexture.ts
  44. 48 1
      src/Materials/babylon.effect.ts
  45. 1 1
      src/Mesh/babylon.mesh.vertexData.ts
  46. 2 0
      src/Tools/babylon.decorators.ts
  47. 18 4
      src/Tools/babylon.observable.ts
  48. 4 0
      src/babylon.mixins.ts

La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 3687 - 3670
dist/preview release/babylon.d.ts


La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 43 - 43
dist/preview release/babylon.js


La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 456 - 393
dist/preview release/babylon.max.js


La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 3687 - 3670
dist/preview release/babylon.module.d.ts


La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 43 - 43
dist/preview release/babylon.worker.js


La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 11630 - 11613
dist/preview release/customConfigurations/minimalGLTFViewer/babylon.d.ts


La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 44 - 44
dist/preview release/customConfigurations/minimalGLTFViewer/babylon.js


La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 621 - 514
dist/preview release/customConfigurations/minimalGLTFViewer/babylon.max.js


La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 11630 - 11613
dist/preview release/customConfigurations/minimalGLTFViewer/babylon.module.d.ts


+ 20 - 19
dist/preview release/gui/babylon.gui.d.ts

@@ -132,6 +132,7 @@ declare module BABYLON.GUI {
         private _zIndex;
         _root: Container;
         _host: AdvancedDynamicTexture;
+        parent: Container;
         _currentMeasure: Measure;
         private _fontFamily;
         private _fontStyle;
@@ -276,11 +277,11 @@ declare module BABYLON.GUI {
         _draw(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
         contains(x: number, y: number): boolean;
         _processPicking(x: number, y: number, type: number, buttonIndex: number): boolean;
-        protected _onPointerMove(coordinates: Vector2): void;
-        protected _onPointerEnter(): boolean;
-        _onPointerOut(): void;
-        protected _onPointerDown(coordinates: Vector2, buttonIndex: number): boolean;
-        protected _onPointerUp(coordinates: Vector2, buttonIndex: number): void;
+        _onPointerMove(target: Control, coordinates: Vector2): void;
+        _onPointerEnter(target: Control): boolean;
+        _onPointerOut(target: Control): void;
+        _onPointerDown(target: Control, coordinates: Vector2, buttonIndex: number): boolean;
+        _onPointerUp(target: Control, coordinates: Vector2, buttonIndex: number): void;
         forcePointerUp(): void;
         _processObservables(type: number, x: number, y: number, buttonIndex: number): boolean;
         private _prepareFont();
@@ -447,9 +448,9 @@ declare module BABYLON.GUI {
         _draw(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
         private _pointerIsDown;
         private _updateValueFromPointer(x);
-        protected _onPointerDown(coordinates: Vector2, buttonIndex: number): boolean;
-        protected _onPointerMove(coordinates: Vector2): void;
-        protected _onPointerUp(coordinates: Vector2, buttonIndex: number): void;
+        _onPointerDown(target: Control, coordinates: Vector2, buttonIndex: number): boolean;
+        _onPointerMove(target: Control, coordinates: Vector2): void;
+        _onPointerUp(target: Control, coordinates: Vector2, buttonIndex: number): void;
     }
 }
 
@@ -469,7 +470,7 @@ declare module BABYLON.GUI {
         constructor(name?: string);
         protected _getTypeName(): string;
         _draw(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
-        protected _onPointerDown(coordinates: Vector2, buttonIndex: number): boolean;
+        _onPointerDown(target: Control, coordinates: Vector2, buttonIndex: number): boolean;
     }
 }
 
@@ -490,7 +491,7 @@ declare module BABYLON.GUI {
         constructor(name?: string);
         protected _getTypeName(): string;
         _draw(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
-        protected _onPointerDown(coordinates: Vector2, buttonIndex: number): boolean;
+        _onPointerDown(target: Control, coordinates: Vector2, buttonIndex: number): boolean;
     }
 }
 
@@ -577,10 +578,10 @@ declare module BABYLON.GUI {
         constructor(name?: string);
         protected _getTypeName(): string;
         _processPicking(x: number, y: number, type: number, buttonIndex: number): boolean;
-        protected _onPointerEnter(): boolean;
-        _onPointerOut(): void;
-        protected _onPointerDown(coordinates: Vector2, buttonIndex: number): boolean;
-        protected _onPointerUp(coordinates: Vector2, buttonIndex: number): void;
+        _onPointerEnter(target: Control): boolean;
+        _onPointerOut(target: Control): void;
+        _onPointerDown(target: Control, coordinates: Vector2, buttonIndex: number): boolean;
+        _onPointerUp(target: Control, coordinates: Vector2, buttonIndex: number): void;
         static CreateImageButton(name: string, text: string, imageUrl: string): Button;
         static CreateImageOnlyButton(name: string, imageUrl: string): Button;
         static CreateSimpleButton(name: string, text: string): Button;
@@ -621,9 +622,9 @@ declare module BABYLON.GUI {
         private _updateValueFromPointer(x, y);
         private _isPointOnSquare(coordinates);
         private _isPointOnWheel(coordinates);
-        protected _onPointerDown(coordinates: Vector2, buttonIndex: number): boolean;
-        protected _onPointerMove(coordinates: Vector2): void;
-        protected _onPointerUp(coordinates: Vector2, buttonIndex: number): void;
+        _onPointerDown(target: Control, coordinates: Vector2, buttonIndex: number): boolean;
+        _onPointerMove(target: Control, coordinates: Vector2): void;
+        _onPointerUp(target: Control, coordinates: Vector2, buttonIndex: number): void;
     }
 }
 
@@ -669,8 +670,8 @@ declare module BABYLON.GUI {
         processKey(keyCode: number, key?: string): void;
         processKeyboard(evt: KeyboardEvent): void;
         _draw(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
-        protected _onPointerDown(coordinates: Vector2, buttonIndex: number): boolean;
-        protected _onPointerUp(coordinates: Vector2, buttonIndex: number): void;
+        _onPointerDown(target: Control, coordinates: Vector2, buttonIndex: number): boolean;
+        _onPointerUp(target: Control, coordinates: Vector2, buttonIndex: number): void;
         dispose(): void;
     }
 }

+ 59 - 56
dist/preview release/gui/babylon.gui.js

@@ -295,7 +295,7 @@ var BABYLON;
                 if (!this._rootContainer._processPicking(x, y, type, buttonIndex)) {
                     if (type === BABYLON.PointerEventTypes.POINTERMOVE) {
                         if (this._lastControlOver) {
-                            this._lastControlOver._onPointerOut();
+                            this._lastControlOver._onPointerOut(this._lastControlOver);
                         }
                         this._lastControlOver = null;
                     }
@@ -346,7 +346,7 @@ var BABYLON;
                     }
                     else if (pi.type === BABYLON.PointerEventTypes.POINTERMOVE) {
                         if (_this._lastControlOver) {
-                            _this._lastControlOver._onPointerOut();
+                            _this._lastControlOver._onPointerOut(_this._lastControlOver);
                         }
                         _this._lastControlOver = null;
                     }
@@ -379,7 +379,7 @@ var BABYLON;
                 var _this = this;
                 this._canvasPointerOutObserver = scene.getEngine().onCanvasPointerOutObservable.add(function () {
                     if (_this._lastControlOver) {
-                        _this._lastControlOver._onPointerOut();
+                        _this._lastControlOver._onPointerOut(_this._lastControlOver);
                     }
                     _this._lastControlOver = null;
                     if (_this._lastControlDown) {
@@ -1548,69 +1548,69 @@ var BABYLON;
                 this._processObservables(type, x, y, buttonIndex);
                 return true;
             };
-            Control.prototype._onPointerMove = function (coordinates) {
-                if (this.onPointerMoveObservable.hasObservers()) {
-                    this.onPointerMoveObservable.notifyObservers(coordinates);
-                }
+            Control.prototype._onPointerMove = function (target, coordinates) {
+                var canNotify = this.onPointerMoveObservable.notifyObservers(coordinates, -1, target, this);
+                if (canNotify && this.parent != null)
+                    this.parent._onPointerMove(target, coordinates);
             };
-            Control.prototype._onPointerEnter = function () {
+            Control.prototype._onPointerEnter = function (target) {
                 if (this._enterCount !== 0) {
                     return false;
                 }
                 this._enterCount++;
-                if (this.onPointerEnterObservable.hasObservers()) {
-                    this.onPointerEnterObservable.notifyObservers(this);
-                }
+                var canNotify = this.onPointerEnterObservable.notifyObservers(this, -1, target, this);
+                if (canNotify && this.parent != null)
+                    this.parent._onPointerEnter(target);
                 return true;
             };
-            Control.prototype._onPointerOut = function () {
+            Control.prototype._onPointerOut = function (target) {
                 this._enterCount = 0;
-                if (this.onPointerOutObservable.hasObservers()) {
-                    this.onPointerOutObservable.notifyObservers(this);
-                }
+                var canNotify = this.onPointerOutObservable.notifyObservers(this, -1, target, this);
+                if (canNotify && this.parent != null)
+                    this.parent._onPointerOut(target);
             };
-            Control.prototype._onPointerDown = function (coordinates, buttonIndex) {
+            Control.prototype._onPointerDown = function (target, coordinates, buttonIndex) {
                 if (this._downCount !== 0) {
                     return false;
                 }
                 this._downCount++;
-                if (this.onPointerDownObservable.hasObservers()) {
-                    this.onPointerDownObservable.notifyObservers(new GUI.Vector2WithInfo(coordinates, buttonIndex));
-                }
+                var canNotify = this.onPointerDownObservable.notifyObservers(new GUI.Vector2WithInfo(coordinates, buttonIndex), -1, target, this);
+                if (canNotify && this.parent != null)
+                    this.parent._onPointerDown(target, coordinates, buttonIndex);
                 return true;
             };
-            Control.prototype._onPointerUp = function (coordinates, buttonIndex) {
+            Control.prototype._onPointerUp = function (target, coordinates, buttonIndex) {
                 this._downCount = 0;
-                if (this.onPointerUpObservable.hasObservers()) {
-                    this.onPointerUpObservable.notifyObservers(new GUI.Vector2WithInfo(coordinates, buttonIndex));
-                }
+                var canNotify = this.onPointerUpObservable.notifyObservers(new GUI.Vector2WithInfo(coordinates, buttonIndex), -1, target, this);
+                if (canNotify && this.parent != null)
+                    this.parent._onPointerUp(target, coordinates, buttonIndex);
             };
             Control.prototype.forcePointerUp = function () {
-                this._onPointerUp(BABYLON.Vector2.Zero(), 0);
+                this._onPointerUp(this, BABYLON.Vector2.Zero(), 0);
             };
             Control.prototype._processObservables = function (type, x, y, buttonIndex) {
                 this._dummyVector2.copyFromFloats(x, y);
                 if (type === BABYLON.PointerEventTypes.POINTERMOVE) {
-                    this._onPointerMove(this._dummyVector2);
+                    this._onPointerMove(this, this._dummyVector2);
                     var previousControlOver = this._host._lastControlOver;
                     if (previousControlOver && previousControlOver !== this) {
-                        previousControlOver._onPointerOut();
+                        previousControlOver._onPointerOut(this);
                     }
                     if (previousControlOver !== this) {
-                        this._onPointerEnter();
+                        this._onPointerEnter(this);
                     }
                     this._host._lastControlOver = this;
                     return true;
                 }
                 if (type === BABYLON.PointerEventTypes.POINTERDOWN) {
-                    this._onPointerDown(this._dummyVector2, buttonIndex);
+                    this._onPointerDown(this, this._dummyVector2, buttonIndex);
                     this._host._lastControlDown = this;
                     this._host._lastPickedControl = this;
                     return true;
                 }
                 if (type === BABYLON.PointerEventTypes.POINTERUP) {
                     if (this._host._lastControlDown) {
-                        this._host._lastControlDown._onPointerUp(this._dummyVector2, buttonIndex);
+                        this._host._lastControlDown._onPointerUp(this, this._dummyVector2, buttonIndex);
                     }
                     this._host._lastControlDown = null;
                     return true;
@@ -1840,6 +1840,7 @@ var BABYLON;
                 var index = this._children.indexOf(control);
                 if (index !== -1) {
                     this._children.splice(index, 1);
+                    control.parent = null;
                 }
                 this._markAsDirty();
                 return this;
@@ -1853,6 +1854,7 @@ var BABYLON;
                     }
                 }
                 this._children.push(control);
+                control.parent = this;
                 this._markAsDirty();
             };
             Container.prototype._markMatrixAsDirty = function () {
@@ -2648,8 +2650,8 @@ var BABYLON;
             Slider.prototype._updateValueFromPointer = function (x) {
                 this.value = this._minimum + ((x - this._currentMeasure.left) / this._currentMeasure.width) * (this._maximum - this._minimum);
             };
-            Slider.prototype._onPointerDown = function (coordinates, buttonIndex) {
-                if (!_super.prototype._onPointerDown.call(this, coordinates, buttonIndex)) {
+            Slider.prototype._onPointerDown = function (target, coordinates, buttonIndex) {
+                if (!_super.prototype._onPointerDown.call(this, target, coordinates, buttonIndex)) {
                     return false;
                 }
                 this._pointerIsDown = true;
@@ -2657,15 +2659,16 @@ var BABYLON;
                 this._host._capturingControl = this;
                 return true;
             };
-            Slider.prototype._onPointerMove = function (coordinates) {
+            Slider.prototype._onPointerMove = function (target, coordinates) {
                 if (this._pointerIsDown) {
                     this._updateValueFromPointer(coordinates.x);
                 }
+                _super.prototype._onPointerMove.call(this, target, coordinates);
             };
-            Slider.prototype._onPointerUp = function (coordinates, buttonIndex) {
+            Slider.prototype._onPointerUp = function (target, coordinates, buttonIndex) {
                 this._pointerIsDown = false;
                 this._host._capturingControl = null;
-                _super.prototype._onPointerUp.call(this, coordinates, buttonIndex);
+                _super.prototype._onPointerUp.call(this, target, coordinates, buttonIndex);
             };
             return Slider;
         }(GUI.Control));
@@ -2776,8 +2779,8 @@ var BABYLON;
                 context.restore();
             };
             // Events
-            Checkbox.prototype._onPointerDown = function (coordinates, buttonIndex) {
-                if (!_super.prototype._onPointerDown.call(this, coordinates, buttonIndex)) {
+            Checkbox.prototype._onPointerDown = function (target, coordinates, buttonIndex) {
+                if (!_super.prototype._onPointerDown.call(this, target, coordinates, buttonIndex)) {
                     return false;
                 }
                 this.isChecked = !this.isChecked;
@@ -2913,8 +2916,8 @@ var BABYLON;
                 context.restore();
             };
             // Events
-            RadioButton.prototype._onPointerDown = function (coordinates, buttonIndex) {
-                if (!_super.prototype._onPointerDown.call(this, coordinates, buttonIndex)) {
+            RadioButton.prototype._onPointerDown = function (target, coordinates, buttonIndex) {
+                if (!_super.prototype._onPointerDown.call(this, target, coordinates, buttonIndex)) {
                     return false;
                 }
                 this.isChecked = !this.isChecked;
@@ -3422,8 +3425,8 @@ var BABYLON;
                 this._processObservables(type, x, y, buttonIndex);
                 return true;
             };
-            Button.prototype._onPointerEnter = function () {
-                if (!_super.prototype._onPointerEnter.call(this)) {
+            Button.prototype._onPointerEnter = function (target) {
+                if (!_super.prototype._onPointerEnter.call(this, target)) {
                     return false;
                 }
                 if (this.pointerEnterAnimation) {
@@ -3431,14 +3434,14 @@ var BABYLON;
                 }
                 return true;
             };
-            Button.prototype._onPointerOut = function () {
+            Button.prototype._onPointerOut = function (target) {
                 if (this.pointerOutAnimation) {
                     this.pointerOutAnimation();
                 }
-                _super.prototype._onPointerOut.call(this);
+                _super.prototype._onPointerOut.call(this, target);
             };
-            Button.prototype._onPointerDown = function (coordinates, buttonIndex) {
-                if (!_super.prototype._onPointerDown.call(this, coordinates, buttonIndex)) {
+            Button.prototype._onPointerDown = function (target, coordinates, buttonIndex) {
+                if (!_super.prototype._onPointerDown.call(this, target, coordinates, buttonIndex)) {
                     return false;
                 }
                 if (this.pointerDownAnimation) {
@@ -3446,11 +3449,11 @@ var BABYLON;
                 }
                 return true;
             };
-            Button.prototype._onPointerUp = function (coordinates, buttonIndex) {
+            Button.prototype._onPointerUp = function (target, coordinates, buttonIndex) {
                 if (this.pointerUpAnimation) {
                     this.pointerUpAnimation();
                 }
-                _super.prototype._onPointerUp.call(this, coordinates, buttonIndex);
+                _super.prototype._onPointerUp.call(this, target, coordinates, buttonIndex);
             };
             // Statics
             Button.CreateImageButton = function (name, text, imageUrl) {
@@ -3820,8 +3823,8 @@ var BABYLON;
                 }
                 return false;
             };
-            ColorPicker.prototype._onPointerDown = function (coordinates, buttonIndex) {
-                if (!_super.prototype._onPointerDown.call(this, coordinates, buttonIndex)) {
+            ColorPicker.prototype._onPointerDown = function (target, coordinates, buttonIndex) {
+                if (!_super.prototype._onPointerDown.call(this, target, coordinates, buttonIndex)) {
                     return false;
                 }
                 this._pointerIsDown = true;
@@ -3837,16 +3840,16 @@ var BABYLON;
                 this._host._capturingControl = this;
                 return true;
             };
-            ColorPicker.prototype._onPointerMove = function (coordinates) {
+            ColorPicker.prototype._onPointerMove = function (target, coordinates) {
                 if (this._pointerIsDown) {
                     this._updateValueFromPointer(coordinates.x, coordinates.y);
                 }
-                _super.prototype._onPointerMove.call(this, coordinates);
+                _super.prototype._onPointerMove.call(this, target, coordinates);
             };
-            ColorPicker.prototype._onPointerUp = function (coordinates, buttonIndex) {
+            ColorPicker.prototype._onPointerUp = function (target, coordinates, buttonIndex) {
                 this._pointerIsDown = false;
                 this._host._capturingControl = null;
-                _super.prototype._onPointerUp.call(this, coordinates, buttonIndex);
+                _super.prototype._onPointerUp.call(this, target, coordinates, buttonIndex);
             };
             return ColorPicker;
         }(GUI.Control));
@@ -4238,8 +4241,8 @@ var BABYLON;
                 }
                 context.restore();
             };
-            InputText.prototype._onPointerDown = function (coordinates, buttonIndex) {
-                if (!_super.prototype._onPointerDown.call(this, coordinates, buttonIndex)) {
+            InputText.prototype._onPointerDown = function (target, coordinates, buttonIndex) {
+                if (!_super.prototype._onPointerDown.call(this, target, coordinates, buttonIndex)) {
                     return false;
                 }
                 this._clickedCoordinate = coordinates.x;
@@ -4252,8 +4255,8 @@ var BABYLON;
                 this._host.focusedControl = this;
                 return true;
             };
-            InputText.prototype._onPointerUp = function (coordinates, buttonIndex) {
-                _super.prototype._onPointerUp.call(this, coordinates, buttonIndex);
+            InputText.prototype._onPointerUp = function (target, coordinates, buttonIndex) {
+                _super.prototype._onPointerUp.call(this, target, coordinates, buttonIndex);
             };
             InputText.prototype.dispose = function () {
                 _super.prototype.dispose.call(this);

La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 3 - 3
dist/preview release/gui/babylon.gui.min.js


+ 20 - 19
dist/preview release/gui/babylon.gui.module.d.ts

@@ -137,6 +137,7 @@ declare module BABYLON.GUI {
         private _zIndex;
         _root: Container;
         _host: AdvancedDynamicTexture;
+        parent: Container;
         _currentMeasure: Measure;
         private _fontFamily;
         private _fontStyle;
@@ -281,11 +282,11 @@ declare module BABYLON.GUI {
         _draw(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
         contains(x: number, y: number): boolean;
         _processPicking(x: number, y: number, type: number, buttonIndex: number): boolean;
-        protected _onPointerMove(coordinates: Vector2): void;
-        protected _onPointerEnter(): boolean;
-        _onPointerOut(): void;
-        protected _onPointerDown(coordinates: Vector2, buttonIndex: number): boolean;
-        protected _onPointerUp(coordinates: Vector2, buttonIndex: number): void;
+        _onPointerMove(target: Control, coordinates: Vector2): void;
+        _onPointerEnter(target: Control): boolean;
+        _onPointerOut(target: Control): void;
+        _onPointerDown(target: Control, coordinates: Vector2, buttonIndex: number): boolean;
+        _onPointerUp(target: Control, coordinates: Vector2, buttonIndex: number): void;
         forcePointerUp(): void;
         _processObservables(type: number, x: number, y: number, buttonIndex: number): boolean;
         private _prepareFont();
@@ -452,9 +453,9 @@ declare module BABYLON.GUI {
         _draw(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
         private _pointerIsDown;
         private _updateValueFromPointer(x);
-        protected _onPointerDown(coordinates: Vector2, buttonIndex: number): boolean;
-        protected _onPointerMove(coordinates: Vector2): void;
-        protected _onPointerUp(coordinates: Vector2, buttonIndex: number): void;
+        _onPointerDown(target: Control, coordinates: Vector2, buttonIndex: number): boolean;
+        _onPointerMove(target: Control, coordinates: Vector2): void;
+        _onPointerUp(target: Control, coordinates: Vector2, buttonIndex: number): void;
     }
 }
 
@@ -474,7 +475,7 @@ declare module BABYLON.GUI {
         constructor(name?: string);
         protected _getTypeName(): string;
         _draw(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
-        protected _onPointerDown(coordinates: Vector2, buttonIndex: number): boolean;
+        _onPointerDown(target: Control, coordinates: Vector2, buttonIndex: number): boolean;
     }
 }
 
@@ -495,7 +496,7 @@ declare module BABYLON.GUI {
         constructor(name?: string);
         protected _getTypeName(): string;
         _draw(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
-        protected _onPointerDown(coordinates: Vector2, buttonIndex: number): boolean;
+        _onPointerDown(target: Control, coordinates: Vector2, buttonIndex: number): boolean;
     }
 }
 
@@ -582,10 +583,10 @@ declare module BABYLON.GUI {
         constructor(name?: string);
         protected _getTypeName(): string;
         _processPicking(x: number, y: number, type: number, buttonIndex: number): boolean;
-        protected _onPointerEnter(): boolean;
-        _onPointerOut(): void;
-        protected _onPointerDown(coordinates: Vector2, buttonIndex: number): boolean;
-        protected _onPointerUp(coordinates: Vector2, buttonIndex: number): void;
+        _onPointerEnter(target: Control): boolean;
+        _onPointerOut(target: Control): void;
+        _onPointerDown(target: Control, coordinates: Vector2, buttonIndex: number): boolean;
+        _onPointerUp(target: Control, coordinates: Vector2, buttonIndex: number): void;
         static CreateImageButton(name: string, text: string, imageUrl: string): Button;
         static CreateImageOnlyButton(name: string, imageUrl: string): Button;
         static CreateSimpleButton(name: string, text: string): Button;
@@ -626,9 +627,9 @@ declare module BABYLON.GUI {
         private _updateValueFromPointer(x, y);
         private _isPointOnSquare(coordinates);
         private _isPointOnWheel(coordinates);
-        protected _onPointerDown(coordinates: Vector2, buttonIndex: number): boolean;
-        protected _onPointerMove(coordinates: Vector2): void;
-        protected _onPointerUp(coordinates: Vector2, buttonIndex: number): void;
+        _onPointerDown(target: Control, coordinates: Vector2, buttonIndex: number): boolean;
+        _onPointerMove(target: Control, coordinates: Vector2): void;
+        _onPointerUp(target: Control, coordinates: Vector2, buttonIndex: number): void;
     }
 }
 
@@ -674,8 +675,8 @@ declare module BABYLON.GUI {
         processKey(keyCode: number, key?: string): void;
         processKeyboard(evt: KeyboardEvent): void;
         _draw(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
-        protected _onPointerDown(coordinates: Vector2, buttonIndex: number): boolean;
-        protected _onPointerUp(coordinates: Vector2, buttonIndex: number): void;
+        _onPointerDown(target: Control, coordinates: Vector2, buttonIndex: number): boolean;
+        _onPointerUp(target: Control, coordinates: Vector2, buttonIndex: number): void;
         dispose(): void;
     }
 }

+ 7 - 4
dist/preview release/loaders/babylon.glTF2FileLoader.d.ts

@@ -228,6 +228,8 @@ declare module BABYLON.GLTF2 {
         targets?: {
             [name: string]: number;
         }[];
+        vertexData: VertexData;
+        targetsVertexData: VertexData[];
     }
     interface IGLTFMesh extends IGLTFChildRootProperty {
         primitives: IGLTFMeshPrimitive[];
@@ -342,10 +344,12 @@ declare module BABYLON.GLTF2 {
         private _loadScene(context, scene, nodeNames);
         _loadNode(context: string, node: IGLTFNode): void;
         private _loadMesh(context, node, mesh);
-        private _loadPrimitive(context, node, mesh, primitive, onSuccess);
+        private _loadAllVertexDataAsync(context, mesh, onSuccess);
         private _loadVertexDataAsync(context, mesh, primitive, onSuccess);
-        private _createMorphTargets(node, mesh, primitive);
-        private _loadMorphTargetsData(context, mesh, primitive, vertexData, babylonMesh);
+        private _createMorphTargets(context, node, mesh);
+        private _loadMorphTargets(context, node, mesh);
+        private _loadAllMorphTargetVertexDataAsync(context, node, mesh, onSuccess);
+        private _loadMorphTargetVertexDataAsync(context, vertexData, attributes, onSuccess);
         private _loadTransform(node);
         private _loadSkin(context, skin);
         private _createBone(node, skin, parent, localMatrix, baseMatrix, index);
@@ -394,7 +398,6 @@ declare module BABYLON.GLTF2 {
         * @param uri: the uri to decode
         */
         static DecodeBase64(uri: string): ArrayBuffer;
-        static ForEach(view: Uint16Array | Uint32Array | Float32Array, func: (nvalue: number, index: number) => void): void;
         static ValidateUri(uri: string): boolean;
         static AssignIndices(array: Array<{
             index?: number;

+ 153 - 107
dist/preview release/loaders/babylon.glTF2FileLoader.js

@@ -591,51 +591,40 @@ var BABYLON;
                 }
             };
             GLTFLoader.prototype._loadMesh = function (context, node, mesh) {
-                node.babylonMesh.name = mesh.name || node.babylonMesh.name;
-                var babylonMultiMaterial = new BABYLON.MultiMaterial(node.babylonMesh.name, this._babylonScene);
-                node.babylonMesh.material = babylonMultiMaterial;
-                var geometry = new BABYLON.Geometry(node.babylonMesh.name, this._babylonScene, null, false, node.babylonMesh);
-                var vertexData = new BABYLON.VertexData();
-                vertexData.positions = [];
-                vertexData.indices = [];
-                var subMeshInfos = [];
-                var numRemainingPrimitives = mesh.primitives.length;
-                for (var index = 0; index < mesh.primitives.length; index++) {
-                    var primitive = mesh.primitives[index];
-                    this._loadPrimitive(context + "/primitives/" + index, node, mesh, primitive, function (subVertexData, loadMaterial) {
-                        subMeshInfos.push({
-                            verticesStart: vertexData.positions.length,
-                            verticesCount: subVertexData.positions.length,
-                            indicesStart: vertexData.indices.length,
-                            indicesCount: subVertexData.indices.length,
-                            loadMaterial: loadMaterial
-                        });
-                        vertexData.merge(subVertexData);
-                        if (--numRemainingPrimitives === 0) {
-                            geometry.setAllVerticesData(vertexData, false);
-                            // TODO: optimize this so that sub meshes can be created without being overwritten after setting vertex data.
-                            // Sub meshes must be cleared and created after setting vertex data because of mesh._createGlobalSubMesh.
-                            node.babylonMesh.subMeshes = [];
-                            for (var index = 0; index < subMeshInfos.length; index++) {
-                                var info = subMeshInfos[index];
-                                BABYLON.SubMesh.AddToMesh(index, info.verticesStart, info.verticesCount, info.indicesStart, info.indicesCount, node.babylonMesh);
-                                info.loadMaterial(index);
-                            }
-                        }
-                    });
-                }
-            };
-            GLTFLoader.prototype._loadPrimitive = function (context, node, mesh, primitive, onSuccess) {
                 var _this = this;
-                var subMaterials = node.babylonMesh.material.subMaterials;
-                if (primitive.mode && primitive.mode !== GLTF2.EMeshPrimitiveMode.TRIANGLES) {
-                    // TODO: handle other primitive modes
-                    throw new Error(context + ": Mode " + primitive.mode + " is not currently supported");
-                }
-                this._createMorphTargets(node, mesh, primitive);
-                this._loadVertexDataAsync(context, mesh, primitive, function (vertexData) {
-                    _this._loadMorphTargetsData(context, mesh, primitive, vertexData, node.babylonMesh);
-                    var loadMaterial = function (index) {
+                node.babylonMesh.name = node.babylonMesh.name || mesh.name;
+                if (!mesh.primitives || mesh.primitives.length === 0) {
+                    throw new Error(context + ": Primitives are missing");
+                }
+                this._createMorphTargets(context, node, mesh);
+                this._loadAllVertexDataAsync(context, mesh, function () {
+                    _this._loadMorphTargets(context, node, mesh);
+                    var primitives = mesh.primitives;
+                    var vertexData = new BABYLON.VertexData();
+                    for (var _i = 0, primitives_1 = primitives; _i < primitives_1.length; _i++) {
+                        var primitive = primitives_1[_i];
+                        vertexData.merge(primitive.vertexData);
+                    }
+                    new BABYLON.Geometry(node.babylonMesh.name, _this._babylonScene, vertexData, false, node.babylonMesh);
+                    // TODO: optimize this so that sub meshes can be created without being overwritten after setting vertex data.
+                    // Sub meshes must be cleared and created after setting vertex data because of mesh._createGlobalSubMesh.
+                    node.babylonMesh.subMeshes = [];
+                    var verticesStart = 0;
+                    var indicesStart = 0;
+                    for (var index = 0; index < primitives.length; index++) {
+                        var vertexData = primitives[index].vertexData;
+                        var verticesCount = vertexData.positions.length;
+                        var indicesCount = vertexData.indices.length;
+                        BABYLON.SubMesh.AddToMesh(index, verticesStart, verticesCount, indicesStart, indicesCount, node.babylonMesh);
+                        verticesStart += verticesCount;
+                        indicesStart += indicesCount;
+                    }
+                    ;
+                    var multiMaterial = new BABYLON.MultiMaterial(node.babylonMesh.name, _this._babylonScene);
+                    node.babylonMesh.material = multiMaterial;
+                    var subMaterials = multiMaterial.subMaterials;
+                    for (var index = 0; index < primitives.length; index++) {
+                        var primitive = primitives[index];
                         if (primitive.material == null) {
                             subMaterials[index] = _this._getDefaultMaterial();
                         }
@@ -660,24 +649,45 @@ var BABYLON;
                                 }
                             });
                         }
-                    };
-                    onSuccess(vertexData, loadMaterial);
+                    }
+                    ;
                 });
             };
+            GLTFLoader.prototype._loadAllVertexDataAsync = function (context, mesh, onSuccess) {
+                var primitives = mesh.primitives;
+                var numRemainingPrimitives = primitives.length;
+                var _loop_1 = function () {
+                    var primitive = primitives[index];
+                    this_1._loadVertexDataAsync(context + "/primitive/" + index, mesh, primitive, function (vertexData) {
+                        primitive.vertexData = vertexData;
+                        if (--numRemainingPrimitives === 0) {
+                            onSuccess();
+                        }
+                    });
+                };
+                var this_1 = this;
+                for (var index = 0; index < primitives.length; index++) {
+                    _loop_1();
+                }
+            };
             GLTFLoader.prototype._loadVertexDataAsync = function (context, mesh, primitive, onSuccess) {
                 var _this = this;
                 var attributes = primitive.attributes;
                 if (!attributes) {
                     throw new Error(context + ": Attributes are missing");
                 }
+                if (primitive.mode && primitive.mode !== GLTF2.EMeshPrimitiveMode.TRIANGLES) {
+                    // TODO: handle other primitive modes
+                    throw new Error(context + ": Mode " + primitive.mode + " is not currently supported");
+                }
                 var vertexData = new BABYLON.VertexData();
                 var numRemainingAttributes = Object.keys(attributes).length;
-                var _loop_1 = function (attribute) {
-                    accessor = GLTF2.GLTFUtils.GetArrayItem(this_1._gltf.accessors, attributes[attribute]);
+                var _loop_2 = function (attribute) {
+                    accessor = GLTF2.GLTFUtils.GetArrayItem(this_2._gltf.accessors, attributes[attribute]);
                     if (!accessor) {
                         throw new Error(context + ": Failed to find attribute '" + attribute + "' accessor " + attributes[attribute]);
                     }
-                    this_1._loadAccessorAsync("#/accessors/" + accessor.index, accessor, function (data) {
+                    this_2._loadAccessorAsync("#/accessors/" + accessor.index, accessor, function (data) {
                         switch (attribute) {
                             case "NORMAL":
                                 vertexData.normals = data;
@@ -726,78 +736,119 @@ var BABYLON;
                         }
                     });
                 };
-                var this_1 = this, accessor;
+                var this_2 = this, accessor;
                 for (var attribute in attributes) {
-                    _loop_1(attribute);
+                    _loop_2(attribute);
                 }
             };
-            GLTFLoader.prototype._createMorphTargets = function (node, mesh, primitive) {
-                var targets = primitive.targets;
+            GLTFLoader.prototype._createMorphTargets = function (context, node, mesh) {
+                var primitives = mesh.primitives;
+                var targets = primitives[0].targets;
                 if (!targets) {
                     return;
                 }
-                if (!node.babylonMesh.morphTargetManager) {
-                    node.babylonMesh.morphTargetManager = new BABYLON.MorphTargetManager();
+                for (var _i = 0, primitives_2 = primitives; _i < primitives_2.length; _i++) {
+                    var primitive = primitives_2[_i];
+                    if (!primitive.targets || primitive.targets.length != targets.length) {
+                        throw new Error(context + ": All primitives are required to list the same number of targets");
+                    }
                 }
+                var morphTargetManager = new BABYLON.MorphTargetManager();
+                node.babylonMesh.morphTargetManager = morphTargetManager;
                 for (var index = 0; index < targets.length; index++) {
                     var weight = node.weights ? node.weights[index] : mesh.weights ? mesh.weights[index] : 0;
-                    node.babylonMesh.morphTargetManager.addTarget(new BABYLON.MorphTarget("morphTarget" + index, weight));
+                    morphTargetManager.addTarget(new BABYLON.MorphTarget("morphTarget" + index, weight));
                 }
             };
-            GLTFLoader.prototype._loadMorphTargetsData = function (context, mesh, primitive, vertexData, babylonMesh) {
-                var targets = primitive.targets;
-                if (!targets) {
+            GLTFLoader.prototype._loadMorphTargets = function (context, node, mesh) {
+                var morphTargetManager = node.babylonMesh.morphTargetManager;
+                if (!morphTargetManager) {
                     return;
                 }
-                var _loop_2 = function () {
-                    var babylonMorphTarget = babylonMesh.morphTargetManager.getTarget(index);
-                    attributes = targets[index];
-                    var _loop_3 = function (attribute) {
-                        accessor = GLTF2.GLTFUtils.GetArrayItem(this_2._gltf.accessors, attributes[attribute]);
-                        if (!accessor) {
-                            throw new Error(context + "/targets/" + index + ": Failed to find attribute '" + attribute + "' accessor " + attributes[attribute]);
+                this._loadAllMorphTargetVertexDataAsync(context, node, mesh, function () {
+                    var numTargets = morphTargetManager.numTargets;
+                    for (var index = 0; index < numTargets; index++) {
+                        var vertexData = new BABYLON.VertexData();
+                        for (var _i = 0, _a = mesh.primitives; _i < _a.length; _i++) {
+                            var primitive = _a[_i];
+                            vertexData.merge(primitive.targetsVertexData[index]);
                         }
-                        this_2._loadAccessorAsync("#/accessors/" + accessor.index, accessor, function (data) {
-                            if (accessor.name) {
-                                babylonMorphTarget.name = accessor.name;
-                            }
-                            // glTF stores morph target information as deltas while babylon.js expects the final data.
-                            // As a result we have to add the original data to the delta to calculate the final data.
-                            var values = data;
-                            switch (attribute) {
-                                case "NORMAL":
-                                    GLTF2.GLTFUtils.ForEach(values, function (v, i) { return values[i] += vertexData.normals[i]; });
-                                    babylonMorphTarget.setNormals(values);
-                                    break;
-                                case "POSITION":
-                                    GLTF2.GLTFUtils.ForEach(values, function (v, i) { return values[i] += vertexData.positions[i]; });
-                                    babylonMorphTarget.setPositions(values);
-                                    break;
-                                case "TANGENT":
-                                    // Tangent data for morph targets is stored as xyz delta.
-                                    // The vertexData.tangent is stored as xyzw.
-                                    // So we need to skip every fourth vertexData.tangent.
-                                    for (var i = 0, j = 0; i < values.length; i++, j++) {
-                                        values[i] += vertexData.tangents[j];
-                                        if ((i + 1) % 3 == 0) {
-                                            j++;
-                                        }
-                                    }
-                                    babylonMorphTarget.setTangents(values);
-                                    break;
-                                default:
-                                    BABYLON.Tools.Warn("Ignoring unrecognized attribute '" + attribute + "'");
-                                    break;
+                        var target = morphTargetManager.getTarget(index);
+                        target.setNormals(vertexData.normals);
+                        target.setPositions(vertexData.positions);
+                        target.setTangents(vertexData.tangents);
+                    }
+                });
+            };
+            GLTFLoader.prototype._loadAllMorphTargetVertexDataAsync = function (context, node, mesh, onSuccess) {
+                var numRemainingTargets = mesh.primitives.length * node.babylonMesh.morphTargetManager.numTargets;
+                for (var _i = 0, _a = mesh.primitives; _i < _a.length; _i++) {
+                    var primitive = _a[_i];
+                    var targets = primitive.targets;
+                    primitive.targetsVertexData = new Array(targets.length);
+                    var _loop_3 = function (index) {
+                        this_3._loadMorphTargetVertexDataAsync(context + "/targets/" + index, primitive.vertexData, targets[index], function (vertexData) {
+                            primitive.targetsVertexData[index] = vertexData;
+                            if (--numRemainingTargets === 0) {
+                                onSuccess();
                             }
                         });
                     };
-                    for (var attribute in attributes) {
-                        _loop_3(attribute);
+                    var this_3 = this;
+                    for (var index = 0; index < targets.length; index++) {
+                        _loop_3(index);
+                    }
+                }
+            };
+            GLTFLoader.prototype._loadMorphTargetVertexDataAsync = function (context, vertexData, attributes, onSuccess) {
+                var targetVertexData = new BABYLON.VertexData();
+                var numRemainingAttributes = Object.keys(attributes).length;
+                var _loop_4 = function (attribute) {
+                    accessor = GLTF2.GLTFUtils.GetArrayItem(this_4._gltf.accessors, attributes[attribute]);
+                    if (!accessor) {
+                        throw new Error(context + ": Failed to find attribute '" + attribute + "' accessor " + attributes[attribute]);
                     }
+                    this_4._loadAccessorAsync("#/accessors/" + accessor.index, accessor, function (data) {
+                        // glTF stores morph target information as deltas while babylon.js expects the final data.
+                        // As a result we have to add the original data to the delta to calculate the final data.
+                        var values = data;
+                        switch (attribute) {
+                            case "NORMAL":
+                                for (var i = 0; i < values.length; i++) {
+                                    values[i] += vertexData.normals[i];
+                                }
+                                targetVertexData.normals = values;
+                                break;
+                            case "POSITION":
+                                for (var i = 0; i < values.length; i++) {
+                                    values[i] += vertexData.positions[i];
+                                }
+                                targetVertexData.positions = values;
+                                break;
+                            case "TANGENT":
+                                // Tangent data for morph targets is stored as xyz delta.
+                                // The vertexData.tangent is stored as xyzw.
+                                // So we need to skip every fourth vertexData.tangent.
+                                for (var i = 0, j = 0; i < values.length; i++, j++) {
+                                    values[i] += vertexData.tangents[j];
+                                    if ((i + 1) % 3 == 0) {
+                                        j++;
+                                    }
+                                }
+                                targetVertexData.tangents = values;
+                                break;
+                            default:
+                                BABYLON.Tools.Warn("Ignoring unrecognized attribute '" + attribute + "'");
+                                break;
+                        }
+                        if (--numRemainingAttributes === 0) {
+                            onSuccess(targetVertexData);
+                        }
+                    });
                 };
-                var this_2 = this, attributes, accessor;
-                for (var index = 0; index < targets.length; index++) {
-                    _loop_2();
+                var this_4 = this, accessor;
+                for (var attribute in attributes) {
+                    _loop_4(attribute);
                 }
             };
             GLTFLoader.prototype._loadTransform = function (node) {
@@ -1512,11 +1563,6 @@ var BABYLON;
                 }
                 return bufferView.buffer;
             };
-            GLTFUtils.ForEach = function (view, func) {
-                for (var index = 0; index < view.length; index++) {
-                    func(view[index], index);
-                }
-            };
             GLTFUtils.ValidateUri = function (uri) {
                 return (uri.indexOf("..") === -1);
             };

La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 2 - 2
dist/preview release/loaders/babylon.glTF2FileLoader.min.js


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

@@ -774,6 +774,8 @@ declare module BABYLON.GLTF2 {
         targets?: {
             [name: string]: number;
         }[];
+        vertexData: VertexData;
+        targetsVertexData: VertexData[];
     }
     interface IGLTFMesh extends IGLTFChildRootProperty {
         primitives: IGLTFMeshPrimitive[];
@@ -888,10 +890,12 @@ declare module BABYLON.GLTF2 {
         private _loadScene(context, scene, nodeNames);
         _loadNode(context: string, node: IGLTFNode): void;
         private _loadMesh(context, node, mesh);
-        private _loadPrimitive(context, node, mesh, primitive, onSuccess);
+        private _loadAllVertexDataAsync(context, mesh, onSuccess);
         private _loadVertexDataAsync(context, mesh, primitive, onSuccess);
-        private _createMorphTargets(node, mesh, primitive);
-        private _loadMorphTargetsData(context, mesh, primitive, vertexData, babylonMesh);
+        private _createMorphTargets(context, node, mesh);
+        private _loadMorphTargets(context, node, mesh);
+        private _loadAllMorphTargetVertexDataAsync(context, node, mesh, onSuccess);
+        private _loadMorphTargetVertexDataAsync(context, vertexData, attributes, onSuccess);
         private _loadTransform(node);
         private _loadSkin(context, skin);
         private _createBone(node, skin, parent, localMatrix, baseMatrix, index);
@@ -940,7 +944,6 @@ declare module BABYLON.GLTF2 {
         * @param uri: the uri to decode
         */
         static DecodeBase64(uri: string): ArrayBuffer;
-        static ForEach(view: Uint16Array | Uint32Array | Float32Array, func: (nvalue: number, index: number) => void): void;
         static ValidateUri(uri: string): boolean;
         static AssignIndices(array: Array<{
             index?: number;

+ 154 - 108
dist/preview release/loaders/babylon.glTFFileLoader.js

@@ -2697,51 +2697,40 @@ var BABYLON;
                 }
             };
             GLTFLoader.prototype._loadMesh = function (context, node, mesh) {
-                node.babylonMesh.name = mesh.name || node.babylonMesh.name;
-                var babylonMultiMaterial = new BABYLON.MultiMaterial(node.babylonMesh.name, this._babylonScene);
-                node.babylonMesh.material = babylonMultiMaterial;
-                var geometry = new BABYLON.Geometry(node.babylonMesh.name, this._babylonScene, null, false, node.babylonMesh);
-                var vertexData = new BABYLON.VertexData();
-                vertexData.positions = [];
-                vertexData.indices = [];
-                var subMeshInfos = [];
-                var numRemainingPrimitives = mesh.primitives.length;
-                for (var index = 0; index < mesh.primitives.length; index++) {
-                    var primitive = mesh.primitives[index];
-                    this._loadPrimitive(context + "/primitives/" + index, node, mesh, primitive, function (subVertexData, loadMaterial) {
-                        subMeshInfos.push({
-                            verticesStart: vertexData.positions.length,
-                            verticesCount: subVertexData.positions.length,
-                            indicesStart: vertexData.indices.length,
-                            indicesCount: subVertexData.indices.length,
-                            loadMaterial: loadMaterial
-                        });
-                        vertexData.merge(subVertexData);
-                        if (--numRemainingPrimitives === 0) {
-                            geometry.setAllVerticesData(vertexData, false);
-                            // TODO: optimize this so that sub meshes can be created without being overwritten after setting vertex data.
-                            // Sub meshes must be cleared and created after setting vertex data because of mesh._createGlobalSubMesh.
-                            node.babylonMesh.subMeshes = [];
-                            for (var index = 0; index < subMeshInfos.length; index++) {
-                                var info = subMeshInfos[index];
-                                BABYLON.SubMesh.AddToMesh(index, info.verticesStart, info.verticesCount, info.indicesStart, info.indicesCount, node.babylonMesh);
-                                info.loadMaterial(index);
-                            }
-                        }
-                    });
-                }
-            };
-            GLTFLoader.prototype._loadPrimitive = function (context, node, mesh, primitive, onSuccess) {
                 var _this = this;
-                var subMaterials = node.babylonMesh.material.subMaterials;
-                if (primitive.mode && primitive.mode !== GLTF2.EMeshPrimitiveMode.TRIANGLES) {
-                    // TODO: handle other primitive modes
-                    throw new Error(context + ": Mode " + primitive.mode + " is not currently supported");
-                }
-                this._createMorphTargets(node, mesh, primitive);
-                this._loadVertexDataAsync(context, mesh, primitive, function (vertexData) {
-                    _this._loadMorphTargetsData(context, mesh, primitive, vertexData, node.babylonMesh);
-                    var loadMaterial = function (index) {
+                node.babylonMesh.name = node.babylonMesh.name || mesh.name;
+                if (!mesh.primitives || mesh.primitives.length === 0) {
+                    throw new Error(context + ": Primitives are missing");
+                }
+                this._createMorphTargets(context, node, mesh);
+                this._loadAllVertexDataAsync(context, mesh, function () {
+                    _this._loadMorphTargets(context, node, mesh);
+                    var primitives = mesh.primitives;
+                    var vertexData = new BABYLON.VertexData();
+                    for (var _i = 0, primitives_1 = primitives; _i < primitives_1.length; _i++) {
+                        var primitive = primitives_1[_i];
+                        vertexData.merge(primitive.vertexData);
+                    }
+                    new BABYLON.Geometry(node.babylonMesh.name, _this._babylonScene, vertexData, false, node.babylonMesh);
+                    // TODO: optimize this so that sub meshes can be created without being overwritten after setting vertex data.
+                    // Sub meshes must be cleared and created after setting vertex data because of mesh._createGlobalSubMesh.
+                    node.babylonMesh.subMeshes = [];
+                    var verticesStart = 0;
+                    var indicesStart = 0;
+                    for (var index = 0; index < primitives.length; index++) {
+                        var vertexData = primitives[index].vertexData;
+                        var verticesCount = vertexData.positions.length;
+                        var indicesCount = vertexData.indices.length;
+                        BABYLON.SubMesh.AddToMesh(index, verticesStart, verticesCount, indicesStart, indicesCount, node.babylonMesh);
+                        verticesStart += verticesCount;
+                        indicesStart += indicesCount;
+                    }
+                    ;
+                    var multiMaterial = new BABYLON.MultiMaterial(node.babylonMesh.name, _this._babylonScene);
+                    node.babylonMesh.material = multiMaterial;
+                    var subMaterials = multiMaterial.subMaterials;
+                    for (var index = 0; index < primitives.length; index++) {
+                        var primitive = primitives[index];
                         if (primitive.material == null) {
                             subMaterials[index] = _this._getDefaultMaterial();
                         }
@@ -2766,24 +2755,45 @@ var BABYLON;
                                 }
                             });
                         }
-                    };
-                    onSuccess(vertexData, loadMaterial);
+                    }
+                    ;
                 });
             };
+            GLTFLoader.prototype._loadAllVertexDataAsync = function (context, mesh, onSuccess) {
+                var primitives = mesh.primitives;
+                var numRemainingPrimitives = primitives.length;
+                var _loop_1 = function () {
+                    var primitive = primitives[index];
+                    this_1._loadVertexDataAsync(context + "/primitive/" + index, mesh, primitive, function (vertexData) {
+                        primitive.vertexData = vertexData;
+                        if (--numRemainingPrimitives === 0) {
+                            onSuccess();
+                        }
+                    });
+                };
+                var this_1 = this;
+                for (var index = 0; index < primitives.length; index++) {
+                    _loop_1();
+                }
+            };
             GLTFLoader.prototype._loadVertexDataAsync = function (context, mesh, primitive, onSuccess) {
                 var _this = this;
                 var attributes = primitive.attributes;
                 if (!attributes) {
                     throw new Error(context + ": Attributes are missing");
                 }
+                if (primitive.mode && primitive.mode !== GLTF2.EMeshPrimitiveMode.TRIANGLES) {
+                    // TODO: handle other primitive modes
+                    throw new Error(context + ": Mode " + primitive.mode + " is not currently supported");
+                }
                 var vertexData = new BABYLON.VertexData();
                 var numRemainingAttributes = Object.keys(attributes).length;
-                var _loop_1 = function (attribute) {
-                    accessor = GLTF2.GLTFUtils.GetArrayItem(this_1._gltf.accessors, attributes[attribute]);
+                var _loop_2 = function (attribute) {
+                    accessor = GLTF2.GLTFUtils.GetArrayItem(this_2._gltf.accessors, attributes[attribute]);
                     if (!accessor) {
                         throw new Error(context + ": Failed to find attribute '" + attribute + "' accessor " + attributes[attribute]);
                     }
-                    this_1._loadAccessorAsync("#/accessors/" + accessor.index, accessor, function (data) {
+                    this_2._loadAccessorAsync("#/accessors/" + accessor.index, accessor, function (data) {
                         switch (attribute) {
                             case "NORMAL":
                                 vertexData.normals = data;
@@ -2832,78 +2842,119 @@ var BABYLON;
                         }
                     });
                 };
-                var this_1 = this, accessor;
+                var this_2 = this, accessor;
                 for (var attribute in attributes) {
-                    _loop_1(attribute);
+                    _loop_2(attribute);
                 }
             };
-            GLTFLoader.prototype._createMorphTargets = function (node, mesh, primitive) {
-                var targets = primitive.targets;
+            GLTFLoader.prototype._createMorphTargets = function (context, node, mesh) {
+                var primitives = mesh.primitives;
+                var targets = primitives[0].targets;
                 if (!targets) {
                     return;
                 }
-                if (!node.babylonMesh.morphTargetManager) {
-                    node.babylonMesh.morphTargetManager = new BABYLON.MorphTargetManager();
+                for (var _i = 0, primitives_2 = primitives; _i < primitives_2.length; _i++) {
+                    var primitive = primitives_2[_i];
+                    if (!primitive.targets || primitive.targets.length != targets.length) {
+                        throw new Error(context + ": All primitives are required to list the same number of targets");
+                    }
                 }
+                var morphTargetManager = new BABYLON.MorphTargetManager();
+                node.babylonMesh.morphTargetManager = morphTargetManager;
                 for (var index = 0; index < targets.length; index++) {
                     var weight = node.weights ? node.weights[index] : mesh.weights ? mesh.weights[index] : 0;
-                    node.babylonMesh.morphTargetManager.addTarget(new BABYLON.MorphTarget("morphTarget" + index, weight));
+                    morphTargetManager.addTarget(new BABYLON.MorphTarget("morphTarget" + index, weight));
                 }
             };
-            GLTFLoader.prototype._loadMorphTargetsData = function (context, mesh, primitive, vertexData, babylonMesh) {
-                var targets = primitive.targets;
-                if (!targets) {
+            GLTFLoader.prototype._loadMorphTargets = function (context, node, mesh) {
+                var morphTargetManager = node.babylonMesh.morphTargetManager;
+                if (!morphTargetManager) {
                     return;
                 }
-                var _loop_2 = function () {
-                    var babylonMorphTarget = babylonMesh.morphTargetManager.getTarget(index);
-                    attributes = targets[index];
-                    var _loop_3 = function (attribute) {
-                        accessor = GLTF2.GLTFUtils.GetArrayItem(this_2._gltf.accessors, attributes[attribute]);
-                        if (!accessor) {
-                            throw new Error(context + "/targets/" + index + ": Failed to find attribute '" + attribute + "' accessor " + attributes[attribute]);
-                        }
-                        this_2._loadAccessorAsync("#/accessors/" + accessor.index, accessor, function (data) {
-                            if (accessor.name) {
-                                babylonMorphTarget.name = accessor.name;
-                            }
-                            // glTF stores morph target information as deltas while babylon.js expects the final data.
-                            // As a result we have to add the original data to the delta to calculate the final data.
-                            var values = data;
-                            switch (attribute) {
-                                case "NORMAL":
-                                    GLTF2.GLTFUtils.ForEach(values, function (v, i) { return values[i] += vertexData.normals[i]; });
-                                    babylonMorphTarget.setNormals(values);
-                                    break;
-                                case "POSITION":
-                                    GLTF2.GLTFUtils.ForEach(values, function (v, i) { return values[i] += vertexData.positions[i]; });
-                                    babylonMorphTarget.setPositions(values);
-                                    break;
-                                case "TANGENT":
-                                    // Tangent data for morph targets is stored as xyz delta.
-                                    // The vertexData.tangent is stored as xyzw.
-                                    // So we need to skip every fourth vertexData.tangent.
-                                    for (var i = 0, j = 0; i < values.length; i++, j++) {
-                                        values[i] += vertexData.tangents[j];
-                                        if ((i + 1) % 3 == 0) {
-                                            j++;
-                                        }
-                                    }
-                                    babylonMorphTarget.setTangents(values);
-                                    break;
-                                default:
-                                    BABYLON.Tools.Warn("Ignoring unrecognized attribute '" + attribute + "'");
-                                    break;
+                this._loadAllMorphTargetVertexDataAsync(context, node, mesh, function () {
+                    var numTargets = morphTargetManager.numTargets;
+                    for (var index = 0; index < numTargets; index++) {
+                        var vertexData = new BABYLON.VertexData();
+                        for (var _i = 0, _a = mesh.primitives; _i < _a.length; _i++) {
+                            var primitive = _a[_i];
+                            vertexData.merge(primitive.targetsVertexData[index]);
+                        }
+                        var target = morphTargetManager.getTarget(index);
+                        target.setNormals(vertexData.normals);
+                        target.setPositions(vertexData.positions);
+                        target.setTangents(vertexData.tangents);
+                    }
+                });
+            };
+            GLTFLoader.prototype._loadAllMorphTargetVertexDataAsync = function (context, node, mesh, onSuccess) {
+                var numRemainingTargets = mesh.primitives.length * node.babylonMesh.morphTargetManager.numTargets;
+                for (var _i = 0, _a = mesh.primitives; _i < _a.length; _i++) {
+                    var primitive = _a[_i];
+                    var targets = primitive.targets;
+                    primitive.targetsVertexData = new Array(targets.length);
+                    var _loop_3 = function (index) {
+                        this_3._loadMorphTargetVertexDataAsync(context + "/targets/" + index, primitive.vertexData, targets[index], function (vertexData) {
+                            primitive.targetsVertexData[index] = vertexData;
+                            if (--numRemainingTargets === 0) {
+                                onSuccess();
                             }
                         });
                     };
-                    for (var attribute in attributes) {
-                        _loop_3(attribute);
+                    var this_3 = this;
+                    for (var index = 0; index < targets.length; index++) {
+                        _loop_3(index);
+                    }
+                }
+            };
+            GLTFLoader.prototype._loadMorphTargetVertexDataAsync = function (context, vertexData, attributes, onSuccess) {
+                var targetVertexData = new BABYLON.VertexData();
+                var numRemainingAttributes = Object.keys(attributes).length;
+                var _loop_4 = function (attribute) {
+                    accessor = GLTF2.GLTFUtils.GetArrayItem(this_4._gltf.accessors, attributes[attribute]);
+                    if (!accessor) {
+                        throw new Error(context + ": Failed to find attribute '" + attribute + "' accessor " + attributes[attribute]);
                     }
+                    this_4._loadAccessorAsync("#/accessors/" + accessor.index, accessor, function (data) {
+                        // glTF stores morph target information as deltas while babylon.js expects the final data.
+                        // As a result we have to add the original data to the delta to calculate the final data.
+                        var values = data;
+                        switch (attribute) {
+                            case "NORMAL":
+                                for (var i = 0; i < values.length; i++) {
+                                    values[i] += vertexData.normals[i];
+                                }
+                                targetVertexData.normals = values;
+                                break;
+                            case "POSITION":
+                                for (var i = 0; i < values.length; i++) {
+                                    values[i] += vertexData.positions[i];
+                                }
+                                targetVertexData.positions = values;
+                                break;
+                            case "TANGENT":
+                                // Tangent data for morph targets is stored as xyz delta.
+                                // The vertexData.tangent is stored as xyzw.
+                                // So we need to skip every fourth vertexData.tangent.
+                                for (var i = 0, j = 0; i < values.length; i++, j++) {
+                                    values[i] += vertexData.tangents[j];
+                                    if ((i + 1) % 3 == 0) {
+                                        j++;
+                                    }
+                                }
+                                targetVertexData.tangents = values;
+                                break;
+                            default:
+                                BABYLON.Tools.Warn("Ignoring unrecognized attribute '" + attribute + "'");
+                                break;
+                        }
+                        if (--numRemainingAttributes === 0) {
+                            onSuccess(targetVertexData);
+                        }
+                    });
                 };
-                var this_2 = this, attributes, accessor;
-                for (var index = 0; index < targets.length; index++) {
-                    _loop_2();
+                var this_4 = this, accessor;
+                for (var attribute in attributes) {
+                    _loop_4(attribute);
                 }
             };
             GLTFLoader.prototype._loadTransform = function (node) {
@@ -3618,11 +3669,6 @@ var BABYLON;
                 }
                 return bufferView.buffer;
             };
-            GLTFUtils.ForEach = function (view, func) {
-                for (var index = 0; index < view.length; index++) {
-                    func(view[index], index);
-                }
-            };
             GLTFUtils.ValidateUri = function (uri) {
                 return (uri.indexOf("..") === -1);
             };

La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 3 - 3
dist/preview release/loaders/babylon.glTFFileLoader.min.js


+ 153 - 107
dist/preview release/loaders/babylonjs.loaders.js

@@ -3650,51 +3650,40 @@ var BABYLON;
                 }
             };
             GLTFLoader.prototype._loadMesh = function (context, node, mesh) {
-                node.babylonMesh.name = mesh.name || node.babylonMesh.name;
-                var babylonMultiMaterial = new BABYLON.MultiMaterial(node.babylonMesh.name, this._babylonScene);
-                node.babylonMesh.material = babylonMultiMaterial;
-                var geometry = new BABYLON.Geometry(node.babylonMesh.name, this._babylonScene, null, false, node.babylonMesh);
-                var vertexData = new BABYLON.VertexData();
-                vertexData.positions = [];
-                vertexData.indices = [];
-                var subMeshInfos = [];
-                var numRemainingPrimitives = mesh.primitives.length;
-                for (var index = 0; index < mesh.primitives.length; index++) {
-                    var primitive = mesh.primitives[index];
-                    this._loadPrimitive(context + "/primitives/" + index, node, mesh, primitive, function (subVertexData, loadMaterial) {
-                        subMeshInfos.push({
-                            verticesStart: vertexData.positions.length,
-                            verticesCount: subVertexData.positions.length,
-                            indicesStart: vertexData.indices.length,
-                            indicesCount: subVertexData.indices.length,
-                            loadMaterial: loadMaterial
-                        });
-                        vertexData.merge(subVertexData);
-                        if (--numRemainingPrimitives === 0) {
-                            geometry.setAllVerticesData(vertexData, false);
-                            // TODO: optimize this so that sub meshes can be created without being overwritten after setting vertex data.
-                            // Sub meshes must be cleared and created after setting vertex data because of mesh._createGlobalSubMesh.
-                            node.babylonMesh.subMeshes = [];
-                            for (var index = 0; index < subMeshInfos.length; index++) {
-                                var info = subMeshInfos[index];
-                                BABYLON.SubMesh.AddToMesh(index, info.verticesStart, info.verticesCount, info.indicesStart, info.indicesCount, node.babylonMesh);
-                                info.loadMaterial(index);
-                            }
-                        }
-                    });
-                }
-            };
-            GLTFLoader.prototype._loadPrimitive = function (context, node, mesh, primitive, onSuccess) {
                 var _this = this;
-                var subMaterials = node.babylonMesh.material.subMaterials;
-                if (primitive.mode && primitive.mode !== GLTF2.EMeshPrimitiveMode.TRIANGLES) {
-                    // TODO: handle other primitive modes
-                    throw new Error(context + ": Mode " + primitive.mode + " is not currently supported");
-                }
-                this._createMorphTargets(node, mesh, primitive);
-                this._loadVertexDataAsync(context, mesh, primitive, function (vertexData) {
-                    _this._loadMorphTargetsData(context, mesh, primitive, vertexData, node.babylonMesh);
-                    var loadMaterial = function (index) {
+                node.babylonMesh.name = node.babylonMesh.name || mesh.name;
+                if (!mesh.primitives || mesh.primitives.length === 0) {
+                    throw new Error(context + ": Primitives are missing");
+                }
+                this._createMorphTargets(context, node, mesh);
+                this._loadAllVertexDataAsync(context, mesh, function () {
+                    _this._loadMorphTargets(context, node, mesh);
+                    var primitives = mesh.primitives;
+                    var vertexData = new BABYLON.VertexData();
+                    for (var _i = 0, primitives_1 = primitives; _i < primitives_1.length; _i++) {
+                        var primitive = primitives_1[_i];
+                        vertexData.merge(primitive.vertexData);
+                    }
+                    new BABYLON.Geometry(node.babylonMesh.name, _this._babylonScene, vertexData, false, node.babylonMesh);
+                    // TODO: optimize this so that sub meshes can be created without being overwritten after setting vertex data.
+                    // Sub meshes must be cleared and created after setting vertex data because of mesh._createGlobalSubMesh.
+                    node.babylonMesh.subMeshes = [];
+                    var verticesStart = 0;
+                    var indicesStart = 0;
+                    for (var index = 0; index < primitives.length; index++) {
+                        var vertexData = primitives[index].vertexData;
+                        var verticesCount = vertexData.positions.length;
+                        var indicesCount = vertexData.indices.length;
+                        BABYLON.SubMesh.AddToMesh(index, verticesStart, verticesCount, indicesStart, indicesCount, node.babylonMesh);
+                        verticesStart += verticesCount;
+                        indicesStart += indicesCount;
+                    }
+                    ;
+                    var multiMaterial = new BABYLON.MultiMaterial(node.babylonMesh.name, _this._babylonScene);
+                    node.babylonMesh.material = multiMaterial;
+                    var subMaterials = multiMaterial.subMaterials;
+                    for (var index = 0; index < primitives.length; index++) {
+                        var primitive = primitives[index];
                         if (primitive.material == null) {
                             subMaterials[index] = _this._getDefaultMaterial();
                         }
@@ -3719,24 +3708,45 @@ var BABYLON;
                                 }
                             });
                         }
-                    };
-                    onSuccess(vertexData, loadMaterial);
+                    }
+                    ;
                 });
             };
+            GLTFLoader.prototype._loadAllVertexDataAsync = function (context, mesh, onSuccess) {
+                var primitives = mesh.primitives;
+                var numRemainingPrimitives = primitives.length;
+                var _loop_1 = function () {
+                    var primitive = primitives[index];
+                    this_1._loadVertexDataAsync(context + "/primitive/" + index, mesh, primitive, function (vertexData) {
+                        primitive.vertexData = vertexData;
+                        if (--numRemainingPrimitives === 0) {
+                            onSuccess();
+                        }
+                    });
+                };
+                var this_1 = this;
+                for (var index = 0; index < primitives.length; index++) {
+                    _loop_1();
+                }
+            };
             GLTFLoader.prototype._loadVertexDataAsync = function (context, mesh, primitive, onSuccess) {
                 var _this = this;
                 var attributes = primitive.attributes;
                 if (!attributes) {
                     throw new Error(context + ": Attributes are missing");
                 }
+                if (primitive.mode && primitive.mode !== GLTF2.EMeshPrimitiveMode.TRIANGLES) {
+                    // TODO: handle other primitive modes
+                    throw new Error(context + ": Mode " + primitive.mode + " is not currently supported");
+                }
                 var vertexData = new BABYLON.VertexData();
                 var numRemainingAttributes = Object.keys(attributes).length;
-                var _loop_1 = function (attribute) {
-                    accessor = GLTF2.GLTFUtils.GetArrayItem(this_1._gltf.accessors, attributes[attribute]);
+                var _loop_2 = function (attribute) {
+                    accessor = GLTF2.GLTFUtils.GetArrayItem(this_2._gltf.accessors, attributes[attribute]);
                     if (!accessor) {
                         throw new Error(context + ": Failed to find attribute '" + attribute + "' accessor " + attributes[attribute]);
                     }
-                    this_1._loadAccessorAsync("#/accessors/" + accessor.index, accessor, function (data) {
+                    this_2._loadAccessorAsync("#/accessors/" + accessor.index, accessor, function (data) {
                         switch (attribute) {
                             case "NORMAL":
                                 vertexData.normals = data;
@@ -3785,78 +3795,119 @@ var BABYLON;
                         }
                     });
                 };
-                var this_1 = this, accessor;
+                var this_2 = this, accessor;
                 for (var attribute in attributes) {
-                    _loop_1(attribute);
+                    _loop_2(attribute);
                 }
             };
-            GLTFLoader.prototype._createMorphTargets = function (node, mesh, primitive) {
-                var targets = primitive.targets;
+            GLTFLoader.prototype._createMorphTargets = function (context, node, mesh) {
+                var primitives = mesh.primitives;
+                var targets = primitives[0].targets;
                 if (!targets) {
                     return;
                 }
-                if (!node.babylonMesh.morphTargetManager) {
-                    node.babylonMesh.morphTargetManager = new BABYLON.MorphTargetManager();
+                for (var _i = 0, primitives_2 = primitives; _i < primitives_2.length; _i++) {
+                    var primitive = primitives_2[_i];
+                    if (!primitive.targets || primitive.targets.length != targets.length) {
+                        throw new Error(context + ": All primitives are required to list the same number of targets");
+                    }
                 }
+                var morphTargetManager = new BABYLON.MorphTargetManager();
+                node.babylonMesh.morphTargetManager = morphTargetManager;
                 for (var index = 0; index < targets.length; index++) {
                     var weight = node.weights ? node.weights[index] : mesh.weights ? mesh.weights[index] : 0;
-                    node.babylonMesh.morphTargetManager.addTarget(new BABYLON.MorphTarget("morphTarget" + index, weight));
+                    morphTargetManager.addTarget(new BABYLON.MorphTarget("morphTarget" + index, weight));
                 }
             };
-            GLTFLoader.prototype._loadMorphTargetsData = function (context, mesh, primitive, vertexData, babylonMesh) {
-                var targets = primitive.targets;
-                if (!targets) {
+            GLTFLoader.prototype._loadMorphTargets = function (context, node, mesh) {
+                var morphTargetManager = node.babylonMesh.morphTargetManager;
+                if (!morphTargetManager) {
                     return;
                 }
-                var _loop_2 = function () {
-                    var babylonMorphTarget = babylonMesh.morphTargetManager.getTarget(index);
-                    attributes = targets[index];
-                    var _loop_3 = function (attribute) {
-                        accessor = GLTF2.GLTFUtils.GetArrayItem(this_2._gltf.accessors, attributes[attribute]);
-                        if (!accessor) {
-                            throw new Error(context + "/targets/" + index + ": Failed to find attribute '" + attribute + "' accessor " + attributes[attribute]);
+                this._loadAllMorphTargetVertexDataAsync(context, node, mesh, function () {
+                    var numTargets = morphTargetManager.numTargets;
+                    for (var index = 0; index < numTargets; index++) {
+                        var vertexData = new BABYLON.VertexData();
+                        for (var _i = 0, _a = mesh.primitives; _i < _a.length; _i++) {
+                            var primitive = _a[_i];
+                            vertexData.merge(primitive.targetsVertexData[index]);
                         }
-                        this_2._loadAccessorAsync("#/accessors/" + accessor.index, accessor, function (data) {
-                            if (accessor.name) {
-                                babylonMorphTarget.name = accessor.name;
-                            }
-                            // glTF stores morph target information as deltas while babylon.js expects the final data.
-                            // As a result we have to add the original data to the delta to calculate the final data.
-                            var values = data;
-                            switch (attribute) {
-                                case "NORMAL":
-                                    GLTF2.GLTFUtils.ForEach(values, function (v, i) { return values[i] += vertexData.normals[i]; });
-                                    babylonMorphTarget.setNormals(values);
-                                    break;
-                                case "POSITION":
-                                    GLTF2.GLTFUtils.ForEach(values, function (v, i) { return values[i] += vertexData.positions[i]; });
-                                    babylonMorphTarget.setPositions(values);
-                                    break;
-                                case "TANGENT":
-                                    // Tangent data for morph targets is stored as xyz delta.
-                                    // The vertexData.tangent is stored as xyzw.
-                                    // So we need to skip every fourth vertexData.tangent.
-                                    for (var i = 0, j = 0; i < values.length; i++, j++) {
-                                        values[i] += vertexData.tangents[j];
-                                        if ((i + 1) % 3 == 0) {
-                                            j++;
-                                        }
-                                    }
-                                    babylonMorphTarget.setTangents(values);
-                                    break;
-                                default:
-                                    BABYLON.Tools.Warn("Ignoring unrecognized attribute '" + attribute + "'");
-                                    break;
+                        var target = morphTargetManager.getTarget(index);
+                        target.setNormals(vertexData.normals);
+                        target.setPositions(vertexData.positions);
+                        target.setTangents(vertexData.tangents);
+                    }
+                });
+            };
+            GLTFLoader.prototype._loadAllMorphTargetVertexDataAsync = function (context, node, mesh, onSuccess) {
+                var numRemainingTargets = mesh.primitives.length * node.babylonMesh.morphTargetManager.numTargets;
+                for (var _i = 0, _a = mesh.primitives; _i < _a.length; _i++) {
+                    var primitive = _a[_i];
+                    var targets = primitive.targets;
+                    primitive.targetsVertexData = new Array(targets.length);
+                    var _loop_3 = function (index) {
+                        this_3._loadMorphTargetVertexDataAsync(context + "/targets/" + index, primitive.vertexData, targets[index], function (vertexData) {
+                            primitive.targetsVertexData[index] = vertexData;
+                            if (--numRemainingTargets === 0) {
+                                onSuccess();
                             }
                         });
                     };
-                    for (var attribute in attributes) {
-                        _loop_3(attribute);
+                    var this_3 = this;
+                    for (var index = 0; index < targets.length; index++) {
+                        _loop_3(index);
+                    }
+                }
+            };
+            GLTFLoader.prototype._loadMorphTargetVertexDataAsync = function (context, vertexData, attributes, onSuccess) {
+                var targetVertexData = new BABYLON.VertexData();
+                var numRemainingAttributes = Object.keys(attributes).length;
+                var _loop_4 = function (attribute) {
+                    accessor = GLTF2.GLTFUtils.GetArrayItem(this_4._gltf.accessors, attributes[attribute]);
+                    if (!accessor) {
+                        throw new Error(context + ": Failed to find attribute '" + attribute + "' accessor " + attributes[attribute]);
                     }
+                    this_4._loadAccessorAsync("#/accessors/" + accessor.index, accessor, function (data) {
+                        // glTF stores morph target information as deltas while babylon.js expects the final data.
+                        // As a result we have to add the original data to the delta to calculate the final data.
+                        var values = data;
+                        switch (attribute) {
+                            case "NORMAL":
+                                for (var i = 0; i < values.length; i++) {
+                                    values[i] += vertexData.normals[i];
+                                }
+                                targetVertexData.normals = values;
+                                break;
+                            case "POSITION":
+                                for (var i = 0; i < values.length; i++) {
+                                    values[i] += vertexData.positions[i];
+                                }
+                                targetVertexData.positions = values;
+                                break;
+                            case "TANGENT":
+                                // Tangent data for morph targets is stored as xyz delta.
+                                // The vertexData.tangent is stored as xyzw.
+                                // So we need to skip every fourth vertexData.tangent.
+                                for (var i = 0, j = 0; i < values.length; i++, j++) {
+                                    values[i] += vertexData.tangents[j];
+                                    if ((i + 1) % 3 == 0) {
+                                        j++;
+                                    }
+                                }
+                                targetVertexData.tangents = values;
+                                break;
+                            default:
+                                BABYLON.Tools.Warn("Ignoring unrecognized attribute '" + attribute + "'");
+                                break;
+                        }
+                        if (--numRemainingAttributes === 0) {
+                            onSuccess(targetVertexData);
+                        }
+                    });
                 };
-                var this_2 = this, attributes, accessor;
-                for (var index = 0; index < targets.length; index++) {
-                    _loop_2();
+                var this_4 = this, accessor;
+                for (var attribute in attributes) {
+                    _loop_4(attribute);
                 }
             };
             GLTFLoader.prototype._loadTransform = function (node) {
@@ -4571,11 +4622,6 @@ var BABYLON;
                 }
                 return bufferView.buffer;
             };
-            GLTFUtils.ForEach = function (view, func) {
-                for (var index = 0; index < view.length; index++) {
-                    func(view[index], index);
-                }
-            };
             GLTFUtils.ValidateUri = function (uri) {
                 return (uri.indexOf("..") === -1);
             };

La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 3 - 3
dist/preview release/loaders/babylonjs.loaders.min.js


+ 7 - 4
dist/preview release/loaders/babylonjs.loaders.module.d.ts

@@ -872,6 +872,8 @@ declare module BABYLON.GLTF2 {
         targets?: {
             [name: string]: number;
         }[];
+        vertexData: VertexData;
+        targetsVertexData: VertexData[];
     }
     interface IGLTFMesh extends IGLTFChildRootProperty {
         primitives: IGLTFMeshPrimitive[];
@@ -986,10 +988,12 @@ declare module BABYLON.GLTF2 {
         private _loadScene(context, scene, nodeNames);
         _loadNode(context: string, node: IGLTFNode): void;
         private _loadMesh(context, node, mesh);
-        private _loadPrimitive(context, node, mesh, primitive, onSuccess);
+        private _loadAllVertexDataAsync(context, mesh, onSuccess);
         private _loadVertexDataAsync(context, mesh, primitive, onSuccess);
-        private _createMorphTargets(node, mesh, primitive);
-        private _loadMorphTargetsData(context, mesh, primitive, vertexData, babylonMesh);
+        private _createMorphTargets(context, node, mesh);
+        private _loadMorphTargets(context, node, mesh);
+        private _loadAllMorphTargetVertexDataAsync(context, node, mesh, onSuccess);
+        private _loadMorphTargetVertexDataAsync(context, vertexData, attributes, onSuccess);
         private _loadTransform(node);
         private _loadSkin(context, skin);
         private _createBone(node, skin, parent, localMatrix, baseMatrix, index);
@@ -1038,7 +1042,6 @@ declare module BABYLON.GLTF2 {
         * @param uri: the uri to decode
         */
         static DecodeBase64(uri: string): ArrayBuffer;
-        static ForEach(view: Uint16Array | Uint32Array | Float32Array, func: (nvalue: number, index: number) => void): void;
         static ValidateUri(uri: string): boolean;
         static AssignIndices(array: Array<{
             index?: number;

+ 2 - 1
dist/preview release/materialsLibrary/babylon.customMaterial.js

@@ -1945,6 +1945,7 @@ vColor=color;\n\
             return arr;
         };
         CustomMaterial.prototype.Builder = function (shaderName, uniforms, uniformBuffers, samplers, defines) {
+            var _this = this;
             if (this._isCreatedShader)
                 return this._createdShaderName;
             this._isCreatedShader = false;
@@ -1954,7 +1955,7 @@ vColor=color;\n\
             this.ReviewUniform("sampler", samplers);
             var fn_afterBind = this._afterBind;
             this._afterBind = function (m, e) {
-                this.AttachAfterBind(m, e);
+                _this.AttachAfterBind(m, e);
                 try {
                     fn_afterBind(m, e);
                 }

La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 1 - 1
dist/preview release/materialsLibrary/babylon.customMaterial.min.js


+ 2 - 1
dist/preview release/materialsLibrary/babylonjs.materials.js

@@ -5874,6 +5874,7 @@ vColor=color;\n\
             return arr;
         };
         CustomMaterial.prototype.Builder = function (shaderName, uniforms, uniformBuffers, samplers, defines) {
+            var _this = this;
             if (this._isCreatedShader)
                 return this._createdShaderName;
             this._isCreatedShader = false;
@@ -5883,7 +5884,7 @@ vColor=color;\n\
             this.ReviewUniform("sampler", samplers);
             var fn_afterBind = this._afterBind;
             this._afterBind = function (m, e) {
-                this.AttachAfterBind(m, e);
+                _this.AttachAfterBind(m, e);
                 try {
                     fn_afterBind(m, e);
                 }

La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 1 - 1
dist/preview release/materialsLibrary/babylonjs.materials.min.js


+ 3 - 3
gui/src/advancedDynamicTexture.ts

@@ -322,7 +322,7 @@ module BABYLON.GUI {
 
                 if (type === BABYLON.PointerEventTypes.POINTERMOVE) {
                     if (this._lastControlOver) {
-                        this._lastControlOver._onPointerOut();
+                        this._lastControlOver._onPointerOut(this._lastControlOver);
                     }
                     
                     this._lastControlOver = null;
@@ -378,7 +378,7 @@ module BABYLON.GUI {
                     this.focusedControl = null;
                 } else if (pi.type === BABYLON.PointerEventTypes.POINTERMOVE) {
                     if (this._lastControlOver) {
-                        this._lastControlOver._onPointerOut();
+                        this._lastControlOver._onPointerOut(this._lastControlOver);
                     }              
                     this._lastControlOver = null;
                 }
@@ -416,7 +416,7 @@ module BABYLON.GUI {
         private _attachToOnPointerOut(scene: Scene): void {
             this._canvasPointerOutObserver = scene.getEngine().onCanvasPointerOutObservable.add(() => {
                 if (this._lastControlOver) {
-                    this._lastControlOver._onPointerOut();
+                    this._lastControlOver._onPointerOut(this._lastControlOver);
                 }            
                 this._lastControlOver = null;
 

+ 8 - 8
gui/src/controls/button.ts

@@ -51,8 +51,8 @@ module BABYLON.GUI {
             return true;
         }
 
-        protected _onPointerEnter(): boolean {
-            if (!super._onPointerEnter()) {
+        public _onPointerEnter(target: Control): boolean {
+            if (!super._onPointerEnter(target)) {
                 return false;
             }
 
@@ -63,16 +63,16 @@ module BABYLON.GUI {
             return true;
         }
 
-        public _onPointerOut(): void {
+        public _onPointerOut(target: Control): void {
             if (this.pointerOutAnimation) {
                 this.pointerOutAnimation();
             }
 
-            super._onPointerOut();
+            super._onPointerOut(target);
         }
 
-        protected _onPointerDown(coordinates: Vector2, buttonIndex: number): boolean {
-            if (!super._onPointerDown(coordinates, buttonIndex)) {
+        public _onPointerDown(target: Control, coordinates: Vector2, buttonIndex: number): boolean {
+            if (!super._onPointerDown(target, coordinates, buttonIndex)) {
                 return false;
             }
 
@@ -84,12 +84,12 @@ module BABYLON.GUI {
             return true;
         }
 
-        protected _onPointerUp(coordinates: Vector2, buttonIndex: number): void {
+        public _onPointerUp(target: Control, coordinates: Vector2, buttonIndex: number): void {
             if (this.pointerUpAnimation) {
                 this.pointerUpAnimation();
             }
 
-            super._onPointerUp(coordinates, buttonIndex);
+            super._onPointerUp(target, coordinates, buttonIndex);
         }        
 
         // Statics

+ 2 - 2
gui/src/controls/checkbox.ts

@@ -102,8 +102,8 @@ module BABYLON.GUI {
         }
 
         // Events
-        protected _onPointerDown(coordinates: Vector2, buttonIndex: number): boolean {
-            if (!super._onPointerDown(coordinates, buttonIndex)) {
+        public _onPointerDown(target: Control, coordinates: Vector2, buttonIndex: number): boolean {
+            if (!super._onPointerDown(target, coordinates, buttonIndex)) {
                 return false;
             }
 

+ 6 - 6
gui/src/controls/colorpicker.ts

@@ -362,8 +362,8 @@ module BABYLON.GUI {
             return false;
         }
 
-        protected _onPointerDown(coordinates: Vector2, buttonIndex: number): boolean {
-            if (!super._onPointerDown(coordinates, buttonIndex)) {
+        public _onPointerDown(target: Control, coordinates: Vector2, buttonIndex: number): boolean {
+            if (!super._onPointerDown(target, coordinates, buttonIndex)) {
                 return false;
             }            
 
@@ -384,19 +384,19 @@ module BABYLON.GUI {
             return true;
         }
 
-        protected _onPointerMove(coordinates: Vector2): void {
+        public _onPointerMove(target: Control, coordinates: Vector2): void {
             if (this._pointerIsDown) {
                 this._updateValueFromPointer(coordinates.x, coordinates.y);
             }
 
-            super._onPointerMove(coordinates);
+            super._onPointerMove(target, coordinates);
         }
 
-        protected _onPointerUp (coordinates: Vector2, buttonIndex: number): void {
+        public _onPointerUp (target: Control, coordinates: Vector2, buttonIndex: number): void {
             this._pointerIsDown = false;
             
             this._host._capturingControl = null;
-            super._onPointerUp(coordinates, buttonIndex);
+            super._onPointerUp(target, coordinates, buttonIndex);
         }     
     }    
 }

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

@@ -76,6 +76,8 @@ module BABYLON.GUI {
 
             if (index !== -1) {
                 this._children.splice(index, 1);
+
+                control.parent = null;
             }
 
             this._markAsDirty();
@@ -94,6 +96,8 @@ module BABYLON.GUI {
 
             this._children.push(control);
 
+            control.parent = this;
+
             this._markAsDirty();
         }
 

+ 32 - 27
gui/src/controls/control.ts

@@ -7,6 +7,7 @@ module BABYLON.GUI {
         private _zIndex = 0;
         public _root: Container;
         public _host: AdvancedDynamicTexture;
+        public parent: Container;
         public _currentMeasure = Measure.Empty();
         private _fontFamily = "Arial";
         private _fontStyle = "";
@@ -835,68 +836,72 @@ module BABYLON.GUI {
             return true;
         }
 
-        protected _onPointerMove(coordinates: Vector2): void {
-            if (this.onPointerMoveObservable.hasObservers()) {
-                this.onPointerMoveObservable.notifyObservers(coordinates);
-            }
+        public _onPointerMove(target: Control, coordinates: Vector2): void {
+            var canNotify: boolean = this.onPointerMoveObservable.notifyObservers(coordinates, -1, target, this);
+
+            if (canNotify && this.parent != null) this.parent._onPointerMove(target, coordinates);
         }
 
-        protected _onPointerEnter(): boolean {
+        public _onPointerEnter(target: Control): boolean {
             if (this._enterCount !== 0) {
                 return false;
             }
 
             this._enterCount++;
-            if (this.onPointerEnterObservable.hasObservers()) {
-                this.onPointerEnterObservable.notifyObservers(this);
-            }
+
+            var canNotify: boolean = this.onPointerEnterObservable.notifyObservers(this, -1, target, this);
+
+            if (canNotify && this.parent != null) this.parent._onPointerEnter(target);
 
             return true;
         }
 
-        public _onPointerOut(): void {
+        public _onPointerOut(target: Control): void {
             this._enterCount = 0;
-            if (this.onPointerOutObservable.hasObservers()) {
-                this.onPointerOutObservable.notifyObservers(this);
-            }
+
+            var canNotify: boolean = this.onPointerOutObservable.notifyObservers(this, -1, target, this);
+
+            if (canNotify && this.parent != null) this.parent._onPointerOut(target);
         }
 
-        protected _onPointerDown(coordinates: Vector2, buttonIndex: number): boolean {
+        public _onPointerDown(target: Control, coordinates: Vector2, buttonIndex: number): boolean {
             if (this._downCount !== 0) {
                 return false;
             }
 
-            this._downCount++;            
-            if (this.onPointerDownObservable.hasObservers()) {
-                this.onPointerDownObservable.notifyObservers(new Vector2WithInfo(coordinates, buttonIndex));
-            }
+            this._downCount++;
+
+            var canNotify: boolean = this.onPointerDownObservable.notifyObservers(new Vector2WithInfo(coordinates, buttonIndex), -1, target, this);
+
+            if (canNotify && this.parent != null) this.parent._onPointerDown(target, coordinates, buttonIndex);
 
             return true;
         }
 
-        protected _onPointerUp(coordinates: Vector2, buttonIndex: number): void {
+        public _onPointerUp(target: Control, coordinates: Vector2, buttonIndex: number): void {
             this._downCount = 0;
-            if (this.onPointerUpObservable.hasObservers()) {
-                this.onPointerUpObservable.notifyObservers(new Vector2WithInfo(coordinates, buttonIndex));
-            }           
+            
+            var canNotify: boolean = this.onPointerUpObservable.notifyObservers(new Vector2WithInfo(coordinates, buttonIndex), -1, target, this);
+            
+            if (canNotify && this.parent != null) this.parent._onPointerUp(target, coordinates, buttonIndex);
         }
 
         public forcePointerUp() {
-            this._onPointerUp(Vector2.Zero(), 0);
+            this._onPointerUp(this, Vector2.Zero(), 0);
         }
 
         public _processObservables(type: number, x: number, y: number, buttonIndex: number): boolean {
             this._dummyVector2.copyFromFloats(x, y);
             if (type === BABYLON.PointerEventTypes.POINTERMOVE) {
-                this._onPointerMove(this._dummyVector2);
+                this._onPointerMove(this, this._dummyVector2);
 
                 var previousControlOver = this._host._lastControlOver;
                 if (previousControlOver && previousControlOver !== this) {
-                    previousControlOver._onPointerOut();                
+                    previousControlOver._onPointerOut(this);                
                 }
 
                 if (previousControlOver !== this) {
-                    this._onPointerEnter();
+                    this._onPointerEnter(this);
                 }
 
                 this._host._lastControlOver = this;
@@ -904,7 +909,7 @@ module BABYLON.GUI {
             }
 
             if (type === BABYLON.PointerEventTypes.POINTERDOWN) {
-                this._onPointerDown(this._dummyVector2, buttonIndex);
+                this._onPointerDown(this, this._dummyVector2, buttonIndex);
                 this._host._lastControlDown = this;
                 this._host._lastPickedControl = this;
                 return true;
@@ -912,7 +917,7 @@ module BABYLON.GUI {
 
             if (type === BABYLON.PointerEventTypes.POINTERUP) {
                 if (this._host._lastControlDown) {
-                    this._host._lastControlDown._onPointerUp(this._dummyVector2, buttonIndex);
+                    this._host._lastControlDown._onPointerUp(this, this._dummyVector2, buttonIndex);
                 }
                 this._host._lastControlDown = null;
                 return true;

+ 4 - 4
gui/src/controls/inputText.ts

@@ -400,8 +400,8 @@ module BABYLON.GUI {
             context.restore();
         }
 
-        protected _onPointerDown(coordinates: Vector2, buttonIndex: number): boolean {
-            if (!super._onPointerDown(coordinates, buttonIndex)) {
+        public _onPointerDown(target: Control, coordinates: Vector2, buttonIndex: number): boolean {
+            if (!super._onPointerDown(target, coordinates, buttonIndex)) {
                 return false;
             }
 
@@ -417,8 +417,8 @@ module BABYLON.GUI {
             return true;
         }
 
-        protected _onPointerUp(coordinates: Vector2, buttonIndex: number): void {
-            super._onPointerUp(coordinates, buttonIndex);
+        public _onPointerUp(target: Control, coordinates: Vector2, buttonIndex: number): void {
+            super._onPointerUp(target, coordinates, buttonIndex);
         }  
 
         public dispose() {

+ 2 - 2
gui/src/controls/radioButton.ts

@@ -131,8 +131,8 @@ module BABYLON.GUI {
         }
 
         // Events
-        protected _onPointerDown(coordinates: Vector2, buttonIndex: number): boolean {
-            if (!super._onPointerDown(coordinates, buttonIndex)) {
+        public _onPointerDown(target: Control, coordinates: Vector2, buttonIndex: number): boolean {
+            if (!super._onPointerDown(target, coordinates, buttonIndex)) {
                 return false;
             }
             this.isChecked = !this.isChecked;

+ 7 - 5
gui/src/controls/slider.ts

@@ -179,8 +179,8 @@ module BABYLON.GUI {
             this.value = this._minimum + ((x - this._currentMeasure.left) / this._currentMeasure.width) * (this._maximum - this._minimum);
         }
 
-        protected _onPointerDown(coordinates: Vector2, buttonIndex: number): boolean {
-            if (!super._onPointerDown(coordinates, buttonIndex)) {
+        public _onPointerDown(target: Control, coordinates: Vector2, buttonIndex: number): boolean {
+            if (!super._onPointerDown(target, coordinates, buttonIndex)) {
                 return false;
             }
 
@@ -192,17 +192,19 @@ module BABYLON.GUI {
             return true;
         }
 
-        protected _onPointerMove(coordinates: Vector2): void {
+        public _onPointerMove(target: Control, coordinates: Vector2): void {
             if (this._pointerIsDown) {
                 this._updateValueFromPointer(coordinates.x);
             }
+
+            super._onPointerMove(target, coordinates);
         }
 
-        protected _onPointerUp (coordinates: Vector2, buttonIndex: number): void {
+        public _onPointerUp (target: Control, coordinates: Vector2, buttonIndex: number): void {
             this._pointerIsDown = false;
             
             this._host._capturingControl = null;
-            super._onPointerUp(coordinates, buttonIndex);
+            super._onPointerUp(target, coordinates, buttonIndex);
         }         
     }    
 }

+ 143 - 99
loaders/src/glTF/2.0/babylon.glTFLoader.ts

@@ -378,63 +378,47 @@ module BABYLON.GLTF2 {
         }
 
         private _loadMesh(context: string, node: IGLTFNode, mesh: IGLTFMesh): void {
-            node.babylonMesh.name = mesh.name || node.babylonMesh.name;
+            node.babylonMesh.name = node.babylonMesh.name || mesh.name;
 
-            var babylonMultiMaterial = new MultiMaterial(node.babylonMesh.name, this._babylonScene);
-            node.babylonMesh.material = babylonMultiMaterial;
-
-            var geometry = new Geometry(node.babylonMesh.name, this._babylonScene, null, false, node.babylonMesh);
-            var vertexData = new VertexData();
-            vertexData.positions = [];
-            vertexData.indices = [];
-
-            var subMeshInfos: { verticesStart: number; verticesCount: number; indicesStart: number; indicesCount: number; loadMaterial: (index: number) => void }[] = [];
-            var numRemainingPrimitives = mesh.primitives.length;
-
-            for (var index = 0; index < mesh.primitives.length; index++) {
-                var primitive = mesh.primitives[index];
-                this._loadPrimitive(context + "/primitives/" + index, node, mesh, primitive, (subVertexData, loadMaterial) => {
-                    subMeshInfos.push({
-                        verticesStart: vertexData.positions.length,
-                        verticesCount: subVertexData.positions.length,
-                        indicesStart: vertexData.indices.length,
-                        indicesCount: subVertexData.indices.length,
-                        loadMaterial: loadMaterial
-                    });
-
-                    vertexData.merge(subVertexData);
-
-                    if (--numRemainingPrimitives === 0) {
-                        geometry.setAllVerticesData(vertexData, false);
+            if (!mesh.primitives || mesh.primitives.length === 0) {
+                throw new Error(context + ": Primitives are missing");
+            }
 
-                        // TODO: optimize this so that sub meshes can be created without being overwritten after setting vertex data.
-                        // Sub meshes must be cleared and created after setting vertex data because of mesh._createGlobalSubMesh.
-                        node.babylonMesh.subMeshes = [];
+            this._createMorphTargets(context, node, mesh);
 
-                        for (var index = 0; index < subMeshInfos.length; index++) {
-                            var info = subMeshInfos[index];
-                            SubMesh.AddToMesh(index, info.verticesStart, info.verticesCount, info.indicesStart, info.indicesCount, node.babylonMesh);
-                            info.loadMaterial(index);
-                        }
-                    }
-                });
-            }
-        }
+            this._loadAllVertexDataAsync(context, mesh, () => {
+                this._loadMorphTargets(context, node, mesh);
 
-        private _loadPrimitive(context: string, node: IGLTFNode, mesh: IGLTFMesh, primitive: IGLTFMeshPrimitive, onSuccess: (vertexData: VertexData, loadMaterial: (index: number) => void) => void): void {
-            var subMaterials = (node.babylonMesh.material as MultiMaterial).subMaterials;
+                var primitives = mesh.primitives;
 
-            if (primitive.mode && primitive.mode !== EMeshPrimitiveMode.TRIANGLES) {
-                // TODO: handle other primitive modes
-                throw new Error(context + ": Mode " + primitive.mode + " is not currently supported");
-            }
+                var vertexData = new VertexData();
+                for (var primitive of primitives) {
+                    vertexData.merge(primitive.vertexData);
+                }
 
-            this._createMorphTargets(node, mesh, primitive);
+                new Geometry(node.babylonMesh.name, this._babylonScene, vertexData, false, node.babylonMesh);
+
+                // TODO: optimize this so that sub meshes can be created without being overwritten after setting vertex data.
+                // Sub meshes must be cleared and created after setting vertex data because of mesh._createGlobalSubMesh.
+                node.babylonMesh.subMeshes = [];
+
+                var verticesStart = 0;
+                var indicesStart = 0;
+                for (var index = 0; index < primitives.length; index++) {
+                    var vertexData = primitives[index].vertexData;
+                    var verticesCount = vertexData.positions.length;
+                    var indicesCount = vertexData.indices.length;
+                    SubMesh.AddToMesh(index, verticesStart, verticesCount, indicesStart, indicesCount, node.babylonMesh);
+                    verticesStart += verticesCount;
+                    indicesStart += indicesCount;
+                };
 
-            this._loadVertexDataAsync(context, mesh, primitive, vertexData => {
-                this._loadMorphTargetsData(context, mesh, primitive, vertexData, node.babylonMesh);
+                var multiMaterial = new MultiMaterial(node.babylonMesh.name, this._babylonScene);
+                node.babylonMesh.material = multiMaterial;
+                var subMaterials = multiMaterial.subMaterials;
+                for (var index = 0; index < primitives.length; index++) {
+                    var primitive = primitives[index];
 
-                var loadMaterial = (index: number) => {
                     if (primitive.material == null) {
                         subMaterials[index] = this._getDefaultMaterial();
                     }
@@ -461,17 +445,34 @@ module BABYLON.GLTF2 {
                         });
                     }
                 };
-
-                onSuccess(vertexData, loadMaterial);
             });
         }
 
+        private _loadAllVertexDataAsync(context: string, mesh: IGLTFMesh, onSuccess: () => void): void {
+            var primitives = mesh.primitives;
+            var numRemainingPrimitives = primitives.length;
+            for (var index = 0; index < primitives.length; index++) {
+                let primitive = primitives[index];
+                this._loadVertexDataAsync(context + "/primitive/" + index, mesh, primitive, vertexData => {
+                    primitive.vertexData = vertexData;
+                    if (--numRemainingPrimitives === 0) {
+                        onSuccess();
+                    }
+                });
+            }
+        }
+
         private _loadVertexDataAsync(context: string, mesh: IGLTFMesh, primitive: IGLTFMeshPrimitive, onSuccess: (vertexData: VertexData) => void): void {
             var attributes = primitive.attributes;
             if (!attributes) {
                 throw new Error(context + ": Attributes are missing");
             }
 
+            if (primitive.mode && primitive.mode !== EMeshPrimitiveMode.TRIANGLES) {
+                // TODO: handle other primitive modes
+                throw new Error(context + ": Mode " + primitive.mode + " is not currently supported");
+            }
+
             var vertexData = new VertexData();
 
             var numRemainingAttributes = Object.keys(attributes).length;
@@ -534,75 +535,118 @@ module BABYLON.GLTF2 {
             }
         }
 
-        private _createMorphTargets(node: IGLTFNode, mesh: IGLTFMesh, primitive: IGLTFMeshPrimitive): void {
-            var targets = primitive.targets;
+        private _createMorphTargets(context: string, node: IGLTFNode, mesh: IGLTFMesh): void {
+            var primitives = mesh.primitives;
+
+            var targets = primitives[0].targets;
             if (!targets) {
                 return;
             }
 
-            if (!node.babylonMesh.morphTargetManager) {
-                node.babylonMesh.morphTargetManager = new MorphTargetManager();
+            for (var primitive of primitives) {
+                if (!primitive.targets || primitive.targets.length != targets.length) {
+                    throw new Error(context + ": All primitives are required to list the same number of targets");
+                }
             }
 
+            var morphTargetManager = new MorphTargetManager();
+            node.babylonMesh.morphTargetManager = morphTargetManager;
             for (var index = 0; index < targets.length; index++) {
                 var weight = node.weights ? node.weights[index] : mesh.weights ? mesh.weights[index] : 0;
-                node.babylonMesh.morphTargetManager.addTarget(new MorphTarget("morphTarget" + index, weight));
+                morphTargetManager.addTarget(new MorphTarget("morphTarget" + index, weight));
             }
         }
 
-        private _loadMorphTargetsData(context: string, mesh: IGLTFMesh, primitive: IGLTFMeshPrimitive, vertexData: VertexData, babylonMesh: Mesh): void {
-            var targets = primitive.targets;
-            if (!targets) {
+        private _loadMorphTargets(context: string, node: IGLTFNode, mesh: IGLTFMesh): void {
+            var morphTargetManager = node.babylonMesh.morphTargetManager;
+            if (!morphTargetManager) {
                 return;
             }
 
-            for (var index = 0; index < targets.length; index++) {
-                let babylonMorphTarget = babylonMesh.morphTargetManager.getTarget(index);
-                var attributes = targets[index];
-                for (let attribute in attributes) {
-                    var accessor = GLTFUtils.GetArrayItem(this._gltf.accessors, attributes[attribute]);
-                    if (!accessor) {
-                        throw new Error(context + "/targets/" + index + ": Failed to find attribute '" + attribute + "' accessor " + attributes[attribute]);
+            this._loadAllMorphTargetVertexDataAsync(context, node, mesh, () => {
+                var numTargets = morphTargetManager.numTargets;
+                for (var index = 0; index < numTargets; index++) {
+                    var vertexData = new VertexData();
+                    for (var primitive of mesh.primitives) {
+                        vertexData.merge(primitive.targetsVertexData[index]);
                     }
 
-                    this._loadAccessorAsync("#/accessors/" + accessor.index, accessor, data => {
-                        if (accessor.name) {
-                            babylonMorphTarget.name = accessor.name;
-                        }
+                    var target = morphTargetManager.getTarget(index);
+                    target.setNormals(vertexData.normals);
+                    target.setPositions(vertexData.positions);
+                    target.setTangents(vertexData.tangents);
+                }
+            });
+        }
 
-                        // glTF stores morph target information as deltas while babylon.js expects the final data.
-                        // As a result we have to add the original data to the delta to calculate the final data.
-                        var values = <Float32Array>data;
-                        switch (attribute) {
-                            case "NORMAL":
-                                GLTFUtils.ForEach(values, (v, i) => values[i] += vertexData.normals[i]);
-                                babylonMorphTarget.setNormals(values);
-                                break;
-                            case "POSITION":
-                                GLTFUtils.ForEach(values, (v, i) => values[i] += vertexData.positions[i]);
-                                babylonMorphTarget.setPositions(values);
-                                break;
-                            case "TANGENT":
-                                // Tangent data for morph targets is stored as xyz delta.
-                                // The vertexData.tangent is stored as xyzw.
-                                // So we need to skip every fourth vertexData.tangent.
-                                for (var i = 0, j = 0; i < values.length; i++, j++) {
-                                    values[i] += vertexData.tangents[j];
-                                    if ((i + 1) % 3 == 0) {
-                                        j++;
-                                    }
-                                }
-                                babylonMorphTarget.setTangents(values);
-                                break;
-                            default:
-                                Tools.Warn("Ignoring unrecognized attribute '" + attribute + "'");
-                                break;
+        private _loadAllMorphTargetVertexDataAsync(context: string, node: IGLTFNode, mesh: IGLTFMesh, onSuccess: () => void): void {
+            var numRemainingTargets = mesh.primitives.length * node.babylonMesh.morphTargetManager.numTargets;
+
+            for (var primitive of mesh.primitives) {
+                var targets = primitive.targets;
+                primitive.targetsVertexData = new Array<VertexData>(targets.length);
+                for (let index = 0; index < targets.length; index++) {
+                    this._loadMorphTargetVertexDataAsync(context + "/targets/" + index, primitive.vertexData, targets[index], vertexData => {
+                        primitive.targetsVertexData[index] = vertexData;
+                        if (--numRemainingTargets === 0) {
+                            onSuccess();
                         }
                     });
                 }
             }
         }
 
+        private _loadMorphTargetVertexDataAsync(context: string, vertexData: VertexData, attributes: { [name: string]: number }, onSuccess: (vertexData: VertexData) => void): void {
+            var targetVertexData = new VertexData();
+
+            var numRemainingAttributes = Object.keys(attributes).length;
+            for (let attribute in attributes) {
+                var accessor = GLTFUtils.GetArrayItem(this._gltf.accessors, attributes[attribute]);
+                if (!accessor) {
+                    throw new Error(context + ": Failed to find attribute '" + attribute + "' accessor " + attributes[attribute]);
+                }
+
+                this._loadAccessorAsync("#/accessors/" + accessor.index, accessor, data => {
+                    // glTF stores morph target information as deltas while babylon.js expects the final data.
+                    // As a result we have to add the original data to the delta to calculate the final data.
+                    var values = <Float32Array>data;
+                    switch (attribute) {
+                        case "NORMAL":
+                            for (var i = 0; i < values.length; i++) {
+                                values[i] += vertexData.normals[i];
+                            }
+                            targetVertexData.normals = values;
+                            break;
+                        case "POSITION":
+                            for (var i = 0; i < values.length; i++) {
+                                values[i] += vertexData.positions[i];
+                            }
+                            targetVertexData.positions = values;
+                            break;
+                        case "TANGENT":
+                            // Tangent data for morph targets is stored as xyz delta.
+                            // The vertexData.tangent is stored as xyzw.
+                            // So we need to skip every fourth vertexData.tangent.
+                            for (var i = 0, j = 0; i < values.length; i++, j++) {
+                                values[i] += vertexData.tangents[j];
+                                if ((i + 1) % 3 == 0) {
+                                    j++;
+                                }
+                            }
+                            targetVertexData.tangents = values;
+                            break;
+                        default:
+                            Tools.Warn("Ignoring unrecognized attribute '" + attribute + "'");
+                            break;
+                    }
+
+                    if (--numRemainingAttributes === 0) {
+                        onSuccess(targetVertexData);
+                    }
+                });
+            }
+        }
+
         private _loadTransform(node: IGLTFNode): void {
             var position: Vector3 = Vector3.Zero();
             var rotation: Quaternion = Quaternion.Identity();
@@ -819,7 +863,7 @@ module BABYLON.GLTF2 {
                     case "influence":
                         getNextOutputValue = () => {
                             var numTargets = targetNode.babylonMesh.morphTargetManager.numTargets;
-                            var value = new Array(numTargets);
+                            var value = new Array<number>(numTargets);
                             for (var i = 0; i < numTargets; i++) {
                                 value[i] = outputData[outputBufferOffset++];
                             }
@@ -1258,7 +1302,7 @@ module BABYLON.GLTF2 {
                     break;
                 case "MASK":
                     babylonMaterial.alphaCutOff = (material.alphaCutoff == null ? 0.5 : material.alphaCutoff);
-                    
+
                     if (colorFactor) {
                         if (colorFactor[3] == 0) {
                             babylonMaterial.alphaCutOff = 1;

+ 4 - 0
loaders/src/glTF/2.0/babylon.glTFLoaderInterfaces.ts

@@ -205,6 +205,10 @@ module BABYLON.GLTF2 {
         material?: number;
         mode?: EMeshPrimitiveMode;
         targets?: { [name: string]: number }[];
+
+        // Runtime values
+        vertexData: VertexData;
+        targetsVertexData: VertexData[];
     }
 
     export interface IGLTFMesh extends IGLTFChildRootProperty {

+ 0 - 6
loaders/src/glTF/2.0/babylon.glTFLoaderUtils.ts

@@ -29,12 +29,6 @@ module BABYLON.GLTF2 {
             return bufferView.buffer;
         }
 
-        public static ForEach(view: Uint16Array | Uint32Array | Float32Array, func: (nvalue: number, index: number) => void): void {
-            for (var index = 0; index < view.length; index++) {
-                func(view[index], index);
-            }
-        }
-
         public static ValidateUri(uri: string): boolean {
             return (uri.indexOf("..") === -1);
         }

+ 1 - 1
materialsLibrary/src/custom/babylon.customMaterial.ts

@@ -2039,7 +2039,7 @@ vColor=color;\n\
             
 
             var fn_afterBind = this._afterBind;
-            this._afterBind = function(m,e){ 
+            this._afterBind = (m,e) => { 
                 this.AttachAfterBind(m,e);
                 try{fn_afterBind(m,e);}catch(e){};
             } ;

+ 1 - 1
src/Cameras/VR/babylon.vrExperienceHelper.ts

@@ -34,7 +34,7 @@ module BABYLON {
         constructor(scene: Scene, public webVROptions: WebVROptions = {}) {
             this._scene = scene;
 
-            if (!this._scene.activeCamera) {
+            if (!this._scene.activeCamera || isNaN(this._scene.activeCamera.position.x)) {
                 this._deviceOrientationCamera = new BABYLON.DeviceOrientationCamera("deviceOrientationVRHelper", new BABYLON.Vector3(0, 2, 0), scene);
             }
             else {

+ 38 - 13
src/Engine/babylon.engine.ts

@@ -1,8 +1,12 @@
 module BABYLON {
     var compileShader = (gl: WebGLRenderingContext, source: string, type: string, defines: string, shaderVersion: string): WebGLShader => {
+        return compileRawShader(gl, shaderVersion + (defines ? defines + "\n" : "") + source, type);
+    };
+
+    var compileRawShader = (gl: WebGLRenderingContext, source: string, type: string): WebGLShader => {
         var shader = gl.createShader(type === "vertex" ? gl.VERTEX_SHADER : gl.FRAGMENT_SHADER);
 
-        gl.shaderSource(shader, shaderVersion + (defines ? defines + "\n" : "") + source);
+        gl.shaderSource(shader, source);
         gl.compileShader(shader);
 
         if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
@@ -2298,9 +2302,15 @@
         public _releaseEffect(effect: Effect): void {
             if (this._compiledEffects[effect._key]) {
                 delete this._compiledEffects[effect._key];
-                if (effect.getProgram()) {
-                    this._gl.deleteProgram(effect.getProgram());
-                }
+
+                this._deleteProgram(effect.getProgram());
+            }
+        }
+
+        public _deleteProgram(program: WebGLProgram): void {
+            if (program) {
+                program.__SPECTOR_rebuildProgram = null;
+                this._gl.deleteProgram(program);
             }
         }
 
@@ -2343,6 +2353,15 @@
                 ["diffuseSampler"].concat(samplers), defines, fallbacks, onCompiled, onError);
         }
 
+        public createRawShaderProgram(vertexCode: string, fragmentCode: string, context?: WebGLRenderingContext): WebGLProgram {
+            context = context || this._gl;
+
+            var vertexShader = compileRawShader(context, vertexCode, "vertex");
+            var fragmentShader = compileRawShader(context, fragmentCode, "fragment");
+
+            return this._createShaderProgram(vertexShader, fragmentShader, context);
+        }
+
         public createShaderProgram(vertexCode: string, fragmentCode: string, defines: string, context?: WebGLRenderingContext): WebGLProgram {
             context = context || this._gl;
 
@@ -2350,6 +2369,10 @@
             var vertexShader = compileShader(context, vertexCode, "vertex", defines, shaderVersion);
             var fragmentShader = compileShader(context, fragmentCode, "fragment", defines, shaderVersion);
 
+            return this._createShaderProgram(vertexShader, fragmentShader, context);
+        }
+
+        private _createShaderProgram(vertexShader: WebGLShader, fragmentShader: WebGLShader, context?: WebGLRenderingContext): WebGLProgram {
             var shaderProgram = context.createProgram();
             context.attachShader(shaderProgram, vertexShader);
             context.attachShader(shaderProgram, fragmentShader);
@@ -2915,7 +2938,7 @@
                     } else {
                         Tools.LoadImage(url, onload, onerror, scene ? scene.database : null);
                     }
-                else if (buffer instanceof Array || typeof buffer === "string")
+                else if (buffer instanceof Array || typeof buffer === "string" || buffer instanceof ArrayBuffer)
                     Tools.LoadImage(buffer, onload, onerror, scene ? scene.database : null);
                 else
                     onload(<HTMLImageElement>buffer);
@@ -3667,13 +3690,15 @@
             var isKTX = false;
             var isDDS = false;
             var lastDot = rootUrl.lastIndexOf('.');
-            var extension = forcedExtension ? forcedExtension : rootUrl.substring(lastDot).toLowerCase();
-            if (this._textureFormatInUse) {
-                extension = this._textureFormatInUse;
-                rootUrl = rootUrl.substring(0, lastDot) + this._textureFormatInUse;
-                isKTX = true;
-            } else {
-                isDDS = (extension === ".dds");
+            if (lastDot > -1) {
+                var extension = forcedExtension ? forcedExtension : rootUrl.substring(lastDot).toLowerCase();
+                if (this._textureFormatInUse) {
+                    extension = this._textureFormatInUse;
+                    rootUrl = rootUrl.substring(0, lastDot) + this._textureFormatInUse;
+                    isKTX = true;
+                } else {
+                    isDDS = (extension === ".dds");
+                }
             }
 
             let onerror = (request: XMLHttpRequest, exception: any) => {
@@ -4388,7 +4413,7 @@
 
         public releaseEffects() {
             for (var name in this._compiledEffects) {
-                this._gl.deleteProgram(this._compiledEffects[name]._program);
+                this._deleteProgram(this._compiledEffects[name]._program)
             }
 
             this._compiledEffects = {};

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

@@ -107,7 +107,9 @@
         }
 
         public createShaderProgram(vertexCode: string, fragmentCode: string, defines: string, context?: WebGLRenderingContext): WebGLProgram {
-            return {};
+            return {
+                __SPECTOR_rebuildProgram: undefined,
+            };
         }
 
         public getUniforms(shaderProgram: WebGLProgram, uniformsNames: string[]): WebGLUniformLocation[] {

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

@@ -305,10 +305,6 @@
                 }
             }
 
-            if (this.renderList && this.renderList.length === 0) {
-                return;
-            }
-
             this.onBeforeBindObservable.notifyObservers(this);
 
             // Set custom projection.

+ 48 - 1
src/Materials/babylon.effect.ts

@@ -114,6 +114,8 @@
         private _fallbacks: EffectFallbacks;
         private _vertexSourceCode: string;
         private _fragmentSourceCode: string;
+        private _vertexSourceCodeOverride: string;
+        private _fragmentSourceCodeOverride: string;
 
         public _program: WebGLProgram;
         private _valueCache: { [key: string]: any };
@@ -516,15 +518,48 @@
             return source;
         }
 
+        public _rebuildProgram(vertexSourceCode: string, fragmentSourceCode: string, onCompiled: (program: WebGLProgram) => void, onError: (message: string) => void) {
+            this._isReady = false;
+
+            this._vertexSourceCodeOverride = vertexSourceCode;
+            this._fragmentSourceCodeOverride = fragmentSourceCode;
+            this.onError = (effect, error) => {
+                if (onError) {
+                    onError(error);
+                }
+            };
+            this.onCompiled = () => {
+                var scenes = this.getEngine().scenes;
+                for (var i = 0; i < scenes.length; i++) {
+                    scenes[i].markAllMaterialsAsDirty(Material.TextureDirtyFlag);
+                }
+
+                if (onCompiled) {
+                    onCompiled(this._program);
+                }
+            };
+            this._fallbacks = null;
+            this._prepareEffect();
+        }
+
         public _prepareEffect() {
             let attributesNames = this._attributesNames;
             let defines = this.defines;
             let fallbacks = this._fallbacks;
             this._valueCache = {};
 
+            var previousProgram = this._program;
+
             try {
                 var engine = this._engine;
-                this._program = engine.createShaderProgram(this._vertexSourceCode, this._fragmentSourceCode, defines);
+
+                if (this._vertexSourceCodeOverride && this._fragmentSourceCodeOverride) {
+                    this._program = engine.createRawShaderProgram(this._vertexSourceCodeOverride, this._fragmentSourceCodeOverride);
+                }
+                else {
+                    this._program = engine.createShaderProgram(this._vertexSourceCode, this._fragmentSourceCode, defines);
+                }
+                this._program.__SPECTOR_rebuildProgram = this._rebuildProgram.bind(this);
 
                 if (engine.webGLVersion > 1) {
                     for (var name in this._uniformBuffersNames) {
@@ -559,6 +594,10 @@
                 if (this._fallbacks) {
                     this._fallbacks.unBindMesh();
                 }
+
+                if (previousProgram) {
+                    this.getEngine()._deleteProgram(previousProgram);
+                }
             } catch (e) {
                 this._compilationError = e.message;
 
@@ -572,6 +611,14 @@
                 }));
                 this._dumpShadersSource(this._vertexSourceCode, this._fragmentSourceCode, defines);
                 Tools.Error("Error: " + this._compilationError);
+                if (previousProgram) {
+                    this._program = previousProgram;
+                    this._isReady = true;
+                    if (this.onError) {
+                        this.onError(this, this._compilationError);
+                    }
+                    this.onErrorObservable.notifyObservers(this);
+                }
 
                 if (fallbacks && fallbacks.isMoreFallbacks) {
                     Tools.Error("Trying next fallback.");

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

@@ -337,7 +337,7 @@
             }
 
             if (!source) {
-                if (length === other.length) {
+                if (length === 0 || length === other.length) {
                     return other;
                 }
 

+ 2 - 0
src/Tools/babylon.decorators.ts

@@ -25,6 +25,8 @@
                         (<any>destination)[property] = sourceProperty;
                         break;
                     case 1:     // Texture
+                        (<any>destination)[property] = (instanciate||sourceProperty.isRenderTarget)?sourceProperty:sourceProperty.clone();
+                        break;
                     case 2:     // Color3
                     case 3:     // FresnelParameters
                     case 4:     // Vector2

+ 18 - 4
src/Tools/babylon.observable.ts

@@ -8,13 +8,15 @@
         /**
         * If the callback of a given Observer set skipNextObservers to true the following observers will be ignored
         */
-        constructor(mask: number, skipNextObservers = false) {
-            this.initalize(mask, skipNextObservers);
+        constructor(mask: number, skipNextObservers = false, target?: any, currentTarget?: any) {
+            this.initalize(mask, skipNextObservers, target, currentTarget);
         }
 
-        public initalize(mask: number, skipNextObservers = false): EventState {
+        public initalize(mask: number, skipNextObservers = false, target?: any, currentTarget?: any): EventState {
             this.mask = mask;
             this.skipNextObservers = skipNextObservers;
+            this.target = target;
+            this.currentTarget = currentTarget;
             return this;
         }
 
@@ -27,6 +29,16 @@
          * Get the mask value that were used to trigger the event corresponding to this EventState object
          */
         public mask: number;
+
+        /**
+         * The object that originally notified the event
+         */
+        public target?: any;
+        
+        /**
+         * The current object in the bubbling phase
+         */
+        public currentTarget?: any;
     }
 
     /**
@@ -153,9 +165,11 @@
          * @param eventData
          * @param mask
          */
-        public notifyObservers(eventData: T, mask: number = -1): boolean {
+        public notifyObservers(eventData: T, mask: number = -1, target?: any, currentTarget?: any): boolean {
             let state = this._eventState;
             state.mask = mask;
+            state.target = target;
+            state.currentTarget = currentTarget;
             state.skipNextObservers = false;
 
             for (var obs of this._observers) {

+ 4 - 0
src/babylon.mixins.ts

@@ -118,6 +118,10 @@ interface WebGLBuffer {
     is32Bits: boolean;
 }
 
+interface WebGLProgram {
+    __SPECTOR_rebuildProgram(vertexSourceCode: string, fragmentSourceCode: string, onCompiled: (program: WebGLProgram) => void, onError: (message: string) => void): void;
+}
+
 interface MouseEvent {
     mozMovementX: number;
     mozMovementY: number;