Selaa lähdekoodia

Nightly + bug fix

David Catuhe 9 vuotta sitten
vanhempi
commit
eac07221cf
100 muutettua tiedostoa jossa 8519 lisäystä ja 6367 poistoa
  1. 22 22
      dist/preview release/babylon.core.js
  2. 4938 4673
      dist/preview release/babylon.d.ts
  3. 37 36
      dist/preview release/babylon.js
  4. 1888 896
      dist/preview release/babylon.max.js
  5. 39 38
      dist/preview release/babylon.noworker.js
  6. 1 1
      src/Actions/babylon.action.js
  7. 2 2
      src/Actions/babylon.actionManager.js
  8. 4 4
      src/Actions/babylon.condition.js
  9. 12 12
      src/Actions/babylon.directActions.js
  10. 1 1
      src/Actions/babylon.interpolateValueAction.js
  11. 1 1
      src/Animations/babylon.animatable.js
  12. 4 4
      src/Animations/babylon.animation.js
  13. 13 13
      src/Animations/babylon.easing.js
  14. 1 1
      src/Audio/babylon.analyser.js
  15. 1 1
      src/Audio/babylon.audioEngine.js
  16. 1 1
      src/Audio/babylon.sound.js
  17. 1 1
      src/Audio/babylon.soundtrack.js
  18. 1 1
      src/Bones/babylon.bone.js
  19. 1 1
      src/Bones/babylon.skeleton.js
  20. 1 1
      src/Cameras/Inputs/babylon.arcrotatecamera.input.gamepad.js
  21. 1 1
      src/Cameras/Inputs/babylon.arcrotatecamera.input.keyboard.js
  22. 1 1
      src/Cameras/Inputs/babylon.arcrotatecamera.input.mousewheel.js
  23. 1 1
      src/Cameras/Inputs/babylon.arcrotatecamera.input.pointers.js
  24. 1 1
      src/Cameras/Inputs/babylon.arcrotatecamera.input.vrdeviceorientation.js
  25. 1 1
      src/Cameras/Inputs/babylon.freecamera.input.deviceorientation.js
  26. 1 1
      src/Cameras/Inputs/babylon.freecamera.input.gamepad.js
  27. 1 1
      src/Cameras/Inputs/babylon.freecamera.input.keyboard.js
  28. 1 1
      src/Cameras/Inputs/babylon.freecamera.input.mouse.js
  29. 1 1
      src/Cameras/Inputs/babylon.freecamera.input.touch.js
  30. 1 1
      src/Cameras/Inputs/babylon.freecamera.input.virtualjoystick.js
  31. 1 1
      src/Cameras/Inputs/babylon.freecamera.input.vrdeviceorientation.js
  32. 1 1
      src/Cameras/VR/babylon.vrCameraMetrics.js
  33. 2 2
      src/Cameras/VR/babylon.vrDeviceOrientationCamera.js
  34. 1 1
      src/Cameras/VR/babylon.webVRCamera.js
  35. 1 1
      src/Cameras/babylon.arcRotateCamera.js
  36. 1 1
      src/Cameras/babylon.arcRotateCameraInputsManager.js
  37. 1 1
      src/Cameras/babylon.camera.js
  38. 1 1
      src/Cameras/babylon.cameraInputsManager.js
  39. 1 1
      src/Cameras/babylon.deviceOrientationCamera.js
  40. 2 2
      src/Cameras/babylon.followCamera.js
  41. 1 1
      src/Cameras/babylon.freeCamera.js
  42. 1 1
      src/Cameras/babylon.freeCameraInputsManager.js
  43. 1 1
      src/Cameras/babylon.gamepadCamera.js
  44. 8 8
      src/Cameras/babylon.stereoscopicCameras.js
  45. 1 1
      src/Cameras/babylon.targetCamera.js
  46. 1 1
      src/Cameras/babylon.touchCamera.js
  47. 1 1
      src/Cameras/babylon.universalCamera.js
  48. 1 1
      src/Cameras/babylon.virtualJoysticksCamera.js
  49. 3 3
      src/Canvas2d/babylon.bounding2d.js
  50. 3 3
      src/Canvas2d/babylon.brushes2d.js
  51. 27 17
      src/Canvas2d/babylon.canvas2d.js
  52. 101 56
      src/Canvas2d/babylon.ellipse2d.js
  53. 335 98
      src/Canvas2d/babylon.group2d.js
  54. 99 52
      src/Canvas2d/babylon.lines2d.js
  55. 168 40
      src/Canvas2d/babylon.modelRenderCache.js
  56. 242 12
      src/Canvas2d/babylon.prim2dBase.js
  57. 96 62
      src/Canvas2d/babylon.rectangle2d.js
  58. 260 120
      src/Canvas2d/babylon.renderablePrim2d.js
  59. 2 2
      src/Canvas2d/babylon.renderablePrim2d.ts
  60. 4 5
      src/Canvas2d/babylon.shape2d.js
  61. 11 8
      src/Canvas2d/babylon.smartPropertyPrim.js
  62. 59 30
      src/Canvas2d/babylon.sprite2d.js
  63. 60 69
      src/Canvas2d/babylon.text2d.js
  64. 1 1
      src/Canvas2d/babylon.worldSpaceCanvas2d.js
  65. 1 1
      src/Collisions/babylon.collider.js
  66. 2 2
      src/Collisions/babylon.collisionCoordinator.js
  67. 3 3
      src/Collisions/babylon.collisionWorker.js
  68. 2 2
      src/Collisions/babylon.pickingInfo.js
  69. 1 1
      src/Culling/Octrees/babylon.octree.js
  70. 1 1
      src/Culling/Octrees/babylon.octreeBlock.js
  71. 1 1
      src/Culling/babylon.boundingBox.js
  72. 1 1
      src/Culling/babylon.boundingInfo.js
  73. 1 1
      src/Culling/babylon.boundingSphere.js
  74. 1 1
      src/Culling/babylon.ray.js
  75. 1 1
      src/Debug/babylon.debugLayer.js
  76. 1 1
      src/Debug/babylon.skeletonViewer.js
  77. 1 1
      src/Layer/babylon.layer.js
  78. 1 1
      src/LensFlare/babylon.lensFlare.js
  79. 1 1
      src/LensFlare/babylon.lensFlareSystem.js
  80. 1 1
      src/Lights/Shadows/babylon.shadowGenerator.js
  81. 1 1
      src/Lights/babylon.directionalLight.js
  82. 1 1
      src/Lights/babylon.hemisphericLight.js
  83. 1 1
      src/Lights/babylon.light.js
  84. 1 1
      src/Lights/babylon.pointLight.js
  85. 1 1
      src/Lights/babylon.spotLight.js
  86. 1 1
      src/Loading/babylon.sceneLoader.js
  87. 1 1
      src/Materials/Textures/Procedurals/babylon.customProceduralTexture.js
  88. 1 1
      src/Materials/Textures/Procedurals/babylon.proceduralTexture.js
  89. 1 1
      src/Materials/Textures/babylon.baseTexture.js
  90. 1 1
      src/Materials/Textures/babylon.colorGradingTexture.js
  91. 1 1
      src/Materials/Textures/babylon.cubeTexture.js
  92. 1 1
      src/Materials/Textures/babylon.dynamicTexture.js
  93. 4 4
      src/Materials/Textures/babylon.fontTexture.js
  94. 1 1
      src/Materials/Textures/babylon.hdrCubeTexture.js
  95. 1 1
      src/Materials/Textures/babylon.mapTexture.js
  96. 1 1
      src/Materials/Textures/babylon.mirrorTexture.js
  97. 1 1
      src/Materials/Textures/babylon.rawTexture.js
  98. 1 1
      src/Materials/Textures/babylon.refractionTexture.js
  99. 1 1
      src/Materials/Textures/babylon.renderTargetTexture.js
  100. 0 0
      src/Materials/Textures/babylon.texture.js

Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 22 - 22
dist/preview release/babylon.core.js


Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 4938 - 4673
dist/preview release/babylon.d.ts


Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 37 - 36
dist/preview release/babylon.js


Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 1888 - 896
dist/preview release/babylon.max.js


Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 39 - 38
dist/preview release/babylon.noworker.js


+ 1 - 1
src/Actions/babylon.action.js

@@ -126,6 +126,6 @@ var BABYLON;
             };
         };
         return Action;
-    }());
+    })();
     BABYLON.Action = Action;
 })(BABYLON || (BABYLON = {}));

+ 2 - 2
src/Actions/babylon.actionManager.js

@@ -50,7 +50,7 @@ var BABYLON;
             return new ActionEvent(prim, pointerPos.x, pointerPos.y, null, evt, additionalData);
         };
         return ActionEvent;
-    }());
+    })();
     BABYLON.ActionEvent = ActionEvent;
     /**
      * Action Manager manages all events to be triggered on a given mesh or the global scene.
@@ -522,6 +522,6 @@ var BABYLON;
         ActionManager.DragMovementThreshold = 10; // in pixels
         ActionManager.LongPressDelay = 500; // in milliseconds
         return ActionManager;
-    }());
+    })();
     BABYLON.ActionManager = ActionManager;
 })(BABYLON || (BABYLON = {}));

+ 4 - 4
src/Actions/babylon.condition.js

@@ -29,7 +29,7 @@ var BABYLON;
             };
         };
         return Condition;
-    }());
+    })();
     BABYLON.Condition = Condition;
     var ValueCondition = (function (_super) {
         __extends(ValueCondition, _super);
@@ -117,7 +117,7 @@ var BABYLON;
         ValueCondition._IsGreater = 2;
         ValueCondition._IsLesser = 3;
         return ValueCondition;
-    }(Condition));
+    })(Condition);
     BABYLON.ValueCondition = ValueCondition;
     var PredicateCondition = (function (_super) {
         __extends(PredicateCondition, _super);
@@ -129,7 +129,7 @@ var BABYLON;
             return this.predicate();
         };
         return PredicateCondition;
-    }(Condition));
+    })(Condition);
     BABYLON.PredicateCondition = PredicateCondition;
     var StateCondition = (function (_super) {
         __extends(StateCondition, _super);
@@ -152,6 +152,6 @@ var BABYLON;
             });
         };
         return StateCondition;
-    }(Condition));
+    })(Condition);
     BABYLON.StateCondition = StateCondition;
 })(BABYLON || (BABYLON = {}));

+ 12 - 12
src/Actions/babylon.directActions.js

@@ -29,7 +29,7 @@ var BABYLON;
             }, parent);
         };
         return SwitchBooleanAction;
-    }(BABYLON.Action));
+    })(BABYLON.Action);
     BABYLON.SwitchBooleanAction = SwitchBooleanAction;
     var SetStateAction = (function (_super) {
         __extends(SetStateAction, _super);
@@ -51,7 +51,7 @@ var BABYLON;
             }, parent);
         };
         return SetStateAction;
-    }(BABYLON.Action));
+    })(BABYLON.Action);
     BABYLON.SetStateAction = SetStateAction;
     var SetValueAction = (function (_super) {
         __extends(SetValueAction, _super);
@@ -82,7 +82,7 @@ var BABYLON;
             }, parent);
         };
         return SetValueAction;
-    }(BABYLON.Action));
+    })(BABYLON.Action);
     BABYLON.SetValueAction = SetValueAction;
     var IncrementValueAction = (function (_super) {
         __extends(IncrementValueAction, _super);
@@ -116,7 +116,7 @@ var BABYLON;
             }, parent);
         };
         return IncrementValueAction;
-    }(BABYLON.Action));
+    })(BABYLON.Action);
     BABYLON.IncrementValueAction = IncrementValueAction;
     var PlayAnimationAction = (function (_super) {
         __extends(PlayAnimationAction, _super);
@@ -145,7 +145,7 @@ var BABYLON;
             }, parent);
         };
         return PlayAnimationAction;
-    }(BABYLON.Action));
+    })(BABYLON.Action);
     BABYLON.PlayAnimationAction = PlayAnimationAction;
     var StopAnimationAction = (function (_super) {
         __extends(StopAnimationAction, _super);
@@ -166,7 +166,7 @@ var BABYLON;
             }, parent);
         };
         return StopAnimationAction;
-    }(BABYLON.Action));
+    })(BABYLON.Action);
     BABYLON.StopAnimationAction = StopAnimationAction;
     var DoNothingAction = (function (_super) {
         __extends(DoNothingAction, _super);
@@ -183,7 +183,7 @@ var BABYLON;
             }, parent);
         };
         return DoNothingAction;
-    }(BABYLON.Action));
+    })(BABYLON.Action);
     BABYLON.DoNothingAction = DoNothingAction;
     var CombineAction = (function (_super) {
         __extends(CombineAction, _super);
@@ -214,7 +214,7 @@ var BABYLON;
             return serializationObject;
         };
         return CombineAction;
-    }(BABYLON.Action));
+    })(BABYLON.Action);
     BABYLON.CombineAction = CombineAction;
     var ExecuteCodeAction = (function (_super) {
         __extends(ExecuteCodeAction, _super);
@@ -226,7 +226,7 @@ var BABYLON;
             this.func(evt);
         };
         return ExecuteCodeAction;
-    }(BABYLON.Action));
+    })(BABYLON.Action);
     BABYLON.ExecuteCodeAction = ExecuteCodeAction;
     var SetParentAction = (function (_super) {
         __extends(SetParentAction, _super);
@@ -256,7 +256,7 @@ var BABYLON;
             }, parent);
         };
         return SetParentAction;
-    }(BABYLON.Action));
+    })(BABYLON.Action);
     BABYLON.SetParentAction = SetParentAction;
     var PlaySoundAction = (function (_super) {
         __extends(PlaySoundAction, _super);
@@ -277,7 +277,7 @@ var BABYLON;
             }, parent);
         };
         return PlaySoundAction;
-    }(BABYLON.Action));
+    })(BABYLON.Action);
     BABYLON.PlaySoundAction = PlaySoundAction;
     var StopSoundAction = (function (_super) {
         __extends(StopSoundAction, _super);
@@ -298,6 +298,6 @@ var BABYLON;
             }, parent);
         };
         return StopSoundAction;
-    }(BABYLON.Action));
+    })(BABYLON.Action);
     BABYLON.StopSoundAction = StopSoundAction;
 })(BABYLON || (BABYLON = {}));

+ 1 - 1
src/Actions/babylon.interpolateValueAction.js

@@ -72,6 +72,6 @@ var BABYLON;
             }, parent);
         };
         return InterpolateValueAction;
-    }(BABYLON.Action));
+    })(BABYLON.Action);
     BABYLON.InterpolateValueAction = InterpolateValueAction;
 })(BABYLON || (BABYLON = {}));

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

@@ -127,6 +127,6 @@ var BABYLON;
             return running;
         };
         return Animatable;
-    }());
+    })();
     BABYLON.Animatable = Animatable;
 })(BABYLON || (BABYLON = {}));

+ 4 - 4
src/Animations/babylon.animation.js

@@ -10,7 +10,7 @@ var BABYLON;
             return new AnimationRange(this.name, this.from, this.to);
         };
         return AnimationRange;
-    }());
+    })();
     BABYLON.AnimationRange = AnimationRange;
     /**
      * Composed of a frame, and an action function
@@ -23,7 +23,7 @@ var BABYLON;
             this.isDone = false;
         }
         return AnimationEvent;
-    }());
+    })();
     BABYLON.AnimationEvent = AnimationEvent;
     var PathCursor = (function () {
         function PathCursor(path) {
@@ -80,7 +80,7 @@ var BABYLON;
             return this;
         };
         return PathCursor;
-    }());
+    })();
     BABYLON.PathCursor = PathCursor;
     var Animation = (function () {
         function Animation(name, targetProperty, framePerSecond, dataType, loopMode, enableBlending) {
@@ -736,6 +736,6 @@ var BABYLON;
         Animation._ANIMATIONLOOPMODE_CYCLE = 1;
         Animation._ANIMATIONLOOPMODE_CONSTANT = 2;
         return Animation;
-    }());
+    })();
     BABYLON.Animation = Animation;
 })(BABYLON || (BABYLON = {}));

+ 13 - 13
src/Animations/babylon.easing.js

@@ -58,7 +58,7 @@ var BABYLON;
         EasingFunction._EASINGMODE_EASEOUT = 1;
         EasingFunction._EASINGMODE_EASEINOUT = 2;
         return EasingFunction;
-    }());
+    })();
     BABYLON.EasingFunction = EasingFunction;
     var CircleEase = (function (_super) {
         __extends(CircleEase, _super);
@@ -70,7 +70,7 @@ var BABYLON;
             return (1.0 - Math.sqrt(1.0 - (gradient * gradient)));
         };
         return CircleEase;
-    }(EasingFunction));
+    })(EasingFunction);
     BABYLON.CircleEase = CircleEase;
     var BackEase = (function (_super) {
         __extends(BackEase, _super);
@@ -84,7 +84,7 @@ var BABYLON;
             return (Math.pow(gradient, 3.0) - ((gradient * num) * Math.sin(3.1415926535897931 * gradient)));
         };
         return BackEase;
-    }(EasingFunction));
+    })(EasingFunction);
     BABYLON.BackEase = BackEase;
     var BounceEase = (function (_super) {
         __extends(BounceEase, _super);
@@ -116,7 +116,7 @@ var BABYLON;
             return (((-Math.pow(1.0 / bounciness, y - num3) / (num2 * num2)) * (num6 - num2)) * (num6 + num2));
         };
         return BounceEase;
-    }(EasingFunction));
+    })(EasingFunction);
     BABYLON.BounceEase = BounceEase;
     var CubicEase = (function (_super) {
         __extends(CubicEase, _super);
@@ -127,7 +127,7 @@ var BABYLON;
             return (gradient * gradient * gradient);
         };
         return CubicEase;
-    }(EasingFunction));
+    })(EasingFunction);
     BABYLON.CubicEase = CubicEase;
     var ElasticEase = (function (_super) {
         __extends(ElasticEase, _super);
@@ -151,7 +151,7 @@ var BABYLON;
             return (num2 * Math.sin(((6.2831853071795862 * num3) + 1.5707963267948966) * gradient));
         };
         return ElasticEase;
-    }(EasingFunction));
+    })(EasingFunction);
     BABYLON.ElasticEase = ElasticEase;
     var ExponentialEase = (function (_super) {
         __extends(ExponentialEase, _super);
@@ -167,7 +167,7 @@ var BABYLON;
             return ((Math.exp(this.exponent * gradient) - 1.0) / (Math.exp(this.exponent) - 1.0));
         };
         return ExponentialEase;
-    }(EasingFunction));
+    })(EasingFunction);
     BABYLON.ExponentialEase = ExponentialEase;
     var PowerEase = (function (_super) {
         __extends(PowerEase, _super);
@@ -181,7 +181,7 @@ var BABYLON;
             return Math.pow(gradient, y);
         };
         return PowerEase;
-    }(EasingFunction));
+    })(EasingFunction);
     BABYLON.PowerEase = PowerEase;
     var QuadraticEase = (function (_super) {
         __extends(QuadraticEase, _super);
@@ -192,7 +192,7 @@ var BABYLON;
             return (gradient * gradient);
         };
         return QuadraticEase;
-    }(EasingFunction));
+    })(EasingFunction);
     BABYLON.QuadraticEase = QuadraticEase;
     var QuarticEase = (function (_super) {
         __extends(QuarticEase, _super);
@@ -203,7 +203,7 @@ var BABYLON;
             return (gradient * gradient * gradient * gradient);
         };
         return QuarticEase;
-    }(EasingFunction));
+    })(EasingFunction);
     BABYLON.QuarticEase = QuarticEase;
     var QuinticEase = (function (_super) {
         __extends(QuinticEase, _super);
@@ -214,7 +214,7 @@ var BABYLON;
             return (gradient * gradient * gradient * gradient * gradient);
         };
         return QuinticEase;
-    }(EasingFunction));
+    })(EasingFunction);
     BABYLON.QuinticEase = QuinticEase;
     var SineEase = (function (_super) {
         __extends(SineEase, _super);
@@ -225,7 +225,7 @@ var BABYLON;
             return (1.0 - Math.sin(1.5707963267948966 * (1.0 - gradient)));
         };
         return SineEase;
-    }(EasingFunction));
+    })(EasingFunction);
     BABYLON.SineEase = SineEase;
     var BezierCurveEase = (function (_super) {
         __extends(BezierCurveEase, _super);
@@ -244,6 +244,6 @@ var BABYLON;
             return BABYLON.BezierCurve.interpolate(gradient, this.x1, this.y1, this.x2, this.y2);
         };
         return BezierCurveEase;
-    }(EasingFunction));
+    })(EasingFunction);
     BABYLON.BezierCurveEase = BezierCurveEase;
 })(BABYLON || (BABYLON = {}));

+ 1 - 1
src/Audio/babylon.analyser.js

@@ -106,6 +106,6 @@ var BABYLON;
             }
         };
         return Analyser;
-    }());
+    })();
     BABYLON.Analyser = Analyser;
 })(BABYLON || (BABYLON = {}));

+ 1 - 1
src/Audio/babylon.audioEngine.js

@@ -101,6 +101,6 @@ var BABYLON;
             }
         };
         return AudioEngine;
-    }());
+    })();
     BABYLON.AudioEngine = AudioEngine;
 })(BABYLON || (BABYLON = {}));

+ 1 - 1
src/Audio/babylon.sound.js

@@ -547,6 +547,6 @@ var BABYLON;
             return newSound;
         };
         return Sound;
-    }());
+    })();
     BABYLON.Sound = Sound;
 })(BABYLON || (BABYLON = {}));

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

@@ -96,6 +96,6 @@ var BABYLON;
             }
         };
         return SoundTrack;
-    }());
+    })();
     BABYLON.SoundTrack = SoundTrack;
 })(BABYLON || (BABYLON = {}));

+ 1 - 1
src/Bones/babylon.bone.js

@@ -124,6 +124,6 @@ var BABYLON;
             return true;
         };
         return Bone;
-    }(BABYLON.Node));
+    })(BABYLON.Node);
     BABYLON.Bone = Bone;
 })(BABYLON || (BABYLON = {}));

+ 1 - 1
src/Bones/babylon.skeleton.js

@@ -333,6 +333,6 @@ var BABYLON;
             return skeleton;
         };
         return Skeleton;
-    }());
+    })();
     BABYLON.Skeleton = Skeleton;
 })(BABYLON || (BABYLON = {}));

+ 1 - 1
src/Cameras/Inputs/babylon.arcrotatecamera.input.gamepad.js

@@ -65,7 +65,7 @@ var BABYLON;
             BABYLON.serialize()
         ], ArcRotateCameraGamepadInput.prototype, "gamepadMoveSensibility", void 0);
         return ArcRotateCameraGamepadInput;
-    }());
+    })();
     BABYLON.ArcRotateCameraGamepadInput = ArcRotateCameraGamepadInput;
     BABYLON.CameraInputTypes["ArcRotateCameraGamepadInput"] = ArcRotateCameraGamepadInput;
 })(BABYLON || (BABYLON = {}));

+ 1 - 1
src/Cameras/Inputs/babylon.arcrotatecamera.input.keyboard.js

@@ -107,7 +107,7 @@ var BABYLON;
             BABYLON.serialize()
         ], ArcRotateCameraKeyboardMoveInput.prototype, "keysRight", void 0);
         return ArcRotateCameraKeyboardMoveInput;
-    }());
+    })();
     BABYLON.ArcRotateCameraKeyboardMoveInput = ArcRotateCameraKeyboardMoveInput;
     BABYLON.CameraInputTypes["ArcRotateCameraKeyboardMoveInput"] = ArcRotateCameraKeyboardMoveInput;
 })(BABYLON || (BABYLON = {}));

+ 1 - 1
src/Cameras/Inputs/babylon.arcrotatecamera.input.mousewheel.js

@@ -51,7 +51,7 @@ var BABYLON;
             BABYLON.serialize()
         ], ArcRotateCameraMouseWheelInput.prototype, "wheelPrecision", void 0);
         return ArcRotateCameraMouseWheelInput;
-    }());
+    })();
     BABYLON.ArcRotateCameraMouseWheelInput = ArcRotateCameraMouseWheelInput;
     BABYLON.CameraInputTypes["ArcRotateCameraMouseWheelInput"] = ArcRotateCameraMouseWheelInput;
 })(BABYLON || (BABYLON = {}));

+ 1 - 1
src/Cameras/Inputs/babylon.arcrotatecamera.input.pointers.js

@@ -213,7 +213,7 @@ var BABYLON;
             BABYLON.serialize()
         ], ArcRotateCameraPointersInput.prototype, "panningSensibility", void 0);
         return ArcRotateCameraPointersInput;
-    }());
+    })();
     BABYLON.ArcRotateCameraPointersInput = ArcRotateCameraPointersInput;
     BABYLON.CameraInputTypes["ArcRotateCameraPointersInput"] = ArcRotateCameraPointersInput;
 })(BABYLON || (BABYLON = {}));

+ 1 - 1
src/Cameras/Inputs/babylon.arcrotatecamera.input.vrdeviceorientation.js

@@ -42,7 +42,7 @@ var BABYLON;
             return "VRDeviceOrientation";
         };
         return ArcRotateCameraVRDeviceOrientationInput;
-    }());
+    })();
     BABYLON.ArcRotateCameraVRDeviceOrientationInput = ArcRotateCameraVRDeviceOrientationInput;
     BABYLON.CameraInputTypes["ArcRotateCameraVRDeviceOrientationInput"] = ArcRotateCameraVRDeviceOrientationInput;
 })(BABYLON || (BABYLON = {}));

+ 1 - 1
src/Cameras/Inputs/babylon.freecamera.input.deviceorientation.js

@@ -56,7 +56,7 @@ var BABYLON;
             return "deviceOrientation";
         };
         return FreeCameraDeviceOrientationInput;
-    }());
+    })();
     BABYLON.FreeCameraDeviceOrientationInput = FreeCameraDeviceOrientationInput;
     BABYLON.CameraInputTypes["FreeCameraDeviceOrientationInput"] = FreeCameraDeviceOrientationInput;
 })(BABYLON || (BABYLON = {}));

+ 1 - 1
src/Cameras/Inputs/babylon.freecamera.input.gamepad.js

@@ -60,7 +60,7 @@ var BABYLON;
             BABYLON.serialize()
         ], FreeCameraGamepadInput.prototype, "gamepadMoveSensibility", void 0);
         return FreeCameraGamepadInput;
-    }());
+    })();
     BABYLON.FreeCameraGamepadInput = FreeCameraGamepadInput;
     BABYLON.CameraInputTypes["FreeCameraGamepadInput"] = FreeCameraGamepadInput;
 })(BABYLON || (BABYLON = {}));

+ 1 - 1
src/Cameras/Inputs/babylon.freecamera.input.keyboard.js

@@ -111,7 +111,7 @@ var BABYLON;
             BABYLON.serialize()
         ], FreeCameraKeyboardMoveInput.prototype, "keysRight", void 0);
         return FreeCameraKeyboardMoveInput;
-    }());
+    })();
     BABYLON.FreeCameraKeyboardMoveInput = FreeCameraKeyboardMoveInput;
     BABYLON.CameraInputTypes["FreeCameraKeyboardMoveInput"] = FreeCameraKeyboardMoveInput;
 })(BABYLON || (BABYLON = {}));

+ 1 - 1
src/Cameras/Inputs/babylon.freecamera.input.mouse.js

@@ -92,7 +92,7 @@ var BABYLON;
             BABYLON.serialize()
         ], FreeCameraMouseInput.prototype, "angularSensibility", void 0);
         return FreeCameraMouseInput;
-    }());
+    })();
     BABYLON.FreeCameraMouseInput = FreeCameraMouseInput;
     BABYLON.CameraInputTypes["FreeCameraMouseInput"] = FreeCameraMouseInput;
 })(BABYLON || (BABYLON = {}));

+ 1 - 1
src/Cameras/Inputs/babylon.freecamera.input.touch.js

@@ -116,7 +116,7 @@ var BABYLON;
             BABYLON.serialize()
         ], FreeCameraTouchInput.prototype, "touchMoveSensibility", void 0);
         return FreeCameraTouchInput;
-    }());
+    })();
     BABYLON.FreeCameraTouchInput = FreeCameraTouchInput;
     BABYLON.CameraInputTypes["FreeCameraTouchInput"] = FreeCameraTouchInput;
 })(BABYLON || (BABYLON = {}));

+ 1 - 1
src/Cameras/Inputs/babylon.freecamera.input.virtualjoystick.js

@@ -48,7 +48,7 @@ var BABYLON;
             return "virtualJoystick";
         };
         return FreeCameraVirtualJoystickInput;
-    }());
+    })();
     BABYLON.FreeCameraVirtualJoystickInput = FreeCameraVirtualJoystickInput;
     BABYLON.CameraInputTypes["FreeCameraVirtualJoystickInput"] = FreeCameraVirtualJoystickInput;
 })(BABYLON || (BABYLON = {}));

+ 1 - 1
src/Cameras/Inputs/babylon.freecamera.input.vrdeviceorientation.js

@@ -47,7 +47,7 @@ var BABYLON;
             return "VRDeviceOrientation";
         };
         return FreeCameraVRDeviceOrientationInput;
-    }());
+    })();
     BABYLON.FreeCameraVRDeviceOrientationInput = FreeCameraVRDeviceOrientationInput;
     BABYLON.CameraInputTypes["FreeCameraVRDeviceOrientationInput"] = FreeCameraVRDeviceOrientationInput;
 })(BABYLON || (BABYLON = {}));

+ 1 - 1
src/Cameras/VR/babylon.vrCameraMetrics.js

@@ -67,6 +67,6 @@ var BABYLON;
             return result;
         };
         return VRCameraMetrics;
-    }());
+    })();
     BABYLON.VRCameraMetrics = VRCameraMetrics;
 })(BABYLON || (BABYLON = {}));

+ 2 - 2
src/Cameras/VR/babylon.vrDeviceOrientationCamera.js

@@ -20,7 +20,7 @@ var BABYLON;
             return "VRDeviceOrientationFreeCamera";
         };
         return VRDeviceOrientationFreeCamera;
-    }(BABYLON.FreeCamera));
+    })(BABYLON.FreeCamera);
     BABYLON.VRDeviceOrientationFreeCamera = VRDeviceOrientationFreeCamera;
     var VRDeviceOrientationArcRotateCamera = (function (_super) {
         __extends(VRDeviceOrientationArcRotateCamera, _super);
@@ -36,6 +36,6 @@ var BABYLON;
             return "VRDeviceOrientationArcRotateCamera";
         };
         return VRDeviceOrientationArcRotateCamera;
-    }(BABYLON.ArcRotateCamera));
+    })(BABYLON.ArcRotateCamera);
     BABYLON.VRDeviceOrientationArcRotateCamera = VRDeviceOrientationArcRotateCamera;
 })(BABYLON || (BABYLON = {}));

+ 1 - 1
src/Cameras/VR/babylon.webVRCamera.js

@@ -75,6 +75,6 @@ var BABYLON;
             return "WebVRFreeCamera";
         };
         return WebVRFreeCamera;
-    }(BABYLON.FreeCamera));
+    })(BABYLON.FreeCamera);
     BABYLON.WebVRFreeCamera = WebVRFreeCamera;
 })(BABYLON || (BABYLON = {}));

+ 1 - 1
src/Cameras/babylon.arcRotateCamera.js

@@ -541,6 +541,6 @@ var BABYLON;
             BABYLON.serialize()
         ], ArcRotateCamera.prototype, "allowUpsideDown", void 0);
         return ArcRotateCamera;
-    }(BABYLON.TargetCamera));
+    })(BABYLON.TargetCamera);
     BABYLON.ArcRotateCamera = ArcRotateCamera;
 })(BABYLON || (BABYLON = {}));

+ 1 - 1
src/Cameras/babylon.arcRotateCameraInputsManager.js

@@ -31,6 +31,6 @@ var BABYLON;
             return this;
         };
         return ArcRotateCameraInputsManager;
-    }(BABYLON.CameraInputsManager));
+    })(BABYLON.CameraInputsManager);
     BABYLON.ArcRotateCameraInputsManager = ArcRotateCameraInputsManager;
 })(BABYLON || (BABYLON = {}));

+ 1 - 1
src/Cameras/babylon.camera.js

@@ -615,6 +615,6 @@ var BABYLON;
             BABYLON.serialize()
         ], Camera.prototype, "isStereoscopicSideBySide", void 0);
         return Camera;
-    }(BABYLON.Node));
+    })(BABYLON.Node);
     BABYLON.Camera = Camera;
 })(BABYLON || (BABYLON = {}));

+ 1 - 1
src/Cameras/babylon.cameraInputsManager.js

@@ -128,6 +128,6 @@ var BABYLON;
             }
         };
         return CameraInputsManager;
-    }());
+    })();
     BABYLON.CameraInputsManager = CameraInputsManager;
 })(BABYLON || (BABYLON = {}));

+ 1 - 1
src/Cameras/babylon.deviceOrientationCamera.js

@@ -36,6 +36,6 @@ var BABYLON;
             return "DeviceOrientationCamera";
         };
         return DeviceOrientationCamera;
-    }(BABYLON.FreeCamera));
+    })(BABYLON.FreeCamera);
     BABYLON.DeviceOrientationCamera = DeviceOrientationCamera;
 })(BABYLON || (BABYLON = {}));

+ 2 - 2
src/Cameras/babylon.followCamera.js

@@ -84,7 +84,7 @@ var BABYLON;
             BABYLON.serializeAsMeshReference("lockedTargetId")
         ], FollowCamera.prototype, "target", void 0);
         return FollowCamera;
-    }(BABYLON.TargetCamera));
+    })(BABYLON.TargetCamera);
     BABYLON.FollowCamera = FollowCamera;
     var ArcFollowCamera = (function (_super) {
         __extends(ArcFollowCamera, _super);
@@ -112,6 +112,6 @@ var BABYLON;
             return "ArcFollowCamera";
         };
         return ArcFollowCamera;
-    }(BABYLON.TargetCamera));
+    })(BABYLON.TargetCamera);
     BABYLON.ArcFollowCamera = ArcFollowCamera;
 })(BABYLON || (BABYLON = {}));

+ 1 - 1
src/Cameras/babylon.freeCamera.js

@@ -180,6 +180,6 @@ var BABYLON;
             BABYLON.serialize()
         ], FreeCamera.prototype, "applyGravity", void 0);
         return FreeCamera;
-    }(BABYLON.TargetCamera));
+    })(BABYLON.TargetCamera);
     BABYLON.FreeCamera = FreeCamera;
 })(BABYLON || (BABYLON = {}));

+ 1 - 1
src/Cameras/babylon.freeCameraInputsManager.js

@@ -40,6 +40,6 @@ var BABYLON;
             return this;
         };
         return FreeCameraInputsManager;
-    }(BABYLON.CameraInputsManager));
+    })(BABYLON.CameraInputsManager);
     BABYLON.FreeCameraInputsManager = FreeCameraInputsManager;
 })(BABYLON || (BABYLON = {}));

+ 1 - 1
src/Cameras/babylon.gamepadCamera.js

@@ -46,6 +46,6 @@ var BABYLON;
             return "GamepadCamera";
         };
         return GamepadCamera;
-    }(BABYLON.UniversalCamera));
+    })(BABYLON.UniversalCamera);
     BABYLON.GamepadCamera = GamepadCamera;
 })(BABYLON || (BABYLON = {}));

+ 8 - 8
src/Cameras/babylon.stereoscopicCameras.js

@@ -16,7 +16,7 @@ var BABYLON;
             return "AnaglyphFreeCamera";
         };
         return AnaglyphFreeCamera;
-    }(BABYLON.FreeCamera));
+    })(BABYLON.FreeCamera);
     BABYLON.AnaglyphFreeCamera = AnaglyphFreeCamera;
     var AnaglyphArcRotateCamera = (function (_super) {
         __extends(AnaglyphArcRotateCamera, _super);
@@ -29,7 +29,7 @@ var BABYLON;
             return "AnaglyphArcRotateCamera";
         };
         return AnaglyphArcRotateCamera;
-    }(BABYLON.ArcRotateCamera));
+    })(BABYLON.ArcRotateCamera);
     BABYLON.AnaglyphArcRotateCamera = AnaglyphArcRotateCamera;
     var AnaglyphGamepadCamera = (function (_super) {
         __extends(AnaglyphGamepadCamera, _super);
@@ -42,7 +42,7 @@ var BABYLON;
             return "AnaglyphGamepadCamera";
         };
         return AnaglyphGamepadCamera;
-    }(BABYLON.GamepadCamera));
+    })(BABYLON.GamepadCamera);
     BABYLON.AnaglyphGamepadCamera = AnaglyphGamepadCamera;
     var AnaglyphUniversalCamera = (function (_super) {
         __extends(AnaglyphUniversalCamera, _super);
@@ -55,7 +55,7 @@ var BABYLON;
             return "AnaglyphUniversalCamera";
         };
         return AnaglyphUniversalCamera;
-    }(BABYLON.UniversalCamera));
+    })(BABYLON.UniversalCamera);
     BABYLON.AnaglyphUniversalCamera = AnaglyphUniversalCamera;
     var StereoscopicFreeCamera = (function (_super) {
         __extends(StereoscopicFreeCamera, _super);
@@ -69,7 +69,7 @@ var BABYLON;
             return "StereoscopicFreeCamera";
         };
         return StereoscopicFreeCamera;
-    }(BABYLON.FreeCamera));
+    })(BABYLON.FreeCamera);
     BABYLON.StereoscopicFreeCamera = StereoscopicFreeCamera;
     var StereoscopicArcRotateCamera = (function (_super) {
         __extends(StereoscopicArcRotateCamera, _super);
@@ -83,7 +83,7 @@ var BABYLON;
             return "StereoscopicArcRotateCamera";
         };
         return StereoscopicArcRotateCamera;
-    }(BABYLON.ArcRotateCamera));
+    })(BABYLON.ArcRotateCamera);
     BABYLON.StereoscopicArcRotateCamera = StereoscopicArcRotateCamera;
     var StereoscopicGamepadCamera = (function (_super) {
         __extends(StereoscopicGamepadCamera, _super);
@@ -97,7 +97,7 @@ var BABYLON;
             return "StereoscopicGamepadCamera";
         };
         return StereoscopicGamepadCamera;
-    }(BABYLON.GamepadCamera));
+    })(BABYLON.GamepadCamera);
     BABYLON.StereoscopicGamepadCamera = StereoscopicGamepadCamera;
     var StereoscopicUniversalCamera = (function (_super) {
         __extends(StereoscopicUniversalCamera, _super);
@@ -111,6 +111,6 @@ var BABYLON;
             return "StereoscopicUniversalCamera";
         };
         return StereoscopicUniversalCamera;
-    }(BABYLON.UniversalCamera));
+    })(BABYLON.UniversalCamera);
     BABYLON.StereoscopicUniversalCamera = StereoscopicUniversalCamera;
 })(BABYLON || (BABYLON = {}));

+ 1 - 1
src/Cameras/babylon.targetCamera.js

@@ -269,6 +269,6 @@ var BABYLON;
             BABYLON.serializeAsMeshReference("lockedTargetId")
         ], TargetCamera.prototype, "lockedTarget", void 0);
         return TargetCamera;
-    }(BABYLON.Camera));
+    })(BABYLON.Camera);
     BABYLON.TargetCamera = TargetCamera;
 })(BABYLON || (BABYLON = {}));

+ 1 - 1
src/Cameras/babylon.touchCamera.js

@@ -53,6 +53,6 @@ var BABYLON;
             }
         };
         return TouchCamera;
-    }(BABYLON.FreeCamera));
+    })(BABYLON.FreeCamera);
     BABYLON.TouchCamera = TouchCamera;
 })(BABYLON || (BABYLON = {}));

+ 1 - 1
src/Cameras/babylon.universalCamera.js

@@ -46,6 +46,6 @@ var BABYLON;
             return "UniversalCamera";
         };
         return UniversalCamera;
-    }(BABYLON.TouchCamera));
+    })(BABYLON.TouchCamera);
     BABYLON.UniversalCamera = UniversalCamera;
 })(BABYLON || (BABYLON = {}));

+ 1 - 1
src/Cameras/babylon.virtualJoysticksCamera.js

@@ -13,6 +13,6 @@ var BABYLON;
             this.inputs.addVirtualJoystick();
         }
         return VirtualJoysticksCamera;
-    }(BABYLON.FreeCamera));
+    })(BABYLON.FreeCamera);
     BABYLON.VirtualJoysticksCamera = VirtualJoysticksCamera;
 })(BABYLON || (BABYLON = {}));

+ 3 - 3
src/Canvas2d/babylon.bounding2d.js

@@ -45,8 +45,8 @@ var BABYLON;
         };
         BoundingInfo2D.CreateFromPointsToRef = function (points, b, origin) {
             var xmin = Number.MAX_VALUE, ymin = Number.MAX_VALUE, xmax = Number.MIN_VALUE, ymax = Number.MIN_VALUE;
-            for (var _i = 0, points_1 = points; _i < points_1.length; _i++) {
-                var p = points_1[_i];
+            for (var _i = 0; _i < points.length; _i++) {
+                var p = points[_i];
                 xmin = Math.min(p.x, xmin);
                 xmax = Math.max(p.x, xmax);
                 ymin = Math.min(p.y, ymin);
@@ -147,6 +147,6 @@ var BABYLON;
             return false;
         };
         return BoundingInfo2D;
-    }());
+    })();
     BABYLON.BoundingInfo2D = BoundingInfo2D;
 })(BABYLON || (BABYLON = {}));

+ 3 - 3
src/Canvas2d/babylon.brushes2d.js

@@ -35,7 +35,7 @@ var BABYLON;
         LockableBase.prototype.onLock = function () {
         };
         return LockableBase;
-    }());
+    })();
     BABYLON.LockableBase = LockableBase;
     /**
      * This class implements a Brush that will be drawn with a uniform solid color (i.e. the same color everywhere in the content where the brush is assigned to).
@@ -82,7 +82,7 @@ var BABYLON;
             BABYLON.className("SolidColorBrush2D")
         ], SolidColorBrush2D);
         return SolidColorBrush2D;
-    }(LockableBase));
+    })(LockableBase);
     BABYLON.SolidColorBrush2D = SolidColorBrush2D;
     var GradientColorBrush2D = (function (_super) {
         __extends(GradientColorBrush2D, _super);
@@ -179,6 +179,6 @@ var BABYLON;
             BABYLON.className("GradientColorBrush2D")
         ], GradientColorBrush2D);
         return GradientColorBrush2D;
-    }(LockableBase));
+    })(LockableBase);
     BABYLON.GradientColorBrush2D = GradientColorBrush2D;
 })(BABYLON || (BABYLON = {}));

+ 27 - 17
src/Canvas2d/babylon.canvas2d.js

@@ -26,7 +26,7 @@ var BABYLON;
             return true;
         };
         return Canvas2DEngineBoundData;
-    }());
+    })();
     BABYLON.Canvas2DEngineBoundData = Canvas2DEngineBoundData;
     var Canvas2D = (function (_super) {
         __extends(Canvas2D, _super);
@@ -43,16 +43,27 @@ var BABYLON;
          * @param scene the Scene that owns the Canvas
          * Options:
          *  - id: a text identifier, for information purpose only
-         *  - pos: the position of the canvas, relative from the bottom/left of the scene's viewport
-         *  - size: the Size of the canvas. If null two behaviors depend on the cachingStrategy: if it's CACHESTRATEGY_CACHECANVAS then it will always auto-fit the rendering device, in all the other modes it will fit the content of the Canvas
-         *  - cachingStrategy: either CACHESTRATEGY_TOPLEVELGROUPS, CACHESTRATEGY_ALLGROUPS, CACHESTRATEGY_CANVAS, CACHESTRATEGY_DONTCACHE. Please refer to their respective documentation for more information. Default is Canvas2D.CACHESTRATEGY_TOPLEVELGROUPS
+         *  - pos: the position of the canvas, relative from the bottom/left of the scene's viewport. Alternatively you can set the x and y properties directly. Default value is [0, 0]
+         *  - size: the Size of the canvas. Alternatively the width and height properties can be set. If null two behaviors depend on the cachingStrategy: if it's CACHESTRATEGY_CACHECANVAS then it will always auto-fit the rendering device, in all the other modes it will fit the content of the Canvas
+         *  - cachingStrategy: either CACHESTRATEGY_TOPLEVELGROUPS, CACHESTRATEGY_ALLGROUPS, CACHESTRATEGY_CANVAS, CACHESTRATEGY_DONTCACHE. Please refer to their respective documentation for more information. Default is Canvas2D.CACHESTRATEGY_DONTCACHE
          *  - enableInteraction: if true the pointer events will be listened and rerouted to the appropriate primitives of the Canvas2D through the Prim2DBase.onPointerEventObservable observable property.
+         *  - isVisible: true if the canvas must be visible, false for hidden. Default is true.
+         *  - marginTop/Left/Right/Bottom: define the margin for the corresponding edge, if all of them are null, margin is not used in layout computing. Default Value is null for each.
+         *  - hAlighment: define horizontal alignment of the Canvas, alignment is optional, default value null: no alignment.
+         *  - vAlighment: define horizontal alignment of the Canvas, alignment is optional, default value null: no alignment.
          */
         Canvas2D.CreateScreenSpace = function (scene, options) {
             var c = new Canvas2D();
-            c.setupCanvas(scene, options && options.id || null, options && options.size || null, true, options && options.cachingStrategy || Canvas2D.CACHESTRATEGY_TOPLEVELGROUPS, options && options.enableInteraction || true);
-            c.position = options && options.pos || BABYLON.Vector2.Zero();
-            c.origin = options && options.origin || BABYLON.Vector2.Zero();
+            if (!options) {
+                c.setupCanvas(scene, null, null, true, Canvas2D.CACHESTRATEGY_DONTCACHE, true, BABYLON.Vector2.Zero(), true, null, null, null, null, null, null);
+                c.position = BABYLON.Vector2.Zero();
+            }
+            else {
+                var pos = options.position || new BABYLON.Vector2(options.x || 0, options.y || 0);
+                var size = (!options.size && !options.width && !options.height) ? null : (options.size || (new BABYLON.Size(options.width || 0, options.height || 0)));
+                c.setupCanvas(scene, options.id || null, size, true, options.cachingStrategy || Canvas2D.CACHESTRATEGY_DONTCACHE, options.enableInteraction || true, options.origin || BABYLON.Vector2.Zero(), options.isVisible || true, options.marginTop, options.marginLeft, options.marginRight, options.marginBottom, options.hAlignment || BABYLON.Prim2DBase.HAlignLeft, options.vAlignment || BABYLON.Prim2DBase.VAlignTop);
+                c.position = pos;
+            }
             return c;
         };
         /**
@@ -69,6 +80,7 @@ var BABYLON;
          * TIPS: if you want a renderScaleFactor independent reference of frame, create a child Group2D in the Canvas with position 0,0 and size set to null, then set its scale property to the same amount than the renderScaleFactor, put all your primitive inside using coordinates regarding the size property you pick for the Canvas and you'll be fine.
          * - sideOrientation: Unexpected behavior occur if the value is different from Mesh.DEFAULTSIDE right now, so please use this one, which is the default.
          * - cachingStrategy Must be CACHESTRATEGY_CANVAS for now, which is the default.
+         * - isVisible: true if the canvas must be visible, false for hidden. Default is true.
          */
         Canvas2D.CreateWorldSpace = function (scene, size, options) {
             var cs = options && options.cachingStrategy || Canvas2D.CACHESTRATEGY_CANVAS;
@@ -81,7 +93,7 @@ var BABYLON;
             var id = options && options.id || null;
             var rsf = options && options.renderScaleFactor || 1;
             var c = new Canvas2D();
-            c.setupCanvas(scene, id, new BABYLON.Size(size.width * rsf, size.height * rsf), false, cs, options && options.enableInteraction || true);
+            c.setupCanvas(scene, id, new BABYLON.Size(size.width * rsf, size.height * rsf), false, cs, options && options.enableInteraction || true, BABYLON.Vector2.Zero(), options && options.isVisible || true, null, null, null, null, null, null);
             var plane = new BABYLON.WorldSpaceCanvas2D(id, scene, c);
             var vertexData = BABYLON.VertexData.CreatePlane({ width: size.width / 2, height: size.height / 2, sideOrientation: options && options.sideOrientation || BABYLON.Mesh.DEFAULTSIDE });
             var mtl = new BABYLON.StandardMaterial(id + "_Material", scene);
@@ -96,7 +108,7 @@ var BABYLON;
             c._worldSpaceNode = plane;
             return c;
         };
-        Canvas2D.prototype.setupCanvas = function (scene, name, size, isScreenSpace, cachingstrategy, enableInteraction) {
+        Canvas2D.prototype.setupCanvas = function (scene, name, size, isScreenSpace, cachingstrategy, enableInteraction, origin, isVisible, marginTop, marginLeft, marginRight, marginBottom, hAlign, vAlign) {
             var _this = this;
             var engine = scene.getEngine();
             this._fitRenderingDevice = !size;
@@ -108,8 +120,8 @@ var BABYLON;
             this._primPointerInfo = new BABYLON.PrimitivePointerInfo();
             this._capturedPointers = new BABYLON.StringDictionary();
             this._pickStartingPosition = BABYLON.Vector2.Zero();
-            this.setupGroup2D(this, null, name, BABYLON.Vector2.Zero(), null, size, this._cachingStrategy === Canvas2D.CACHESTRATEGY_ALLGROUPS ? BABYLON.Group2D.GROUPCACHEBEHAVIOR_DONTCACHEOVERRIDE : BABYLON.Group2D.GROUPCACHEBEHAVIOR_FOLLOWCACHESTRATEGY);
-            this._hierarchyLevelMaxSiblingCount = 100;
+            this.setupGroup2D(this, null, name, BABYLON.Vector2.Zero(), origin, size, isVisible, this._cachingStrategy === Canvas2D.CACHESTRATEGY_ALLGROUPS ? BABYLON.Group2D.GROUPCACHEBEHAVIOR_DONTCACHEOVERRIDE : BABYLON.Group2D.GROUPCACHEBEHAVIOR_FOLLOWCACHESTRATEGY, marginTop, marginLeft, marginRight, marginBottom, hAlign, vAlign);
+            this._hierarchyLevelMaxSiblingCount = 10;
             this._hierarchyDepthOffset = 0;
             this._siblingDepthOffset = 1 / this._hierarchyLevelMaxSiblingCount;
             this._scene = scene;
@@ -693,8 +705,7 @@ var BABYLON;
                     this._background.size = this.size;
                 }
             }
-            var context = new BABYLON.Render2DContext();
-            context.forceRefreshPrimitive = false;
+            var context = new BABYLON.PreapreRender2DContext();
             ++this._globalTransformProcessStep;
             this.updateGlobalTransVis(false);
             this._prepareGroupRender(context);
@@ -709,11 +720,10 @@ var BABYLON;
                 this._updateIntersectionList(this._primPointerInfo.canvasPointerPos, false);
                 this._updateOverStatus(); // TODO this._primPointerInfo may not be up to date!
             }
-            var context = new BABYLON.Render2DContext();
-            this._groupRender(context);
+            this._groupRender();
             // If the canvas is cached at canvas level, we must manually render the sprite that will display its content
             if (this._cachingStrategy === Canvas2D.CACHESTRATEGY_CANVAS && this._cachedCanvasGroup) {
-                this._cachedCanvasGroup._renderCachedCanvas(context);
+                this._cachedCanvasGroup._renderCachedCanvas();
             }
         };
         /**
@@ -833,6 +843,6 @@ var BABYLON;
             BABYLON.className("Canvas2D")
         ], Canvas2D);
         return Canvas2D;
-    }(BABYLON.Group2D));
+    })(BABYLON.Group2D);
     BABYLON.Canvas2D = Canvas2D;
 })(BABYLON || (BABYLON = {}));

+ 101 - 56
src/Canvas2d/babylon.ellipse2d.js

@@ -13,69 +13,87 @@ var BABYLON;
 (function (BABYLON) {
     var Ellipse2DRenderCache = (function (_super) {
         __extends(Ellipse2DRenderCache, _super);
-        function Ellipse2DRenderCache(engine, modelKey, isTransparent) {
-            _super.call(this, engine, modelKey, isTransparent);
+        function Ellipse2DRenderCache(engine, modelKey) {
+            _super.call(this, engine, modelKey);
+            this.effectsReady = false;
+            this.fillVB = null;
+            this.fillIB = null;
+            this.fillIndicesCount = 0;
+            this.instancingFillAttributes = null;
+            this.effectFillInstanced = null;
+            this.effectFill = null;
+            this.borderVB = null;
+            this.borderIB = null;
+            this.borderIndicesCount = 0;
+            this.instancingBorderAttributes = null;
+            this.effectBorderInstanced = null;
+            this.effectBorder = null;
         }
         Ellipse2DRenderCache.prototype.render = function (instanceInfo, context) {
             // Do nothing if the shader is still loading/preparing 
-            if ((this.effectFill && !this.effectFill.isReady()) || (this.effectBorder && !this.effectBorder.isReady())) {
-                return false;
+            if (!this.effectsReady) {
+                if ((this.effectFill && (!this.effectFill.isReady() || (this.effectFillInstanced && !this.effectFillInstanced.isReady()))) ||
+                    (this.effectBorder && (!this.effectBorder.isReady() || (this.effectBorderInstanced && !this.effectBorderInstanced.isReady())))) {
+                    return false;
+                }
+                this.effectsReady = true;
             }
-            var engine = instanceInfo._owner.owner.engine;
+            var engine = instanceInfo.owner.owner.engine;
             var depthFunction = 0;
             if (this.effectFill && this.effectBorder) {
                 depthFunction = engine.getDepthFunction();
                 engine.setDepthFunctionToLessOrEqual();
             }
-            var cur;
-            if (this.isTransparent) {
-                cur = engine.getAlphaMode();
-                engine.setAlphaMode(BABYLON.Engine.ALPHA_COMBINE);
-            }
+            var curAlphaMode = engine.getAlphaMode();
             if (this.effectFill) {
-                var partIndex = instanceInfo._partIndexFromId.get(BABYLON.Shape2D.SHAPE2D_FILLPARTID.toString());
-                engine.enableEffect(this.effectFill);
-                engine.bindBuffersDirectly(this.fillVB, this.fillIB, [1], 4, this.effectFill);
-                var count = instanceInfo._instancesPartsData[partIndex].usedElementCount;
-                if (instanceInfo._owner.owner.supportInstancedArray) {
+                var partIndex = instanceInfo.partIndexFromId.get(BABYLON.Shape2D.SHAPE2D_FILLPARTID.toString());
+                var pid = context.groupInfoPartData[partIndex];
+                if (context.renderMode !== BABYLON.Render2DContext.RenderModeOpaque) {
+                    engine.setAlphaMode(BABYLON.Engine.ALPHA_COMBINE);
+                }
+                var effect = context.useInstancing ? this.effectFillInstanced : this.effectFill;
+                engine.enableEffect(effect);
+                engine.bindBuffersDirectly(this.fillVB, this.fillIB, [1], 4, effect);
+                if (context.useInstancing) {
                     if (!this.instancingFillAttributes) {
-                        // Compute the offset locations of the attributes in the vertex shader that will be mapped to the instance buffer data
-                        this.instancingFillAttributes = this.loadInstancingAttributes(BABYLON.Shape2D.SHAPE2D_FILLPARTID, this.effectFill);
+                        this.instancingFillAttributes = this.loadInstancingAttributes(BABYLON.Shape2D.SHAPE2D_FILLPARTID, effect);
                     }
-                    engine.updateAndBindInstancesBuffer(instanceInfo._instancesPartsBuffer[partIndex], null, this.instancingFillAttributes);
-                    engine.draw(true, 0, this.fillIndicesCount, count);
+                    engine.updateAndBindInstancesBuffer(pid._partBuffer, null, this.instancingFillAttributes);
+                    engine.draw(true, 0, this.fillIndicesCount, pid._partData.usedElementCount);
                     engine.unbindInstanceAttributes();
                 }
                 else {
-                    for (var i = 0; i < count; i++) {
-                        this.setupUniforms(this.effectFill, partIndex, instanceInfo._instancesPartsData[partIndex], i);
+                    for (var i = context.partDataStartIndex; i < context.partDataEndIndex; i++) {
+                        this.setupUniforms(effect, partIndex, pid._partData, i);
                         engine.draw(true, 0, this.fillIndicesCount);
                     }
                 }
             }
             if (this.effectBorder) {
-                var partIndex = instanceInfo._partIndexFromId.get(BABYLON.Shape2D.SHAPE2D_BORDERPARTID.toString());
-                engine.enableEffect(this.effectBorder);
-                engine.bindBuffersDirectly(this.borderVB, this.borderIB, [1], 4, this.effectBorder);
-                var count = instanceInfo._instancesPartsData[partIndex].usedElementCount;
-                if (instanceInfo._owner.owner.supportInstancedArray) {
+                var partIndex = instanceInfo.partIndexFromId.get(BABYLON.Shape2D.SHAPE2D_BORDERPARTID.toString());
+                var pid = context.groupInfoPartData[partIndex];
+                if (context.renderMode !== BABYLON.Render2DContext.RenderModeOpaque) {
+                    engine.setAlphaMode(BABYLON.Engine.ALPHA_COMBINE);
+                }
+                var effect = context.useInstancing ? this.effectBorderInstanced : this.effectBorder;
+                engine.enableEffect(effect);
+                engine.bindBuffersDirectly(this.borderVB, this.borderIB, [1], 4, effect);
+                if (context.useInstancing) {
                     if (!this.instancingBorderAttributes) {
-                        this.instancingBorderAttributes = this.loadInstancingAttributes(BABYLON.Shape2D.SHAPE2D_BORDERPARTID, this.effectBorder);
+                        this.instancingBorderAttributes = this.loadInstancingAttributes(BABYLON.Shape2D.SHAPE2D_BORDERPARTID, effect);
                     }
-                    engine.updateAndBindInstancesBuffer(instanceInfo._instancesPartsBuffer[partIndex], null, this.instancingBorderAttributes);
-                    engine.draw(true, 0, this.borderIndicesCount, count);
+                    engine.updateAndBindInstancesBuffer(pid._partBuffer, null, this.instancingBorderAttributes);
+                    engine.draw(true, 0, this.borderIndicesCount, pid._partData.usedElementCount);
                     engine.unbindInstanceAttributes();
                 }
                 else {
-                    for (var i = 0; i < count; i++) {
-                        this.setupUniforms(this.effectBorder, partIndex, instanceInfo._instancesPartsData[partIndex], i);
+                    for (var i = context.partDataStartIndex; i < context.partDataEndIndex; i++) {
+                        this.setupUniforms(this.effectBorder, partIndex, pid._partData, i);
                         engine.draw(true, 0, this.borderIndicesCount);
                     }
                 }
             }
-            if (this.isTransparent) {
-                engine.setAlphaMode(cur);
-            }
+            engine.setAlphaMode(curAlphaMode);
             if (this.effectFill && this.effectBorder) {
                 engine.setDepthFunction(depthFunction);
             }
@@ -97,6 +115,10 @@ var BABYLON;
                 this._engine._releaseEffect(this.effectFill);
                 this.effectFill = null;
             }
+            if (this.effectFillInstanced) {
+                this._engine._releaseEffect(this.effectFillInstanced);
+                this.effectFillInstanced = null;
+            }
             if (this.borderVB) {
                 this._engine._releaseBuffer(this.borderVB);
                 this.borderVB = null;
@@ -109,10 +131,14 @@ var BABYLON;
                 this._engine._releaseEffect(this.effectBorder);
                 this.effectBorder = null;
             }
+            if (this.effectBorderInstanced) {
+                this._engine._releaseEffect(this.effectBorderInstanced);
+                this.effectBorderInstanced = null;
+            }
             return true;
         };
         return Ellipse2DRenderCache;
-    }(BABYLON.ModelRenderCache));
+    })(BABYLON.ModelRenderCache);
     BABYLON.Ellipse2DRenderCache = Ellipse2DRenderCache;
     var Ellipse2DInstanceData = (function (_super) {
         __extends(Ellipse2DInstanceData, _super);
@@ -130,7 +156,7 @@ var BABYLON;
             BABYLON.instanceData()
         ], Ellipse2DInstanceData.prototype, "properties", null);
         return Ellipse2DInstanceData;
-    }(BABYLON.Shape2DInstanceData));
+    })(BABYLON.Shape2DInstanceData);
     BABYLON.Ellipse2DInstanceData = Ellipse2DInstanceData;
     var Ellipse2D = (function (_super) {
         __extends(Ellipse2D, _super);
@@ -174,10 +200,8 @@ var BABYLON;
         Ellipse2D.prototype.updateLevelBoundingInfo = function () {
             BABYLON.BoundingInfo2D.CreateFromSizeToRef(this.size, this._levelBoundingInfo, this.origin);
         };
-        Ellipse2D.prototype.setupEllipse2D = function (owner, parent, id, position, origin, size, subdivisions, fill, border, borderThickness) {
-            if (subdivisions === void 0) { subdivisions = 64; }
-            if (borderThickness === void 0) { borderThickness = 1; }
-            this.setupShape2D(owner, parent, id, position, origin, true, fill, border, borderThickness);
+        Ellipse2D.prototype.setupEllipse2D = function (owner, parent, id, position, origin, size, subdivisions, fill, border, borderThickness, isVisible, marginTop, marginLeft, marginRight, marginBottom, vAlignment, hAlignment) {
+            this.setupShape2D(owner, parent, id, position, origin, isVisible, fill, border, borderThickness, marginTop, marginLeft, marginRight, marginBottom, hAlignment, vAlignment);
             this.size = size;
             this.subdivisions = subdivisions;
         };
@@ -186,31 +210,40 @@ var BABYLON;
          * @param parent the parent primitive, must be a valid primitive (or the Canvas)
          * options:
          *  - id: a text identifier, for information purpose
-         *  - x: the X position relative to its parent, default is 0
-         *  - y: the Y position relative to its parent, default is 0
+         *  - position: the X & Y positions relative to its parent. Alternatively the x and y properties can be set. Default is [0;0]
          *  - origin: define the normalized origin point location, default [0.5;0.5]
-         *  - width: the width of the ellipse, default is 10
-         *  - height: the height of the ellipse, default is 10
+         *  - size: the size of the group. Alternatively the width and height properties can be set. Default will be [10;10].
          *  - subdivision: the number of subdivision to create the ellipse perimeter, default is 64.
          *  - fill: the brush used to draw the fill content of the ellipse, you can set null to draw nothing (but you will have to set a border brush), default is a SolidColorBrush of plain white.
          *  - border: the brush used to draw the border of the ellipse, you can set null to draw nothing (but you will have to set a fill brush), default is null.
          *  - borderThickness: the thickness of the drawn border, default is 1.
+         *  - isVisible: true if the primitive must be visible, false for hidden. Default is true.
+         *  - marginTop/Left/Right/Bottom: define the margin for the corresponding edge, if all of them are null, margin is not used in layout computing. Default Value is null for each.
+         *  - hAlighment: define horizontal alignment of the Canvas, alignment is optional, default value null: no alignment.
+         *  - vAlighment: define horizontal alignment of the Canvas, alignment is optional, default value null: no alignment.
          */
         Ellipse2D.Create = function (parent, options) {
             BABYLON.Prim2DBase.CheckParent(parent);
-            var fill;
-            if (options && options.fill !== undefined) {
-                fill = options.fill;
+            var ellipse = new Ellipse2D();
+            if (!options) {
+                ellipse.setupEllipse2D(parent.owner, parent, null, BABYLON.Vector2.Zero(), null, new BABYLON.Size(10, 10), 64, BABYLON.Canvas2D.GetSolidColorBrushFromHex("#FFFFFFFF"), null, 1, true, null, null, null, null, null, null);
             }
             else {
-                fill = BABYLON.Canvas2D.GetSolidColorBrushFromHex("#FFFFFFFF");
+                var fill;
+                if (options.fill === undefined) {
+                    fill = BABYLON.Canvas2D.GetSolidColorBrushFromHex("#FFFFFFFF");
+                }
+                else {
+                    fill = options.fill;
+                }
+                var pos = options.position || new BABYLON.Vector2(options.x || 0, options.y || 0);
+                var size = options.size || (new BABYLON.Size(options.width || 10, options.height || 10));
+                ellipse.setupEllipse2D(parent.owner, parent, options.id || null, pos, options.origin || null, size, options.subdivisions || 64, fill, options.border || null, options.borderThickness || 1, options.isVisible || true, options.marginTop || null, options.marginLeft || null, options.marginRight || null, options.marginBottom || null, options.vAlignment || null, options.hAlignment || null);
             }
-            var ellipse = new Ellipse2D();
-            ellipse.setupEllipse2D(parent.owner, parent, options && options.id || null, new BABYLON.Vector2(options && options.x || 0, options && options.y || 0), options && options.origin || null, new BABYLON.Size(options && options.width || 10, options && options.height || 10), options && options.subdivisions || 64, fill, options && options.border || null, options && options.borderThickness || 1);
             return ellipse;
         };
-        Ellipse2D.prototype.createModelRenderCache = function (modelKey, isTransparent) {
-            var renderCache = new Ellipse2DRenderCache(this.owner.engine, modelKey, isTransparent);
+        Ellipse2D.prototype.createModelRenderCache = function (modelKey) {
+            var renderCache = new Ellipse2DRenderCache(this.owner.engine, modelKey);
             return renderCache;
         };
         Ellipse2D.prototype.setupModelRenderCache = function (modelRenderCache) {
@@ -234,7 +267,13 @@ var BABYLON;
                 ib[triCount * 3 - 2] = 1;
                 renderCache.fillIB = engine.createIndexBuffer(ib);
                 renderCache.fillIndicesCount = triCount * 3;
-                var ei = this.getDataPartEffectInfo(BABYLON.Shape2D.SHAPE2D_FILLPARTID, ["index"]);
+                // Get the instanced version of the effect, if the engine does not support it, null is return and we'll only draw on by one
+                var ei = this.getDataPartEffectInfo(BABYLON.Shape2D.SHAPE2D_FILLPARTID, ["index"], true);
+                if (ei) {
+                    renderCache.effectFillInstanced = engine.createEffect({ vertex: "ellipse2d", fragment: "ellipse2d" }, ei.attributes, ei.uniforms, [], ei.defines, null);
+                }
+                // Get the non instanced version
+                ei = this.getDataPartEffectInfo(BABYLON.Shape2D.SHAPE2D_FILLPARTID, ["index"], false);
                 renderCache.effectFill = engine.createEffect({ vertex: "ellipse2d", fragment: "ellipse2d" }, ei.attributes, ei.uniforms, [], ei.defines, null);
             }
             // Need to create WebGL resource for border part?
@@ -260,8 +299,14 @@ var BABYLON;
                 }
                 renderCache.borderIB = engine.createIndexBuffer(ib);
                 renderCache.borderIndicesCount = (triCount * 3);
-                var ei = this.getDataPartEffectInfo(BABYLON.Shape2D.SHAPE2D_BORDERPARTID, ["index"]);
-                renderCache.effectBorder = engine.createEffect({ vertex: "ellipse2d", fragment: "ellipse2d" }, ei.attributes, ei.uniforms, [], ei.defines, null);
+                // Get the instanced version of the effect, if the engine does not support it, null is return and we'll only draw on by one
+                var ei = this.getDataPartEffectInfo(BABYLON.Shape2D.SHAPE2D_BORDERPARTID, ["index"], true);
+                if (ei) {
+                    renderCache.effectBorderInstanced = engine.createEffect("ellipse2d", ei.attributes, ei.uniforms, [], ei.defines, null);
+                }
+                // Get the non instanced version
+                ei = this.getDataPartEffectInfo(BABYLON.Shape2D.SHAPE2D_BORDERPARTID, ["index"], false);
+                renderCache.effectBorder = engine.createEffect("ellipse2d", ei.attributes, ei.uniforms, [], ei.defines, null);
             }
             return renderCache;
         };
@@ -301,6 +346,6 @@ var BABYLON;
             BABYLON.className("Ellipse2D")
         ], Ellipse2D);
         return Ellipse2D;
-    }(BABYLON.Shape2D));
+    })(BABYLON.Shape2D);
     BABYLON.Ellipse2D = Ellipse2D;
 })(BABYLON || (BABYLON = {}));

+ 335 - 98
src/Canvas2d/babylon.group2d.js

@@ -18,43 +18,51 @@ var BABYLON;
          */
         function Group2D() {
             _super.call(this);
-            this._primDirtyList = new Array();
-            this._childrenRenderableGroups = new Array();
-            this._renderGroupInstancesInfo = new BABYLON.StringDictionary();
         }
         /**
          * Create an Logical or Renderable Group.
          * @param parent the parent primitive, must be a valid primitive (or the Canvas)
          * options:
          *  - id a text identifier, for information purpose
-         *  - position: the X & Y positions relative to its parent, default is [0;0]
+         *  - position: the X & Y positions relative to its parent. Alternatively the x and y properties can be set. Default is [0;0]
          *  - origin: define the normalized origin point location, default [0.5;0.5]
-         *  - size: the size of the group, if null the size will be computed from its content, default is null.
+         *  - size: the size of the group. Alternatively the width and height properties can be set. If null the size will be computed from its content, default is null.
          *  - cacheBehavior: Define how the group should behave regarding the Canvas's cache strategy, default is Group2D.GROUPCACHEBEHAVIOR_FOLLOWCACHESTRATEGY
+         *  - isVisible: true if the group must be visible, false for hidden. Default is true.
+         *  - marginTop/Left/Right/Bottom: define the margin for the corresponding edge, if all of them are null, margin is not used in layout computing. Default Value is null for each.
+         *  - hAlighment: define horizontal alignment of the Canvas, alignment is optional, default value null: no alignment.
+         *  - vAlighment: define horizontal alignment of the Canvas, alignment is optional, default value null: no alignment.
          */
         Group2D.CreateGroup2D = function (parent, options) {
             BABYLON.Prim2DBase.CheckParent(parent);
             var g = new Group2D();
-            g.setupGroup2D(parent.owner, parent, options && options.id || null, options && options.position || BABYLON.Vector2.Zero(), options && options.origin || null, options && options.size || null, options && options.cacheBehavior || Group2D.GROUPCACHEBEHAVIOR_FOLLOWCACHESTRATEGY);
+            if (!options) {
+                g.setupGroup2D(parent.owner, parent, null, BABYLON.Vector2.Zero(), null, null, true, Group2D.GROUPCACHEBEHAVIOR_FOLLOWCACHESTRATEGY, null, null, null, null, null, null);
+            }
+            else {
+                var pos = options.position || new BABYLON.Vector2(options.x || 0, options.y || 0);
+                var size = (!options.size && !options.width && !options.height) ? null : (options.size || (new BABYLON.Size(options.width || 0, options.height || 0)));
+                g.setupGroup2D(parent.owner, parent, options.id || null, pos, options.origin || null, size, options.isVisible || true, options.cacheBehavior || Group2D.GROUPCACHEBEHAVIOR_FOLLOWCACHESTRATEGY, options.marginTop, options.marginLeft, options.marginRight, options.marginBottom, options.hAlignment || BABYLON.Prim2DBase.HAlignLeft, options.vAlignment || BABYLON.Prim2DBase.VAlignTop);
+            }
             return g;
         };
         Group2D._createCachedCanvasGroup = function (owner) {
             var g = new Group2D();
-            g.setupGroup2D(owner, null, "__cachedCanvasGroup__", BABYLON.Vector2.Zero(), null);
+            g.setupGroup2D(owner, null, "__cachedCanvasGroup__", BABYLON.Vector2.Zero(), BABYLON.Vector2.Zero(), null, true, Group2D.GROUPCACHEBEHAVIOR_FOLLOWCACHESTRATEGY, null, null, null, null, null, null);
             g.origin = BABYLON.Vector2.Zero();
             return g;
         };
         Group2D.prototype.applyCachedTexture = function (vertexData, material) {
             this._bindCacheTarget();
             var uv = vertexData.uvs;
-            var nodeuv = this._cacheNode.UVs;
+            var nodeuv = this._renderableData._cacheNode.UVs;
             for (var i = 0; i < 4; i++) {
                 uv[i * 2 + 0] = nodeuv[i].x;
                 uv[i * 2 + 1] = nodeuv[i].y;
             }
-            material.diffuseTexture = this._cacheTexture;
+            material.diffuseTexture = this._renderableData._cacheTexture;
             material.emissiveColor = new BABYLON.Color3(1, 1, 1);
-            this._cacheTexture.hasAlpha = true;
+            this._renderableData._cacheTexture.hasAlpha = true;
             this._unbindCacheTarget();
         };
         /**
@@ -64,31 +72,15 @@ var BABYLON;
             if (!_super.prototype.dispose.call(this)) {
                 return false;
             }
-            if (this._cacheRenderSprite) {
-                this._cacheRenderSprite.dispose();
-                this._cacheRenderSprite = null;
-            }
-            if (this._cacheTexture && this._cacheNode) {
-                this._cacheTexture.freeRect(this._cacheNode);
-                this._cacheTexture = null;
-                this._cacheNode = null;
-            }
-            if (this._primDirtyList) {
-                this._primDirtyList.splice(0);
-                this._primDirtyList = null;
-            }
-            if (this._renderGroupInstancesInfo) {
-                this._renderGroupInstancesInfo.forEach(function (k, v) {
-                    v.dispose();
-                });
-                this._renderGroupInstancesInfo = null;
+            if (this._renderableData) {
+                this._renderableData.dispose();
+                this._renderableData = null;
             }
             return true;
         };
-        Group2D.prototype.setupGroup2D = function (owner, parent, id, position, origin, size, cacheBehavior) {
-            if (cacheBehavior === void 0) { cacheBehavior = Group2D.GROUPCACHEBEHAVIOR_FOLLOWCACHESTRATEGY; }
+        Group2D.prototype.setupGroup2D = function (owner, parent, id, position, origin, size, isVisible, cacheBehavior, marginTop, marginLeft, marginRight, marginBottom, hAlign, vAlign) {
             this._cacheBehavior = cacheBehavior;
-            this.setupPrim2DBase(owner, parent, id, position, origin);
+            this.setupPrim2DBase(owner, parent, id, position, origin, isVisible, marginTop, marginLeft, marginRight, marginBottom, hAlign, vAlign);
             this.size = size;
             this._viewportPosition = BABYLON.Vector2.Zero();
         };
@@ -168,12 +160,13 @@ var BABYLON;
             configurable: true
         });
         Group2D.prototype._addPrimToDirtyList = function (prim) {
-            this._primDirtyList.push(prim);
+            this._renderableData._primDirtyList.push(prim);
         };
-        Group2D.prototype._renderCachedCanvas = function (context) {
+        Group2D.prototype._renderCachedCanvas = function () {
             this.updateGlobalTransVis(true);
+            var context = new BABYLON.PreapreRender2DContext();
             this._prepareGroupRender(context);
-            this._groupRender(context);
+            this._groupRender();
         };
         Group2D.prototype.levelIntersect = function (intersectInfo) {
             // If we've made it so far it means the boundingInfo intersection test succeed, the Group2D is shaped the same, so we always return true
@@ -194,8 +187,8 @@ var BABYLON;
         Group2D.prototype._prepareGroupRender = function (context) {
             var sortedDirtyList = null;
             // Update the Global Transformation and visibility status of the changed primitives
-            if ((this._primDirtyList.length > 0) || context.forceRefreshPrimitive) {
-                sortedDirtyList = this._primDirtyList.sort(function (a, b) { return a.hierarchyDepth - b.hierarchyDepth; });
+            if ((this._renderableData._primDirtyList.length > 0) || context.forceRefreshPrimitive) {
+                sortedDirtyList = this._renderableData._primDirtyList.sort(function (a, b) { return a.hierarchyDepth - b.hierarchyDepth; });
                 this.updateGlobalTransVisOf(sortedDirtyList, true);
             }
             // Setup the size of the rendering viewport
@@ -232,7 +225,7 @@ var BABYLON;
                 }
                 this._viewportSize = newSize;
             }
-            if ((this._primDirtyList.length > 0) || context.forceRefreshPrimitive) {
+            if ((this._renderableData._primDirtyList.length > 0) || context.forceRefreshPrimitive) {
                 // If the group is cached, set the dirty flag to true because of the incoming changes
                 this._cacheGroupDirty = this._isCachedGroup;
                 // If it's a force refresh, prepare all the children
@@ -246,7 +239,7 @@ var BABYLON;
                     // Each primitive that changed at least once was added into the primDirtyList, we have to sort this level using
                     //  the hierarchyDepth in order to prepare primitives from top to bottom
                     if (!sortedDirtyList) {
-                        sortedDirtyList = this._primDirtyList.sort(function (a, b) { return a.hierarchyDepth - b.hierarchyDepth; });
+                        sortedDirtyList = this._renderableData._primDirtyList.sort(function (a, b) { return a.hierarchyDepth - b.hierarchyDepth; });
                     }
                     sortedDirtyList.forEach(function (p) {
                         // We need to check if prepare is needed because even if the primitive is in the dirtyList, its parent primitive may also have been modified, then prepared, then recurse on its children primitives (this one for instance) if the changes where impacting them.
@@ -256,23 +249,23 @@ var BABYLON;
                         }
                     });
                     // Everything is updated, clear the dirty list
-                    this._primDirtyList.forEach(function (p) { return p._resetPropertiesDirty(); });
-                    this._primDirtyList.splice(0);
+                    this._renderableData._primDirtyList.forEach(function (p) { return p._resetPropertiesDirty(); });
+                    this._renderableData._primDirtyList.splice(0);
                 }
             }
             // A renderable group has a list of direct children that are also renderable groups, we recurse on them to also prepare them
-            this._childrenRenderableGroups.forEach(function (g) {
+            this._renderableData._childrenRenderableGroups.forEach(function (g) {
                 g._prepareGroupRender(context);
             });
         };
-        Group2D.prototype._groupRender = function (context) {
+        Group2D.prototype._groupRender = function () {
             var _this = this;
             var engine = this.owner.engine;
             var failedCount = 0;
             // First recurse to children render group to render them (in their cache or on screen)
-            for (var _i = 0, _a = this._childrenRenderableGroups; _i < _a.length; _i++) {
+            for (var _i = 0, _a = this._renderableData._childrenRenderableGroups; _i < _a.length; _i++) {
                 var childGroup = _a[_i];
-                childGroup._groupRender(context);
+                childGroup._groupRender();
             }
             // Render the primitives if needed: either if we don't cache the content or if the content is cached but has changed
             if (!this.isCachedGroup || this._cacheGroupDirty) {
@@ -282,47 +275,65 @@ var BABYLON;
                 else {
                     var curVP = engine.setDirectViewport(this._viewportPosition.x, this._viewportPosition.y, this._viewportSize.width, this._viewportSize.height);
                 }
+                // ===================================================================
+                // First pass, update the InstancedArray and render Opaque primitives
+                // Disable Alpha Testing, Enable Depth Write
+                engine.setAlphaTesting(false);
+                engine.setDepthWrite(true);
                 // For each different model of primitive to render
-                var totalRenderCount_1 = 0;
-                this._renderGroupInstancesInfo.forEach(function (k, v) {
-                    // This part will pack the dynamicfloatarray and update the instanced array WebGLBufffer
-                    // Skip it if instanced arrays are not supported
-                    if (_this.owner.supportInstancedArray) {
-                        for (var i = 0; i < v._instancesPartsData.length; i++) {
-                            // If the instances of the model was changed, pack the data
-                            var array = v._instancesPartsData[i];
-                            var instanceData_1 = array.pack();
-                            totalRenderCount_1 += array.usedElementCount;
-                            // Compute the size the instance buffer should have
-                            var neededSize = array.usedElementCount * array.stride * 4;
-                            // Check if we have to (re)create the instancesBuffer because there's none or the size is too small
-                            if (!v._instancesPartsBuffer[i] || (v._instancesPartsBufferSize[i] < neededSize)) {
-                                if (v._instancesPartsBuffer[i]) {
-                                    engine.deleteInstancesBuffer(v._instancesPartsBuffer[i]);
-                                }
-                                v._instancesPartsBuffer[i] = engine.createInstancesBuffer(neededSize);
-                                v._instancesPartsBufferSize[i] = neededSize;
-                                v._dirtyInstancesData = false;
-                                // Update the WebGL buffer to match the new content of the instances data
-                                engine._gl.bufferSubData(engine._gl.ARRAY_BUFFER, 0, instanceData_1);
-                            }
-                            else if (v._dirtyInstancesData) {
-                                // Update the WebGL buffer to match the new content of the instances data
-                                engine._gl.bindBuffer(engine._gl.ARRAY_BUFFER, v._instancesPartsBuffer[i]);
-                                engine._gl.bufferSubData(engine._gl.ARRAY_BUFFER, 0, instanceData_1);
-                            }
-                        }
-                        v._dirtyInstancesData = false;
+                var context = new BABYLON.Render2DContext(BABYLON.Render2DContext.RenderModeOpaque);
+                this._renderableData._renderGroupInstancesInfo.forEach(function (k, v) {
+                    // Prepare the context object, update the WebGL Instanced Array buffer if needed
+                    var renderCount = _this._prepareContext(engine, context, v);
+                    // If null is returned, there's no opaque data to render
+                    if (renderCount === null) {
+                        return;
+                    }
+                    // Submit render only if we have something to render (everything may be hidden and the floatarray empty)
+                    if (!_this.owner.supportInstancedArray || renderCount > 0) {
+                        // render all the instances of this model, if the render method returns true then our instances are no longer dirty
+                        var renderFailed = !v.modelRenderCache.render(v, context);
+                        // Update dirty flag/related
+                        v.opaqueDirty = renderFailed;
+                        failedCount += renderFailed ? 1 : 0;
+                    }
+                });
+                // =======================================================================
+                // Second pass, update the InstancedArray and render AlphaTest primitives
+                // Enable Alpha Testing, Enable Depth Write
+                engine.setAlphaTesting(true);
+                engine.setDepthWrite(true);
+                // For each different model of primitive to render
+                context = new BABYLON.Render2DContext(BABYLON.Render2DContext.RenderModeAlphaTest);
+                this._renderableData._renderGroupInstancesInfo.forEach(function (k, v) {
+                    // Prepare the context object, update the WebGL Instanced Array buffer if needed
+                    var renderCount = _this._prepareContext(engine, context, v);
+                    // If null is returned, there's no opaque data to render
+                    if (renderCount === null) {
+                        return;
                     }
                     // Submit render only if we have something to render (everything may be hidden and the floatarray empty)
-                    if (!_this.owner.supportInstancedArray || totalRenderCount_1 > 0) {
+                    if (!_this.owner.supportInstancedArray || renderCount > 0) {
                         // render all the instances of this model, if the render method returns true then our instances are no longer dirty
-                        var renderFailed = !v._modelCache.render(v, context);
+                        var renderFailed = !v.modelRenderCache.render(v, context);
                         // Update dirty flag/related
-                        v._dirtyInstancesData = renderFailed;
+                        v.opaqueDirty = renderFailed;
                         failedCount += renderFailed ? 1 : 0;
                     }
                 });
+                // =======================================================================
+                // Third pass, transparent primitive rendering
+                // Enable Alpha Testing, Disable Depth Write
+                engine.setAlphaTesting(true);
+                engine.setDepthWrite(false);
+                // First Check if the transparent List change so we can update the TransparentSegment and PartData (sort if needed)
+                if (this._renderableData._transparentListChanged) {
+                    this._updateTransparentData();
+                }
+                // From this point on we have up to date data to render, so let's go
+                failedCount += this._renderTransparentData();
+                // =======================================================================
+                //  Unbind target/restore viewport setting, clear dirty flag, and quit
                 // The group's content is no longer dirty
                 this._cacheGroupDirty = failedCount !== 0;
                 if (this.isCachedGroup) {
@@ -335,58 +346,210 @@ var BABYLON;
                 }
             }
         };
+        Group2D.prototype._updateTransparentData = function () {
+            var rd = this._renderableData;
+            // If null, there was no change of ZOrder, we have nothing to do
+            if (rd._firstChangedPrim === null) {
+                return;
+            }
+            // Sort all the primitive from their depth, max (bottom) to min (top)
+            rd._transparentPrimitives.sort(function (a, b) { return b._primitive.getActualZOffset() - a._primitive.getActualZOffset(); });
+            var checkAndAddPrimInSegment = function (seg, tpiI) {
+                var tpi = rd._transparentPrimitives[tpiI];
+                // Fast rejection: if gii are different
+                if (seg.groupInsanceInfo !== tpi._groupInstanceInfo) {
+                    return false;
+                }
+                var tpiZ = tpi._primitive.getActualZOffset();
+                // We've made it so far, the tpi can be part of the segment, add it
+                tpi._transparentSegment = seg;
+                // Check if we have to update endZ, a smaller value means one above the current one
+                if (tpiZ < seg.endZ) {
+                    seg.endZ = tpiZ;
+                    seg.endDataIndex = tpi._primitive._getLastIndexInDataBuffer() + 1; // Still exclusive
+                }
+                return true;
+            };
+            rd._transparentSegments.splice(0);
+            var prevSeg = null;
+            for (var tpiI = 0; tpiI < rd._transparentPrimitives.length; tpiI++) {
+                var tpi = rd._transparentPrimitives[tpiI];
+                // Check if the Data in which the primitive is stored is not sorted properly
+                if (tpi._groupInstanceInfo.transparentOrderDirty) {
+                    tpi._groupInstanceInfo.sortTransparentData();
+                }
+                // Reset the segment, we have to create/rebuild it
+                tpi._transparentSegment = null;
+                // If there's a previous valid segment, check if this prim can be part of it
+                if (prevSeg) {
+                    checkAndAddPrimInSegment(prevSeg, tpiI);
+                }
+                // If we couldn't insert in the adjacent segments, he have to create one
+                if (!tpi._transparentSegment) {
+                    var ts = new BABYLON.TransparentSegment();
+                    ts.groupInsanceInfo = tpi._groupInstanceInfo;
+                    var prim = tpi._primitive;
+                    ts.startZ = prim.getActualZOffset();
+                    ts.startDataIndex = prim._getFirstIndexInDataBuffer();
+                    ts.endDataIndex = prim._getLastIndexInDataBuffer() + 1; // Make it exclusive, more natural to use in a for loop
+                    ts.endZ = ts.startZ;
+                    tpi._transparentSegment = ts;
+                    rd._transparentSegments.push(ts);
+                }
+                // Update prevSeg
+                prevSeg = tpi._transparentSegment;
+            }
+            rd._firstChangedPrim = null;
+            rd._transparentListChanged = false;
+        };
+        Group2D.prototype._renderTransparentData = function () {
+            var failedCount = 0;
+            var context = new BABYLON.Render2DContext(BABYLON.Render2DContext.RenderModeTransparent);
+            var rd = this._renderableData;
+            var length = rd._transparentSegments.length;
+            for (var i = 0; i < length; i++) {
+                var ts = rd._transparentSegments[i];
+                var gii = ts.groupInsanceInfo;
+                var mrc = gii.modelRenderCache;
+                context.useInstancing = false;
+                context.partDataStartIndex = ts.startDataIndex;
+                context.partDataEndIndex = ts.endDataIndex;
+                context.groupInfoPartData = gii.transparentData;
+                var renderFailed = !mrc.render(gii, context);
+                failedCount += renderFailed ? 1 : 0;
+            }
+            return failedCount;
+        };
+        Group2D.prototype._prepareContext = function (engine, context, gii) {
+            var gipd = null;
+            var setDirty;
+            var getDirty;
+            // Render Mode specifics
+            switch (context.renderMode) {
+                case BABYLON.Render2DContext.RenderModeOpaque:
+                    {
+                        if (!gii.hasOpaqueData) {
+                            return null;
+                        }
+                        setDirty = function (dirty) { gii.opaqueDirty = dirty; };
+                        getDirty = function () { return gii.opaqueDirty; };
+                        context.groupInfoPartData = gii.opaqueData;
+                        gipd = gii.opaqueData;
+                        break;
+                    }
+                case BABYLON.Render2DContext.RenderModeAlphaTest:
+                    {
+                        if (!gii.hasAlphaTestData) {
+                            return null;
+                        }
+                        setDirty = function (dirty) { gii.alphaTestDirty = dirty; };
+                        getDirty = function () { return gii.alphaTestDirty; };
+                        context.groupInfoPartData = gii.alphaTestData;
+                        gipd = gii.alphaTestData;
+                        break;
+                    }
+                default:
+                    throw new Error("_prepareContext is only for opaque or alphaTest");
+            }
+            var renderCount = 0;
+            // This part will pack the dynamicfloatarray and update the instanced array WebGLBufffer
+            // Skip it if instanced arrays are not supported
+            if (this.owner.supportInstancedArray) {
+                // Flag for instancing
+                context.useInstancing = true;
+                // Make sure all the WebGLBuffers of the Instanced Array are created/up to date for the parts to render.
+                for (var i = 0; i < gipd.length; i++) {
+                    var pid = gipd[i];
+                    // If the instances of the model was changed, pack the data
+                    var array = pid._partData;
+                    var instanceData_1 = array.pack();
+                    renderCount += array.usedElementCount;
+                    // Compute the size the instance buffer should have
+                    var neededSize = array.usedElementCount * array.stride * 4;
+                    // Check if we have to (re)create the instancesBuffer because there's none or the size is too small
+                    if (!pid._partBuffer || (pid._partBufferSize < neededSize)) {
+                        if (pid._partBuffer) {
+                            engine.deleteInstancesBuffer(pid._partBuffer);
+                        }
+                        pid._partBuffer = engine.createInstancesBuffer(neededSize); // Create + bind
+                        pid._partBufferSize = neededSize;
+                        setDirty(false);
+                        // Update the WebGL buffer to match the new content of the instances data
+                        engine.updateArrayBuffer(instanceData_1);
+                    }
+                    else if (getDirty()) {
+                        // Update the WebGL buffer to match the new content of the instances data
+                        engine.bindArrayBuffer(pid._partBuffer);
+                        engine.updateArrayBuffer(instanceData_1);
+                    }
+                }
+                setDirty(false);
+            }
+            else {
+                context.partDataStartIndex = 0;
+                // Find the first valid object to get the count
+                var i = 0;
+                while (!context.groupInfoPartData[i]) {
+                    i++;
+                }
+                context.partDataEndIndex = context.groupInfoPartData[i]._partData.usedElementCount;
+            }
+            return renderCount;
+        };
         Group2D.prototype._bindCacheTarget = function () {
             var curWidth;
             var curHeight;
-            if (this._cacheNode) {
-                var size = this._cacheNode.contentSize;
+            var rd = this._renderableData;
+            if (rd._cacheNode) {
+                var size = rd._cacheNode.contentSize;
                 var groupWidth = Math.ceil(this.actualSize.width);
                 var groupHeight = Math.ceil(this.actualSize.height);
                 if ((size.width < groupWidth) || (size.height < groupHeight)) {
                     curWidth = Math.floor(size.width * 1.07); // Grow 5% more to avoid frequent resizing for few pixels...
                     curHeight = Math.floor(size.height * 1.07);
                     //console.log(`[${this._globalTransformProcessStep}] Resize group ${this.id}, width: ${curWidth}, height: ${curHeight}`);
-                    this._cacheTexture.freeRect(this._cacheNode);
-                    this._cacheNode = null;
+                    rd._cacheTexture.freeRect(rd._cacheNode);
+                    rd._cacheNode = null;
                 }
             }
-            if (!this._cacheNode) {
+            if (!rd._cacheNode) {
                 // Check if we have to allocate a rendering zone in the global cache texture
                 var res = this.owner._allocateGroupCache(this, this.renderGroup, curWidth ? new BABYLON.Size(curWidth, curHeight) : null);
-                this._cacheNode = res.node;
-                this._cacheTexture = res.texture;
-                this._cacheRenderSprite = res.sprite;
-                var size = this._cacheNode.contentSize;
+                rd._cacheNode = res.node;
+                rd._cacheTexture = res.texture;
+                rd._cacheRenderSprite = res.sprite;
+                var size = rd._cacheNode.contentSize;
             }
-            var n = this._cacheNode;
-            this._cacheTexture.bindTextureForPosSize(n.pos, this.actualSize, true);
+            var n = rd._cacheNode;
+            rd._cacheTexture.bindTextureForPosSize(n.pos, this.actualSize, true);
         };
         Group2D.prototype._unbindCacheTarget = function () {
-            if (this._cacheTexture) {
-                this._cacheTexture.unbindTexture();
+            if (this._renderableData._cacheTexture) {
+                this._renderableData._cacheTexture.unbindTexture();
             }
         };
         Group2D.prototype.handleGroupChanged = function (prop) {
             // This method is only for cachedGroup
-            if (!this.isCachedGroup || !this._cacheRenderSprite) {
+            var rd = this._renderableData;
+            if (!this.isCachedGroup || !rd._cacheRenderSprite) {
                 return;
             }
             // For now we only support these property changes
             // TODO: add more! :)
             if (prop.id === BABYLON.Prim2DBase.positionProperty.id) {
-                this._cacheRenderSprite.position = this.position.clone();
+                rd._cacheRenderSprite.position = this.position.clone();
             }
             else if (prop.id === BABYLON.Prim2DBase.rotationProperty.id) {
-                this._cacheRenderSprite.rotation = this.rotation;
+                rd._cacheRenderSprite.rotation = this.rotation;
             }
             else if (prop.id === BABYLON.Prim2DBase.scaleProperty.id) {
-                this._cacheRenderSprite.scale = this.scale;
+                rd._cacheRenderSprite.scale = this.scale;
             }
             else if (prop.id === BABYLON.Prim2DBase.originProperty.id) {
-                this._cacheRenderSprite.origin = this.origin.clone();
+                rd._cacheRenderSprite.origin = this.origin.clone();
             }
             else if (prop.id === Group2D.actualSizeProperty.id) {
-                this._cacheRenderSprite.spriteSize = this.actualSize.clone();
+                rd._cacheRenderSprite.spriteSize = this.actualSize.clone();
             }
         };
         Group2D.prototype.detectGroupStates = function () {
@@ -434,12 +597,15 @@ var BABYLON;
                     this._isCachedGroup = true;
                 }
             }
+            if (this._isRenderableGroup) {
+                this._renderableData = new RenderableGroupData();
+            }
             // If the group is tagged as renderable we add it to the renderable tree
             if (this._isCachedGroup) {
                 var cur = this.parent;
                 while (cur) {
                     if (cur instanceof Group2D && cur._isRenderableGroup) {
-                        cur._childrenRenderableGroups.push(this);
+                        cur._renderableData._childrenRenderableGroups.push(this);
                         break;
                     }
                     cur = cur.parent;
@@ -470,6 +636,77 @@ var BABYLON;
             BABYLON.className("Group2D")
         ], Group2D);
         return Group2D;
-    }(BABYLON.Prim2DBase));
+    })(BABYLON.Prim2DBase);
     BABYLON.Group2D = Group2D;
+    var RenderableGroupData = (function () {
+        function RenderableGroupData() {
+            this._primDirtyList = new Array();
+            this._childrenRenderableGroups = new Array();
+            this._renderGroupInstancesInfo = new BABYLON.StringDictionary();
+            this._transparentPrimitives = new Array();
+            this._transparentSegments = new Array();
+            this._firstChangedPrim = null;
+            this._transparentListChanged = false;
+        }
+        RenderableGroupData.prototype.dispose = function () {
+            if (this._cacheRenderSprite) {
+                this._cacheRenderSprite.dispose();
+                this._cacheRenderSprite = null;
+            }
+            if (this._cacheTexture && this._cacheNode) {
+                this._cacheTexture.freeRect(this._cacheNode);
+                this._cacheTexture = null;
+                this._cacheNode = null;
+            }
+            if (this._primDirtyList) {
+                this._primDirtyList.splice(0);
+                this._primDirtyList = null;
+            }
+            if (this._renderGroupInstancesInfo) {
+                this._renderGroupInstancesInfo.forEach(function (k, v) {
+                    v.dispose();
+                });
+                this._renderGroupInstancesInfo = null;
+            }
+        };
+        RenderableGroupData.prototype.addNewTransparentPrimitiveInfo = function (prim, gii) {
+            var tpi = new TransparentPrimitiveInfo();
+            tpi._primitive = prim;
+            tpi._groupInstanceInfo = gii;
+            tpi._transparentSegment = null;
+            this._transparentPrimitives.push(tpi);
+            this._transparentListChanged = true;
+            this.updateSmallestZChangedPrim(tpi);
+            return tpi;
+        };
+        RenderableGroupData.prototype.removeTransparentPrimitiveInfo = function (tpi) {
+            var index = this._transparentPrimitives.indexOf(tpi);
+            if (index !== -1) {
+                this._transparentPrimitives.splice(index, 1);
+                this._transparentListChanged = true;
+                this.updateSmallestZChangedPrim(tpi);
+            }
+        };
+        RenderableGroupData.prototype.transparentPrimitiveZChanged = function (tpi) {
+            this._transparentListChanged = true;
+            this.updateSmallestZChangedPrim(tpi);
+        };
+        RenderableGroupData.prototype.updateSmallestZChangedPrim = function (tpi) {
+            if (tpi._primitive) {
+                var newZ = tpi._primitive.getActualZOffset();
+                var curZ = this._firstChangedPrim ? this._firstChangedPrim._primitive.getActualZOffset() : Number.MIN_VALUE;
+                if (newZ > curZ) {
+                    this._firstChangedPrim = tpi;
+                }
+            }
+        };
+        return RenderableGroupData;
+    })();
+    BABYLON.RenderableGroupData = RenderableGroupData;
+    var TransparentPrimitiveInfo = (function () {
+        function TransparentPrimitiveInfo() {
+        }
+        return TransparentPrimitiveInfo;
+    })();
+    BABYLON.TransparentPrimitiveInfo = TransparentPrimitiveInfo;
 })(BABYLON || (BABYLON = {}));

+ 99 - 52
src/Canvas2d/babylon.lines2d.js

@@ -13,69 +13,87 @@ var BABYLON;
 (function (BABYLON) {
     var Lines2DRenderCache = (function (_super) {
         __extends(Lines2DRenderCache, _super);
-        function Lines2DRenderCache(engine, modelKey, isTransparent) {
-            _super.call(this, engine, modelKey, isTransparent);
+        function Lines2DRenderCache(engine, modelKey) {
+            _super.call(this, engine, modelKey);
+            this.effectsReady = false;
+            this.fillVB = null;
+            this.fillIB = null;
+            this.fillIndicesCount = 0;
+            this.instancingFillAttributes = null;
+            this.effectFill = null;
+            this.effectFillInstanced = null;
+            this.borderVB = null;
+            this.borderIB = null;
+            this.borderIndicesCount = 0;
+            this.instancingBorderAttributes = null;
+            this.effectBorder = null;
+            this.effectBorderInstanced = null;
         }
         Lines2DRenderCache.prototype.render = function (instanceInfo, context) {
             // Do nothing if the shader is still loading/preparing 
-            if ((this.effectFill && !this.effectFill.isReady()) || (this.effectBorder && !this.effectBorder.isReady())) {
-                return false;
+            if (!this.effectsReady) {
+                if ((this.effectFill && (!this.effectFill.isReady() || (this.effectFillInstanced && !this.effectFillInstanced.isReady()))) ||
+                    (this.effectBorder && (!this.effectBorder.isReady() || (this.effectBorderInstanced && !this.effectBorderInstanced.isReady())))) {
+                    return false;
+                }
+                this.effectsReady = true;
             }
-            var engine = instanceInfo._owner.owner.engine;
+            var engine = instanceInfo.owner.owner.engine;
             var depthFunction = 0;
             if (this.effectFill && this.effectBorder) {
                 depthFunction = engine.getDepthFunction();
                 engine.setDepthFunctionToLessOrEqual();
             }
-            var cur;
-            if (this.isTransparent) {
-                cur = engine.getAlphaMode();
-                engine.setAlphaMode(BABYLON.Engine.ALPHA_COMBINE);
-            }
+            var curAlphaMode = engine.getAlphaMode();
             if (this.effectFill) {
-                var partIndex = instanceInfo._partIndexFromId.get(BABYLON.Shape2D.SHAPE2D_FILLPARTID.toString());
-                engine.enableEffect(this.effectFill);
-                engine.bindBuffersDirectly(this.fillVB, this.fillIB, [2], 2 * 4, this.effectFill);
-                var count = instanceInfo._instancesPartsData[partIndex].usedElementCount;
-                if (instanceInfo._owner.owner.supportInstancedArray) {
+                var partIndex = instanceInfo.partIndexFromId.get(BABYLON.Shape2D.SHAPE2D_FILLPARTID.toString());
+                var pid = context.groupInfoPartData[partIndex];
+                if (context.renderMode !== BABYLON.Render2DContext.RenderModeOpaque) {
+                    engine.setAlphaMode(BABYLON.Engine.ALPHA_COMBINE);
+                }
+                var effect = context.useInstancing ? this.effectFillInstanced : this.effectFill;
+                engine.enableEffect(effect);
+                engine.bindBuffersDirectly(this.fillVB, this.fillIB, [2], 2 * 4, effect);
+                if (context.useInstancing) {
                     if (!this.instancingFillAttributes) {
-                        // Compute the offset locations of the attributes in the vertex shader that will be mapped to the instance buffer data
-                        this.instancingFillAttributes = this.loadInstancingAttributes(BABYLON.Shape2D.SHAPE2D_FILLPARTID, this.effectFill);
+                        this.instancingFillAttributes = this.loadInstancingAttributes(BABYLON.Shape2D.SHAPE2D_FILLPARTID, effect);
                     }
-                    engine.updateAndBindInstancesBuffer(instanceInfo._instancesPartsBuffer[partIndex], null, this.instancingFillAttributes);
-                    engine.draw(true, 0, this.fillIndicesCount, count);
+                    engine.updateAndBindInstancesBuffer(pid._partBuffer, null, this.instancingFillAttributes);
+                    engine.draw(true, 0, this.fillIndicesCount, pid._partData.usedElementCount);
                     engine.unbindInstanceAttributes();
                 }
                 else {
-                    for (var i = 0; i < count; i++) {
-                        this.setupUniforms(this.effectFill, partIndex, instanceInfo._instancesPartsData[partIndex], i);
+                    for (var i = context.partDataStartIndex; i < context.partDataEndIndex; i++) {
+                        this.setupUniforms(effect, partIndex, pid._partData, i);
                         engine.draw(true, 0, this.fillIndicesCount);
                     }
                 }
             }
             if (this.effectBorder) {
-                var partIndex = instanceInfo._partIndexFromId.get(BABYLON.Shape2D.SHAPE2D_BORDERPARTID.toString());
-                engine.enableEffect(this.effectBorder);
-                engine.bindBuffersDirectly(this.borderVB, this.borderIB, [2], 2 * 4, this.effectBorder);
-                var count = instanceInfo._instancesPartsData[partIndex].usedElementCount;
-                if (instanceInfo._owner.owner.supportInstancedArray) {
+                var partIndex = instanceInfo.partIndexFromId.get(BABYLON.Shape2D.SHAPE2D_BORDERPARTID.toString());
+                var pid = context.groupInfoPartData[partIndex];
+                if (context.renderMode !== BABYLON.Render2DContext.RenderModeOpaque) {
+                    engine.setAlphaMode(BABYLON.Engine.ALPHA_COMBINE);
+                }
+                var effect = context.useInstancing ? this.effectBorderInstanced : this.effectBorder;
+                engine.enableEffect(effect);
+                engine.bindBuffersDirectly(this.borderVB, this.borderIB, [2], 2 * 4, effect);
+                if (context.useInstancing) {
                     if (!this.instancingBorderAttributes) {
-                        this.instancingBorderAttributes = this.loadInstancingAttributes(BABYLON.Shape2D.SHAPE2D_BORDERPARTID, this.effectBorder);
+                        this.instancingBorderAttributes = this.loadInstancingAttributes(BABYLON.Shape2D.SHAPE2D_BORDERPARTID, effect);
                     }
-                    engine.updateAndBindInstancesBuffer(instanceInfo._instancesPartsBuffer[partIndex], null, this.instancingBorderAttributes);
-                    engine.draw(true, 0, this.borderIndicesCount, count);
+                    engine.updateAndBindInstancesBuffer(pid._partBuffer, null, this.instancingBorderAttributes);
+                    engine.draw(true, 0, this.borderIndicesCount, pid._partData.usedElementCount);
                     engine.unbindInstanceAttributes();
                 }
                 else {
-                    for (var i = 0; i < count; i++) {
-                        this.setupUniforms(this.effectBorder, partIndex, instanceInfo._instancesPartsData[partIndex], i);
+                    for (var i = context.partDataStartIndex; i < context.partDataEndIndex; i++) {
+                        this.setupUniforms(effect, partIndex, pid._partData, i);
                         engine.draw(true, 0, this.borderIndicesCount);
                     }
                 }
             }
-            if (this.isTransparent) {
-                engine.setAlphaMode(cur);
-            }
+            engine.setAlphaMode(curAlphaMode);
             if (this.effectFill && this.effectBorder) {
                 engine.setDepthFunction(depthFunction);
             }
@@ -97,6 +115,10 @@ var BABYLON;
                 this._engine._releaseEffect(this.effectFill);
                 this.effectFill = null;
             }
+            if (this.effectFillInstanced) {
+                this._engine._releaseEffect(this.effectFillInstanced);
+                this.effectFillInstanced = null;
+            }
             if (this.borderVB) {
                 this._engine._releaseBuffer(this.borderVB);
                 this.borderVB = null;
@@ -109,10 +131,14 @@ var BABYLON;
                 this._engine._releaseEffect(this.effectBorder);
                 this.effectBorder = null;
             }
+            if (this.effectBorderInstanced) {
+                this._engine._releaseEffect(this.effectBorderInstanced);
+                this.effectBorderInstanced = null;
+            }
             return true;
         };
         return Lines2DRenderCache;
-    }(BABYLON.ModelRenderCache));
+    })(BABYLON.ModelRenderCache);
     BABYLON.Lines2DRenderCache = Lines2DRenderCache;
     var Lines2DInstanceData = (function (_super) {
         __extends(Lines2DInstanceData, _super);
@@ -140,7 +166,7 @@ var BABYLON;
             BABYLON.instanceData()
         ], Lines2DInstanceData.prototype, "boundingMax", null);
         return Lines2DInstanceData;
-    }(BABYLON.Shape2DInstanceData));
+    })(BABYLON.Shape2DInstanceData);
     BABYLON.Lines2DInstanceData = Lines2DInstanceData;
     var Lines2D = (function (_super) {
         __extends(Lines2D, _super);
@@ -294,8 +320,8 @@ var BABYLON;
         Lines2D.prototype.updateLevelBoundingInfo = function () {
             BABYLON.BoundingInfo2D.CreateFromSizeToRef(this.size, this._levelBoundingInfo, this.origin);
         };
-        Lines2D.prototype.setupLines2D = function (owner, parent, id, position, origin, points, fillThickness, startCap, endCap, fill, border, borderThickness, closed) {
-            this.setupShape2D(owner, parent, id, position, origin, true, fill, border, borderThickness);
+        Lines2D.prototype.setupLines2D = function (owner, parent, id, position, origin, points, fillThickness, startCap, endCap, fill, border, borderThickness, closed, isVisible, marginTop, marginLeft, marginRight, marginBottom, vAlignment, hAlignment) {
+            this.setupShape2D(owner, parent, id, position, origin, isVisible, fill, border, borderThickness, marginTop, marginLeft, marginRight, marginBottom, hAlignment, vAlignment);
             this.fillThickness = fillThickness;
             this.startCap = startCap;
             this.endCap = endCap;
@@ -311,8 +337,7 @@ var BABYLON;
          * @param points an array that describe the points to use to draw the line, must contain at least two entries.
          * options:
          *  - id a text identifier, for information purpose
-         *  - x: the X position relative to its parent, default is 0
-         *  - y: the Y position relative to its parent, default is 0
+         *  - position: the X & Y positions relative to its parent. Alternatively the x and y properties can be set. Default is [0;0]
          *  - origin: define the normalized origin point location, default [0.5;0.5]
          *  - fillThickness: the thickness of the fill part of the line, can be null to draw nothing (but a border brush must be given), default is 1.
          *  - closed: if false the lines are said to be opened, the first point and the latest DON'T connect. if true the lines are said to be closed, the first and last point will be connected by a line. For instance you can define the 4 points of a rectangle, if you set closed to true a 4 edges rectangle will be drawn. If you set false, only three edges will be drawn, the edge formed by the first and last point won't exist. Default is false.
@@ -321,22 +346,32 @@ var BABYLON;
          *  - fill: the brush used to draw the fill content of the lines, you can set null to draw nothing (but you will have to set a border brush), default is a SolidColorBrush of plain white.
          *  - border: the brush used to draw the border of the lines, you can set null to draw nothing (but you will have to set a fill brush), default is null.
          *  - borderThickness: the thickness of the drawn border, default is 1.
+         *  - isVisible: true if the primitive must be visible, false for hidden. Default is true.
+         *  - marginTop/Left/Right/Bottom: define the margin for the corresponding edge, if all of them are null, margin is not used in layout computing. Default Value is null for each.
+         *  - hAlighment: define horizontal alignment of the Canvas, alignment is optional, default value null: no alignment.
+         *  - vAlighment: define horizontal alignment of the Canvas, alignment is optional, default value null: no alignment.
          */
         Lines2D.Create = function (parent, points, options) {
             BABYLON.Prim2DBase.CheckParent(parent);
-            var fill;
-            if (options && options.fill !== undefined) {
-                fill = options.fill;
+            var lines = new Lines2D();
+            if (!options) {
+                lines.setupLines2D(parent.owner, parent, null, BABYLON.Vector2.Zero(), null, points, 1, 0, 0, BABYLON.Canvas2D.GetSolidColorBrushFromHex("#FFFFFFFF"), null, 1, false, true, null, null, null, null, null, null);
             }
             else {
-                fill = BABYLON.Canvas2D.GetSolidColorBrushFromHex("#FFFFFFFF");
+                var fill;
+                if (options.fill === undefined) {
+                    fill = BABYLON.Canvas2D.GetSolidColorBrushFromHex("#FFFFFFFF");
+                }
+                else {
+                    fill = options.fill;
+                }
+                var pos = options.position || new BABYLON.Vector2(options.x || 0, options.y || 0);
+                lines.setupLines2D(parent.owner, parent, options.id || null, pos, options.origin || null, points, options.fillThickness || 1, options.startCap || 0, options.endCap || 0, fill, options.border || null, options.borderThickness || 1, options.closed || false, options.isVisible || true, options.marginTop || null, options.marginLeft || null, options.marginRight || null, options.marginBottom || null, options.vAlignment || null, options.hAlignment || null);
             }
-            var lines = new Lines2D();
-            lines.setupLines2D(parent.owner, parent, options && options.id || null, new BABYLON.Vector2(options && options.x || 0, options && options.y || 0), options && options.origin || null, points, options && options.fillThickness || 1, options && options.startCap || 0, options && options.endCap || 0, fill, options && options.border || null, options && options.borderThickness || 0, options && options.closed || false);
             return lines;
         };
-        Lines2D.prototype.createModelRenderCache = function (modelKey, isTransparent) {
-            var renderCache = new Lines2DRenderCache(this.owner.engine, modelKey, isTransparent);
+        Lines2D.prototype.createModelRenderCache = function (modelKey) {
+            var renderCache = new Lines2DRenderCache(this.owner.engine, modelKey);
             return renderCache;
         };
         Lines2D.prototype.setupModelRenderCache = function (modelRenderCache) {
@@ -888,8 +923,14 @@ var BABYLON;
                 renderCache.fillVB = engine.createVertexBuffer(vb);
                 renderCache.fillIB = engine.createIndexBuffer(ib);
                 renderCache.fillIndicesCount = ib.length;
-                var ei = this.getDataPartEffectInfo(BABYLON.Shape2D.SHAPE2D_FILLPARTID, ["position"]);
-                renderCache.effectFill = engine.createEffect({ vertex: "lines2d", fragment: "lines2d" }, ei.attributes, ei.uniforms, [], ei.defines, null);
+                // Get the instanced version of the effect, if the engine does not support it, null is return and we'll only draw on by one
+                var ei = this.getDataPartEffectInfo(BABYLON.Shape2D.SHAPE2D_FILLPARTID, ["position"], true);
+                if (ei) {
+                    renderCache.effectFillInstanced = engine.createEffect("lines2d", ei.attributes, ei.uniforms, [], ei.defines, null);
+                }
+                // Get the non instanced version
+                ei = this.getDataPartEffectInfo(BABYLON.Shape2D.SHAPE2D_FILLPARTID, ["position"], false);
+                renderCache.effectFill = engine.createEffect("lines2d", ei.attributes, ei.uniforms, [], ei.defines, null);
             }
             // Need to create WebGL resources for border part?
             if (this.border) {
@@ -924,7 +965,13 @@ var BABYLON;
                 renderCache.borderVB = engine.createVertexBuffer(vb);
                 renderCache.borderIB = engine.createIndexBuffer(ib);
                 renderCache.borderIndicesCount = ib.length;
-                var ei = this.getDataPartEffectInfo(BABYLON.Shape2D.SHAPE2D_BORDERPARTID, ["position"]);
+                // Get the instanced version of the effect, if the engine does not support it, null is return and we'll only draw on by one
+                var ei = this.getDataPartEffectInfo(BABYLON.Shape2D.SHAPE2D_BORDERPARTID, ["position"], true);
+                if (ei) {
+                    renderCache.effectBorderInstanced = engine.createEffect({ vertex: "lines2d", fragment: "lines2d" }, ei.attributes, ei.uniforms, [], ei.defines, null);
+                }
+                // Get the non instanced version
+                ei = this.getDataPartEffectInfo(BABYLON.Shape2D.SHAPE2D_BORDERPARTID, ["position"], false);
                 renderCache.effectBorder = engine.createEffect({ vertex: "lines2d", fragment: "lines2d" }, ei.attributes, ei.uniforms, [], ei.defines, null);
             }
             this._contour = contour;
@@ -986,6 +1033,6 @@ var BABYLON;
             BABYLON.className("Lines2D")
         ], Lines2D);
         return Lines2D;
-    }(BABYLON.Shape2D));
+    })(BABYLON.Shape2D);
     BABYLON.Lines2D = Lines2D;
 })(BABYLON || (BABYLON = {}));

+ 168 - 40
src/Canvas2d/babylon.modelRenderCache.js

@@ -1,46 +1,174 @@
+var __extends = (this && this.__extends) || function (d, b) {
+    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
+    function __() { this.constructor = d; }
+    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
+};
 var BABYLON;
 (function (BABYLON) {
     var GroupInstanceInfo = (function () {
-        function GroupInstanceInfo(owner, cache) {
-            this._owner = owner;
-            this._modelCache = cache;
-            this._modelCache.addRef();
-            this._instancesPartsData = new Array();
-            this._instancesPartsBuffer = new Array();
-            this._instancesPartsBufferSize = new Array();
-            this._partIndexFromId = new BABYLON.StringDictionary();
-            this._instancesPartsUsedShaderCategories = new Array();
+        function GroupInstanceInfo(owner, mrc, partCount) {
+            this._partCount = partCount;
+            this.owner = owner;
+            this.modelRenderCache = mrc;
+            this.modelRenderCache.addRef();
+            this.partIndexFromId = new BABYLON.StringDictionary();
+            this._usedShaderCategories = new Array(partCount);
+            this._strides = new Array(partCount);
+            this._opaqueData = null;
+            this._alphaTestData = null;
+            this._transparentData = null;
+            this.opaqueDirty = this.alphaTestDirty = this.transparentDirty = this.transparentOrderDirty = false;
         }
         GroupInstanceInfo.prototype.dispose = function () {
             if (this._isDisposed) {
                 return false;
             }
-            if (this._modelCache) {
-                this._modelCache.dispose();
+            if (this.modelRenderCache) {
+                this.modelRenderCache.dispose();
             }
-            var engine = this._owner.owner.engine;
-            if (this._instancesPartsBuffer) {
-                this._instancesPartsBuffer.forEach(function (b) {
-                    engine._releaseBuffer(b);
-                });
+            var engine = this.owner.owner.engine;
+            if (this.opaqueData) {
+                this.opaqueData.forEach(function (d) { return d.dispose(engine); });
+                this.opaqueData = null;
             }
-            this._partIndexFromId = null;
-            this._instancesPartsData = null;
-            this._instancesPartsBufferSize = null;
-            this._instancesPartsUsedShaderCategories = null;
+            this.partIndexFromId = null;
+            this._isDisposed = true;
             return true;
         };
+        Object.defineProperty(GroupInstanceInfo.prototype, "hasOpaqueData", {
+            get: function () {
+                return this._opaqueData != null;
+            },
+            enumerable: true,
+            configurable: true
+        });
+        Object.defineProperty(GroupInstanceInfo.prototype, "hasAlphaTestData", {
+            get: function () {
+                return this._alphaTestData != null;
+            },
+            enumerable: true,
+            configurable: true
+        });
+        Object.defineProperty(GroupInstanceInfo.prototype, "hasTransparentData", {
+            get: function () {
+                return this._transparentData != null;
+            },
+            enumerable: true,
+            configurable: true
+        });
+        Object.defineProperty(GroupInstanceInfo.prototype, "opaqueData", {
+            get: function () {
+                if (!this._opaqueData) {
+                    this._opaqueData = new Array(this._partCount);
+                    for (var i = 0; i < this._partCount; i++) {
+                        this._opaqueData[i] = new GroupInfoPartData(this._strides[i]);
+                    }
+                }
+                return this._opaqueData;
+            },
+            enumerable: true,
+            configurable: true
+        });
+        Object.defineProperty(GroupInstanceInfo.prototype, "alphaTestData", {
+            get: function () {
+                if (!this._alphaTestData) {
+                    this._alphaTestData = new Array(this._partCount);
+                    for (var i = 0; i < this._partCount; i++) {
+                        this._alphaTestData[i] = new GroupInfoPartData(this._strides[i]);
+                    }
+                }
+                return this._alphaTestData;
+            },
+            enumerable: true,
+            configurable: true
+        });
+        Object.defineProperty(GroupInstanceInfo.prototype, "transparentData", {
+            get: function () {
+                if (!this._transparentData) {
+                    this._transparentData = new Array(this._partCount);
+                    for (var i = 0; i < this._partCount; i++) {
+                        var zoff = this.modelRenderCache._partData[i]._zBiasOffset;
+                        this._transparentData[i] = new TransparentGroupInfoPartData(this._strides[i], zoff);
+                    }
+                }
+                return this._transparentData;
+            },
+            enumerable: true,
+            configurable: true
+        });
+        GroupInstanceInfo.prototype.sortTransparentData = function () {
+            if (!this.transparentOrderDirty) {
+                return;
+            }
+            for (var i = 0; i < this._transparentData.length; i++) {
+                var td = this._transparentData[i];
+                td._partData.sort();
+            }
+            this.transparentOrderDirty = false;
+        };
+        Object.defineProperty(GroupInstanceInfo.prototype, "usedShaderCategories", {
+            get: function () {
+                return this._usedShaderCategories;
+            },
+            enumerable: true,
+            configurable: true
+        });
+        Object.defineProperty(GroupInstanceInfo.prototype, "strides", {
+            get: function () {
+                return this._strides;
+            },
+            enumerable: true,
+            configurable: true
+        });
         return GroupInstanceInfo;
-    }());
+    })();
     BABYLON.GroupInstanceInfo = GroupInstanceInfo;
+    var TransparentSegment = (function () {
+        function TransparentSegment() {
+        }
+        return TransparentSegment;
+    })();
+    BABYLON.TransparentSegment = TransparentSegment;
+    var GroupInfoPartData = (function () {
+        function GroupInfoPartData(stride) {
+            this._partData = null;
+            this._partBuffer = null;
+            this._partBufferSize = 0;
+            this._partData = new BABYLON.DynamicFloatArray(stride / 4, 50);
+            this._isDisposed = false;
+        }
+        GroupInfoPartData.prototype.dispose = function (engine) {
+            if (this._isDisposed) {
+                return false;
+            }
+            if (this._partBuffer) {
+                engine._releaseBuffer(this._partBuffer);
+                this._partBuffer = null;
+            }
+            this._partData = null;
+            this._isDisposed = true;
+        };
+        return GroupInfoPartData;
+    })();
+    BABYLON.GroupInfoPartData = GroupInfoPartData;
+    var TransparentGroupInfoPartData = (function (_super) {
+        __extends(TransparentGroupInfoPartData, _super);
+        function TransparentGroupInfoPartData(stride, zoff) {
+            _super.call(this, stride);
+            this._partData.compareValueOffset = zoff;
+            this._partData.sortingAscending = false;
+        }
+        return TransparentGroupInfoPartData;
+    })(GroupInfoPartData);
+    BABYLON.TransparentGroupInfoPartData = TransparentGroupInfoPartData;
     var ModelRenderCache = (function () {
-        function ModelRenderCache(engine, modelKey, isTransparent) {
+        function ModelRenderCache(engine, modelKey) {
             this._engine = engine;
             this._modelKey = modelKey;
-            this._isTransparent = isTransparent;
             this._nextKey = 1;
             this._refCounter = 1;
             this._instancesData = new BABYLON.StringDictionary();
+            this._partData = null;
         }
         ModelRenderCache.prototype.dispose = function () {
             if (--this._refCounter !== 0) {
@@ -91,8 +219,8 @@ var BABYLON;
             this._instancesData.remove(key);
         };
         ModelRenderCache.prototype.getPartIndexFromId = function (partId) {
-            for (var i = 0; i < this._partIdList.length; i++) {
-                if (this._partIdList[i] === partId) {
+            for (var i = 0; i < this._partData.length; i++) {
+                if (this._partData[i]._partId === partId) {
                     return i;
                 }
             }
@@ -104,26 +232,27 @@ var BABYLON;
                 return null;
             }
             var ci = this._partsClassInfo[i];
-            var categories = this._partsUsedCategories[i];
+            var categories = this._partData[i]._partUsedCategories;
             var res = ci.classContent.getInstancingAttributeInfos(effect, categories);
             return res;
         };
         ModelRenderCache.prototype.setupUniforms = function (effect, partIndex, data, elementCount) {
-            var offset = (this._partsDataStride[partIndex] / 4) * elementCount;
+            var pd = this._partData[partIndex];
+            var offset = (pd._partDataStride / 4) * elementCount;
             var pci = this._partsClassInfo[partIndex];
             var self = this;
             pci.fullContent.forEach(function (k, v) {
-                if (!v.category || self._partsUsedCategories[partIndex].indexOf(v.category) !== 1) {
+                if (!v.category || pd._partUsedCategories.indexOf(v.category) !== -1) {
                     switch (v.dataType) {
                         case 4 /* float */:
                             {
-                                var attribOffset = v.instanceOffset.get(self._partsJoinedUsedCategories[partIndex]);
+                                var attribOffset = v.instanceOffset.get(pd._partJoinedUsedCategories);
                                 effect.setFloat(v.attributeName, data.buffer[offset + attribOffset]);
                                 break;
                             }
                         case 0 /* Vector2 */:
                             {
-                                var attribOffset = v.instanceOffset.get(self._partsJoinedUsedCategories[partIndex]);
+                                var attribOffset = v.instanceOffset.get(pd._partJoinedUsedCategories);
                                 ModelRenderCache.v2.x = data.buffer[offset + attribOffset + 0];
                                 ModelRenderCache.v2.y = data.buffer[offset + attribOffset + 1];
                                 effect.setVector2(v.attributeName, ModelRenderCache.v2);
@@ -132,7 +261,7 @@ var BABYLON;
                         case 5 /* Color3 */:
                         case 1 /* Vector3 */:
                             {
-                                var attribOffset = v.instanceOffset.get(self._partsJoinedUsedCategories[partIndex]);
+                                var attribOffset = v.instanceOffset.get(pd._partJoinedUsedCategories);
                                 ModelRenderCache.v3.x = data.buffer[offset + attribOffset + 0];
                                 ModelRenderCache.v3.y = data.buffer[offset + attribOffset + 1];
                                 ModelRenderCache.v3.z = data.buffer[offset + attribOffset + 2];
@@ -142,7 +271,7 @@ var BABYLON;
                         case 6 /* Color4 */:
                         case 2 /* Vector4 */:
                             {
-                                var attribOffset = v.instanceOffset.get(self._partsJoinedUsedCategories[partIndex]);
+                                var attribOffset = v.instanceOffset.get(pd._partJoinedUsedCategories);
                                 ModelRenderCache.v4.x = data.buffer[offset + attribOffset + 0];
                                 ModelRenderCache.v4.y = data.buffer[offset + attribOffset + 1];
                                 ModelRenderCache.v4.z = data.buffer[offset + attribOffset + 2];
@@ -155,13 +284,6 @@ var BABYLON;
                 }
             });
         };
-        Object.defineProperty(ModelRenderCache.prototype, "isTransparent", {
-            get: function () {
-                return this._isTransparent;
-            },
-            enumerable: true,
-            configurable: true
-        });
         //setupUniformsLocation(effect: Effect, uniforms: string[], partId: number) {
         //    let i = this.getPartIndexFromId(partId);
         //    if (i === null) {
@@ -178,6 +300,12 @@ var BABYLON;
         ModelRenderCache.v3 = BABYLON.Vector3.Zero();
         ModelRenderCache.v4 = BABYLON.Vector4.Zero();
         return ModelRenderCache;
-    }());
+    })();
     BABYLON.ModelRenderCache = ModelRenderCache;
+    var ModelRenderCachePartData = (function () {
+        function ModelRenderCachePartData() {
+        }
+        return ModelRenderCachePartData;
+    })();
+    BABYLON.ModelRenderCachePartData = ModelRenderCachePartData;
 })(BABYLON || (BABYLON = {}));

+ 242 - 12
src/Canvas2d/babylon.prim2dBase.js

@@ -11,11 +11,68 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
 };
 var BABYLON;
 (function (BABYLON) {
+    var PreapreRender2DContext = (function () {
+        function PreapreRender2DContext() {
+            this.forceRefreshPrimitive = false;
+        }
+        return PreapreRender2DContext;
+    })();
+    BABYLON.PreapreRender2DContext = PreapreRender2DContext;
     var Render2DContext = (function () {
-        function Render2DContext() {
+        function Render2DContext(renderMode) {
+            this._renderMode = renderMode;
+            this.useInstancing = false;
+            this.groupInfoPartData = null;
+            this.partDataStartIndex = this.partDataEndIndex = null;
         }
+        Object.defineProperty(Render2DContext.prototype, "renderMode", {
+            /**
+             * Define which render Mode should be used to render the primitive: one of Render2DContext.RenderModeXxxx property
+             */
+            get: function () {
+                return this._renderMode;
+            },
+            enumerable: true,
+            configurable: true
+        });
+        Object.defineProperty(Render2DContext, "RenderModeOpaque", {
+            /**
+             * The set of primitives to render is opaque.
+             * This is the first rendering pass. All Opaque primitives are rendered. Depth Compare and Write are both enabled.
+             */
+            get: function () {
+                return Render2DContext._renderModeOpaque;
+            },
+            enumerable: true,
+            configurable: true
+        });
+        Object.defineProperty(Render2DContext, "RenderModeAlphaTest", {
+            /**
+             * The set of primitives to render is using Alpha Test (aka masking).
+             * Alpha Blend is enabled, the AlphaMode must be manually set, the render occurs after the RenderModeOpaque and is depth independent (i.e. primitives are not sorted by depth). Depth Compare and Write are both enabled.
+             */
+            get: function () {
+                return Render2DContext._renderModeAlphaTest;
+            },
+            enumerable: true,
+            configurable: true
+        });
+        Object.defineProperty(Render2DContext, "RenderModeTransparent", {
+            /**
+             * The set of primitives to render is transparent.
+             * Alpha Blend is enabled, the AlphaMode must be manually set, the render occurs after the RenderModeAlphaTest and is depth dependent (i.e. primitives are stored by depth and rendered back to front). Depth Compare is on, but Depth write is Off.
+             */
+            get: function () {
+                return Render2DContext._renderModeTransparent;
+            },
+            enumerable: true,
+            configurable: true
+        });
+        Render2DContext._renderModeOpaque = 1;
+        Render2DContext._renderModeAlphaTest = 2;
+        Render2DContext._renderModeTransparent = 3;
         return Render2DContext;
-    }());
+    })();
     BABYLON.Render2DContext = Render2DContext;
     /**
      * This class store information for the pointerEventObservable Observable.
@@ -175,7 +232,7 @@ var BABYLON;
         PrimitivePointerInfo._pointerLostCapture = 0x0200;
         PrimitivePointerInfo._mouseWheelPrecision = 3.0;
         return PrimitivePointerInfo;
-    }());
+    })();
     BABYLON.PrimitivePointerInfo = PrimitivePointerInfo;
     /**
      * Stores information about a Primitive that was intersected
@@ -186,8 +243,75 @@ var BABYLON;
             this.intersectionLocation = intersectionLocation;
         }
         return PrimitiveIntersectedInfo;
-    }());
+    })();
     BABYLON.PrimitiveIntersectedInfo = PrimitiveIntersectedInfo;
+    var PrimitiveMargin = (function () {
+        function PrimitiveMargin(owner) {
+            this._owner = owner;
+            this._left = this._top = this._bottom = this.right = 0;
+        }
+        Object.defineProperty(PrimitiveMargin.prototype, "top", {
+            get: function () {
+                return this._top;
+            },
+            set: function (value) {
+                if (value === this._top) {
+                    return;
+                }
+                this._top = value;
+                this._owner._marginChanged();
+            },
+            enumerable: true,
+            configurable: true
+        });
+        Object.defineProperty(PrimitiveMargin.prototype, "left", {
+            get: function () {
+                return this._left;
+            },
+            set: function (value) {
+                if (value === this._left) {
+                    return;
+                }
+                this._left = value;
+                this._owner._marginChanged();
+            },
+            enumerable: true,
+            configurable: true
+        });
+        Object.defineProperty(PrimitiveMargin.prototype, "right", {
+            get: function () {
+                return this._right;
+            },
+            set: function (value) {
+                if (value === this._right) {
+                    return;
+                }
+                this._right = value;
+                this._owner._marginChanged();
+            },
+            enumerable: true,
+            configurable: true
+        });
+        Object.defineProperty(PrimitiveMargin.prototype, "bottom", {
+            get: function () {
+                return this._bottom;
+            },
+            set: function (value) {
+                if (value === this._bottom) {
+                    return;
+                }
+                this._bottom = value;
+                this._owner._marginChanged();
+            },
+            enumerable: true,
+            configurable: true
+        });
+        PrimitiveMargin.Zero = function (owner) {
+            return new PrimitiveMargin(owner);
+        };
+        return PrimitiveMargin;
+    })();
+    BABYLON.PrimitiveMargin = PrimitiveMargin;
     /**
      * Main class used for the Primitive Intersection API
      */
@@ -223,18 +347,65 @@ var BABYLON;
             }
         };
         return IntersectInfo2D;
-    }());
+    })();
     BABYLON.IntersectInfo2D = IntersectInfo2D;
     var Prim2DBase = (function (_super) {
         __extends(Prim2DBase, _super);
         function Prim2DBase() {
             _super.apply(this, arguments);
         }
-        Prim2DBase.prototype.setupPrim2DBase = function (owner, parent, id, position, origin, isVisible) {
-            if (isVisible === void 0) { isVisible = true; }
+        Object.defineProperty(Prim2DBase, "HAlignLeft", {
+            get: function () { return Prim2DBase._hAlignLeft; },
+            enumerable: true,
+            configurable: true
+        });
+        Object.defineProperty(Prim2DBase, "HAlignCenter", {
+            get: function () { return Prim2DBase._hAlignCenter; },
+            enumerable: true,
+            configurable: true
+        });
+        Object.defineProperty(Prim2DBase, "HAlignRight", {
+            get: function () { return Prim2DBase._hAlignRight; },
+            enumerable: true,
+            configurable: true
+        });
+        Object.defineProperty(Prim2DBase, "HAlignStretch", {
+            get: function () { return Prim2DBase._hAlignStretch; },
+            enumerable: true,
+            configurable: true
+        });
+        Object.defineProperty(Prim2DBase, "VAlignTop", {
+            get: function () { return Prim2DBase._vAlignTop; },
+            enumerable: true,
+            configurable: true
+        });
+        Object.defineProperty(Prim2DBase, "VAlignCenter", {
+            get: function () { return Prim2DBase._vAlignCenter; },
+            enumerable: true,
+            configurable: true
+        });
+        Object.defineProperty(Prim2DBase, "VAlignBottom", {
+            get: function () { return Prim2DBase._vAlignBottom; },
+            enumerable: true,
+            configurable: true
+        });
+        Object.defineProperty(Prim2DBase, "VAlignStretch", {
+            get: function () { return Prim2DBase._vAlignStretch; },
+            enumerable: true,
+            configurable: true
+        });
+        Prim2DBase.prototype.setupPrim2DBase = function (owner, parent, id, position, origin, isVisible, marginTop, marginLeft, marginRight, marginBottom, vAlignment, hAlignment) {
             if (!(this instanceof BABYLON.Group2D) && !(this instanceof BABYLON.Sprite2D && id !== null && id.indexOf("__cachedSpriteOfGroup__") === 0) && (owner.cachingStrategy === BABYLON.Canvas2D.CACHESTRATEGY_TOPLEVELGROUPS) && (parent === owner)) {
                 throw new Error("Can't create a primitive with the canvas as direct parent when the caching strategy is TOPLEVELGROUPS. You need to create a Group below the canvas and use it as the parent for the primitive");
             }
+            var m = null;
+            if (marginTop || marginLeft || marginRight || marginBottom) {
+                m = new PrimitiveMargin(this);
+                m.top = marginTop || 0;
+                m.left = marginLeft || 0;
+                m.right = marginRight || 0;
+                m.bottom = marginBottom || 0;
+            }
             this.setupSmartPropertyPrim();
             this._pointerEventObservable = new BABYLON.Observable();
             this._isPickable = true;
@@ -243,6 +414,7 @@ var BABYLON;
             this._boundingInfo = new BABYLON.BoundingInfo2D();
             this._owner = owner;
             this._parent = parent;
+            this._id = id;
             if (parent != null) {
                 this._hierarchyDepth = parent._hierarchyDepth + 1;
                 this._renderGroup = this.parent.traverseUp(function (p) { return p instanceof BABYLON.Group2D && p.isRenderableGroup; });
@@ -252,7 +424,6 @@ var BABYLON;
                 this._hierarchyDepth = 0;
                 this._renderGroup = null;
             }
-            this._id = id;
             this.propertyChanged = new BABYLON.Observable();
             this._children = new Array();
             this._globalTransformProcessStep = 0;
@@ -266,6 +437,9 @@ var BABYLON;
             this.scale = 1;
             this.levelVisible = isVisible;
             this.origin = origin || new BABYLON.Vector2(0.5, 0.5);
+            this.margin = m;
+            this.hAlignment = hAlignment;
+            this.vAlignment = vAlignment;
         };
         Object.defineProperty(Prim2DBase.prototype, "actionManager", {
             get: function () {
@@ -418,6 +592,40 @@ var BABYLON;
             },
             set: function (value) {
                 this._zOrder = value;
+                this.onZOrderChanged();
+            },
+            enumerable: true,
+            configurable: true
+        });
+        Object.defineProperty(Prim2DBase.prototype, "margin", {
+            get: function () {
+                if (!this._margin) {
+                    this._margin = new PrimitiveMargin(this);
+                }
+                return this._margin;
+            },
+            set: function (value) {
+                this._margin = value;
+            },
+            enumerable: true,
+            configurable: true
+        });
+        Object.defineProperty(Prim2DBase.prototype, "hAlignment", {
+            get: function () {
+                return this._hAlignment;
+            },
+            set: function (value) {
+                this._hAlignment = value;
+            },
+            enumerable: true,
+            configurable: true
+        });
+        Object.defineProperty(Prim2DBase.prototype, "vAlignment", {
+            get: function () {
+                return this._vAlignment;
+            },
+            set: function (value) {
+                this._vAlignment = value;
             },
             enumerable: true,
             configurable: true
@@ -521,6 +729,8 @@ var BABYLON;
             enumerable: true,
             configurable: true
         });
+        Prim2DBase.prototype.onZOrderChanged = function () {
+        };
         Prim2DBase.prototype.levelIntersect = function (intersectInfo) {
             return false;
         };
@@ -621,6 +831,7 @@ var BABYLON;
         };
         Prim2DBase.prototype.addChild = function (child) {
             child._hierarchyDepthOffset = this._hierarchyDepthOffset + ((this._children.length + 1) * this._siblingDepthOffset);
+            console.log("Node: " + child.id + " has depth: " + child._hierarchyDepthOffset);
             child._siblingDepthOffset = this._siblingDepthOffset / this.owner.hierarchyLevelMaxSiblingCount;
             this._children.push(child);
         };
@@ -656,6 +867,8 @@ var BABYLON;
                 this._renderGroup._addPrimToDirtyList(this);
             }
         };
+        Prim2DBase.prototype._marginChanged = function () {
+        };
         Prim2DBase.prototype._needPrepare = function () {
             return this._visibilityChanged || this._modelDirty || (this._instanceDirtyFlags !== 0) || (this._globalTransformProcessStep !== this._globalTransformStep);
         };
@@ -696,8 +909,8 @@ var BABYLON;
             }
         };
         Prim2DBase.prototype.updateGlobalTransVisOf = function (list, recurse) {
-            for (var _i = 0, list_1 = list; _i < list_1.length; _i++) {
-                var cur = list_1[_i];
+            for (var _i = 0; _i < list.length; _i++) {
+                var cur = list[_i];
                 cur.updateGlobalTransVis(recurse);
             }
         };
@@ -752,7 +965,15 @@ var BABYLON;
                 }
             }
         };
-        Prim2DBase.PRIM2DBASE_PROPCOUNT = 10;
+        Prim2DBase.PRIM2DBASE_PROPCOUNT = 12;
+        Prim2DBase._hAlignLeft = 1;
+        Prim2DBase._hAlignCenter = 2;
+        Prim2DBase._hAlignRight = 3;
+        Prim2DBase._hAlignStretch = 4;
+        Prim2DBase._vAlignTop = 1;
+        Prim2DBase._vAlignCenter = 2;
+        Prim2DBase._vAlignBottom = 3;
+        Prim2DBase._vAlignStretch = 4;
         __decorate([
             BABYLON.instanceLevelProperty(1, function (pi) { return Prim2DBase.positionProperty = pi; }, false, true)
         ], Prim2DBase.prototype, "position", null);
@@ -774,10 +995,19 @@ var BABYLON;
         __decorate([
             BABYLON.instanceLevelProperty(7, function (pi) { return Prim2DBase.zOrderProperty = pi; })
         ], Prim2DBase.prototype, "zOrder", null);
+        __decorate([
+            BABYLON.dynamicLevelProperty(8, function (pi) { return Prim2DBase.marginProperty = pi; })
+        ], Prim2DBase.prototype, "margin", null);
+        __decorate([
+            BABYLON.dynamicLevelProperty(9, function (pi) { return Prim2DBase.hAlignmentProperty = pi; })
+        ], Prim2DBase.prototype, "hAlignment", null);
+        __decorate([
+            BABYLON.dynamicLevelProperty(10, function (pi) { return Prim2DBase.vAlignmentProperty = pi; })
+        ], Prim2DBase.prototype, "vAlignment", null);
         Prim2DBase = __decorate([
             BABYLON.className("Prim2DBase")
         ], Prim2DBase);
         return Prim2DBase;
-    }(BABYLON.SmartPropertyPrim));
+    })(BABYLON.SmartPropertyPrim);
     BABYLON.Prim2DBase = Prim2DBase;
 })(BABYLON || (BABYLON = {}));

+ 96 - 62
src/Canvas2d/babylon.rectangle2d.js

@@ -13,69 +13,87 @@ var BABYLON;
 (function (BABYLON) {
     var Rectangle2DRenderCache = (function (_super) {
         __extends(Rectangle2DRenderCache, _super);
-        function Rectangle2DRenderCache(engine, modelKey, isTransparent) {
-            _super.call(this, engine, modelKey, isTransparent);
+        function Rectangle2DRenderCache(engine, modelKey) {
+            _super.call(this, engine, modelKey);
+            this.effectsReady = false;
+            this.fillVB = null;
+            this.fillIB = null;
+            this.fillIndicesCount = 0;
+            this.instancingFillAttributes = null;
+            this.effectFill = null;
+            this.effectFillInstanced = null;
+            this.borderVB = null;
+            this.borderIB = null;
+            this.borderIndicesCount = 0;
+            this.instancingBorderAttributes = null;
+            this.effectBorder = null;
+            this.effectBorderInstanced = null;
         }
         Rectangle2DRenderCache.prototype.render = function (instanceInfo, context) {
-            // Do nothing if the shader is still loading/preparing
-            if ((this.effectFill && !this.effectFill.isReady()) || (this.effectBorder && !this.effectBorder.isReady())) {
-                return false;
+            // Do nothing if the shader is still loading/preparing 
+            if (!this.effectsReady) {
+                if ((this.effectFill && (!this.effectFill.isReady() || (this.effectFillInstanced && !this.effectFillInstanced.isReady()))) ||
+                    (this.effectBorder && (!this.effectBorder.isReady() || (this.effectBorderInstanced && !this.effectBorderInstanced.isReady())))) {
+                    return false;
+                }
+                this.effectsReady = true;
             }
-            var engine = instanceInfo._owner.owner.engine;
+            var engine = instanceInfo.owner.owner.engine;
             var depthFunction = 0;
             if (this.effectFill && this.effectBorder) {
                 depthFunction = engine.getDepthFunction();
                 engine.setDepthFunctionToLessOrEqual();
             }
-            var cur;
-            if (this.isTransparent) {
-                cur = engine.getAlphaMode();
-                engine.setAlphaMode(BABYLON.Engine.ALPHA_COMBINE);
-            }
+            var curAlphaMode = engine.getAlphaMode();
             if (this.effectFill) {
-                var partIndex = instanceInfo._partIndexFromId.get(BABYLON.Shape2D.SHAPE2D_FILLPARTID.toString());
-                engine.enableEffect(this.effectFill);
-                engine.bindBuffersDirectly(this.fillVB, this.fillIB, [1], 4, this.effectFill);
-                var count = instanceInfo._instancesPartsData[partIndex].usedElementCount;
-                if (instanceInfo._owner.owner.supportInstancedArray) {
+                var partIndex = instanceInfo.partIndexFromId.get(BABYLON.Shape2D.SHAPE2D_FILLPARTID.toString());
+                var pid = context.groupInfoPartData[partIndex];
+                if (context.renderMode !== BABYLON.Render2DContext.RenderModeOpaque) {
+                    engine.setAlphaMode(BABYLON.Engine.ALPHA_COMBINE);
+                }
+                var effect = context.useInstancing ? this.effectFillInstanced : this.effectFill;
+                engine.enableEffect(effect);
+                engine.bindBuffersDirectly(this.fillVB, this.fillIB, [1], 4, effect);
+                if (context.useInstancing) {
                     if (!this.instancingFillAttributes) {
-                        // Compute the offset locations of the attributes in the vertex shader that will be mapped to the instance buffer data
-                        this.instancingFillAttributes = this.loadInstancingAttributes(BABYLON.Shape2D.SHAPE2D_FILLPARTID, this.effectFill);
+                        this.instancingFillAttributes = this.loadInstancingAttributes(BABYLON.Shape2D.SHAPE2D_FILLPARTID, effect);
                     }
-                    engine.updateAndBindInstancesBuffer(instanceInfo._instancesPartsBuffer[partIndex], null, this.instancingFillAttributes);
-                    engine.draw(true, 0, this.fillIndicesCount, count);
+                    engine.updateAndBindInstancesBuffer(pid._partBuffer, null, this.instancingFillAttributes);
+                    engine.draw(true, 0, this.fillIndicesCount, pid._partData.usedElementCount);
                     engine.unbindInstanceAttributes();
                 }
                 else {
-                    for (var i = 0; i < count; i++) {
-                        this.setupUniforms(this.effectFill, partIndex, instanceInfo._instancesPartsData[partIndex], i);
+                    for (var i = context.partDataStartIndex; i < context.partDataEndIndex; i++) {
+                        this.setupUniforms(effect, partIndex, pid._partData, i);
                         engine.draw(true, 0, this.fillIndicesCount);
                     }
                 }
             }
             if (this.effectBorder) {
-                var partIndex = instanceInfo._partIndexFromId.get(BABYLON.Shape2D.SHAPE2D_BORDERPARTID.toString());
-                engine.enableEffect(this.effectBorder);
-                engine.bindBuffersDirectly(this.borderVB, this.borderIB, [1], 4, this.effectBorder);
-                var count = instanceInfo._instancesPartsData[partIndex].usedElementCount;
-                if (instanceInfo._owner.owner.supportInstancedArray) {
+                var partIndex = instanceInfo.partIndexFromId.get(BABYLON.Shape2D.SHAPE2D_BORDERPARTID.toString());
+                var pid = context.groupInfoPartData[partIndex];
+                if (context.renderMode !== BABYLON.Render2DContext.RenderModeOpaque) {
+                    engine.setAlphaMode(BABYLON.Engine.ALPHA_COMBINE);
+                }
+                var effect = context.useInstancing ? this.effectBorderInstanced : this.effectBorder;
+                engine.enableEffect(effect);
+                engine.bindBuffersDirectly(this.borderVB, this.borderIB, [1], 4, effect);
+                if (context.useInstancing) {
                     if (!this.instancingBorderAttributes) {
-                        this.instancingBorderAttributes = this.loadInstancingAttributes(BABYLON.Shape2D.SHAPE2D_BORDERPARTID, this.effectBorder);
+                        this.instancingBorderAttributes = this.loadInstancingAttributes(BABYLON.Shape2D.SHAPE2D_BORDERPARTID, effect);
                     }
-                    engine.updateAndBindInstancesBuffer(instanceInfo._instancesPartsBuffer[partIndex], null, this.instancingBorderAttributes);
-                    engine.draw(true, 0, this.borderIndicesCount, count);
+                    engine.updateAndBindInstancesBuffer(pid._partBuffer, null, this.instancingBorderAttributes);
+                    engine.draw(true, 0, this.borderIndicesCount, pid._partData.usedElementCount);
                     engine.unbindInstanceAttributes();
                 }
                 else {
-                    for (var i = 0; i < count; i++) {
-                        this.setupUniforms(this.effectBorder, partIndex, instanceInfo._instancesPartsData[partIndex], i);
+                    for (var i = context.partDataStartIndex; i < context.partDataEndIndex; i++) {
+                        this.setupUniforms(effect, partIndex, pid._partData, i);
                         engine.draw(true, 0, this.borderIndicesCount);
                     }
                 }
             }
-            if (this.isTransparent) {
-                engine.setAlphaMode(cur);
-            }
+            engine.setAlphaMode(curAlphaMode);
             if (this.effectFill && this.effectBorder) {
                 engine.setDepthFunction(depthFunction);
             }
@@ -97,6 +115,10 @@ var BABYLON;
                 this._engine._releaseEffect(this.effectFill);
                 this.effectFill = null;
             }
+            if (this.effectFillInstanced) {
+                this._engine._releaseEffect(this.effectFillInstanced);
+                this.effectFillInstanced = null;
+            }
             if (this.borderVB) {
                 this._engine._releaseBuffer(this.borderVB);
                 this.borderVB = null;
@@ -109,10 +131,14 @@ var BABYLON;
                 this._engine._releaseEffect(this.effectBorder);
                 this.effectBorder = null;
             }
+            if (this.effectBorderInstanced) {
+                this._engine._releaseEffect(this.effectBorderInstanced);
+                this.effectBorderInstanced = null;
+            }
             return true;
         };
         return Rectangle2DRenderCache;
-    }(BABYLON.ModelRenderCache));
+    })(BABYLON.ModelRenderCache);
     BABYLON.Rectangle2DRenderCache = Rectangle2DRenderCache;
     var Rectangle2DInstanceData = (function (_super) {
         __extends(Rectangle2DInstanceData, _super);
@@ -130,7 +156,7 @@ var BABYLON;
             BABYLON.instanceData()
         ], Rectangle2DInstanceData.prototype, "properties", null);
         return Rectangle2DInstanceData;
-    }(BABYLON.Shape2DInstanceData));
+    })(BABYLON.Shape2DInstanceData);
     BABYLON.Rectangle2DInstanceData = Rectangle2DInstanceData;
     var Rectangle2D = (function (_super) {
         __extends(Rectangle2D, _super);
@@ -187,10 +213,8 @@ var BABYLON;
         Rectangle2D.prototype.updateLevelBoundingInfo = function () {
             BABYLON.BoundingInfo2D.CreateFromSizeToRef(this.size, this._levelBoundingInfo, this.origin);
         };
-        Rectangle2D.prototype.setupRectangle2D = function (owner, parent, id, position, origin, size, roundRadius, fill, border, borderThickness) {
-            if (roundRadius === void 0) { roundRadius = 0; }
-            if (borderThickness === void 0) { borderThickness = 1; }
-            this.setupShape2D(owner, parent, id, position, origin, true, fill, border, borderThickness);
+        Rectangle2D.prototype.setupRectangle2D = function (owner, parent, id, position, origin, size, roundRadius, fill, border, borderThickness, isVisible, marginTop, marginLeft, marginRight, marginBottom, vAlignment, hAlignment) {
+            this.setupShape2D(owner, parent, id, position, origin, isVisible, fill, border, borderThickness, marginTop, marginLeft, marginRight, marginBottom, hAlignment, vAlignment);
             this.size = size;
             this.notRounded = !roundRadius;
             this.roundRadius = roundRadius;
@@ -200,32 +224,34 @@ var BABYLON;
          * @param parent the parent primitive, must be a valid primitive (or the Canvas)
          * options:
          *  - id a text identifier, for information purpose
-         *  - x: the X position relative to its parent, default is 0
-         *  - y: the Y position relative to its parent, default is 0
+         *  - position: the X & Y positions relative to its parent. Alternatively the x and y properties can be set. Default is [0;0]
          *  - origin: define the normalized origin point location, default [0.5;0.5]
-         *  - width: the width of the rectangle, default is 10
-         *  - height: the height of the rectangle, default is 10
+         *  - size: the size of the group. Alternatively the width and height properties can be set. Default will be [10;10].
          *  - roundRadius: if the rectangle has rounded corner, set their radius, default is 0 (to get a sharp rectangle).
          *  - fill: the brush used to draw the fill content of the ellipse, you can set null to draw nothing (but you will have to set a border brush), default is a SolidColorBrush of plain white.
          *  - border: the brush used to draw the border of the ellipse, you can set null to draw nothing (but you will have to set a fill brush), default is null.
          *  - borderThickness: the thickness of the drawn border, default is 1.
+         *  - isVisible: true if the primitive must be visible, false for hidden. Default is true.
+         *  - marginTop/Left/Right/Bottom: define the margin for the corresponding edge, if all of them are null, margin is not used in layout computing. Default Value is null for each.
+         *  - hAlighment: define horizontal alignment of the Canvas, alignment is optional, default value null: no alignment.
+         *  - vAlighment: define horizontal alignment of the Canvas, alignment is optional, default value null: no alignment.
          */
         Rectangle2D.Create = function (parent, options) {
             BABYLON.Prim2DBase.CheckParent(parent);
             var rect = new Rectangle2D();
-            rect.setupRectangle2D(parent.owner, parent, options && options.id || null, new BABYLON.Vector2(options && options.x || 0, options && options.y || 0), options && options.origin || null, new BABYLON.Size(options && options.width || 10, options && options.height || 10), options && options.roundRadius || 0);
-            if (options && options.fill !== undefined) {
-                rect.fill = options.fill;
+            if (!options) {
+                rect.setupRectangle2D(parent.owner, parent, null, BABYLON.Vector2.Zero(), null, new BABYLON.Size(10, 10), 0, BABYLON.Canvas2D.GetSolidColorBrushFromHex("#FFFFFFFF"), null, 1, true, null, null, null, null, null, null);
             }
             else {
-                rect.fill = BABYLON.Canvas2D.GetSolidColorBrushFromHex("#FFFFFFFF");
+                var pos = options.position || new BABYLON.Vector2(options.x || 0, options.y || 0);
+                var size = options.size || (new BABYLON.Size(options.width || 10, options.height || 10));
+                var fill = options.fill === undefined ? BABYLON.Canvas2D.GetSolidColorBrushFromHex("#FFFFFFFF") : options.fill;
+                rect.setupRectangle2D(parent.owner, parent, options.id || null, pos, options.origin || null, size, options.roundRadius || 0, fill, options.border || null, options.borderThickness || 1, options.isVisible || true, options.marginTop || null, options.marginLeft || null, options.marginRight || null, options.marginBottom || null, options.vAlignment || null, options.hAlignment || null);
             }
-            rect.border = options && options.border || null;
-            rect.borderThickness = options && options.borderThickness || 1;
             return rect;
         };
-        Rectangle2D.prototype.createModelRenderCache = function (modelKey, isTransparent) {
-            var renderCache = new Rectangle2DRenderCache(this.owner.engine, modelKey, isTransparent);
+        Rectangle2D.prototype.createModelRenderCache = function (modelKey) {
+            var renderCache = new Rectangle2DRenderCache(this.owner.engine, modelKey);
             return renderCache;
         };
         Rectangle2D.prototype.setupModelRenderCache = function (modelRenderCache) {
@@ -249,10 +275,14 @@ var BABYLON;
                 ib[triCount * 3 - 2] = 1;
                 renderCache.fillIB = engine.createIndexBuffer(ib);
                 renderCache.fillIndicesCount = triCount * 3;
-                var ei = this.getDataPartEffectInfo(BABYLON.Shape2D.SHAPE2D_FILLPARTID, ["index"]);
-                renderCache.effectFill = engine.createEffect({ vertex: "rect2d", fragment: "rect2d" }, ei.attributes, ei.uniforms, [], ei.defines, null, function (e) {
-                    //                    renderCache.setupUniformsLocation(e, ei.uniforms, Shape2D.SHAPE2D_FILLPARTID);
-                });
+                // Get the instanced version of the effect, if the engine does not support it, null is return and we'll only draw on by one
+                var ei = this.getDataPartEffectInfo(BABYLON.Shape2D.SHAPE2D_FILLPARTID, ["index"], true);
+                if (ei) {
+                    renderCache.effectFillInstanced = engine.createEffect("rect2d", ei.attributes, ei.uniforms, [], ei.defines, null);
+                }
+                // Get the non instanced version
+                ei = this.getDataPartEffectInfo(BABYLON.Shape2D.SHAPE2D_FILLPARTID, ["index"], false);
+                renderCache.effectFill = engine.createEffect("rect2d", ei.attributes, ei.uniforms, [], ei.defines, null);
             }
             // Need to create WebGL resource for border part?
             if (this.border) {
@@ -277,10 +307,14 @@ var BABYLON;
                 }
                 renderCache.borderIB = engine.createIndexBuffer(ib);
                 renderCache.borderIndicesCount = triCount * 3;
-                var ei = this.getDataPartEffectInfo(BABYLON.Shape2D.SHAPE2D_BORDERPARTID, ["index"]);
-                renderCache.effectBorder = engine.createEffect({ vertex: "rect2d", fragment: "rect2d" }, ei.attributes, ei.uniforms, [], ei.defines, null, function (e) {
-                    //                    renderCache.setupUniformsLocation(e, ei.uniforms, Shape2D.SHAPE2D_BORDERPARTID);
-                });
+                // Get the instanced version of the effect, if the engine does not support it, null is return and we'll only draw on by one
+                var ei = this.getDataPartEffectInfo(BABYLON.Shape2D.SHAPE2D_BORDERPARTID, ["index"], true);
+                if (ei) {
+                    renderCache.effectBorderInstanced = engine.createEffect("rect2d", ei.attributes, ei.uniforms, [], ei.defines, null);
+                }
+                // Get the non instanced version
+                ei = this.getDataPartEffectInfo(BABYLON.Shape2D.SHAPE2D_BORDERPARTID, ["index"], false);
+                renderCache.effectBorder = engine.createEffect("rect2d", ei.attributes, ei.uniforms, [], ei.defines, null);
             }
             return renderCache;
         };
@@ -324,6 +358,6 @@ var BABYLON;
             BABYLON.className("Rectangle2D")
         ], Rectangle2D);
         return Rectangle2D;
-    }(BABYLON.Shape2D));
+    })(BABYLON.Shape2D);
     BABYLON.Rectangle2D = Rectangle2D;
 })(BABYLON || (BABYLON = {}));

+ 260 - 120
src/Canvas2d/babylon.renderablePrim2d.js

@@ -73,7 +73,7 @@ var BABYLON;
             return curOffset;
         };
         return InstanceClassInfo;
-    }());
+    })();
     BABYLON.InstanceClassInfo = InstanceClassInfo;
     var InstancePropInfo = (function () {
         function InstancePropInfo() {
@@ -187,7 +187,7 @@ var BABYLON;
             }
         };
         return InstancePropInfo;
-    }());
+    })();
     BABYLON.InstancePropInfo = InstancePropInfo;
     function instanceData(category, shaderAttributeName) {
         return function (target, propName, descriptor) {
@@ -319,13 +319,23 @@ var BABYLON;
             instanceData()
         ], InstanceDataBase.prototype, "origin", null);
         return InstanceDataBase;
-    }());
+    })();
     BABYLON.InstanceDataBase = InstanceDataBase;
     var RenderablePrim2D = (function (_super) {
         __extends(RenderablePrim2D, _super);
         function RenderablePrim2D() {
             _super.apply(this, arguments);
         }
+        Object.defineProperty(RenderablePrim2D.prototype, "isAlphaTest", {
+            get: function () {
+                return this._isAlphaTest;
+            },
+            set: function (value) {
+                this._isAlphaTest = value;
+            },
+            enumerable: true,
+            configurable: true
+        });
         Object.defineProperty(RenderablePrim2D.prototype, "isTransparent", {
             get: function () {
                 return this._isTransparent;
@@ -336,9 +346,11 @@ var BABYLON;
             enumerable: true,
             configurable: true
         });
-        RenderablePrim2D.prototype.setupRenderablePrim2D = function (owner, parent, id, position, origin, isVisible) {
-            this.setupPrim2DBase(owner, parent, id, position, origin);
+        RenderablePrim2D.prototype.setupRenderablePrim2D = function (owner, parent, id, position, origin, isVisible, marginTop, marginLeft, marginRight, marginBottom, hAlign, vAlign) {
+            this.setupPrim2DBase(owner, parent, id, position, origin, isVisible, marginTop, marginLeft, marginRight, marginBottom, hAlign, vAlign);
             this._isTransparent = false;
+            this._isAlphaTest = false;
+            this._transparentPrimitiveInfo = null;
         };
         RenderablePrim2D.prototype.dispose = function () {
             if (!_super.prototype.dispose.call(this)) {
@@ -361,7 +373,6 @@ var BABYLON;
             return true;
         };
         RenderablePrim2D.prototype._prepareRenderPre = function (context) {
-            var _this = this;
             _super.prototype._prepareRenderPre.call(this, context);
             // If the model changed and we have already an instance, we must remove this instance from the obsolete model
             if (this._modelDirty && this._modelRenderInstanceID) {
@@ -371,98 +382,15 @@ var BABYLON;
             // Need to create the model?
             var setupModelRenderCache = false;
             if (!this._modelRenderCache || this._modelDirty) {
-                if (this._modelRenderCache) {
-                    this._modelRenderCache.dispose();
-                }
-                this._modelRenderCache = this.owner._engineData.GetOrAddModelCache(this.modelKey, function (key) {
-                    var mrc = _this.createModelRenderCache(key, _this.isTransparent);
-                    setupModelRenderCache = true;
-                    return mrc;
-                });
-                this._modelDirty = false;
-                // if this is still false it means the MRC already exists, so we add a reference to it
-                if (!setupModelRenderCache) {
-                    this._modelRenderCache.addRef();
-                }
+                setupModelRenderCache = this._createModelRenderCache();
             }
-            var gii;
+            var gii = null;
             var newInstance = false;
             // Need to create the instance data parts?
             if (!this._modelRenderInstanceID) {
                 // Yes, flag it for later, more processing will have to be done
                 newInstance = true;
-                // Create the instance data parts of the primitive and store them
-                var parts = this.createInstanceDataParts();
-                this._instanceDataParts = parts;
-                // Check if the ModelRenderCache for this particular instance is also brand new, initialize it if it's the case
-                if (!this._modelRenderCache._partsDataStride) {
-                    var ctiArray = new Array();
-                    var dataStrides = new Array();
-                    var usedCatList = new Array();
-                    var partIdList = new Array();
-                    var joinedUsedCatList = new Array();
-                    for (var _i = 0, parts_1 = parts; _i < parts_1.length; _i++) {
-                        var dataPart = parts_1[_i];
-                        var cat = this.getUsedShaderCategories(dataPart);
-                        var cti = dataPart.getClassTreeInfo();
-                        // Make sure the instance is visible other the properties won't be set and their size/offset wont be computed
-                        var curVisible = this.isVisible;
-                        this.isVisible = true;
-                        // We manually trigger refreshInstanceData for the only sake of evaluating each instance property size and offset in the instance data, this can only be made at runtime. Once it's done we have all the information to create the instance data buffer.
-                        //console.log("Build Prop Layout for " + Tools.getClassName(this._instanceDataParts[0]));
-                        var joinCat = ";" + cat.join(";") + ";";
-                        joinedUsedCatList.push(joinCat);
-                        InstanceClassInfo._CurCategories = joinCat;
-                        var obj = this.beforeRefreshForLayoutConstruction(dataPart);
-                        this.refreshInstanceDataPart(dataPart);
-                        this.afterRefreshForLayoutConstruction(dataPart, obj);
-                        this.isVisible = curVisible;
-                        var size = 0;
-                        cti.fullContent.forEach(function (k, v) {
-                            if (!v.category || cat.indexOf(v.category) !== -1) {
-                                if (!v.size) {
-                                    console.log("ERROR: Couldn't detect the size of the Property " + v.attributeName + " from type " + BABYLON.Tools.getClassName(cti.type) + ". Property is ignored.");
-                                }
-                                else {
-                                    size += v.size;
-                                }
-                            }
-                        });
-                        dataStrides.push(size);
-                        usedCatList.push(cat);
-                        ctiArray.push(cti);
-                        partIdList.push(dataPart.id);
-                    }
-                    this._modelRenderCache._partsDataStride = dataStrides;
-                    this._modelRenderCache._partsUsedCategories = usedCatList;
-                    this._modelRenderCache._partsJoinedUsedCategories = joinedUsedCatList;
-                    this._modelRenderCache._partsClassInfo = ctiArray;
-                    this._modelRenderCache._partIdList = partIdList;
-                }
-                // The Rendering resources (Effect, VB, IB, Textures) are stored in the ModelRenderCache
-                // But it's the RenderGroup that will store all the Instanced related data to render all the primitive it owns.
-                // So for a given ModelKey we getOrAdd a GroupInstanceInfo that will store all these data
-                gii = this.renderGroup._renderGroupInstancesInfo.getOrAddWithFactory(this.modelKey, function (k) { return new BABYLON.GroupInstanceInfo(_this.renderGroup, _this._modelRenderCache); });
-                // First time init of the GroupInstanceInfo
-                if (gii._instancesPartsData.length === 0) {
-                    for (var j = 0; j < this._modelRenderCache._partsDataStride.length; j++) {
-                        var stride = this._modelRenderCache._partsDataStride[j];
-                        gii._instancesPartsData.push(new BABYLON.DynamicFloatArray(stride / 4, 50));
-                        gii._partIndexFromId.add(this._modelRenderCache._partIdList[j].toString(), j);
-                        for (var _a = 0, _b = this._instanceDataParts; _a < _b.length; _a++) {
-                            var part = _b[_a];
-                            gii._instancesPartsUsedShaderCategories[gii._partIndexFromId.get(part.id.toString())] = ";" + this.getUsedShaderCategories(part).join(";") + ";";
-                        }
-                    }
-                }
-                // For each instance data part of the primitive, allocate the instanced element it needs for render
-                for (var i = 0; i < parts.length; i++) {
-                    var part = parts[i];
-                    part.dataBuffer = gii._instancesPartsData[i];
-                    part.allocElements();
-                }
-                // Add the instance data parts in the ModelRenderCache they belong, track them by storing their ID in the primitive in case we need to change the model later on, so we'll have to release the allocated instance data parts because they won't fit anymore
-                this._modelRenderInstanceID = this._modelRenderCache.addInstanceDataParts(this._instanceDataParts);
+                gii = this._createModelDataParts();
             }
             // If the ModelRenderCache is brand new, now is the time to call the implementation's specific setup method to create the rendering resources
             if (setupModelRenderCache) {
@@ -471,30 +399,225 @@ var BABYLON;
             // At this stage we have everything correctly initialized, ModelRenderCache is setup, Model Instance data are good too, they have allocated elements in the Instanced DynamicFloatArray.
             // The last thing to do is check if the instanced related data must be updated because a InstanceLevel property had changed or the primitive visibility changed.
             if (this._visibilityChanged || context.forceRefreshPrimitive || newInstance || (this._instanceDirtyFlags !== 0) || (this._globalTransformProcessStep !== this._globalTransformStep)) {
-                // Fetch the GroupInstanceInfo if we don't already have it
-                if (!gii) {
-                    gii = this.renderGroup._renderGroupInstancesInfo.get(this.modelKey);
+                this._updateInstanceDataParts(gii);
+            }
+        };
+        RenderablePrim2D.prototype._createModelRenderCache = function () {
+            var _this = this;
+            var setupModelRenderCache = false;
+            if (this._modelRenderCache) {
+                this._modelRenderCache.dispose();
+            }
+            this._modelRenderCache = this.owner._engineData.GetOrAddModelCache(this.modelKey, function (key) {
+                var mrc = _this.createModelRenderCache(key);
+                setupModelRenderCache = true;
+                return mrc;
+            });
+            this._modelDirty = false;
+            // if this is still false it means the MRC already exists, so we add a reference to it
+            if (!setupModelRenderCache) {
+                this._modelRenderCache.addRef();
+            }
+            return setupModelRenderCache;
+        };
+        RenderablePrim2D.prototype._createModelDataParts = function () {
+            var _this = this;
+            // Create the instance data parts of the primitive and store them
+            var parts = this.createInstanceDataParts();
+            this._instanceDataParts = parts;
+            // Check if the ModelRenderCache for this particular instance is also brand new, initialize it if it's the case
+            if (!this._modelRenderCache._partData) {
+                this._setupModelRenderCache(parts);
+            }
+            // The Rendering resources (Effect, VB, IB, Textures) are stored in the ModelRenderCache
+            // But it's the RenderGroup that will store all the Instanced related data to render all the primitive it owns.
+            // So for a given ModelKey we getOrAdd a GroupInstanceInfo that will store all these data
+            var gii = this.renderGroup._renderableData._renderGroupInstancesInfo.getOrAddWithFactory(this.modelKey, function (k) {
+                var res = new BABYLON.GroupInstanceInfo(_this.renderGroup, _this._modelRenderCache, _this._modelRenderCache._partData.length);
+                for (var j = 0; j < _this._modelRenderCache._partData.length; j++) {
+                    var part = _this._instanceDataParts[j];
+                    res.partIndexFromId.add(part.id.toString(), j);
+                    res.usedShaderCategories[j] = ";" + _this.getUsedShaderCategories(part).join(";") + ";";
+                    res.strides[j] = _this._modelRenderCache._partData[j]._partDataStride;
                 }
-                // For each Instance Data part, refresh it to update the data in the DynamicFloatArray
-                for (var _c = 0, _d = this._instanceDataParts; _c < _d.length; _c++) {
-                    var part = _d[_c];
-                    // Check if we need to allocate data elements (hidden prim which becomes visible again)
-                    if (this._visibilityChanged && !part.dataElements) {
-                        part.allocElements();
+                return res;
+            });
+            // Get the GroupInfoDataPart corresponding to the render category of the part
+            var gipd = null;
+            if (this.isTransparent) {
+                gipd = gii.transparentData;
+            }
+            else if (this.isAlphaTest) {
+                gipd = gii.alphaTestData;
+            }
+            else {
+                gipd = gii.opaqueData;
+            }
+            // For each instance data part of the primitive, allocate the instanced element it needs for render
+            for (var i = 0; i < parts.length; i++) {
+                var part = parts[i];
+                part.dataBuffer = gipd[i]._partData;
+                part.allocElements();
+            }
+            // Add the instance data parts in the ModelRenderCache they belong, track them by storing their ID in the primitive in case we need to change the model later on, so we'll have to release the allocated instance data parts because they won't fit anymore
+            this._modelRenderInstanceID = this._modelRenderCache.addInstanceDataParts(this._instanceDataParts);
+            return gii;
+        };
+        RenderablePrim2D.prototype._setupModelRenderCache = function (parts) {
+            var ctiArray = new Array();
+            this._modelRenderCache._partData = new Array();
+            for (var _i = 0; _i < parts.length; _i++) {
+                var dataPart = parts[_i];
+                var pd = new BABYLON.ModelRenderCachePartData();
+                this._modelRenderCache._partData.push(pd);
+                var cat = this.getUsedShaderCategories(dataPart);
+                var cti = dataPart.getClassTreeInfo();
+                // Make sure the instance is visible other the properties won't be set and their size/offset wont be computed
+                var curVisible = this.isVisible;
+                this.isVisible = true;
+                // We manually trigger refreshInstanceData for the only sake of evaluating each instance property size and offset in the instance data, this can only be made at runtime. Once it's done we have all the information to create the instance data buffer.
+                //console.log("Build Prop Layout for " + Tools.getClassName(this._instanceDataParts[0]));
+                var joinCat = ";" + cat.join(";") + ";";
+                pd._partJoinedUsedCategories = joinCat;
+                InstanceClassInfo._CurCategories = joinCat;
+                var obj = this.beforeRefreshForLayoutConstruction(dataPart);
+                this.refreshInstanceDataPart(dataPart);
+                this.afterRefreshForLayoutConstruction(dataPart, obj);
+                this.isVisible = curVisible;
+                var size = 0;
+                cti.fullContent.forEach(function (k, v) {
+                    if (!v.category || cat.indexOf(v.category) !== -1) {
+                        if (v.attributeName === "zBias") {
+                            pd._zBiasOffset = v.instanceOffset.get(joinCat);
+                        }
+                        if (!v.size) {
+                            console.log("ERROR: Couldn't detect the size of the Property " + v.attributeName + " from type " + BABYLON.Tools.getClassName(cti.type) + ". Property is ignored.");
+                        }
+                        else {
+                            size += v.size;
+                        }
                     }
-                    InstanceClassInfo._CurCategories = gii._instancesPartsUsedShaderCategories[gii._partIndexFromId.get(part.id.toString())];
-                    // Will return false if the instance should not be rendered (not visible or other any reasons)
-                    if (!this.refreshInstanceDataPart(part)) {
-                        // Free the data element
-                        if (part.dataElements) {
-                            part.freeElements();
+                });
+                pd._partDataStride = size;
+                pd._partUsedCategories = cat;
+                pd._partId = dataPart.id;
+                ctiArray.push(cti);
+            }
+            this._modelRenderCache._partsClassInfo = ctiArray;
+        };
+        RenderablePrim2D.prototype.onZOrderChanged = function () {
+            if (this.isTransparent && this._transparentPrimitiveInfo) {
+                this.renderGroup._renderableData.transparentPrimitiveZChanged(this._transparentPrimitiveInfo);
+                var gii = this.renderGroup._renderableData._renderGroupInstancesInfo.get(this.modelKey);
+                // Flag the transparentData dirty has will have to sort it again
+                gii.transparentOrderDirty = true;
+            }
+        };
+        RenderablePrim2D.prototype._updateInstanceDataParts = function (gii) {
+            // Fetch the GroupInstanceInfo if we don't already have it
+            if (!gii) {
+                gii = this.renderGroup._renderableData._renderGroupInstancesInfo.get(this.modelKey);
+            }
+            // Handle changes related to ZOffset
+            if (this.isTransparent) {
+                // Handle visibility change, which is also triggered when the primitive just got created
+                if (this._visibilityChanged) {
+                    if (this.isVisible) {
+                        if (!this._transparentPrimitiveInfo) {
+                            // Add the primitive to the list of transparent ones in the group that render is
+                            this._transparentPrimitiveInfo = this.renderGroup._renderableData.addNewTransparentPrimitiveInfo(this, gii);
+                        }
+                    }
+                    else {
+                        if (this._transparentPrimitiveInfo) {
+                            this.renderGroup._renderableData.removeTransparentPrimitiveInfo(this._transparentPrimitiveInfo);
                         }
                     }
+                    gii.transparentOrderDirty = true;
+                }
+            }
+            // For each Instance Data part, refresh it to update the data in the DynamicFloatArray
+            for (var _i = 0, _a = this._instanceDataParts; _i < _a.length; _i++) {
+                var part = _a[_i];
+                // Check if we need to allocate data elements (hidden prim which becomes visible again)
+                if (this._visibilityChanged && !part.dataElements) {
+                    part.allocElements();
+                }
+                InstanceClassInfo._CurCategories = gii.usedShaderCategories[gii.partIndexFromId.get(part.id.toString())];
+                // Will return false if the instance should not be rendered (not visible or other any reasons)
+                if (!this.refreshInstanceDataPart(part)) {
+                    // Free the data element
+                    if (part.dataElements) {
+                        part.freeElements();
+                    }
+                }
+            }
+            this._instanceDirtyFlags = 0;
+            // Make the appropriate data dirty
+            if (this.isTransparent) {
+                gii.transparentDirty = true;
+            }
+            else if (this.isAlphaTest) {
+                gii.alphaTestDirty = true;
+            }
+            else {
+                gii.opaqueDirty = true;
+            }
+            this._visibilityChanged = false; // Reset the flag as we've handled the case            
+        };
+        RenderablePrim2D.prototype._getFirstIndexInDataBuffer = function () {
+            for (var _i = 0, _a = this._instanceDataParts; _i < _a.length; _i++) {
+                var part = _a[_i];
+                if (part) {
+                    return part.dataElements[0].offset / part.dataBuffer.stride;
+                }
+            }
+            return null;
+        };
+        RenderablePrim2D.prototype._getLastIndexInDataBuffer = function () {
+            for (var _i = 0, _a = this._instanceDataParts; _i < _a.length; _i++) {
+                var part = _a[_i];
+                if (part) {
+                    return part.dataElements[part.dataElements.length - 1].offset / part.dataBuffer.stride;
+                }
+            }
+            return null;
+        };
+        // This internal method is mainly used for transparency processing
+        RenderablePrim2D.prototype._getNextPrimZOrder = function () {
+            var length = this._instanceDataParts.length;
+            for (var i = 0; i < length; i++) {
+                var part = this._instanceDataParts[i];
+                if (part) {
+                    var stride = part.dataBuffer.stride;
+                    var lastElementOffset = part.dataElements[part.dataElements.length - 1].offset;
+                    // check if it's the last in the DFA
+                    if (part.dataBuffer.totalElementCount * stride <= lastElementOffset) {
+                        return null;
+                    }
+                    // Return the Z of the next primitive that lies in the DFA
+                    return part.dataBuffer[lastElementOffset + stride + this.modelRenderCache._partData[i]._zBiasOffset];
                 }
-                this._instanceDirtyFlags = 0;
-                gii._dirtyInstancesData = true;
-                this._visibilityChanged = false; // Reset the flag as we've handled the case
             }
+            return null;
+        };
+        // This internal method is mainly used for transparency processing
+        RenderablePrim2D.prototype._getPrevPrimZOrder = function () {
+            var length = this._instanceDataParts.length;
+            for (var i = 0; i < length; i++) {
+                var part = this._instanceDataParts[i];
+                if (part) {
+                    var stride = part.dataBuffer.stride;
+                    var firstElementOffset = part.dataElements[0].offset;
+                    // check if it's the first in the DFA
+                    if (firstElementOffset === 0) {
+                        return null;
+                    }
+                    // Return the Z of the previous primitive that lies in the DFA
+                    return part.dataBuffer[firstElementOffset - stride + this.modelRenderCache._partData[i]._zBiasOffset];
+                }
+            }
+            return null;
         };
         /**
          * Transform a given point using the Primitive's origin setting.
@@ -513,12 +636,27 @@ var BABYLON;
             this.transformPointWithOriginByRef(p, originOffset, res);
             return res;
         };
-        RenderablePrim2D.prototype.getDataPartEffectInfo = function (dataPartId, vertexBufferAttributes) {
+        /**
+         * Get the info for a given effect based on the dataPart metadata
+         * @param dataPartId partId in part list to get the info
+         * @param vertexBufferAttributes vertex buffer attributes to manually add
+         * @param useInstanced specified if Instanced Array should be used, if null the engine caps will be used (so true if WebGL supports it, false otherwise), but you have the possibility to override the engine capability. However, if you manually set true but the engine does not support Instanced Array, this method will return null
+         */
+        RenderablePrim2D.prototype.getDataPartEffectInfo = function (dataPartId, vertexBufferAttributes, useInstanced) {
+            if (useInstanced === void 0) { useInstanced = null; }
             var dataPart = BABYLON.Tools.first(this._instanceDataParts, function (i) { return i.id === dataPartId; });
             if (!dataPart) {
                 return null;
             }
             var instancedArray = this.owner.supportInstancedArray;
+            if (useInstanced != null) {
+                // Check if the caller ask for Instanced Array and the engine does not support it, return null if it's the case
+                if (useInstanced && instancedArray === false) {
+                    return null;
+                }
+                // Use the caller's setting
+                instancedArray = useInstanced;
+            }
             var cti = dataPart.getClassTreeInfo();
             var categories = this.getUsedShaderCategories(dataPart);
             var att = cti.classContent.getShaderAttributes(categories);
@@ -536,7 +674,7 @@ var BABYLON;
             enumerable: true,
             configurable: true
         });
-        RenderablePrim2D.prototype.createModelRenderCache = function (modelKey, isTransparent) {
+        RenderablePrim2D.prototype.createModelRenderCache = function (modelKey) {
             return null;
         };
         RenderablePrim2D.prototype.setupModelRenderCache = function (modelRenderCache) {
@@ -584,15 +722,14 @@ var BABYLON;
             }
             // Have to convert the coordinates to clip space which is ranged between [-1;1] on X and Y axis, with 0,0 being the left/bottom corner
             // Current coordinates are expressed in renderGroup coordinates ([0, renderGroup.actualSize.width|height]) with 0,0 being at the left/top corner
-            // RenderGroup Width and Height are multiplied by zBias because the VertexShader will multiply X and Y by W, which is 1/zBias. As we divide our coordinate by these Width/Height, we will also divide by the zBias to compensate the operation made by the VertexShader.
             // So for X: 
             //  - tx.x = value * 2 / width: is to switch from [0, renderGroup.width] to [0, 2]
-            //  - tx.w = (value * 2 / width) - 1: w stores the translation in renderGroup coordinates so (value * 2 / width) to switch to a clip space translation value. - 1 is to offset the overall [0;2] to [-1;1]. Don't forget it's -(1/zBias) and not -1 because everything need to be scaled by 1/zBias.
-            var w = size.width * zBias;
-            var h = size.height * zBias;
+            //  - tx.w = (value * 2 / width) - 1: w stores the translation in renderGroup coordinates so (value * 2 / width) to switch to a clip space translation value. - 1 is to offset the overall [0;2] to [-1;1].
+            var w = size.width;
+            var h = size.height;
             var invZBias = 1 / zBias;
-            var tx = new BABYLON.Vector4(t.m[0] * 2 / w, t.m[4] * 2 / w, 0 /*t.m[8]*/, ((t.m[12] + offX) * 2 / w) - (invZBias));
-            var ty = new BABYLON.Vector4(t.m[1] * 2 / h, t.m[5] * 2 / h, 0 /*t.m[9]*/, ((t.m[13] + offY) * 2 / h) - (invZBias));
+            var tx = new BABYLON.Vector4(t.m[0] * 2 / w, t.m[4] * 2 / w, 0 /*t.m[8]*/, ((t.m[12] + offX) * 2 / w) - 1);
+            var ty = new BABYLON.Vector4(t.m[1] * 2 / h, t.m[5] * 2 / h, 0 /*t.m[9]*/, ((t.m[13] + offY) * 2 / h) - 1);
             part.transformX = tx;
             part.transformY = ty;
             part.origin = this.origin;
@@ -601,12 +738,15 @@ var BABYLON;
         };
         RenderablePrim2D.RENDERABLEPRIM2D_PROPCOUNT = BABYLON.Prim2DBase.PRIM2DBASE_PROPCOUNT + 5;
         __decorate([
-            BABYLON.modelLevelProperty(BABYLON.Prim2DBase.PRIM2DBASE_PROPCOUNT + 1, function (pi) { return RenderablePrim2D.isTransparentProperty = pi; })
+            BABYLON.dynamicLevelProperty(BABYLON.Prim2DBase.PRIM2DBASE_PROPCOUNT + 0, function (pi) { return RenderablePrim2D.isAlphaTestProperty = pi; })
+        ], RenderablePrim2D.prototype, "isAlphaTest", null);
+        __decorate([
+            BABYLON.dynamicLevelProperty(BABYLON.Prim2DBase.PRIM2DBASE_PROPCOUNT + 1, function (pi) { return RenderablePrim2D.isTransparentProperty = pi; })
         ], RenderablePrim2D.prototype, "isTransparent", null);
         RenderablePrim2D = __decorate([
             BABYLON.className("RenderablePrim2D")
         ], RenderablePrim2D);
         return RenderablePrim2D;
-    }(BABYLON.Prim2DBase));
+    })(BABYLON.Prim2DBase);
     BABYLON.RenderablePrim2D = RenderablePrim2D;
 })(BABYLON || (BABYLON = {}));

+ 2 - 2
src/Canvas2d/babylon.renderablePrim2d.ts

@@ -498,7 +498,7 @@
             let ctiArray = new Array<ClassTreeInfo<InstanceClassInfo, InstancePropInfo>>();
             this._modelRenderCache._partData = new Array<ModelRenderCachePartData>();
             for (let dataPart of parts) {
-                let pd = new ModelRenderCachePartData();
+                var pd = new ModelRenderCachePartData();
                 this._modelRenderCache._partData.push(pd)
                 var cat = this.getUsedShaderCategories(dataPart);
                 var cti = dataPart.getClassTreeInfo();
@@ -507,7 +507,7 @@
                 this.isVisible = true;
                 // We manually trigger refreshInstanceData for the only sake of evaluating each instance property size and offset in the instance data, this can only be made at runtime. Once it's done we have all the information to create the instance data buffer.
                 //console.log("Build Prop Layout for " + Tools.getClassName(this._instanceDataParts[0]));
-                let joinCat = ";" + cat.join(";") + ";";
+                var joinCat = ";" + cat.join(";") + ";";
                 pd._partJoinedUsedCategories = joinCat;
                 InstanceClassInfo._CurCategories = joinCat;
                 let obj = this.beforeRefreshForLayoutConstruction(dataPart);

+ 4 - 5
src/Canvas2d/babylon.shape2d.js

@@ -48,9 +48,8 @@ var BABYLON;
             enumerable: true,
             configurable: true
         });
-        Shape2D.prototype.setupShape2D = function (owner, parent, id, position, origin, isVisible, fill, border, borderThickness) {
-            if (borderThickness === void 0) { borderThickness = 1.0; }
-            this.setupRenderablePrim2D(owner, parent, id, position, origin, isVisible);
+        Shape2D.prototype.setupShape2D = function (owner, parent, id, position, origin, isVisible, fill, border, borderThickness, marginTop, marginLeft, marginRight, marginBottom, vAlignment, hAlignment) {
+            this.setupRenderablePrim2D(owner, parent, id, position, origin, isVisible, marginTop, marginLeft, marginRight, marginBottom, hAlignment || BABYLON.Prim2DBase.HAlignLeft, vAlignment || BABYLON.Prim2DBase.VAlignTop);
             this.border = border;
             this.fill = fill;
             this.borderThickness = borderThickness;
@@ -144,7 +143,7 @@ var BABYLON;
             BABYLON.className("Shape2D")
         ], Shape2D);
         return Shape2D;
-    }(BABYLON.RenderablePrim2D));
+    })(BABYLON.RenderablePrim2D);
     BABYLON.Shape2D = Shape2D;
     var Shape2DInstanceData = (function (_super) {
         __extends(Shape2DInstanceData, _super);
@@ -244,6 +243,6 @@ var BABYLON;
             BABYLON.instanceData(Shape2D.SHAPE2D_CATEGORY_BORDERGRADIENT)
         ], Shape2DInstanceData.prototype, "borderGradientTY", null);
         return Shape2DInstanceData;
-    }(BABYLON.InstanceDataBase));
+    })(BABYLON.InstanceDataBase);
     BABYLON.Shape2DInstanceData = Shape2DInstanceData;
 })(BABYLON || (BABYLON = {}));

+ 11 - 8
src/Canvas2d/babylon.smartPropertyPrim.js

@@ -10,7 +10,7 @@ var BABYLON;
         function Prim2DClassInfo() {
         }
         return Prim2DClassInfo;
-    }());
+    })();
     BABYLON.Prim2DClassInfo = Prim2DClassInfo;
     var Prim2DPropInfo = (function () {
         function Prim2DPropInfo() {
@@ -19,13 +19,13 @@ var BABYLON;
         Prim2DPropInfo.PROPKIND_INSTANCE = 2;
         Prim2DPropInfo.PROPKIND_DYNAMIC = 3;
         return Prim2DPropInfo;
-    }());
+    })();
     BABYLON.Prim2DPropInfo = Prim2DPropInfo;
     var PropertyChangedInfo = (function () {
         function PropertyChangedInfo() {
         }
         return PropertyChangedInfo;
-    }());
+    })();
     BABYLON.PropertyChangedInfo = PropertyChangedInfo;
     var ClassTreeInfo = (function () {
         function ClassTreeInfo(baseClass, type, classContentFactory) {
@@ -62,13 +62,13 @@ var BABYLON;
         Object.defineProperty(ClassTreeInfo.prototype, "fullContent", {
             get: function () {
                 if (!this._fullContent) {
-                    var dic_1 = new BABYLON.StringDictionary();
+                    var dic = new BABYLON.StringDictionary();
                     var curLevel = this;
                     while (curLevel) {
-                        curLevel.levelContent.forEach(function (k, v) { return dic_1.add(k, v); });
+                        curLevel.levelContent.forEach(function (k, v) { return dic.add(k, v); });
                         curLevel = curLevel._baseClass;
                     }
-                    this._fullContent = dic_1;
+                    this._fullContent = dic;
                 }
                 return this._fullContent;
             },
@@ -128,7 +128,7 @@ var BABYLON;
             return dic;
         };
         return ClassTreeInfo;
-    }());
+    })();
     BABYLON.ClassTreeInfo = ClassTreeInfo;
     var SmartPropertyPrim = (function () {
         function SmartPropertyPrim() {
@@ -278,6 +278,9 @@ var BABYLON;
             return false;
         };
         SmartPropertyPrim.prototype.markAsDirty = function (propertyName) {
+            if (this.isDisposed) {
+                return;
+            }
             var i = propertyName.indexOf(".");
             if (i !== -1) {
                 propertyName = propertyName.substr(0, i);
@@ -419,7 +422,7 @@ var BABYLON;
             BABYLON.className("SmartPropertyPrim")
         ], SmartPropertyPrim);
         return SmartPropertyPrim;
-    }());
+    })();
     BABYLON.SmartPropertyPrim = SmartPropertyPrim;
     function modelLevelProperty(propId, piStore, typeLevelCompare, dirtyBoundingInfo) {
         if (typeLevelCompare === void 0) { typeLevelCompare = false; }

+ 59 - 30
src/Canvas2d/babylon.sprite2d.js

@@ -15,31 +15,44 @@ var BABYLON;
         __extends(Sprite2DRenderCache, _super);
         function Sprite2DRenderCache() {
             _super.apply(this, arguments);
+            this.effectsReady = false;
+            this.vb = null;
+            this.ib = null;
+            this.instancingAttributes = null;
+            this.texture = null;
+            this.effect = null;
+            this.effectInstanced = null;
         }
         Sprite2DRenderCache.prototype.render = function (instanceInfo, context) {
-            // Do nothing if the shader is still loading/preparing
-            if (!this.effect.isReady() || !this.texture.isReady()) {
-                return false;
+            // Do nothing if the shader is still loading/preparing 
+            if (!this.effectsReady) {
+                if ((!this.effect.isReady() || (this.effectInstanced && !this.effectInstanced.isReady()))) {
+                    return false;
+                }
+                this.effectsReady = true;
             }
             // Compute the offset locations of the attributes in the vertex shader that will be mapped to the instance buffer data
-            var engine = instanceInfo._owner.owner.engine;
-            engine.enableEffect(this.effect);
-            this.effect.setTexture("diffuseSampler", this.texture);
-            engine.bindBuffersDirectly(this.vb, this.ib, [1], 4, this.effect);
+            var engine = instanceInfo.owner.owner.engine;
+            var effect = context.useInstancing ? this.effectInstanced : this.effect;
+            engine.enableEffect(effect);
+            effect.setTexture("diffuseSampler", this.texture);
+            engine.bindBuffersDirectly(this.vb, this.ib, [1], 4, effect);
             var cur = engine.getAlphaMode();
-            engine.setAlphaMode(BABYLON.Engine.ALPHA_COMBINE);
-            var count = instanceInfo._instancesPartsData[0].usedElementCount;
-            if (instanceInfo._owner.owner.supportInstancedArray) {
+            if (context.renderMode !== BABYLON.Render2DContext.RenderModeOpaque) {
+                engine.setAlphaMode(BABYLON.Engine.ALPHA_COMBINE);
+            }
+            var pid = context.groupInfoPartData[0];
+            if (context.useInstancing) {
                 if (!this.instancingAttributes) {
-                    this.instancingAttributes = this.loadInstancingAttributes(Sprite2D.SPRITE2D_MAINPARTID, this.effect);
+                    this.instancingAttributes = this.loadInstancingAttributes(Sprite2D.SPRITE2D_MAINPARTID, effect);
                 }
-                engine.updateAndBindInstancesBuffer(instanceInfo._instancesPartsBuffer[0], null, this.instancingAttributes);
-                engine.draw(true, 0, 6, count);
+                engine.updateAndBindInstancesBuffer(pid._partBuffer, null, this.instancingAttributes);
+                engine.draw(true, 0, 6, pid._partData.usedElementCount);
                 engine.unbindInstanceAttributes();
             }
             else {
-                for (var i = 0; i < count; i++) {
-                    this.setupUniforms(this.effect, 0, instanceInfo._instancesPartsData[0], i);
+                for (var i = context.partDataStartIndex; i < context.partDataEndIndex; i++) {
+                    this.setupUniforms(effect, 0, pid._partData, i);
                     engine.draw(true, 0, 6);
                 }
             }
@@ -66,10 +79,14 @@ var BABYLON;
                 this._engine._releaseEffect(this.effect);
                 this.effect = null;
             }
+            if (this.effectInstanced) {
+                this._engine._releaseEffect(this.effectInstanced);
+                this.effectInstanced = null;
+            }
             return true;
         };
         return Sprite2DRenderCache;
-    }(BABYLON.ModelRenderCache));
+    })(BABYLON.ModelRenderCache);
     BABYLON.Sprite2DRenderCache = Sprite2DRenderCache;
     var Sprite2DInstanceData = (function (_super) {
         __extends(Sprite2DInstanceData, _super);
@@ -127,7 +144,7 @@ var BABYLON;
             BABYLON.instanceData()
         ], Sprite2DInstanceData.prototype, "invertY", null);
         return Sprite2DInstanceData;
-    }(BABYLON.InstanceDataBase));
+    })(BABYLON.InstanceDataBase);
     BABYLON.Sprite2DInstanceData = Sprite2DInstanceData;
     var Sprite2D = (function (_super) {
         __extends(Sprite2D, _super);
@@ -205,8 +222,8 @@ var BABYLON;
             // If we've made it so far it means the boundingInfo intersection test succeed, the Sprite2D is shaped the same, so we always return true
             return true;
         };
-        Sprite2D.prototype.setupSprite2D = function (owner, parent, id, position, origin, texture, spriteSize, spriteLocation, invertY) {
-            this.setupRenderablePrim2D(owner, parent, id, position, origin, true);
+        Sprite2D.prototype.setupSprite2D = function (owner, parent, id, position, origin, texture, spriteSize, spriteLocation, invertY, isVisible, marginTop, marginLeft, marginRight, marginBottom, vAlignment, hAlignment) {
+            this.setupRenderablePrim2D(owner, parent, id, position, origin, isVisible, marginTop, marginLeft, marginRight, marginBottom, hAlignment, vAlignment);
             this.texture = texture;
             this.texture.wrapU = BABYLON.Texture.CLAMP_ADDRESSMODE;
             this.texture.wrapV = BABYLON.Texture.CLAMP_ADDRESSMODE;
@@ -226,26 +243,35 @@ var BABYLON;
          * @param texture the texture that stores the sprite to render
          * options:
          *  - id a text identifier, for information purpose
-         *  - x: the X position relative to its parent, default is 0
-         *  - y: the Y position relative to its parent, default is 0
+         *  - position: the X & Y positions relative to its parent. Alternatively the x and y properties can be set. Default is [0;0]
          *  - origin: define the normalized origin point location, default [0.5;0.5]
          *  - spriteSize: the size of the sprite, if null the size of the given texture will be used, default is null.
          *  - spriteLocation: the location in the texture of the top/left corner of the Sprite to display, default is null (0,0)
          *  - invertY: if true the texture Y will be inverted, default is false.
+         *  - isVisible: true if the sprite must be visible, false for hidden. Default is true.
+         *  - marginTop/Left/Right/Bottom: define the margin for the corresponding edge, if all of them are null, margin is not used in layout computing. Default Value is null for each.
+         *  - hAlighment: define horizontal alignment of the Canvas, alignment is optional, default value null: no alignment.
+         *  - vAlighment: define horizontal alignment of the Canvas, alignment is optional, default value null: no alignment.
          */
         Sprite2D.Create = function (parent, texture, options) {
             BABYLON.Prim2DBase.CheckParent(parent);
             var sprite = new Sprite2D();
-            sprite.setupSprite2D(parent.owner, parent, options && options.id || null, new BABYLON.Vector2(options && options.x || 0, options && options.y || 0), options && options.origin || null, texture, options && options.spriteSize || null, options && options.spriteLocation || null, options && options.invertY || false);
+            if (!options) {
+                sprite.setupSprite2D(parent.owner, parent, null, BABYLON.Vector2.Zero(), null, texture, null, null, false, true, null, null, null, null, null, null);
+            }
+            else {
+                var pos = options.position || new BABYLON.Vector2(options.x || 0, options.y || 0);
+                sprite.setupSprite2D(parent.owner, parent, options.id || null, pos, options.origin || null, texture, options.spriteSize || null, options.spriteLocation || null, options.invertY || false, options.isVisible || true, options.marginTop || null, options.marginLeft || null, options.marginRight || null, options.marginBottom || null, options.vAlignment || null, options.hAlignment || null);
+            }
             return sprite;
         };
         Sprite2D._createCachedCanvasSprite = function (owner, texture, size, pos) {
             var sprite = new Sprite2D();
-            sprite.setupSprite2D(owner, null, "__cachedCanvasSprite__", new BABYLON.Vector2(0, 0), null, texture, size, pos, false);
+            sprite.setupSprite2D(owner, null, "__cachedCanvasSprite__", new BABYLON.Vector2(0, 0), null, texture, size, pos, false, true, null, null, null, null, null, null);
             return sprite;
         };
-        Sprite2D.prototype.createModelRenderCache = function (modelKey, isTransparent) {
-            var renderCache = new Sprite2DRenderCache(this.owner.engine, modelKey, isTransparent);
+        Sprite2D.prototype.createModelRenderCache = function (modelKey) {
+            var renderCache = new Sprite2DRenderCache(this.owner.engine, modelKey);
             return renderCache;
         };
         Sprite2D.prototype.setupModelRenderCache = function (modelRenderCache) {
@@ -265,10 +291,13 @@ var BABYLON;
             ib[5] = 2;
             renderCache.ib = engine.createIndexBuffer(ib);
             renderCache.texture = this.texture;
-            var ei = this.getDataPartEffectInfo(Sprite2D.SPRITE2D_MAINPARTID, ["index"]);
-            renderCache.effect = engine.createEffect({ vertex: "sprite2d", fragment: "sprite2d" }, ei.attributes, ei.uniforms, ["diffuseSampler"], ei.defines, null, function (e) {
-                //                renderCache.setupUniformsLocation(e, ei.uniforms, Sprite2D.SPRITE2D_MAINPARTID);
-            });
+            // Get the instanced version of the effect, if the engine does not support it, null is return and we'll only draw on by one
+            var ei = this.getDataPartEffectInfo(Sprite2D.SPRITE2D_MAINPARTID, ["index"], true);
+            if (ei) {
+                renderCache.effectInstanced = engine.createEffect("sprite2d", ei.attributes, ei.uniforms, ["diffuseSampler"], ei.defines, null);
+            }
+            ei = this.getDataPartEffectInfo(Sprite2D.SPRITE2D_MAINPARTID, ["index"], false);
+            renderCache.effect = engine.createEffect("sprite2d", ei.attributes, ei.uniforms, ["diffuseSampler"], ei.defines, null);
             return renderCache;
         };
         Sprite2D.prototype.createInstanceDataParts = function () {
@@ -312,6 +341,6 @@ var BABYLON;
             BABYLON.className("Sprite2D")
         ], Sprite2D);
         return Sprite2D;
-    }(BABYLON.RenderablePrim2D));
+    })(BABYLON.RenderablePrim2D);
     BABYLON.Sprite2D = Sprite2D;
 })(BABYLON || (BABYLON = {}));

Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 60 - 69
src/Canvas2d/babylon.text2d.js


+ 1 - 1
src/Canvas2d/babylon.worldSpaceCanvas2d.js

@@ -22,6 +22,6 @@ var BABYLON;
             }
         };
         return WorldSpaceCanvas2D;
-    }(BABYLON.Mesh));
+    })(BABYLON.Mesh);
     BABYLON.WorldSpaceCanvas2D = WorldSpaceCanvas2D;
 })(BABYLON || (BABYLON = {}));

+ 1 - 1
src/Collisions/babylon.collider.js

@@ -267,6 +267,6 @@ var BABYLON;
             this._destinationPoint.subtractToRef(this.intersectionPoint, vel);
         };
         return Collider;
-    }());
+    })();
     BABYLON.Collider = Collider;
 })(BABYLON || (BABYLON = {}));

+ 2 - 2
src/Collisions/babylon.collisionCoordinator.js

@@ -205,7 +205,7 @@ var BABYLON;
             };
         };
         return CollisionCoordinatorWorker;
-    }());
+    })();
     BABYLON.CollisionCoordinatorWorker = CollisionCoordinatorWorker;
     var CollisionCoordinatorLegacy = (function () {
         function CollisionCoordinatorLegacy() {
@@ -268,6 +268,6 @@ var BABYLON;
             this._collideWithWorld(position, velocity, collider, maximumRetry, finalPosition, excludedMesh);
         };
         return CollisionCoordinatorLegacy;
-    }());
+    })();
     BABYLON.CollisionCoordinatorLegacy = CollisionCoordinatorLegacy;
 })(BABYLON || (BABYLON = {}));

+ 3 - 3
src/Collisions/babylon.collisionWorker.js

@@ -32,7 +32,7 @@ var BABYLON;
             delete this._geometries[id];
         };
         return CollisionCache;
-    }());
+    })();
     BABYLON.CollisionCache = CollisionCache;
     var CollideWorker = (function () {
         function CollideWorker(collider, _collisionCache, finalPosition) {
@@ -144,7 +144,7 @@ var BABYLON;
             return this.collider._canDoCollision(BABYLON.Vector3.FromArray(subMesh.sphereCenter), subMesh.sphereRadius, BABYLON.Vector3.FromArray(subMesh.boxMinimum), BABYLON.Vector3.FromArray(subMesh.boxMaximum));
         };
         return CollideWorker;
-    }());
+    })();
     BABYLON.CollideWorker = CollideWorker;
     var CollisionDetectorTransferable = (function () {
         function CollisionDetectorTransferable() {
@@ -206,7 +206,7 @@ var BABYLON;
             postMessage(reply, undefined);
         };
         return CollisionDetectorTransferable;
-    }());
+    })();
     BABYLON.CollisionDetectorTransferable = CollisionDetectorTransferable;
     //check if we are in a web worker, as this code should NOT run on the main UI thread
     try {

+ 2 - 2
src/Collisions/babylon.pickingInfo.js

@@ -9,7 +9,7 @@ var BABYLON;
             this.subMeshId = 0;
         }
         return IntersectionInfo;
-    }());
+    })();
     BABYLON.IntersectionInfo = IntersectionInfo;
     var PickingInfo = (function () {
         function PickingInfo() {
@@ -71,6 +71,6 @@ var BABYLON;
             return new BABYLON.Vector2(uv0.x + uv1.x + uv2.x, uv0.y + uv1.y + uv2.y);
         };
         return PickingInfo;
-    }());
+    })();
     BABYLON.PickingInfo = PickingInfo;
 })(BABYLON || (BABYLON = {}));

+ 1 - 1
src/Culling/Octrees/babylon.octree.js

@@ -83,6 +83,6 @@ var BABYLON;
             }
         };
         return Octree;
-    }());
+    })();
     BABYLON.Octree = Octree;
 })(BABYLON || (BABYLON = {}));

+ 1 - 1
src/Culling/Octrees/babylon.octreeBlock.js

@@ -117,6 +117,6 @@ var BABYLON;
             BABYLON.Octree._CreateBlocks(this._minPoint, this._maxPoint, this.entries, this._capacity, this._depth, this._maxDepth, this, this._creationFunc);
         };
         return OctreeBlock;
-    }());
+    })();
     BABYLON.OctreeBlock = OctreeBlock;
 })(BABYLON || (BABYLON = {}));

+ 1 - 1
src/Culling/babylon.boundingBox.js

@@ -138,6 +138,6 @@ var BABYLON;
             return true;
         };
         return BoundingBox;
-    }());
+    })();
     BABYLON.BoundingBox = BoundingBox;
 })(BABYLON || (BABYLON = {}));

+ 1 - 1
src/Culling/babylon.boundingInfo.js

@@ -114,6 +114,6 @@ var BABYLON;
             return true;
         };
         return BoundingInfo;
-    }());
+    })();
     BABYLON.BoundingInfo = BoundingInfo;
 })(BABYLON || (BABYLON = {}));

+ 1 - 1
src/Culling/babylon.boundingSphere.js

@@ -44,6 +44,6 @@ var BABYLON;
             return true;
         };
         return BoundingSphere;
-    }());
+    })();
     BABYLON.BoundingSphere = BoundingSphere;
 })(BABYLON || (BABYLON = {}));

+ 1 - 1
src/Culling/babylon.ray.js

@@ -269,6 +269,6 @@ var BABYLON;
         Ray.smallnum = 0.00000001;
         Ray.rayl = 10e8;
         return Ray;
-    }());
+    })();
     BABYLON.Ray = Ray;
 })(BABYLON || (BABYLON = {}));

+ 1 - 1
src/Debug/babylon.debugLayer.js

@@ -674,6 +674,6 @@ var BABYLON;
             }
         };
         return DebugLayer;
-    }());
+    })();
     BABYLON.DebugLayer = DebugLayer;
 })(BABYLON || (BABYLON = {}));

+ 1 - 1
src/Debug/babylon.skeletonViewer.js

@@ -131,7 +131,7 @@ var BABYLON;
                 }
             };
             return SkeletonViewer;
-        }());
+        })();
         Debug.SkeletonViewer = SkeletonViewer;
     })(Debug = BABYLON.Debug || (BABYLON.Debug = {}));
 })(BABYLON || (BABYLON = {}));

+ 1 - 1
src/Layer/babylon.layer.js

@@ -135,6 +135,6 @@ var BABYLON;
             this.onBeforeRenderObservable.clear();
         };
         return Layer;
-    }());
+    })();
     BABYLON.Layer = Layer;
 })(BABYLON || (BABYLON = {}));

+ 1 - 1
src/LensFlare/babylon.lensFlare.js

@@ -18,6 +18,6 @@ var BABYLON;
             system.lensFlares.push(this);
         }
         return LensFlare;
-    }());
+    })();
     BABYLON.LensFlare = LensFlare;
 })(BABYLON || (BABYLON = {}));

+ 1 - 1
src/LensFlare/babylon.lensFlareSystem.js

@@ -209,6 +209,6 @@ var BABYLON;
             return serializationObject;
         };
         return LensFlareSystem;
-    }());
+    })();
     BABYLON.LensFlareSystem = LensFlareSystem;
 })(BABYLON || (BABYLON = {}));

+ 1 - 1
src/Lights/Shadows/babylon.shadowGenerator.js

@@ -402,6 +402,6 @@ var BABYLON;
         ShadowGenerator._FILTER_POISSONSAMPLING = 2;
         ShadowGenerator._FILTER_BLURVARIANCESHADOWMAP = 3;
         return ShadowGenerator;
-    }());
+    })();
     BABYLON.ShadowGenerator = ShadowGenerator;
 })(BABYLON || (BABYLON = {}));

+ 1 - 1
src/Lights/babylon.directionalLight.js

@@ -124,6 +124,6 @@ var BABYLON;
             BABYLON.serialize()
         ], DirectionalLight.prototype, "autoUpdateExtends", void 0);
         return DirectionalLight;
-    }(BABYLON.Light));
+    })(BABYLON.Light);
     BABYLON.DirectionalLight = DirectionalLight;
 })(BABYLON || (BABYLON = {}));

+ 1 - 1
src/Lights/babylon.hemisphericLight.js

@@ -46,6 +46,6 @@ var BABYLON;
             BABYLON.serializeAsVector3()
         ], HemisphericLight.prototype, "direction", void 0);
         return HemisphericLight;
-    }(BABYLON.Light));
+    })(BABYLON.Light);
     BABYLON.HemisphericLight = HemisphericLight;
 })(BABYLON || (BABYLON = {}));

+ 1 - 1
src/Lights/babylon.light.js

@@ -189,6 +189,6 @@ var BABYLON;
             BABYLON.serialize()
         ], Light.prototype, "radius", void 0);
         return Light;
-    }(BABYLON.Node));
+    })(BABYLON.Node);
     BABYLON.Light = Light;
 })(BABYLON || (BABYLON = {}));

+ 1 - 1
src/Lights/babylon.pointLight.js

@@ -82,6 +82,6 @@ var BABYLON;
             BABYLON.serializeAsVector3()
         ], PointLight.prototype, "position", void 0);
         return PointLight;
-    }(BABYLON.Light));
+    })(BABYLON.Light);
     BABYLON.PointLight = PointLight;
 })(BABYLON || (BABYLON = {}));

+ 1 - 1
src/Lights/babylon.spotLight.js

@@ -93,6 +93,6 @@ var BABYLON;
             BABYLON.serialize()
         ], SpotLight.prototype, "exponent", void 0);
         return SpotLight;
-    }(BABYLON.Light));
+    })(BABYLON.Light);
     BABYLON.SpotLight = SpotLight;
 })(BABYLON || (BABYLON = {}));

+ 1 - 1
src/Loading/babylon.sceneLoader.js

@@ -257,7 +257,7 @@ var BABYLON;
         // Members
         SceneLoader._registeredPlugins = new Array();
         return SceneLoader;
-    }());
+    })();
     BABYLON.SceneLoader = SceneLoader;
     ;
 })(BABYLON || (BABYLON = {}));

+ 1 - 1
src/Materials/Textures/Procedurals/babylon.customProceduralTexture.js

@@ -119,6 +119,6 @@ var BABYLON;
             configurable: true
         });
         return CustomProceduralTexture;
-    }(BABYLON.ProceduralTexture));
+    })(BABYLON.ProceduralTexture);
     BABYLON.CustomProceduralTexture = CustomProceduralTexture;
 })(BABYLON || (BABYLON = {}));

+ 1 - 1
src/Materials/Textures/Procedurals/babylon.proceduralTexture.js

@@ -279,6 +279,6 @@ var BABYLON;
             _super.prototype.dispose.call(this);
         };
         return ProceduralTexture;
-    }(BABYLON.Texture));
+    })(BABYLON.Texture);
     BABYLON.ProceduralTexture = ProceduralTexture;
 })(BABYLON || (BABYLON = {}));

+ 1 - 1
src/Materials/Textures/babylon.baseTexture.js

@@ -182,6 +182,6 @@ var BABYLON;
             BABYLON.serialize()
         ], BaseTexture.prototype, "isRenderTarget", void 0);
         return BaseTexture;
-    }());
+    })();
     BABYLON.BaseTexture = BaseTexture;
 })(BABYLON || (BABYLON = {}));

+ 1 - 1
src/Materials/Textures/babylon.colorGradingTexture.js

@@ -177,6 +177,6 @@ var BABYLON;
          */
         ColorGradingTexture._noneEmptyLineRegex = /\S+/;
         return ColorGradingTexture;
-    }(BABYLON.BaseTexture));
+    })(BABYLON.BaseTexture);
     BABYLON.ColorGradingTexture = ColorGradingTexture;
 })(BABYLON || (BABYLON = {}));

+ 1 - 1
src/Materials/Textures/babylon.cubeTexture.js

@@ -77,6 +77,6 @@ var BABYLON;
             }, this);
         };
         return CubeTexture;
-    }(BABYLON.BaseTexture));
+    })(BABYLON.BaseTexture);
     BABYLON.CubeTexture = CubeTexture;
 })(BABYLON || (BABYLON = {}));

+ 1 - 1
src/Materials/Textures/babylon.dynamicTexture.js

@@ -88,6 +88,6 @@ var BABYLON;
             return newTexture;
         };
         return DynamicTexture;
-    }(BABYLON.Texture));
+    })(BABYLON.Texture);
     BABYLON.DynamicTexture = DynamicTexture;
 })(BABYLON || (BABYLON = {}));

+ 4 - 4
src/Materials/Textures/babylon.fontTexture.js

@@ -12,7 +12,7 @@ var BABYLON;
         function CharInfo() {
         }
         return CharInfo;
-    }());
+    })();
     BABYLON.CharInfo = CharInfo;
     var FontTexture = (function (_super) {
         __extends(FontTexture, _super);
@@ -160,8 +160,8 @@ var BABYLON;
             var lineCount = 1;
             var charxpos = 0;
             // Parse each char of the string
-            for (var _i = 0, text_1 = text; _i < text_1.length; _i++) {
-                var char = text_1[_i];
+            for (var _i = 0; _i < text.length; _i++) {
+                var char = text[_i];
                 // Next line feed?
                 if (char === "\n") {
                     maxWidth = Math.max(maxWidth, curWidth);
@@ -246,6 +246,6 @@ var BABYLON;
             return null;
         };
         return FontTexture;
-    }(BABYLON.Texture));
+    })(BABYLON.Texture);
     BABYLON.FontTexture = FontTexture;
 })(BABYLON || (BABYLON = {}));

+ 1 - 1
src/Materials/Textures/babylon.hdrCubeTexture.js

@@ -442,6 +442,6 @@ var BABYLON;
             "back"
         ];
         return HDRCubeTexture;
-    }(BABYLON.BaseTexture));
+    })(BABYLON.BaseTexture);
     BABYLON.HDRCubeTexture = HDRCubeTexture;
 })(BABYLON || (BABYLON = {}));

+ 1 - 1
src/Materials/Textures/babylon.mapTexture.js

@@ -105,6 +105,6 @@ var BABYLON;
             return null;
         };
         return MapTexture;
-    }(BABYLON.Texture));
+    })(BABYLON.Texture);
     BABYLON.MapTexture = MapTexture;
 })(BABYLON || (BABYLON = {}));

+ 1 - 1
src/Materials/Textures/babylon.mirrorTexture.js

@@ -49,6 +49,6 @@ var BABYLON;
             return serializationObject;
         };
         return MirrorTexture;
-    }(BABYLON.RenderTargetTexture));
+    })(BABYLON.RenderTargetTexture);
     BABYLON.MirrorTexture = MirrorTexture;
 })(BABYLON || (BABYLON = {}));

+ 1 - 1
src/Materials/Textures/babylon.rawTexture.js

@@ -52,6 +52,6 @@ var BABYLON;
             return new RawTexture(data, width, height, BABYLON.Engine.TEXTUREFORMAT_RGBA, scene, generateMipMaps, invertY, samplingMode);
         };
         return RawTexture;
-    }(BABYLON.Texture));
+    })(BABYLON.Texture);
     BABYLON.RawTexture = RawTexture;
 })(BABYLON || (BABYLON = {}));

+ 1 - 1
src/Materials/Textures/babylon.refractionTexture.js

@@ -47,6 +47,6 @@ var BABYLON;
             return serializationObject;
         };
         return RefractionTexture;
-    }(BABYLON.RenderTargetTexture));
+    })(BABYLON.RenderTargetTexture);
     BABYLON.RefractionTexture = RefractionTexture;
 })(BABYLON || (BABYLON = {}));

+ 1 - 1
src/Materials/Textures/babylon.renderTargetTexture.js

@@ -329,6 +329,6 @@ var BABYLON;
         RenderTargetTexture._REFRESHRATE_RENDER_ONEVERYFRAME = 1;
         RenderTargetTexture._REFRESHRATE_RENDER_ONEVERYTWOFRAMES = 2;
         return RenderTargetTexture;
-    }(BABYLON.Texture));
+    })(BABYLON.Texture);
     BABYLON.RenderTargetTexture = RenderTargetTexture;
 })(BABYLON || (BABYLON = {}));

+ 0 - 0
src/Materials/Textures/babylon.texture.js


Kaikkia tiedostoja ei voida näyttää, sillä liian monta tiedostoa muuttui tässä diffissä