瀏覽代碼

Merge pull request #7 from BabylonJS/master

update from upstream
Loïc Baumann 9 年之前
父節點
當前提交
70da4aea6b
共有 100 個文件被更改,包括 12955 次插入7099 次删除
  1. 8 2
      Exporters/Blender/io_export_babylon.py
  2. 2 0
      Exporters/Unity 5/Unity3D2Babylon/ExportationOptions.cs
  3. 1 1
      Exporters/Unity 5/Unity3D2Babylon/ExporterWindow.cs
  4. 27 23
      Tools/Gulp/config.json
  5. 21 10
      Tools/Gulp/gulpfile.js
  6. 2 1
      Tools/Gulp/package.json
  7. 25 25
      dist/preview release/babylon.core.js
  8. 6315 5696
      dist/preview release/babylon.d.ts
  9. 38 37
      dist/preview release/babylon.js
  10. 3204 847
      dist/preview release/babylon.max.js
  11. 38 37
      dist/preview release/babylon.noworker.js
  12. 26 8
      dist/preview release/what's new.md
  13. 1 1
      src/Actions/babylon.action.js
  14. 2 2
      src/Actions/babylon.actionManager.js
  15. 4 4
      src/Actions/babylon.condition.js
  16. 12 12
      src/Actions/babylon.directActions.js
  17. 1 1
      src/Actions/babylon.interpolateValueAction.js
  18. 1 1
      src/Animations/babylon.animatable.js
  19. 4 4
      src/Animations/babylon.animation.js
  20. 13 13
      src/Animations/babylon.easing.js
  21. 1 1
      src/Audio/babylon.analyser.js
  22. 1 1
      src/Audio/babylon.audioEngine.js
  23. 1 1
      src/Audio/babylon.sound.js
  24. 1 1
      src/Audio/babylon.soundtrack.js
  25. 1 1
      src/Bones/babylon.bone.js
  26. 5 1
      src/Bones/babylon.skeleton.js
  27. 20 16
      src/Bones/babylon.skeleton.ts
  28. 1 1
      src/Cameras/Inputs/babylon.arcrotatecamera.input.gamepad.js
  29. 1 1
      src/Cameras/Inputs/babylon.arcrotatecamera.input.keyboard.js
  30. 1 1
      src/Cameras/Inputs/babylon.arcrotatecamera.input.mousewheel.js
  31. 1 1
      src/Cameras/Inputs/babylon.arcrotatecamera.input.pointers.js
  32. 1 1
      src/Cameras/Inputs/babylon.arcrotatecamera.input.vrdeviceorientation.js
  33. 1 1
      src/Cameras/Inputs/babylon.freecamera.input.deviceorientation.js
  34. 1 1
      src/Cameras/Inputs/babylon.freecamera.input.gamepad.js
  35. 1 1
      src/Cameras/Inputs/babylon.freecamera.input.keyboard.js
  36. 1 1
      src/Cameras/Inputs/babylon.freecamera.input.mouse.js
  37. 1 1
      src/Cameras/Inputs/babylon.freecamera.input.touch.js
  38. 1 1
      src/Cameras/Inputs/babylon.freecamera.input.virtualjoystick.js
  39. 1 1
      src/Cameras/Inputs/babylon.freecamera.input.vrdeviceorientation.js
  40. 1 1
      src/Cameras/VR/babylon.vrCameraMetrics.js
  41. 2 2
      src/Cameras/VR/babylon.vrDeviceOrientationCamera.js
  42. 11 8
      src/Cameras/VR/babylon.webVRCamera.js
  43. 12 9
      src/Cameras/VR/babylon.webVRCamera.ts
  44. 1 1
      src/Cameras/babylon.arcRotateCamera.js
  45. 1 1
      src/Cameras/babylon.arcRotateCameraInputsManager.js
  46. 4 1
      src/Cameras/babylon.camera.js
  47. 37 38
      src/Cameras/babylon.camera.ts
  48. 1 1
      src/Cameras/babylon.cameraInputsManager.js
  49. 1 1
      src/Cameras/babylon.deviceOrientationCamera.js
  50. 2 2
      src/Cameras/babylon.followCamera.js
  51. 1 1
      src/Cameras/babylon.freeCamera.js
  52. 1 1
      src/Cameras/babylon.freeCameraInputsManager.js
  53. 1 1
      src/Cameras/babylon.gamepadCamera.js
  54. 8 8
      src/Cameras/babylon.stereoscopicCameras.js
  55. 1 1
      src/Cameras/babylon.targetCamera.js
  56. 1 1
      src/Cameras/babylon.touchCamera.js
  57. 1 1
      src/Cameras/babylon.universalCamera.js
  58. 1 1
      src/Cameras/babylon.virtualJoysticksCamera.js
  59. 3 3
      src/Canvas2d/babylon.bounding2d.js
  60. 3 3
      src/Canvas2d/babylon.brushes2d.js
  61. 42 37
      src/Canvas2d/babylon.canvas2d.js
  62. 46 33
      src/Canvas2d/babylon.canvas2d.ts
  63. 306 0
      src/Canvas2d/babylon.ellipse2d.js
  64. 321 0
      src/Canvas2d/babylon.ellipse2d.ts
  65. 21 11
      src/Canvas2d/babylon.group2d.js
  66. 17 6
      src/Canvas2d/babylon.group2d.ts
  67. 991 0
      src/Canvas2d/babylon.lines2d.js
  68. 973 0
      src/Canvas2d/babylon.lines2d.ts
  69. 2 2
      src/Canvas2d/babylon.modelRenderCache.js
  70. 1 1
      src/Canvas2d/babylon.modelRenderCache.ts
  71. 9 9
      src/Canvas2d/babylon.prim2dBase.js
  72. 2 2
      src/Canvas2d/babylon.prim2dBase.ts
  73. 34 22
      src/Canvas2d/babylon.rectangle2d.js
  74. 30 19
      src/Canvas2d/babylon.rectangle2d.ts
  75. 48 12
      src/Canvas2d/babylon.renderablePrim2d.js
  76. 46 6
      src/Canvas2d/babylon.renderablePrim2d.ts
  77. 4 4
      src/Canvas2d/babylon.shape2d.js
  78. 2 4
      src/Canvas2d/babylon.shape2d.ts
  79. 21 8
      src/Canvas2d/babylon.smartPropertyPrim.js
  80. 16 1
      src/Canvas2d/babylon.smartPropertyPrim.ts
  81. 30 14
      src/Canvas2d/babylon.sprite2d.js
  82. 28 10
      src/Canvas2d/babylon.sprite2d.ts
  83. 25 12
      src/Canvas2d/babylon.text2d.js
  84. 22 6
      src/Canvas2d/babylon.text2d.ts
  85. 7 7
      src/Canvas2d/babylon.worldSpaceCanvas2d.js
  86. 1 1
      src/Canvas2d/babylon.worldSpaceCanvas2d.ts
  87. 1 1
      src/Collisions/babylon.collider.js
  88. 2 2
      src/Collisions/babylon.collisionCoordinator.js
  89. 3 3
      src/Collisions/babylon.collisionWorker.js
  90. 2 2
      src/Collisions/babylon.pickingInfo.js
  91. 1 1
      src/Culling/Octrees/babylon.octree.js
  92. 1 1
      src/Culling/Octrees/babylon.octreeBlock.js
  93. 1 1
      src/Culling/babylon.boundingBox.js
  94. 1 1
      src/Culling/babylon.boundingInfo.js
  95. 1 1
      src/Culling/babylon.boundingSphere.js
  96. 1 1
      src/Culling/babylon.ray.js
  97. 1 1
      src/Debug/babylon.debugLayer.js
  98. 1 1
      src/Debug/babylon.skeletonViewer.js
  99. 13 11
      src/Layer/babylon.layer.js
  100. 0 0
      src/Layer/babylon.layer.ts

+ 8 - 2
Exporters/Blender/io_export_babylon.py

@@ -1,7 +1,7 @@
 bl_info = {
 bl_info = {
     'name': 'Babylon.js',
     'name': 'Babylon.js',
     'author': 'David Catuhe, Jeff Palmer',
     'author': 'David Catuhe, Jeff Palmer',
-    'version': (4, 5, 0),
+    'version': (4, 6, 0),
     'blender': (2, 75, 0),
     'blender': (2, 75, 0),
     'location': 'File > Export > Babylon.js (.babylon)',
     'location': 'File > Export > Babylon.js (.babylon)',
     'description': 'Export Babylon.js scenes (.babylon)',
     'description': 'Export Babylon.js scenes (.babylon)',
@@ -304,6 +304,7 @@ class Main(bpy.types.Operator, bpy_extras.io_utils.ExportHelper):
 
 
             # separate loop doing all skeletons, so available in Mesh to make skipping IK bones possible
             # separate loop doing all skeletons, so available in Mesh to make skipping IK bones possible
             for object in [object for object in scene.objects]:
             for object in [object for object in scene.objects]:
+                scene.frame_set(currentFrame)
                 if object.type == 'ARMATURE':  #skeleton.pose.bones
                 if object.type == 'ARMATURE':  #skeleton.pose.bones
                     if object.is_visible(scene):
                     if object.is_visible(scene):
                         self.skeletons.append(Skeleton(object, scene, skeletonId))
                         self.skeletons.append(Skeleton(object, scene, skeletonId))
@@ -311,9 +312,9 @@ class Main(bpy.types.Operator, bpy_extras.io_utils.ExportHelper):
                     else:
                     else:
                         Main.warn('The following armature not visible in scene thus ignored: ' + object.name)
                         Main.warn('The following armature not visible in scene thus ignored: ' + object.name)
 
 
-            bpy.context.scene.frame_set(0)
             # exclude lamps in this pass, so ShadowGenerator constructor can be passed meshesAnNodes
             # exclude lamps in this pass, so ShadowGenerator constructor can be passed meshesAnNodes
             for object in [object for object in scene.objects]:
             for object in [object for object in scene.objects]:
+                scene.frame_set(currentFrame)
                 if object.type == 'CAMERA':
                 if object.type == 'CAMERA':
                     if object.is_visible(scene): # no isInSelectedLayer() required, is_visible() handles this for them
                     if object.is_visible(scene): # no isInSelectedLayer() required, is_visible() handles this for them
                         self.cameras.append(Camera(object))
                         self.cameras.append(Camera(object))
@@ -354,6 +355,7 @@ class Main(bpy.types.Operator, bpy_extras.io_utils.ExportHelper):
 
 
             # Lamp / shadow Generator pass; meshesAnNodes complete & forceParents included
             # Lamp / shadow Generator pass; meshesAnNodes complete & forceParents included
             for object in [object for object in scene.objects]:
             for object in [object for object in scene.objects]:
+                scene.frame_set(currentFrame)
                 if object.type == 'LAMP':
                 if object.type == 'LAMP':
                     if object.is_visible(scene): # no isInSelectedLayer() required, is_visible() handles this for them
                     if object.is_visible(scene): # no isInSelectedLayer() required, is_visible() handles this for them
                         bulb = Light(object)
                         bulb = Light(object)
@@ -1425,6 +1427,9 @@ class Skeleton:
         scene.objects.active = skeleton
         scene.objects.active = skeleton
         bpy.ops.object.mode_set(mode='EDIT')
         bpy.ops.object.mode_set(mode='EDIT')
 
 
+        # dimensions when in edit mode, are those at rest
+        self.dimensions = skeleton.dimensions
+
         # you need to access edit_bones from skeleton.data not skeleton.pose when in edit mode
         # you need to access edit_bones from skeleton.data not skeleton.pose when in edit mode
         for editBone in skeleton.data.edit_bones:
         for editBone in skeleton.data.edit_bones:
             for myBoneObj in self.bones:
             for myBoneObj in self.bones:
@@ -1447,6 +1452,7 @@ class Skeleton:
         file_handler.write('{')
         file_handler.write('{')
         write_string(file_handler, 'name', self.name, True)
         write_string(file_handler, 'name', self.name, True)
         write_int(file_handler, 'id', self.id)  # keep int for legacy of original exporter
         write_int(file_handler, 'id', self.id)  # keep int for legacy of original exporter
+        write_vector(file_handler, 'dimensionsAtRest', self.dimensions)
 
 
         file_handler.write(',"bones":[')
         file_handler.write(',"bones":[')
         first = True
         first = True

+ 2 - 0
Exporters/Unity 5/Unity3D2Babylon/ExportationOptions.cs

@@ -9,6 +9,7 @@ namespace Unity3D2Babylon
         public float ReflectionDefaultLevel { get; set; }
         public float ReflectionDefaultLevel { get; set; }
         public bool ExportCollisions { get; set; }
         public bool ExportCollisions { get; set; }
         public bool ExportPhysics { get; set; }
         public bool ExportPhysics { get; set; }
+        public bool ExportShadows { get; set; }
         public SerializableVector3 CameraEllipsoid { get; set; }
         public SerializableVector3 CameraEllipsoid { get; set; }
         public SerializableVector3 Gravity { get; set; }
         public SerializableVector3 Gravity { get; set; }
 
 
@@ -18,6 +19,7 @@ namespace Unity3D2Babylon
             ReflectionDefaultLevel = 0.3f;
             ReflectionDefaultLevel = 0.3f;
             ExportCollisions = false;
             ExportCollisions = false;
             ExportPhysics = false;
             ExportPhysics = false;
+            ExportShadows = false;
             CameraEllipsoid = new Vector3(0.5f, 1.0f, 0.5f);
             CameraEllipsoid = new Vector3(0.5f, 1.0f, 0.5f);
             Gravity = new Vector3(0, -0.9f, 0);
             Gravity = new Vector3(0, -0.9f, 0);
         }
         }

+ 1 - 1
Exporters/Unity 5/Unity3D2Babylon/ExporterWindow.cs

@@ -143,7 +143,7 @@ namespace Unity3D2Babylon
                 var outputFile = sceneBuilder.WriteToBabylonFile();
                 var outputFile = sceneBuilder.WriteToBabylonFile();
 
 
                 watch.Stop();
                 watch.Stop();
-                ReportProgress(1, $"Exportation done in {watch.Elapsed.TotalSeconds:0.00}s");
+                ReportProgress(1, string.Format("Exportation done in {0:0.00}s", watch.Elapsed.TotalSeconds));
                 EditorUtility.ClearProgressBar();
                 EditorUtility.ClearProgressBar();
 
 
                 sceneBuilder.GenerateStatus(logs);
                 sceneBuilder.GenerateStatus(logs);

+ 27 - 23
Tools/Gulp/config.json

@@ -14,7 +14,7 @@
       "!../../src/**/*.d.ts",
       "!../../src/**/*.d.ts",
       "../../external references/**/*.d.ts"
       "../../external references/**/*.d.ts"
     ],
     ],
-   "files": [
+    "files": [
       "../../src/Math/babylon.math.js",
       "../../src/Math/babylon.math.js",
       "../../src/Tools/babylon.decorators.js",
       "../../src/Tools/babylon.decorators.js",
       "../../src/Tools/babylon.observable.js",
       "../../src/Tools/babylon.observable.js",
@@ -43,18 +43,18 @@
       "../../src/Collisions/babylon.collider.js",
       "../../src/Collisions/babylon.collider.js",
       "../../src/Collisions/babylon.collisionCoordinator.js",
       "../../src/Collisions/babylon.collisionCoordinator.js",
       "../../src/Cameras/babylon.camera.js",
       "../../src/Cameras/babylon.camera.js",
-      "../../src/Cameras/babylon.camerainputsmanager.js",
-      "../../src/Cameras/inputs/babylon.freecamera.input.mouse.js",
-      "../../src/Cameras/inputs/babylon.freecamera.input.keyboard.js",
-      "../../src/Cameras/inputs/babylon.freecamera.input.touch.js",
-      "../../src/Cameras/inputs/babylon.freecamera.input.deviceorientation.js",
-      "../../src/Cameras/inputs/babylon.freecamera.input.vrdeviceorientation.js",
-      "../../src/Cameras/inputs/babylon.freecamera.input.gamepad.js",
-      "../../src/Cameras/inputs/babylon.arcrotatecamera.input.keyboard.js",
-      "../../src/Cameras/inputs/babylon.arcrotatecamera.input.mousewheel.js",
-      "../../src/Cameras/inputs/babylon.arcrotatecamera.input.pointers.js",
-      "../../src/Cameras/inputs/babylon.arcrotatecamera.input.gamepad.js",
-      "../../src/Cameras/inputs/babylon.arcrotatecamera.input.vrdeviceorientation.js",
+      "../../src/Cameras/babylon.cameraInputsManager.js",
+      "../../src/Cameras/Inputs/babylon.freecamera.input.mouse.js",
+      "../../src/Cameras/Inputs/babylon.freecamera.input.keyboard.js",
+      "../../src/Cameras/Inputs/babylon.freecamera.input.touch.js",
+      "../../src/Cameras/Inputs/babylon.freecamera.input.deviceorientation.js",
+      "../../src/Cameras/Inputs/babylon.freecamera.input.vrdeviceorientation.js",
+      "../../src/Cameras/Inputs/babylon.freecamera.input.gamepad.js",
+      "../../src/Cameras/Inputs/babylon.arcrotatecamera.input.keyboard.js",
+      "../../src/Cameras/Inputs/babylon.arcrotatecamera.input.mousewheel.js",
+      "../../src/Cameras/Inputs/babylon.arcrotatecamera.input.pointers.js",
+      "../../src/Cameras/Inputs/babylon.arcrotatecamera.input.gamepad.js",
+      "../../src/Cameras/Inputs/babylon.arcrotatecamera.input.vrdeviceorientation.js",
       "../../src/Cameras/babylon.targetCamera.js",
       "../../src/Cameras/babylon.targetCamera.js",
       "../../src/Cameras/babylon.freeCamera.js",
       "../../src/Cameras/babylon.freeCamera.js",
       "../../src/Cameras/babylon.freeCameraInputsManager.js",
       "../../src/Cameras/babylon.freeCameraInputsManager.js",
@@ -65,6 +65,7 @@
       "../../src/Rendering/babylon.renderingManager.js",
       "../../src/Rendering/babylon.renderingManager.js",
       "../../src/Rendering/babylon.renderingGroup.js",
       "../../src/Rendering/babylon.renderingGroup.js",
       "../../src/babylon.scene.js",
       "../../src/babylon.scene.js",
+      "../../src/Mesh/babylon.buffer.js",
       "../../src/Mesh/babylon.vertexBuffer.js",
       "../../src/Mesh/babylon.vertexBuffer.js",
       "../../src/Mesh/babylon.instancedMesh.js",
       "../../src/Mesh/babylon.instancedMesh.js",
       "../../src/Mesh/babylon.mesh.js",
       "../../src/Mesh/babylon.mesh.js",
@@ -166,10 +167,12 @@
       "../../src/Canvas2d/babylon.shape2d.js",
       "../../src/Canvas2d/babylon.shape2d.js",
       "../../src/Canvas2d/babylon.group2d.js",
       "../../src/Canvas2d/babylon.group2d.js",
       "../../src/Canvas2d/babylon.rectangle2d.js",
       "../../src/Canvas2d/babylon.rectangle2d.js",
+      "../../src/Canvas2d/babylon.ellipse2d.js",
       "../../src/Canvas2d/babylon.sprite2d.js",
       "../../src/Canvas2d/babylon.sprite2d.js",
       "../../src/Canvas2d/babylon.text2d.js",
       "../../src/Canvas2d/babylon.text2d.js",
+      "../../src/Canvas2d/babylon.lines2d.js",
       "../../src/Canvas2d/babylon.canvas2d.js",
       "../../src/Canvas2d/babylon.canvas2d.js",
-      "../../src/Canvas2d/babylon.worldspacecanvas2d.js",
+      "../../src/Canvas2d/babylon.worldSpaceCanvas2d.js",
       "../../src/Materials/babylon.shaderMaterial.js",
       "../../src/Materials/babylon.shaderMaterial.js",
       "../../src/Tools/babylon.tools.dds.js",
       "../../src/Tools/babylon.tools.dds.js",
       "../../src/Physics/Plugins/babylon.cannonJSPlugin.js",
       "../../src/Physics/Plugins/babylon.cannonJSPlugin.js",
@@ -181,11 +184,11 @@
       "../../src/PostProcess/babylon.vrDistortionCorrectionPostProcess.js",
       "../../src/PostProcess/babylon.vrDistortionCorrectionPostProcess.js",
       "../../src/Tools/babylon.virtualJoystick.js",
       "../../src/Tools/babylon.virtualJoystick.js",
       "../../src/Cameras/babylon.virtualJoysticksCamera.js",      
       "../../src/Cameras/babylon.virtualJoysticksCamera.js",      
-      "../../src/cameras/inputs/babylon.freecamera.input.virtualjoystick.js",
+      "../../src/Cameras/Inputs/babylon.freecamera.input.virtualjoystick.js",
       "../../src/PostProcess/babylon.anaglyphPostProcess.js",
       "../../src/PostProcess/babylon.anaglyphPostProcess.js",
       "../../src/Rendering/babylon.outlineRenderer.js",
       "../../src/Rendering/babylon.outlineRenderer.js",
       "../../src/Tools/babylon.assetsManager.js",
       "../../src/Tools/babylon.assetsManager.js",
-      "../../src/cameras/vr/babylon.vrCameraMetrics.js",
+      "../../src/Cameras/VR/babylon.vrCameraMetrics.js",
       "../../src/Cameras/VR/babylon.vrDeviceOrientationCamera.js",
       "../../src/Cameras/VR/babylon.vrDeviceOrientationCamera.js",
       "../../src/Cameras/VR/babylon.webVRCamera.js",
       "../../src/Cameras/VR/babylon.webVRCamera.js",
       "../../src/Tools/babylon.sceneOptimizer.js",
       "../../src/Tools/babylon.sceneOptimizer.js",
@@ -220,14 +223,15 @@
       "../../src/Probes/babylon.reflectionProbe.js",
       "../../src/Probes/babylon.reflectionProbe.js",
       "../../src/Particles/babylon.solidParticle.js",
       "../../src/Particles/babylon.solidParticle.js",
       "../../src/Particles/babylon.solidParticleSystem.js",
       "../../src/Particles/babylon.solidParticleSystem.js",
-      "../../src/tools/hdr/babylon.tools.cubemaptosphericalpolynomial.js",
-      "../../src/tools/hdr/babylon.tools.panoramatocubemap.js",
-      "../../src/tools/hdr/babylon.tools.hdr.js",
-      "../../src/tools/hdr/babylon.tools.pmremGenerator.js",
-      "../../src/materials/textures/babylon.hdrcubetexture.js",
-      "../../src/debug/babylon.skeletonViewer.js",
+      "../../src/Tools/HDR/babylon.tools.cubemapToSphericalPolynomial.js",
+      "../../src/Tools/HDR/babylon.tools.panoramaToCubemap.js",
+      "../../src/Tools/HDR/babylon.tools.hdr.js",
+      "../../src/Tools/HDR/babylon.tools.pmremgenerator.js",
+      "../../src/Materials/Textures/babylon.hdrCubeTexture.js",
+      "../../src/Debug/babylon.skeletonViewer.js",
       "../../src/Materials/Textures/babylon.colorGradingTexture.js",
       "../../src/Materials/Textures/babylon.colorGradingTexture.js",
-      "../../src/materials/babylon.pbrmaterial.js",      
+      "../../src/Materials/babylon.colorCurves.js",
+      "../../src/Materials/babylon.pbrMaterial.js",      
       "../../src/Debug/babylon.debugLayer.js"
       "../../src/Debug/babylon.debugLayer.js"
     ]
     ]
   }
   }

+ 21 - 10
Tools/Gulp/gulpfile.js

@@ -12,6 +12,7 @@ var changed = require('gulp-changed');
 var runSequence = require('run-sequence');
 var runSequence = require('run-sequence');
 var replace = require("gulp-replace");
 var replace = require("gulp-replace");
 var uncommentShader = require("./gulp-removeShaderComments");
 var uncommentShader = require("./gulp-removeShaderComments");
+var expect = require('gulp-expect-file');
 
 
 var config = require("./config.json");
 var config = require("./config.json");
 
 
@@ -36,6 +37,7 @@ function includeShadersName(filename) {
 gulp.task("includeShaders", function (cb) {
 gulp.task("includeShaders", function (cb) {
     includeShadersStream = config.includeShadersDirectories.map(function (shadersDef) {
     includeShadersStream = config.includeShadersDirectories.map(function (shadersDef) {
         return gulp.src(shadersDef.files).
         return gulp.src(shadersDef.files).
+            pipe(expect.real({ errorOnFailure: true }, shadersDef.files)).
             pipe(uncommentShader()).
             pipe(uncommentShader()).
             pipe(srcToVariable({
             pipe(srcToVariable({
             variableName: shadersDef.variable, asMap: true, namingCallback: includeShadersName
             variableName: shadersDef.variable, asMap: true, namingCallback: includeShadersName
@@ -47,6 +49,7 @@ gulp.task("includeShaders", function (cb) {
 gulp.task("shaders", ["includeShaders"], function (cb) {
 gulp.task("shaders", ["includeShaders"], function (cb) {
     shadersStream = config.shadersDirectories.map(function (shadersDef) {
     shadersStream = config.shadersDirectories.map(function (shadersDef) {
         return gulp.src(shadersDef.files).
         return gulp.src(shadersDef.files).
+            pipe(expect.real({ errorOnFailure: true }, shadersDef.files)).
             pipe(uncommentShader()).
             pipe(uncommentShader()).
             pipe(srcToVariable({
             pipe(srcToVariable({
             variableName: shadersDef.variable, asMap: true, namingCallback: shadersName
             variableName: shadersDef.variable, asMap: true, namingCallback: shadersName
@@ -57,9 +60,12 @@ gulp.task("shaders", ["includeShaders"], function (cb) {
 
 
 gulp.task("workers", function (cb) {
 gulp.task("workers", function (cb) {
     workersStream = config.workers.map(function (workerDef) {
     workersStream = config.workers.map(function (workerDef) {
-        return gulp.src(workerDef.files).pipe(uglify()).pipe(srcToVariable({
-            variableName: workerDef.variable
-        }));
+        return gulp.src(workerDef.files).
+            pipe(expect.real({ errorOnFailure: true }, workerDef.files)).
+            pipe(uglify()).
+            pipe(srcToVariable({
+                variableName: workerDef.variable
+            }));
     });
     });
     cb();
     cb();
 });
 });
@@ -68,8 +74,8 @@ gulp.task("workers", function (cb) {
 Compiles all typescript files and creating a declaration file.
 Compiles all typescript files and creating a declaration file.
 */
 */
 gulp.task('typescript-compile', function () {
 gulp.task('typescript-compile', function () {
-    var tsResult = gulp.src(config.core.typescript)
-        .pipe(typescript({
+    var tsResult = gulp.src(config.core.typescript).
+        pipe(typescript({
             noExternalResolve: true,
             noExternalResolve: true,
             target: 'ES5',
             target: 'ES5',
             declarationFiles: true,
             declarationFiles: true,
@@ -114,7 +120,8 @@ gulp.task('typescript-sourcemaps', function () {
 
 
 gulp.task("buildCore", ["shaders"], function () {
 gulp.task("buildCore", ["shaders"], function () {
     return merge2(
     return merge2(
-        gulp.src(config.core.files),
+        gulp.src(config.core.files).        
+            pipe(expect.real({ errorOnFailure: true }, config.core.files)),
         shadersStream,
         shadersStream,
         includeShadersStream
         includeShadersStream
         )
         )
@@ -129,8 +136,10 @@ gulp.task("buildCore", ["shaders"], function () {
 
 
 gulp.task("buildNoWorker", ["shaders"], function () {
 gulp.task("buildNoWorker", ["shaders"], function () {
     return merge2(
     return merge2(
-        gulp.src(config.core.files),
-        gulp.src(config.extras.files),
+        gulp.src(config.core.files).        
+            pipe(expect.real({ errorOnFailure: true }, config.core.files)),
+        gulp.src(config.extras.files).        
+            pipe(expect.real({ errorOnFailure: true }, config.extras.files)),
         shadersStream,
         shadersStream,
         includeShadersStream
         includeShadersStream
         )
         )
@@ -145,8 +154,10 @@ gulp.task("buildNoWorker", ["shaders"], function () {
 
 
 gulp.task("build", ["workers", "shaders"], function () {
 gulp.task("build", ["workers", "shaders"], function () {
     return merge2(
     return merge2(
-        gulp.src(config.core.files),
-        gulp.src(config.extras.files),
+        gulp.src(config.core.files).        
+            pipe(expect.real({ errorOnFailure: true }, config.core.files)),
+        gulp.src(config.extras.files).        
+            pipe(expect.real({ errorOnFailure: true }, config.extras.files)),   
         shadersStream,
         shadersStream,
         includeShadersStream,
         includeShadersStream,
         workersStream
         workersStream

+ 2 - 1
Tools/Gulp/package.json

@@ -21,6 +21,7 @@
     "gulp-changed": "~1.2.1",
     "gulp-changed": "~1.2.1",
     "run-sequence": "~1.1.0",
     "run-sequence": "~1.1.0",
     "gulp-replace": "~0.5.3",
     "gulp-replace": "~0.5.3",
-    "gulp-content-to-variable": "^0.1.0"
+    "gulp-content-to-variable": "^0.1.0",
+    "gulp-expect-file": "^0.0.7"
   }
   }
 }
 }

文件差異過大導致無法顯示
+ 25 - 25
dist/preview release/babylon.core.js


文件差異過大導致無法顯示
+ 6315 - 5696
dist/preview release/babylon.d.ts


文件差異過大導致無法顯示
+ 38 - 37
dist/preview release/babylon.js


文件差異過大導致無法顯示
+ 3204 - 847
dist/preview release/babylon.max.js


文件差異過大導致無法顯示
+ 38 - 37
dist/preview release/babylon.noworker.js


+ 26 - 8
dist/preview release/what's new.md

@@ -1,23 +1,27 @@
 - 2.4.0:
 - 2.4.0:
   - **Major updates**    
   - **Major updates**    
     - New refraction channel for Standard material (including fresnel support). Refraction texture can be provided by a reflection probe or a refraction texture. [See demo here](http://www.babylonjs.com/Demos/refraction/) ([deltakosh](https://github.com/deltakosh))
     - New refraction channel for Standard material (including fresnel support). Refraction texture can be provided by a reflection probe or a refraction texture. [See demo here](http://www.babylonjs.com/Demos/refraction/) ([deltakosh](https://github.com/deltakosh))
-    - Added support for HDR cubemaps ([sebavan](https://github.com/sebavan))
+    - Added support for HDR cubemaps. [demo here](http://www.babylonjs-playground.com/#19JGPR#4) ([sebavan](https://github.com/sebavan))
     - Support for shaders includes ([deltakosh](https://github.com/deltakosh))
     - Support for shaders includes ([deltakosh](https://github.com/deltakosh))
-    - New mesh type : `LineSystem` ([jerome](https://github.com/jbousquie))
+    - New mesh type : `LineSystem`. [Demo here](http://www.babylonjs-playground.com/#2K1IS4#5) ([jerome](https://github.com/jbousquie))
     - SerializationHelper for complex classes using TypeScript decorators ([deltakosh](https://github.com/deltakosh))
     - SerializationHelper for complex classes using TypeScript decorators ([deltakosh](https://github.com/deltakosh))
     - StandardMaterial now supports Parallax and Parallax Occlusion Mapping ([tutorial](http://doc.babylonjs.com/tutorials/Using_parallax_mapping)) ([nockawa](https://github.com/nockawa))
     - StandardMaterial now supports Parallax and Parallax Occlusion Mapping ([tutorial](http://doc.babylonjs.com/tutorials/Using_parallax_mapping)) ([nockawa](https://github.com/nockawa))
     - Animations blending. See [demo here](http://www.babylonjs-playground.com/#2BLI9T#3). More [info here](http://doc.babylonjs.com/tutorials/Animations#animation-blending) ([deltakosh](https://github.com/deltakosh))
     - Animations blending. See [demo here](http://www.babylonjs-playground.com/#2BLI9T#3). More [info here](http://doc.babylonjs.com/tutorials/Animations#animation-blending) ([deltakosh](https://github.com/deltakosh))
     - New debuger tool: SkeletonViewer. See [demo here](http://www.babylonjs-playground.com/#1BZJVJ#8) (Adam & [deltakosh](https://github.com/deltakosh))
     - New debuger tool: SkeletonViewer. See [demo here](http://www.babylonjs-playground.com/#1BZJVJ#8) (Adam & [deltakosh](https://github.com/deltakosh))
-    - Added Camera Inputs Manager to manage camera inputs (mouse, touch, keyboard, gamepad, ...) in a composable way, without relying on class inheritance ([gleborgne](https://github.com/gleborgne))
-    - Introduced new observable system to handle events ([nockawa](https://github.com/nockawa), [deltakosh](https://github.com/deltakosh))
-    - Added a new VR camera : VRDeviceOrientationArcRotateCamera ([temechon](https://github.com/Temechon)
+    - Added Camera Inputs Manager to manage camera inputs (mouse, touch, keyboard, gamepad, ...) in a composable way, without relying on class inheritance. [Documentation here](http://doc.babylonjs.com/tutorials/Customizing_Camera_Inputs) ([gleborgne](https://github.com/gleborgne))
+    - Introduced new observable system to handle events. [Documentation here](http://doc.babylonjs.com/overviews/Observables) ([nockawa](https://github.com/nockawa), [deltakosh](https://github.com/deltakosh))
+    - Added a new VR camera : VRDeviceOrientationArcRotateCamera ([temechon](https://github.com/Temechon))
     - Moved PBR Material to core ([deltakosh](https://github.com/deltakosh))
     - Moved PBR Material to core ([deltakosh](https://github.com/deltakosh))
-    - StandardMaterial.maxSimultaneousLights can define how many dynamic lights the material can handle ([deltakosh](https://github.com/deltakosh))
+    - StandardMaterial.maxSimultaneousLights can define how many dynamic lights the material can handle. [Demo here](http://www.babylonjs-playground.com/#IRVAX#10) ([deltakosh](https://github.com/deltakosh))
     - Introduced Canvas2D feature: a 2D engine to render primitives, sprites in 2D, text. Canvas2D can be displayed in Screen Space (above the 3D scene) or in World Space to be a part of the Scene. [overview](http://doc.babylonjs.com/overviews/Using_The_Canvas2D), [tutorial](http://doc.babylonjs.com/tutorials/Using_the_Canvas2D) ([nockawa](https://github.com/nockawa))
     - Introduced Canvas2D feature: a 2D engine to render primitives, sprites in 2D, text. Canvas2D can be displayed in Screen Space (above the 3D scene) or in World Space to be a part of the Scene. [overview](http://doc.babylonjs.com/overviews/Using_The_Canvas2D), [tutorial](http://doc.babylonjs.com/tutorials/Using_the_Canvas2D) ([nockawa](https://github.com/nockawa))
     - Added two new types of Texture: FontTexture and MapTexture ([quick doc](http://www.html5gamedevs.com/topic/22565-two-new-texture-types-fonttexture-and-maptexture/)) ([nockawa](https://github.com/nockawa))
     - Added two new types of Texture: FontTexture and MapTexture ([quick doc](http://www.html5gamedevs.com/topic/22565-two-new-texture-types-fonttexture-and-maptexture/)) ([nockawa](https://github.com/nockawa))
     - Added a dynamic [2D Bin Packing Algorithm](http://stackoverflow.com/questions/8762569/how-is-2d-bin-packing-achieved-programmatically), ([more info here](http://www.html5gamedevs.com/topic/22565-two-new-texture-types-fonttexture-and-maptexture/)) ([nockawa](https://github.com/nockawa))
     - Added a dynamic [2D Bin Packing Algorithm](http://stackoverflow.com/questions/8762569/how-is-2d-bin-packing-achieved-programmatically), ([more info here](http://www.html5gamedevs.com/topic/22565-two-new-texture-types-fonttexture-and-maptexture/)) ([nockawa](https://github.com/nockawa))
-    - Introduced Canvas2D feature: a 2D engine to render primitives, sprites in 2D, text. Canvas2D can be displayed in Screen Space (above the 3D scene) or in World Space to be a part of the Scene. [overview](http://doc.babylonjs.com/overviews/Using_The_Canvas2D), [tutorial](http://doc.babylonjs.com/tutorials/Using_the_Canvas2D) ([nockawa](https://github.com/nockawa))	
+    - Physics engine was completely rewritten, including both plugins for Oimo.js and Cannon.js. [overview](http://doc.babylonjs.com/overviews/Using_The_Physics_Engine) ([RaananW](https://github.com/RaananW))
+	- Interleaved buffers are now directly supported. Create a `Buffer` object and then use `buffer.createVertexBuffer` to specify the vertex buffers ([benaadams](https://github.com/benaadams)) 
+	- Vertex buffers can be marked as instanced to allow custom instancing attributes ([benaadams](https://github.com/benaadams)) 
+	- Mesh can have `overridenInstanceCount` set to specify the number of meshes to draw when custom instancing is used ([benaadams](https://github.com/benaadams)) 
   - **Updates**
   - **Updates**
+    - Added `mesh.toLefthanded()` to convert a mesh from right handed system ([kesshi](https://github.com/Kesshi))
     - Renderlists can now also be defined using predicates ([deltakosh](https://github.com/deltakosh))
     - Renderlists can now also be defined using predicates ([deltakosh](https://github.com/deltakosh))
     - Added support for various normal maps conventions ([deltakosh](https://github.com/deltakosh))
     - Added support for various normal maps conventions ([deltakosh](https://github.com/deltakosh))
     - Added postprocess.enablePixelPerfectMode to avoid texture scaling/stretching when dealing with non-power of 2 resolutions. cannot be used on post-processes chain ([deltakosh](https://github.com/deltakosh))
     - Added postprocess.enablePixelPerfectMode to avoid texture scaling/stretching when dealing with non-power of 2 resolutions. cannot be used on post-processes chain ([deltakosh](https://github.com/deltakosh))
@@ -38,10 +42,17 @@
     - LinesMesh class now supports Intersection. Added the intersectionThreshold property to set a tolerance margin during intersection with wire lines. ([nockawa](https://github.com/nockawa))
     - LinesMesh class now supports Intersection. Added the intersectionThreshold property to set a tolerance margin during intersection with wire lines. ([nockawa](https://github.com/nockawa))
     - Geometry.boundingBias property to enlarge the boundingInfo objects ([nockawa](https://github.com/nockawa))
     - Geometry.boundingBias property to enlarge the boundingInfo objects ([nockawa](https://github.com/nockawa))
     - Tools.ExtractMinAndMax & ExtractMinAndMaxIndexed now supports an optional Bias for Extent computation.
     - Tools.ExtractMinAndMax & ExtractMinAndMaxIndexed now supports an optional Bias for Extent computation.
-    - Added StringDictionary<T> class to implement an efficient generic typed string dictionary based on Javascript associative array. ([quick dock](http://www.html5gamedevs.com/topic/22566-be-efficient-my-friend-use-stringdictionary/)) ([nockawa](https://github.com/nockawa))
+    - Added StringDictionary<T> class to implement an efficient generic typed string dictionary based on Javascript associative array. ([quick doc](http://www.html5gamedevs.com/topic/22566-be-efficient-my-friend-use-stringdictionary/)) ([nockawa](https://github.com/nockawa))
     - Added RectanglePackingMap class to fit several rectangles in a big map in the most optimal way, dynamically. ([nockawa](https://github.com/nockawa))
     - Added RectanglePackingMap class to fit several rectangles in a big map in the most optimal way, dynamically. ([nockawa](https://github.com/nockawa))
     - Added DynamicFloatArray class to store float32 based elements of a given size (stride) into one big Float32Array, with allocation/free/pack operations to then access an optimal buffer that can be used to update a WebGLBuffer dynamically.([quick doc](http://www.html5gamedevs.com/topic/22567-dynamicfloatarray-to-the-rescue-for-efficient-instanced-array/)) ([nockawa](https://github.com/nockawa))
     - Added DynamicFloatArray class to store float32 based elements of a given size (stride) into one big Float32Array, with allocation/free/pack operations to then access an optimal buffer that can be used to update a WebGLBuffer dynamically.([quick doc](http://www.html5gamedevs.com/topic/22567-dynamicfloatarray-to-the-rescue-for-efficient-instanced-array/)) ([nockawa](https://github.com/nockawa))
     - Scene.onPointerObservable property added to enable a unique Observable event for user input (see ArcRotateCamera inputs for examples) ([nockawa](https://github.com/nockawa))
     - Scene.onPointerObservable property added to enable a unique Observable event for user input (see ArcRotateCamera inputs for examples) ([nockawa](https://github.com/nockawa))
+    - Oimo.js updated to the latest version ([RaananW](https://github.com/RaananW))
+    - Added PhysicsImpostor and PhysicsJoint classes  ([RaananW](https://github.com/RaananW))
+    - LensFlareSystem now has both ID and name  ([RaananW](https://github.com/RaananW))
+    - TargetCamera has now a rotationQuaternion variable to can be used to set the camera's rotation  ([RaananW](https://github.com/RaananW))
+    - SSAORenderingPipeline now uses bilateral blur post-processes instead of standard blur post-process, in order to remove more efficiently the "textile effect"
+    - `Engine.updateDynamicVertexBuffer` now has optional count as well as offset to allow partial updates ([benaadams](https://github.com/benaadams)) 
+    - vertex attributes are only disabled if they aren't going to be reeabled by the next draw, to reduce gpu state changes ([benaadams](https://github.com/benaadams)) 
   - **Exporters**
   - **Exporters**
     - Unity3D exporter: Added support for lightmaps ([davrous](https://github.com/davrous), [deltakosh](https://github.com/deltakosh))
     - Unity3D exporter: Added support for lightmaps ([davrous](https://github.com/davrous), [deltakosh](https://github.com/deltakosh))
     - Unity3D exporter: Added support for export and run (local webserver) ([davrous](https://github.com/davrous), [deltakosh](https://github.com/deltakosh))
     - Unity3D exporter: Added support for export and run (local webserver) ([davrous](https://github.com/davrous), [deltakosh](https://github.com/deltakosh))
@@ -57,7 +68,14 @@
     - Fixed bug with billboards and parenting ([deltakosh](https://github.com/deltakosh))
     - Fixed bug with billboards and parenting ([deltakosh](https://github.com/deltakosh))
     - Fixed bug with ArcRotateCamera.setTarget ([deltakosh](https://github.com/deltakosh))
     - Fixed bug with ArcRotateCamera.setTarget ([deltakosh](https://github.com/deltakosh))
     - Fixed bug with OBJ Loader - All meshes were concatenated with the previous one ([Temechon](https://github.com/Temechon))
     - Fixed bug with OBJ Loader - All meshes were concatenated with the previous one ([Temechon](https://github.com/Temechon))
+    - Fixed the device orientation cameras (both VR and non-VR cameras)  ([RaananW](https://github.com/RaananW))
+    - Fixed the WebVR implementation  ([RaananW](https://github.com/RaananW))
   - **Breaking changes**
   - **Breaking changes**
     - `VertexData.CreateLines()` removed as `MeshBuilder.CreateLines()` now calls `MeshBuilder.CreateLineSystem()`
     - `VertexData.CreateLines()` removed as `MeshBuilder.CreateLines()` now calls `MeshBuilder.CreateLineSystem()`
     - `scene.onNewXXXAdded` and `scene.onXXXRemoved` callbacks were removed and replaced by `scene.onNewXXXAddedObservable` and `scene.onXXXRemovedObservable`
     - `scene.onNewXXXAdded` and `scene.onXXXRemoved` callbacks were removed and replaced by `scene.onNewXXXAddedObservable` and `scene.onXXXRemovedObservable`
     - `Material.dispose` does not dispose textures by default. You have to call `material.dispose(false, true)` to get the previous behavior.
     - `Material.dispose` does not dispose textures by default. You have to call `material.dispose(false, true)` to get the previous behavior.
+    - `SSAORenderingPipeline.getBlurHPostProcess` and `SSAORenderingPipeline.getBlurVPostProcess`. The SSAO rendering pipeline doesn't use standard blur post-process anymore. A bilateral blur post-process is used instead.
+    - `Engine.bindBuffers` is now `Engine.bindBuffersDirectly` ([benaadams](https://github.com/benaadams))
+    - `Engine.bindMultiBuffers` is now `Engine.bindBuffers` and strongly typed `{ [key: string]: VertexBuffer; }` of buffers ([benaadams](https://github.com/benaadams))
+    - `Engine.createDynamicVertexBuffer` takes vertices rather than capacity, creating and initalizing in one gpu instruction ([benaadams](https://github.com/benaadams)) 
+    - Internally new `Engine.bindBuffer` is used rather than `gl.bindBuffer` which only binds when the bound buffer is changing ([benaadams](https://github.com/benaadams)) 

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

@@ -272,6 +272,7 @@ var BABYLON;
             var serializationObject = {};
             var serializationObject = {};
             serializationObject.name = this.name;
             serializationObject.name = this.name;
             serializationObject.id = this.id;
             serializationObject.id = this.id;
+            serializationObject.dimensionsAtRest = this.dimensionsAtRest;
             serializationObject.bones = [];
             serializationObject.bones = [];
             serializationObject.needInitialSkinMatrix = this.needInitialSkinMatrix;
             serializationObject.needInitialSkinMatrix = this.needInitialSkinMatrix;
             for (var index = 0; index < this.bones.length; index++) {
             for (var index = 0; index < this.bones.length; index++) {
@@ -302,6 +303,9 @@ var BABYLON;
         };
         };
         Skeleton.Parse = function (parsedSkeleton, scene) {
         Skeleton.Parse = function (parsedSkeleton, scene) {
             var skeleton = new Skeleton(parsedSkeleton.name, parsedSkeleton.id, scene);
             var skeleton = new Skeleton(parsedSkeleton.name, parsedSkeleton.id, scene);
+            if (parsedSkeleton.dimensionsAtRest) {
+                skeleton.dimensionsAtRest = BABYLON.Vector3.FromArray(parsedSkeleton.dimensionsAtRest);
+            }
             skeleton.needInitialSkinMatrix = parsedSkeleton.needInitialSkinMatrix;
             skeleton.needInitialSkinMatrix = parsedSkeleton.needInitialSkinMatrix;
             var index;
             var index;
             for (index = 0; index < parsedSkeleton.bones.length; index++) {
             for (index = 0; index < parsedSkeleton.bones.length; index++) {
@@ -329,6 +333,6 @@ var BABYLON;
             return skeleton;
             return skeleton;
         };
         };
         return Skeleton;
         return Skeleton;
-    })();
+    }());
     BABYLON.Skeleton = Skeleton;
     BABYLON.Skeleton = Skeleton;
 })(BABYLON || (BABYLON = {}));
 })(BABYLON || (BABYLON = {}));

+ 20 - 16
src/Bones/babylon.skeleton.ts

@@ -1,7 +1,7 @@
 module BABYLON {
 module BABYLON {
     export class Skeleton {
     export class Skeleton {
         public bones = new Array<Bone>();
         public bones = new Array<Bone>();
-
+        public dimensionsAtRest: Vector3;
         public needInitialSkinMatrix = false;
         public needInitialSkinMatrix = false;
 
 
         private _scene: Scene;
         private _scene: Scene;
@@ -41,23 +41,23 @@
         /**
         /**
          * @param {boolean} fullDetails - support for multiple levels of logging within scene loading
          * @param {boolean} fullDetails - support for multiple levels of logging within scene loading
          */
          */
-        public toString(fullDetails? : boolean) : string {
+        public toString(fullDetails?: boolean): string {
             var ret = `Name: ${this.name}, nBones: ${this.bones.length}`;
             var ret = `Name: ${this.name}, nBones: ${this.bones.length}`;
             ret += `, nAnimationRanges: ${this._ranges ? Object.keys(this._ranges).length : "none"}`;
             ret += `, nAnimationRanges: ${this._ranges ? Object.keys(this._ranges).length : "none"}`;
             if (fullDetails) {
             if (fullDetails) {
-                ret += ", Ranges: {"; 
+                ret += ", Ranges: {";
                 let first = true;
                 let first = true;
                 for (let name in this._ranges) {
                 for (let name in this._ranges) {
                     if (first) {
                     if (first) {
                         ret += ", ";
                         ret += ", ";
-                        first = false; 
+                        first = false;
                     }
                     }
-                    ret += name; 
+                    ret += name;
                 }
                 }
                 ret += "}";
                 ret += "}";
             }
             }
             return ret;
             return ret;
-        } 
+        }
 
 
         /**
         /**
         * Get bone's index searching by name
         * Get bone's index searching by name
@@ -72,7 +72,7 @@
             }
             }
             return -1;
             return -1;
         }
         }
-        
+
         public createAnimationRange(name: string, from: number, to: number): void {
         public createAnimationRange(name: string, from: number, to: number): void {
             // check name not already in use
             // check name not already in use
             if (!this._ranges[name]) {
             if (!this._ranges[name]) {
@@ -97,15 +97,15 @@
         public getAnimationRange(name: string): AnimationRange {
         public getAnimationRange(name: string): AnimationRange {
             return this._ranges[name];
             return this._ranges[name];
         }
         }
-        
+
         /**
         /**
          *  Returns as an Array, all AnimationRanges defined on this skeleton
          *  Returns as an Array, all AnimationRanges defined on this skeleton
          */
          */
         public getAnimationRanges(): AnimationRange[] {
         public getAnimationRanges(): AnimationRange[] {
-            var animationRanges :  AnimationRange[] = [];
-            var name : string;
+            var animationRanges: AnimationRange[] = [];
+            var name: string;
             var i: number = 0;
             var i: number = 0;
-            for (name in this._ranges){
+            for (name in this._ranges) {
                 animationRanges[i] = this._ranges[name];
                 animationRanges[i] = this._ranges[name];
                 i++;
                 i++;
             }
             }
@@ -121,7 +121,7 @@
             }
             }
             var ret = true;
             var ret = true;
             var frameOffset = this._getHighestAnimationFrame() + 1;
             var frameOffset = this._getHighestAnimationFrame() + 1;
-            
+
             // make a dictionary of source skeleton's bones, so exact same order or doublely nested loop is not required
             // make a dictionary of source skeleton's bones, so exact same order or doublely nested loop is not required
             var boneDict = {};
             var boneDict = {};
             var sourceBones = source.bones;
             var sourceBones = source.bones;
@@ -131,11 +131,11 @@
                 boneDict[sourceBones[i].name] = sourceBones[i];
                 boneDict[sourceBones[i].name] = sourceBones[i];
             }
             }
 
 
-            if (this.bones.length !== sourceBones.length){
+            if (this.bones.length !== sourceBones.length) {
                 Tools.Warn(`copyAnimationRange: this rig has ${this.bones.length} bones, while source as ${sourceBones.length}`);
                 Tools.Warn(`copyAnimationRange: this rig has ${this.bones.length} bones, while source as ${sourceBones.length}`);
                 ret = false;
                 ret = false;
             }
             }
-            
+
             for (i = 0, nBones = this.bones.length; i < nBones; i++) {
             for (i = 0, nBones = this.bones.length; i < nBones; i++) {
                 var boneName = this.bones[i].name;
                 var boneName = this.bones[i].name;
                 var sourceBone = boneDict[boneName];
                 var sourceBone = boneDict[boneName];
@@ -325,6 +325,7 @@
 
 
             serializationObject.name = this.name;
             serializationObject.name = this.name;
             serializationObject.id = this.id;
             serializationObject.id = this.id;
+            serializationObject.dimensionsAtRest = this.dimensionsAtRest;
 
 
             serializationObject.bones = [];
             serializationObject.bones = [];
 
 
@@ -364,6 +365,9 @@
 
 
         public static Parse(parsedSkeleton: any, scene: Scene): Skeleton {
         public static Parse(parsedSkeleton: any, scene: Scene): Skeleton {
             var skeleton = new Skeleton(parsedSkeleton.name, parsedSkeleton.id, scene);
             var skeleton = new Skeleton(parsedSkeleton.name, parsedSkeleton.id, scene);
+            if (parsedSkeleton.dimensionsAtRest) {
+                skeleton.dimensionsAtRest = Vector3.FromArray(parsedSkeleton.dimensionsAtRest);
+            }
 
 
             skeleton.needInitialSkinMatrix = parsedSkeleton.needInitialSkinMatrix;
             skeleton.needInitialSkinMatrix = parsedSkeleton.needInitialSkinMatrix;
 
 
@@ -386,7 +390,7 @@
                     bone.animations.push(Animation.Parse(parsedBone.animation));
                     bone.animations.push(Animation.Parse(parsedBone.animation));
                 }
                 }
             }
             }
-            
+
             // placed after bones, so createAnimationRange can cascade down
             // placed after bones, so createAnimationRange can cascade down
             if (parsedSkeleton.ranges) {
             if (parsedSkeleton.ranges) {
                 for (index = 0; index < parsedSkeleton.ranges.length; index++) {
                 for (index = 0; index < parsedSkeleton.ranges.length; index++) {
@@ -397,4 +401,4 @@
             return skeleton;
             return skeleton;
         }
         }
     }
     }
-}
+}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

+ 11 - 8
src/Cameras/VR/babylon.webVRCamera.js

@@ -13,13 +13,12 @@ var BABYLON;
             this._hmdDevice = null;
             this._hmdDevice = null;
             this._sensorDevice = null;
             this._sensorDevice = null;
             this._cacheState = null;
             this._cacheState = null;
-            this._cacheQuaternion = new BABYLON.Quaternion();
-            this._cacheRotation = BABYLON.Vector3.Zero();
             this._vrEnabled = false;
             this._vrEnabled = false;
             var metrics = BABYLON.VRCameraMetrics.GetDefault();
             var metrics = BABYLON.VRCameraMetrics.GetDefault();
             metrics.compensateDistortion = compensateDistortion;
             metrics.compensateDistortion = compensateDistortion;
             this.setCameraRigMode(BABYLON.Camera.RIG_MODE_VR, { vrCameraMetrics: metrics });
             this.setCameraRigMode(BABYLON.Camera.RIG_MODE_VR, { vrCameraMetrics: metrics });
             this._getWebVRDevices = this._getWebVRDevices.bind(this);
             this._getWebVRDevices = this._getWebVRDevices.bind(this);
+            this.rotationQuaternion = new BABYLON.Quaternion();
         }
         }
         WebVRFreeCamera.prototype._getWebVRDevices = function (devices) {
         WebVRFreeCamera.prototype._getWebVRDevices = function (devices) {
             var size = devices.length;
             var size = devices.length;
@@ -46,11 +45,10 @@ var BABYLON;
         WebVRFreeCamera.prototype._checkInputs = function () {
         WebVRFreeCamera.prototype._checkInputs = function () {
             if (this._vrEnabled) {
             if (this._vrEnabled) {
                 this._cacheState = this._sensorDevice.getState();
                 this._cacheState = this._sensorDevice.getState();
-                this._cacheQuaternion.copyFromFloats(this._cacheState.orientation.x, this._cacheState.orientation.y, this._cacheState.orientation.z, this._cacheState.orientation.w);
-                this._cacheQuaternion.toEulerAnglesToRef(this._cacheRotation);
-                this.rotation.x = -this._cacheRotation.x;
-                this.rotation.y = -this._cacheRotation.y;
-                this.rotation.z = this._cacheRotation.z;
+                this.rotationQuaternion.copyFrom(this._cacheState.orientation);
+                //Flip in XY plane
+                this.rotationQuaternion.z *= -1;
+                this.rotationQuaternion.w *= -1;
             }
             }
             _super.prototype._checkInputs.call(this);
             _super.prototype._checkInputs.call(this);
         };
         };
@@ -68,10 +66,15 @@ var BABYLON;
             _super.prototype.detachControl.call(this, element);
             _super.prototype.detachControl.call(this, element);
             this._vrEnabled = false;
             this._vrEnabled = false;
         };
         };
+        WebVRFreeCamera.prototype.requestVRFullscreen = function (requestPointerlock) {
+            if (!this._hmdDevice)
+                return;
+            this.getEngine().switchFullscreen(requestPointerlock, { vrDisplay: this._hmdDevice });
+        };
         WebVRFreeCamera.prototype.getTypeName = function () {
         WebVRFreeCamera.prototype.getTypeName = function () {
             return "WebVRFreeCamera";
             return "WebVRFreeCamera";
         };
         };
         return WebVRFreeCamera;
         return WebVRFreeCamera;
-    })(BABYLON.FreeCamera);
+    }(BABYLON.FreeCamera));
     BABYLON.WebVRFreeCamera = WebVRFreeCamera;
     BABYLON.WebVRFreeCamera = WebVRFreeCamera;
 })(BABYLON || (BABYLON = {}));
 })(BABYLON || (BABYLON = {}));

+ 12 - 9
src/Cameras/VR/babylon.webVRCamera.ts

@@ -5,9 +5,7 @@ module BABYLON {
     export class WebVRFreeCamera extends FreeCamera {
     export class WebVRFreeCamera extends FreeCamera {
         public _hmdDevice = null;
         public _hmdDevice = null;
         public _sensorDevice = null;
         public _sensorDevice = null;
-        public _cacheState = null;
-        public _cacheQuaternion = new Quaternion();
-        public _cacheRotation = Vector3.Zero();
+        private _cacheState = null;
         public _vrEnabled = false;
         public _vrEnabled = false;
 
 
         constructor(name: string, position: Vector3, scene: Scene, compensateDistortion = true) {
         constructor(name: string, position: Vector3, scene: Scene, compensateDistortion = true) {
@@ -18,6 +16,8 @@ module BABYLON {
             this.setCameraRigMode(Camera.RIG_MODE_VR, { vrCameraMetrics: metrics });
             this.setCameraRigMode(Camera.RIG_MODE_VR, { vrCameraMetrics: metrics });
 
 
             this._getWebVRDevices = this._getWebVRDevices.bind(this);
             this._getWebVRDevices = this._getWebVRDevices.bind(this);
+
+            this.rotationQuaternion = new Quaternion();
         }
         }
 
 
         private _getWebVRDevices(devices: Array<any>): void {
         private _getWebVRDevices(devices: Array<any>): void {
@@ -51,12 +51,10 @@ module BABYLON {
         public _checkInputs(): void {
         public _checkInputs(): void {
             if (this._vrEnabled) {
             if (this._vrEnabled) {
                 this._cacheState = this._sensorDevice.getState();
                 this._cacheState = this._sensorDevice.getState();
-                this._cacheQuaternion.copyFromFloats(this._cacheState.orientation.x, this._cacheState.orientation.y, this._cacheState.orientation.z, this._cacheState.orientation.w);
-                this._cacheQuaternion.toEulerAnglesToRef(this._cacheRotation);
-
-                this.rotation.x = -this._cacheRotation.x;
-                this.rotation.y = -this._cacheRotation.y;
-                this.rotation.z = this._cacheRotation.z;
+                this.rotationQuaternion.copyFrom(this._cacheState.orientation);
+                //Flip in XY plane
+                this.rotationQuaternion.z *= -1;
+                this.rotationQuaternion.w *= -1;
             }
             }
 
 
             super._checkInputs();
             super._checkInputs();
@@ -80,6 +78,11 @@ module BABYLON {
             this._vrEnabled = false;
             this._vrEnabled = false;
         }
         }
 
 
+        public requestVRFullscreen(requestPointerlock: boolean) {
+            if (!this._hmdDevice) return;
+            this.getEngine().switchFullscreen(requestPointerlock, { vrDisplay: this._hmdDevice })
+        }
+
         public getTypeName(): string {
         public getTypeName(): string {
             return "WebVRFreeCamera";
             return "WebVRFreeCamera";
         }
         }

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

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

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

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

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

@@ -247,6 +247,9 @@ var BABYLON;
                     cam._postProcesses = this._postProcesses.slice(0).concat(rigPostProcess);
                     cam._postProcesses = this._postProcesses.slice(0).concat(rigPostProcess);
                     rigPostProcess.markTextureDirty();
                     rigPostProcess.markTextureDirty();
                 }
                 }
+                else {
+                    cam._postProcesses = this._postProcesses.slice(0);
+                }
             }
             }
         };
         };
         Camera.prototype.attachPostProcess = function (postProcess, insertAt) {
         Camera.prototype.attachPostProcess = function (postProcess, insertAt) {
@@ -612,6 +615,6 @@ var BABYLON;
             BABYLON.serialize()
             BABYLON.serialize()
         ], Camera.prototype, "isStereoscopicSideBySide", void 0);
         ], Camera.prototype, "isStereoscopicSideBySide", void 0);
         return Camera;
         return Camera;
-    })(BABYLON.Node);
+    }(BABYLON.Node));
     BABYLON.Camera = Camera;
     BABYLON.Camera = Camera;
 })(BABYLON || (BABYLON = {}));
 })(BABYLON || (BABYLON = {}));

+ 37 - 38
src/Cameras/babylon.camera.ts

@@ -1,7 +1,7 @@
 module BABYLON {
 module BABYLON {
     export class Camera extends Node {
     export class Camera extends Node {
         public inputs: CameraInputsManager<Camera>;
         public inputs: CameraInputsManager<Camera>;
-        
+
         // Statics
         // Statics
         private static _PERSPECTIVE_CAMERA = 0;
         private static _PERSPECTIVE_CAMERA = 0;
         private static _ORTHOGRAPHIC_CAMERA = 1;
         private static _ORTHOGRAPHIC_CAMERA = 1;
@@ -57,7 +57,7 @@
         }
         }
 
 
         public static ForceAttachControlToAlwaysPreventDefault = false;
         public static ForceAttachControlToAlwaysPreventDefault = false;
-        
+
         // Members
         // Members
         @serializeAsVector3()
         @serializeAsVector3()
         public position: Vector3;
         public position: Vector3;
@@ -100,7 +100,7 @@
 
 
         @serialize()
         @serialize()
         public fovMode: number = Camera.FOVMODE_VERTICAL_FIXED;
         public fovMode: number = Camera.FOVMODE_VERTICAL_FIXED;
-   
+
         // Camera rig members
         // Camera rig members
         @serialize()
         @serialize()
         public cameraRigMode = Camera.RIG_MODE_NONE;
         public cameraRigMode = Camera.RIG_MODE_NONE;
@@ -113,7 +113,7 @@
 
 
         public _cameraRigParams: any;
         public _cameraRigParams: any;
         public _rigCameras = new Array<Camera>();
         public _rigCameras = new Array<Camera>();
-        public _rigPostProcess : PostProcess;
+        public _rigPostProcess: PostProcess;
 
 
         // Cache
         // Cache
         private _computedViewMatrix = Matrix.Identity();
         private _computedViewMatrix = Matrix.Identity();
@@ -274,27 +274,30 @@
 
 
         public _checkInputs(): void {
         public _checkInputs(): void {
         }
         }
-        
-        private _cascadePostProcessesToRigCams() : void {
+
+        private _cascadePostProcessesToRigCams(): void {
             // invalidate framebuffer
             // invalidate framebuffer
-            if (this._postProcesses.length > 0){
+            if (this._postProcesses.length > 0) {
                 this._postProcesses[0].markTextureDirty();
                 this._postProcesses[0].markTextureDirty();
             }
             }
-            
+
             // glue the rigPostProcess to the end of the user postprocesses & assign to each sub-camera
             // glue the rigPostProcess to the end of the user postprocesses & assign to each sub-camera
-            for(var i = 0, len = this._rigCameras.length; i < len; i++){
+            for (var i = 0, len = this._rigCameras.length; i < len; i++) {
                 var cam = this._rigCameras[i];
                 var cam = this._rigCameras[i];
                 var rigPostProcess = cam._rigPostProcess;
                 var rigPostProcess = cam._rigPostProcess;
-                
+
                 // for VR rig, there does not have to be a post process 
                 // for VR rig, there does not have to be a post process 
-                if (rigPostProcess){
+                if (rigPostProcess) {
                     var isPass = rigPostProcess instanceof PassPostProcess;
                     var isPass = rigPostProcess instanceof PassPostProcess;
-                    if (isPass){
+                    if (isPass) {
                         // any rig which has a PassPostProcess for rig[0], cannot be isIntermediate when there are also user postProcesses
                         // any rig which has a PassPostProcess for rig[0], cannot be isIntermediate when there are also user postProcesses
                         cam.isIntermediate = this._postProcesses.length === 0;
                         cam.isIntermediate = this._postProcesses.length === 0;
-                    }               
+                    }
                     cam._postProcesses = this._postProcesses.slice(0).concat(rigPostProcess);
                     cam._postProcesses = this._postProcesses.slice(0).concat(rigPostProcess);
                     rigPostProcess.markTextureDirty();
                     rigPostProcess.markTextureDirty();
+
+                } else {
+                    cam._postProcesses = this._postProcesses.slice(0);
                 }
                 }
             }
             }
         }
         }
@@ -304,17 +307,17 @@
                 Tools.Error("You're trying to reuse a post process not defined as reusable.");
                 Tools.Error("You're trying to reuse a post process not defined as reusable.");
                 return 0;
                 return 0;
             }
             }
-            
+
             if (insertAt == null || insertAt < 0) {
             if (insertAt == null || insertAt < 0) {
                 this._postProcesses.push(postProcess);
                 this._postProcesses.push(postProcess);
-                
-            }else{
+
+            } else {
                 this._postProcesses.splice(insertAt, 0, postProcess);
                 this._postProcesses.splice(insertAt, 0, postProcess);
             }
             }
             this._cascadePostProcessesToRigCams(); // also ensures framebuffer invalidated            
             this._cascadePostProcessesToRigCams(); // also ensures framebuffer invalidated            
             return this._postProcesses.indexOf(postProcess);
             return this._postProcesses.indexOf(postProcess);
         }
         }
-        
+
         public detachPostProcess(postProcess: PostProcess, atIndices: any = null): number[] {
         public detachPostProcess(postProcess: PostProcess, atIndices: any = null): number[] {
             var result = [];
             var result = [];
             var i: number;
             var i: number;
@@ -322,14 +325,14 @@
 
 
             if (!atIndices) {
             if (!atIndices) {
                 var idx = this._postProcesses.indexOf(postProcess);
                 var idx = this._postProcesses.indexOf(postProcess);
-                if (idx !== -1){
+                if (idx !== -1) {
                     this._postProcesses.splice(idx, 1);
                     this._postProcesses.splice(idx, 1);
                 }
                 }
             } else {
             } else {
                 atIndices = (atIndices instanceof Array) ? atIndices : [atIndices];
                 atIndices = (atIndices instanceof Array) ? atIndices : [atIndices];
                 // iterate descending, so can just splice as we go
                 // iterate descending, so can just splice as we go
                 for (i = atIndices.length - 1; i >= 0; i--) {
                 for (i = atIndices.length - 1; i >= 0; i--) {
-                    if ( this._postProcesses[atIndices[i]] !== postProcess) {
+                    if (this._postProcesses[atIndices[i]] !== postProcess) {
                         result.push(i);
                         result.push(i);
                         continue;
                         continue;
                     }
                     }
@@ -339,7 +342,7 @@
             this._cascadePostProcessesToRigCams(); // also ensures framebuffer invalidated
             this._cascadePostProcessesToRigCams(); // also ensures framebuffer invalidated
             return result;
             return result;
         }
         }
-        
+
         public getWorldMatrix(): Matrix {
         public getWorldMatrix(): Matrix {
             if (!this._worldMatrix) {
             if (!this._worldMatrix) {
                 this._worldMatrix = Matrix.Identity();
                 this._worldMatrix = Matrix.Identity();
@@ -434,7 +437,7 @@
 
 
             super.dispose();
             super.dispose();
         }
         }
-        
+
         // ---- Camera rigs section ----
         // ---- Camera rigs section ----
         public setCameraRigMode(mode: number, rigParams: any): void {
         public setCameraRigMode(mode: number, rigParams: any): void {
             while (this._rigCameras.length > 0) {
             while (this._rigCameras.length > 0) {
@@ -448,7 +451,7 @@
             this._cameraRigParams.stereoHalfAngle = BABYLON.Tools.ToRadians(this._cameraRigParams.interaxialDistance / 0.0637);
             this._cameraRigParams.stereoHalfAngle = BABYLON.Tools.ToRadians(this._cameraRigParams.interaxialDistance / 0.0637);
 
 
             // create the rig cameras, unless none
             // create the rig cameras, unless none
-            if (this.cameraRigMode !== Camera.RIG_MODE_NONE){
+            if (this.cameraRigMode !== Camera.RIG_MODE_NONE) {
                 this._rigCameras.push(this.createRigCamera(this.name + "_L", 0));
                 this._rigCameras.push(this.createRigCamera(this.name + "_L", 0));
                 this._rigCameras.push(this.createRigCamera(this.name + "_R", 1));
                 this._rigCameras.push(this.createRigCamera(this.name + "_R", 1));
             }
             }
@@ -463,14 +466,14 @@
                 case Camera.RIG_MODE_STEREOSCOPIC_SIDEBYSIDE_CROSSEYED:
                 case Camera.RIG_MODE_STEREOSCOPIC_SIDEBYSIDE_CROSSEYED:
                 case Camera.RIG_MODE_STEREOSCOPIC_OVERUNDER:
                 case Camera.RIG_MODE_STEREOSCOPIC_OVERUNDER:
                     var isStereoscopicHoriz = this.cameraRigMode === Camera.RIG_MODE_STEREOSCOPIC_SIDEBYSIDE_PARALLEL || this.cameraRigMode === Camera.RIG_MODE_STEREOSCOPIC_SIDEBYSIDE_CROSSEYED;
                     var isStereoscopicHoriz = this.cameraRigMode === Camera.RIG_MODE_STEREOSCOPIC_SIDEBYSIDE_PARALLEL || this.cameraRigMode === Camera.RIG_MODE_STEREOSCOPIC_SIDEBYSIDE_CROSSEYED;
-                    
+
                     this._rigCameras[0]._rigPostProcess = new PassPostProcess(this.name + "_passthru", 1.0, this._rigCameras[0]);
                     this._rigCameras[0]._rigPostProcess = new PassPostProcess(this.name + "_passthru", 1.0, this._rigCameras[0]);
                     this._rigCameras[1]._rigPostProcess = new StereoscopicInterlacePostProcess(this.name + "_stereoInterlace", this._rigCameras, isStereoscopicHoriz);
                     this._rigCameras[1]._rigPostProcess = new StereoscopicInterlacePostProcess(this.name + "_stereoInterlace", this._rigCameras, isStereoscopicHoriz);
                     break;
                     break;
 
 
                 case Camera.RIG_MODE_VR:
                 case Camera.RIG_MODE_VR:
                     var metrics = rigParams.vrCameraMetrics || VRCameraMetrics.GetDefault();
                     var metrics = rigParams.vrCameraMetrics || VRCameraMetrics.GetDefault();
-                    
+
                     this._rigCameras[0]._cameraRigParams.vrMetrics = metrics;
                     this._rigCameras[0]._cameraRigParams.vrMetrics = metrics;
                     this._rigCameras[0].viewport = new Viewport(0, 0, 0.5, 1.0);
                     this._rigCameras[0].viewport = new Viewport(0, 0, 0.5, 1.0);
                     this._rigCameras[0]._cameraRigParams.vrWorkMatrix = new Matrix();
                     this._rigCameras[0]._cameraRigParams.vrWorkMatrix = new Matrix();
@@ -492,7 +495,7 @@
                     break;
                     break;
             }
             }
 
 
-            this._cascadePostProcessesToRigCams(); 
+            this._cascadePostProcessesToRigCams();
             this._update();
             this._update();
         }
         }
 
 
@@ -503,8 +506,8 @@
         }
         }
 
 
         public setCameraRigParameter(name: string, value: any) {
         public setCameraRigParameter(name: string, value: any) {
-            if (!this._cameraRigParams){
-               this._cameraRigParams = {}; 
+            if (!this._cameraRigParams) {
+                this._cameraRigParams = {};
             }
             }
             this._cameraRigParams[name] = value;
             this._cameraRigParams[name] = value;
             //provisionnally:
             //provisionnally:
@@ -512,14 +515,14 @@
                 this._cameraRigParams.stereoHalfAngle = Tools.ToRadians(value / 0.0637);
                 this._cameraRigParams.stereoHalfAngle = Tools.ToRadians(value / 0.0637);
             }
             }
         }
         }
-        
+
         /**
         /**
          * needs to be overridden by children so sub has required properties to be copied
          * needs to be overridden by children so sub has required properties to be copied
          */
          */
         public createRigCamera(name: string, cameraIndex: number): Camera {
         public createRigCamera(name: string, cameraIndex: number): Camera {
-           return null;
+            return null;
         }
         }
-        
+
         /**
         /**
          * May need to be overridden by children
          * May need to be overridden by children
          */
          */
@@ -529,7 +532,7 @@
                 this._rigCameras[i].maxZ = this.maxZ;
                 this._rigCameras[i].maxZ = this.maxZ;
                 this._rigCameras[i].fov = this.fov;
                 this._rigCameras[i].fov = this.fov;
             }
             }
-            
+
             // only update viewport when ANAGLYPH
             // only update viewport when ANAGLYPH
             if (this.cameraRigMode === Camera.RIG_MODE_STEREOSCOPIC_ANAGLYPH) {
             if (this.cameraRigMode === Camera.RIG_MODE_STEREOSCOPIC_ANAGLYPH) {
                 this._rigCameras[0].viewport = this._rigCameras[1].viewport = this.viewport;
                 this._rigCameras[0].viewport = this._rigCameras[1].viewport = this.viewport;
@@ -621,14 +624,14 @@
             if (parsedCamera.parentId) {
             if (parsedCamera.parentId) {
                 camera._waitingParentId = parsedCamera.parentId;
                 camera._waitingParentId = parsedCamera.parentId;
             }
             }
-            
+
             //If camera has an input manager, let it parse inputs settings
             //If camera has an input manager, let it parse inputs settings
             if (camera.inputs) {
             if (camera.inputs) {
                 camera.inputs.parse(parsedCamera);
                 camera.inputs.parse(parsedCamera);
 
 
                 camera._setupInputs();
                 camera._setupInputs();
             }
             }
-            
+
             // Target
             // Target
             if (parsedCamera.target) {
             if (parsedCamera.target) {
                 if ((<any>camera).setTarget) {
                 if ((<any>camera).setTarget) {
@@ -659,8 +662,4 @@
             return camera;
             return camera;
         }
         }
     }
     }
-}
-
-
-
-
+}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

@@ -35,7 +35,7 @@ var BABYLON;
         LockableBase.prototype.onLock = function () {
         LockableBase.prototype.onLock = function () {
         };
         };
         return LockableBase;
         return LockableBase;
-    })();
+    }());
     BABYLON.LockableBase = 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).
      * 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")
             BABYLON.className("SolidColorBrush2D")
         ], SolidColorBrush2D);
         ], SolidColorBrush2D);
         return SolidColorBrush2D;
         return SolidColorBrush2D;
-    })(LockableBase);
+    }(LockableBase));
     BABYLON.SolidColorBrush2D = SolidColorBrush2D;
     BABYLON.SolidColorBrush2D = SolidColorBrush2D;
     var GradientColorBrush2D = (function (_super) {
     var GradientColorBrush2D = (function (_super) {
         __extends(GradientColorBrush2D, _super);
         __extends(GradientColorBrush2D, _super);
@@ -179,6 +179,6 @@ var BABYLON;
             BABYLON.className("GradientColorBrush2D")
             BABYLON.className("GradientColorBrush2D")
         ], GradientColorBrush2D);
         ], GradientColorBrush2D);
         return GradientColorBrush2D;
         return GradientColorBrush2D;
-    })(LockableBase);
+    }(LockableBase));
     BABYLON.GradientColorBrush2D = GradientColorBrush2D;
     BABYLON.GradientColorBrush2D = GradientColorBrush2D;
 })(BABYLON || (BABYLON = {}));
 })(BABYLON || (BABYLON = {}));

+ 42 - 37
src/Canvas2d/babylon.canvas2d.js

@@ -26,7 +26,7 @@ var BABYLON;
             return true;
             return true;
         };
         };
         return Canvas2DEngineBoundData;
         return Canvas2DEngineBoundData;
-    })();
+    }());
     BABYLON.Canvas2DEngineBoundData = Canvas2DEngineBoundData;
     BABYLON.Canvas2DEngineBoundData = Canvas2DEngineBoundData;
     var Canvas2D = (function (_super) {
     var Canvas2D = (function (_super) {
         __extends(Canvas2D, _super);
         __extends(Canvas2D, _super);
@@ -36,64 +36,62 @@ var BABYLON;
             this._mapCounter = 0;
             this._mapCounter = 0;
         }
         }
         /**
         /**
-         * Create a new 2D ScreenSpace Rendering Canvas, it is a 2D rectangle that has a size (width/height) and a position relative to the top/left corner of the screen.
+         * Create a new 2D ScreenSpace Rendering Canvas, it is a 2D rectangle that has a size (width/height) and a position relative to the bottom/left corner of the screen.
          * ScreenSpace Canvas will be drawn in the Viewport as a 2D Layer lying to the top of the 3D Scene. Typically used for traditional UI.
          * ScreenSpace Canvas will be drawn in the Viewport as a 2D Layer lying to the top of the 3D Scene. Typically used for traditional UI.
          * All caching strategies will be available.
          * All caching strategies will be available.
          * PLEASE NOTE: the origin of a Screen Space Canvas is set to [0;0] (bottom/left) which is different than the default origin of a Primitive which is centered [0.5;0.5]
          * PLEASE NOTE: the origin of a Screen Space Canvas is set to [0;0] (bottom/left) which is different than the default origin of a Primitive which is centered [0.5;0.5]
          * @param scene the Scene that owns the Canvas
          * @param scene the Scene that owns the Canvas
-         * @param name the name of the Canvas, for information purpose only
-         * @param pos the position of the canvas, relative from the bottom/left of the scene's viewport
-         * @param 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
-         * @param cachingStrategy either CACHESTRATEGY_TOPLEVELGROUPS, CACHESTRATEGY_ALLGROUPS, CACHESTRATEGY_CANVAS, CACHESTRATEGY_DONTCACHE. Please refer to their respective documentation for more information.
+         * 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
+         *  - enableInteraction: if true the pointer events will be listened and rerouted to the appropriate primitives of the Canvas2D through the Prim2DBase.onPointerEventObservable observable property.
          */
          */
-        Canvas2D.CreateScreenSpace = function (scene, name, pos, size, cachingStrategy, enableInteraction) {
-            if (cachingStrategy === void 0) { cachingStrategy = Canvas2D.CACHESTRATEGY_TOPLEVELGROUPS; }
-            if (enableInteraction === void 0) { enableInteraction = true; }
+        Canvas2D.CreateScreenSpace = function (scene, options) {
             var c = new Canvas2D();
             var c = new Canvas2D();
-            c.setupCanvas(scene, name, size, true, cachingStrategy, enableInteraction);
-            c.position = pos;
-            c.origin = BABYLON.Vector2.Zero();
+            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();
             return c;
             return c;
         };
         };
         /**
         /**
          * Create a new 2D WorldSpace Rendering Canvas, it is a 2D rectangle that has a size (width/height) and a world transformation information to place it in the world space.
          * Create a new 2D WorldSpace Rendering Canvas, it is a 2D rectangle that has a size (width/height) and a world transformation information to place it in the world space.
          * This kind of canvas can't have its Primitives directly drawn in the Viewport, they need to be cached in a bitmap at some point, as a consequence the DONT_CACHE strategy is unavailable. For now only CACHESTRATEGY_CANVAS is supported, but the remaining strategies will be soon.
          * This kind of canvas can't have its Primitives directly drawn in the Viewport, they need to be cached in a bitmap at some point, as a consequence the DONT_CACHE strategy is unavailable. For now only CACHESTRATEGY_CANVAS is supported, but the remaining strategies will be soon.
          * @param scene the Scene that owns the Canvas
          * @param scene the Scene that owns the Canvas
-         * @param name the name of the Canvas, for information purpose only
-         * @param position the position of the Canvas in World Space
-         * @param rotation the rotation of the Canvas in World Space
          * @param size the dimension of the Canvas in World Space
          * @param size the dimension of the Canvas in World Space
-         * @param renderScaleFactor A scale factor applied to create the rendering texture that will be mapped in the Scene Rectangle. If you set 2 for instance the texture will be twice large in width and height. A greater value will allow to achieve a better rendering quality.
+         * Options:
+         *  - id: a text identifier, for information purpose only, default is null.
+         *  - position the position of the Canvas in World Space, default is [0,0,0]
+         *  - rotation the rotation of the Canvas in World Space, default is Quaternion.Identity()
+         *  - renderScaleFactor A scale factor applied to create the rendering texture that will be mapped in the Scene Rectangle. If you set 2 for instance the texture will be twice large in width and height. A greater value will allow to achieve a better rendering quality. Default value is 1.
          * BE AWARE that the Canvas true dimension will be size*renderScaleFactor, then all coordinates and size will have to be express regarding this size.
          * BE AWARE that the Canvas true dimension will be size*renderScaleFactor, then all coordinates and size will have to be express regarding this size.
          * 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.
          * 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.
-         * @param sideOrientation Unexpected behavior occur if the value is different from Mesh.DEFAULTSIDE right now, so please use this one.
-         * @param cachingStrategy Must be CACHESTRATEGY_CANVAS for now
+         * - 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.
          */
          */
-        Canvas2D.CreateWorldSpace = function (scene, name, position, rotation, size, renderScaleFactor, sideOrientation, cachingStrategy, enableInteraction) {
-            if (renderScaleFactor === void 0) { renderScaleFactor = 1; }
-            if (cachingStrategy === void 0) { cachingStrategy = Canvas2D.CACHESTRATEGY_TOPLEVELGROUPS; }
-            if (enableInteraction === void 0) { enableInteraction = true; }
-            if (cachingStrategy !== Canvas2D.CACHESTRATEGY_CANVAS) {
+        Canvas2D.CreateWorldSpace = function (scene, size, options) {
+            var cs = options && options.cachingStrategy || Canvas2D.CACHESTRATEGY_CANVAS;
+            if (cs !== Canvas2D.CACHESTRATEGY_CANVAS) {
                 throw new Error("Right now only the CACHESTRATEGY_CANVAS cache Strategy is supported for WorldSpace Canvas. More will come soon!");
                 throw new Error("Right now only the CACHESTRATEGY_CANVAS cache Strategy is supported for WorldSpace Canvas. More will come soon!");
             }
             }
             //if (cachingStrategy === Canvas2D.CACHESTRATEGY_DONTCACHE) {
             //if (cachingStrategy === Canvas2D.CACHESTRATEGY_DONTCACHE) {
             //    throw new Error("CACHESTRATEGY_DONTCACHE cache Strategy can't be used for WorldSpace Canvas");
             //    throw new Error("CACHESTRATEGY_DONTCACHE cache Strategy can't be used for WorldSpace Canvas");
             //}
             //}
-            if (!sideOrientation) {
-                sideOrientation = BABYLON.Mesh.DEFAULTSIDE;
-            }
+            var id = options && options.id || null;
+            var rsf = options && options.renderScaleFactor || 1;
             var c = new Canvas2D();
             var c = new Canvas2D();
-            c.setupCanvas(scene, name, new BABYLON.Size(size.width * renderScaleFactor, size.height * renderScaleFactor), false, cachingStrategy, enableInteraction);
-            var plane = new BABYLON.WorldSpaceCanvas2d(name, scene, c);
-            var vertexData = BABYLON.VertexData.CreatePlane({ width: size.width / 2, height: size.height / 2, sideOrientation: sideOrientation });
-            var mtl = new BABYLON.StandardMaterial(name + "_Material", scene);
+            c.setupCanvas(scene, id, new BABYLON.Size(size.width * rsf, size.height * rsf), false, cs, options && options.enableInteraction || true);
+            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);
             c.applyCachedTexture(vertexData, mtl);
             c.applyCachedTexture(vertexData, mtl);
             vertexData.applyToMesh(plane, false);
             vertexData.applyToMesh(plane, false);
             mtl.specularColor = new BABYLON.Color3(0, 0, 0);
             mtl.specularColor = new BABYLON.Color3(0, 0, 0);
             mtl.disableLighting = true;
             mtl.disableLighting = true;
             mtl.useAlphaFromDiffuseTexture = true;
             mtl.useAlphaFromDiffuseTexture = true;
-            plane.position = position;
-            plane.rotationQuaternion = rotation;
+            plane.position = options && options.position || BABYLON.Vector3.Zero();
+            plane.rotationQuaternion = options && options.rotation || BABYLON.Quaternion.Identity();
             plane.material = mtl;
             plane.material = mtl;
             c._worldSpaceNode = plane;
             c._worldSpaceNode = plane;
             return c;
             return c;
@@ -110,7 +108,7 @@ var BABYLON;
             this._primPointerInfo = new BABYLON.PrimitivePointerInfo();
             this._primPointerInfo = new BABYLON.PrimitivePointerInfo();
             this._capturedPointers = new BABYLON.StringDictionary();
             this._capturedPointers = new BABYLON.StringDictionary();
             this._pickStartingPosition = BABYLON.Vector2.Zero();
             this._pickStartingPosition = BABYLON.Vector2.Zero();
-            this.setupGroup2D(this, null, name, BABYLON.Vector2.Zero(), size, this._cachingStrategy === Canvas2D.CACHESTRATEGY_ALLGROUPS ? BABYLON.Group2D.GROUPCACHEBEHAVIOR_DONTCACHEOVERRIDE : BABYLON.Group2D.GROUPCACHEBEHAVIOR_FOLLOWCACHESTRATEGY);
+            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._hierarchyLevelMaxSiblingCount = 100;
             this._hierarchyDepthOffset = 0;
             this._hierarchyDepthOffset = 0;
             this._siblingDepthOffset = 1 / this._hierarchyLevelMaxSiblingCount;
             this._siblingDepthOffset = 1 / this._hierarchyLevelMaxSiblingCount;
@@ -122,7 +120,7 @@ var BABYLON;
                 _this.dispose();
                 _this.dispose();
             });
             });
             if (cachingstrategy !== Canvas2D.CACHESTRATEGY_TOPLEVELGROUPS) {
             if (cachingstrategy !== Canvas2D.CACHESTRATEGY_TOPLEVELGROUPS) {
-                this._background = BABYLON.Rectangle2D.Create(this, "###CANVAS BACKGROUND###", 0, 0, size.width, size.height);
+                this._background = BABYLON.Rectangle2D.Create(this, { id: "###CANVAS BACKGROUND###", width: size.width, height: size.height });
                 this._background.isPickable = false;
                 this._background.isPickable = false;
                 this._background.origin = BABYLON.Vector2.Zero();
                 this._background.origin = BABYLON.Vector2.Zero();
                 this._background.levelVisible = false;
                 this._background.levelVisible = false;
@@ -222,6 +220,10 @@ var BABYLON;
             return this._capturedPointers.get(pointerId.toString());
             return this._capturedPointers.get(pointerId.toString());
         };
         };
         Canvas2D.prototype._handlePointerEventForInteraction = function (eventData, eventState) {
         Canvas2D.prototype._handlePointerEventForInteraction = function (eventData, eventState) {
+            // Dispose check
+            if (this.isDisposed) {
+                return;
+            }
             // Update the this._primPointerInfo structure we'll send to observers using the PointerEvent data
             // Update the this._primPointerInfo structure we'll send to observers using the PointerEvent data
             this._updatePointerInfo(eventData);
             this._updatePointerInfo(eventData);
             var capturedPrim = this.getCapturedPrimitive(this._primPointerInfo.pointerId);
             var capturedPrim = this.getCapturedPrimitive(this._primPointerInfo.pointerId);
@@ -668,6 +670,9 @@ var BABYLON;
                 throw Error("Can't use Canvas Background with the caching strategy TOPLEVELGROUPS");
                 throw Error("Can't use Canvas Background with the caching strategy TOPLEVELGROUPS");
             }
             }
         };
         };
+        Canvas2D.prototype.onPrimBecomesDirty = function () {
+            this._addPrimToDirtyList(this);
+        };
         Canvas2D.prototype._updateCanvasState = function () {
         Canvas2D.prototype._updateCanvasState = function () {
             // Check if the update has already been made for this render Frame
             // Check if the update has already been made for this render Frame
             if (this.scene.getRenderId() === this._updateRenderId) {
             if (this.scene.getRenderId() === this._updateRenderId) {
@@ -752,12 +757,12 @@ var BABYLON;
                 // Special case if the canvas is entirely cached: create a group that will have a single sprite it will be rendered specifically at the very end of the rendering process
                 // Special case if the canvas is entirely cached: create a group that will have a single sprite it will be rendered specifically at the very end of the rendering process
                 if (this._cachingStrategy === Canvas2D.CACHESTRATEGY_CANVAS) {
                 if (this._cachingStrategy === Canvas2D.CACHESTRATEGY_CANVAS) {
                     this._cachedCanvasGroup = BABYLON.Group2D._createCachedCanvasGroup(this);
                     this._cachedCanvasGroup = BABYLON.Group2D._createCachedCanvasGroup(this);
-                    var sprite = BABYLON.Sprite2D.Create(this._cachedCanvasGroup, "__cachedCanvasSprite__", 0, 0, map, node.contentSize, node.pos);
+                    var sprite = BABYLON.Sprite2D.Create(this._cachedCanvasGroup, map, { id: "__cachedCanvasSprite__", spriteSize: node.contentSize, spriteLocation: node.pos });
                     sprite.zOrder = 1;
                     sprite.zOrder = 1;
                     sprite.origin = BABYLON.Vector2.Zero();
                     sprite.origin = BABYLON.Vector2.Zero();
                 }
                 }
                 else {
                 else {
-                    var sprite = BABYLON.Sprite2D.Create(parent, "__cachedSpriteOfGroup__" + group.id, group.position.x, group.position.y, map, node.contentSize, node.pos, false);
+                    var sprite = BABYLON.Sprite2D.Create(parent, map, { id: "__cachedSpriteOfGroup__" + group.id, x: group.position.x, y: group.position.y, spriteSize: node.contentSize, spriteLocation: node.pos });
                     sprite.origin = group.origin.clone();
                     sprite.origin = group.origin.clone();
                     res.sprite = sprite;
                     res.sprite = sprite;
                 }
                 }
@@ -821,6 +826,6 @@ var BABYLON;
             BABYLON.className("Canvas2D")
             BABYLON.className("Canvas2D")
         ], Canvas2D);
         ], Canvas2D);
         return Canvas2D;
         return Canvas2D;
-    })(BABYLON.Group2D);
+    }(BABYLON.Group2D));
     BABYLON.Canvas2D = Canvas2D;
     BABYLON.Canvas2D = Canvas2D;
 })(BABYLON || (BABYLON = {}));
 })(BABYLON || (BABYLON = {}));

+ 46 - 33
src/Canvas2d/babylon.canvas2d.ts

@@ -48,21 +48,23 @@
         public static CACHESTRATEGY_DONTCACHE = 4;
         public static CACHESTRATEGY_DONTCACHE = 4;
 
 
         /**
         /**
-         * Create a new 2D ScreenSpace Rendering Canvas, it is a 2D rectangle that has a size (width/height) and a position relative to the top/left corner of the screen.
+         * Create a new 2D ScreenSpace Rendering Canvas, it is a 2D rectangle that has a size (width/height) and a position relative to the bottom/left corner of the screen.
          * ScreenSpace Canvas will be drawn in the Viewport as a 2D Layer lying to the top of the 3D Scene. Typically used for traditional UI.
          * ScreenSpace Canvas will be drawn in the Viewport as a 2D Layer lying to the top of the 3D Scene. Typically used for traditional UI.
          * All caching strategies will be available.
          * All caching strategies will be available.
          * PLEASE NOTE: the origin of a Screen Space Canvas is set to [0;0] (bottom/left) which is different than the default origin of a Primitive which is centered [0.5;0.5]
          * PLEASE NOTE: the origin of a Screen Space Canvas is set to [0;0] (bottom/left) which is different than the default origin of a Primitive which is centered [0.5;0.5]
          * @param scene the Scene that owns the Canvas
          * @param scene the Scene that owns the Canvas
-         * @param name the name of the Canvas, for information purpose only
-         * @param pos the position of the canvas, relative from the bottom/left of the scene's viewport
-         * @param 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
-         * @param cachingStrategy either CACHESTRATEGY_TOPLEVELGROUPS, CACHESTRATEGY_ALLGROUPS, CACHESTRATEGY_CANVAS, CACHESTRATEGY_DONTCACHE. Please refer to their respective documentation for more information.
+         * 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
+         *  - enableInteraction: if true the pointer events will be listened and rerouted to the appropriate primitives of the Canvas2D through the Prim2DBase.onPointerEventObservable observable property.
          */
          */
-        static CreateScreenSpace(scene: Scene, name: string, pos: Vector2, size: Size, cachingStrategy: number = Canvas2D.CACHESTRATEGY_TOPLEVELGROUPS, enableInteraction: boolean = true): Canvas2D {
+        static CreateScreenSpace(scene: Scene, options: { id?: string, pos?: Vector2, origin?: Vector2, size?: Size, cachingStrategy?: number, enableInteraction?: boolean }): Canvas2D {
             let c = new Canvas2D();
             let c = new Canvas2D();
-            c.setupCanvas(scene, name, size, true, cachingStrategy, enableInteraction);
-            c.position = pos;
-            c.origin = Vector2.Zero();
+            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 || Vector2.Zero();
+            c.origin = options && options.origin || Vector2.Zero();
 
 
             return c;
             return c;
         }
         }
@@ -71,18 +73,22 @@
          * Create a new 2D WorldSpace Rendering Canvas, it is a 2D rectangle that has a size (width/height) and a world transformation information to place it in the world space.
          * Create a new 2D WorldSpace Rendering Canvas, it is a 2D rectangle that has a size (width/height) and a world transformation information to place it in the world space.
          * This kind of canvas can't have its Primitives directly drawn in the Viewport, they need to be cached in a bitmap at some point, as a consequence the DONT_CACHE strategy is unavailable. For now only CACHESTRATEGY_CANVAS is supported, but the remaining strategies will be soon.
          * This kind of canvas can't have its Primitives directly drawn in the Viewport, they need to be cached in a bitmap at some point, as a consequence the DONT_CACHE strategy is unavailable. For now only CACHESTRATEGY_CANVAS is supported, but the remaining strategies will be soon.
          * @param scene the Scene that owns the Canvas
          * @param scene the Scene that owns the Canvas
-         * @param name the name of the Canvas, for information purpose only
-         * @param position the position of the Canvas in World Space
-         * @param rotation the rotation of the Canvas in World Space
          * @param size the dimension of the Canvas in World Space
          * @param size the dimension of the Canvas in World Space
-         * @param renderScaleFactor A scale factor applied to create the rendering texture that will be mapped in the Scene Rectangle. If you set 2 for instance the texture will be twice large in width and height. A greater value will allow to achieve a better rendering quality.
+         * Options:
+         *  - id: a text identifier, for information purpose only, default is null.
+         *  - position the position of the Canvas in World Space, default is [0,0,0]
+         *  - rotation the rotation of the Canvas in World Space, default is Quaternion.Identity()
+         *  - renderScaleFactor A scale factor applied to create the rendering texture that will be mapped in the Scene Rectangle. If you set 2 for instance the texture will be twice large in width and height. A greater value will allow to achieve a better rendering quality. Default value is 1.
          * BE AWARE that the Canvas true dimension will be size*renderScaleFactor, then all coordinates and size will have to be express regarding this size.
          * BE AWARE that the Canvas true dimension will be size*renderScaleFactor, then all coordinates and size will have to be express regarding this size.
          * 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.
          * 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.
-         * @param sideOrientation Unexpected behavior occur if the value is different from Mesh.DEFAULTSIDE right now, so please use this one.
-         * @param cachingStrategy Must be CACHESTRATEGY_CANVAS for now
+         * - 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.
          */
          */
-        static CreateWorldSpace(scene: Scene, name: string, position: Vector3, rotation: Quaternion, size: Size, renderScaleFactor: number = 1, sideOrientation?: number, cachingStrategy: number = Canvas2D.CACHESTRATEGY_TOPLEVELGROUPS, enableInteraction: boolean = true): Canvas2D {
-            if (cachingStrategy !== Canvas2D.CACHESTRATEGY_CANVAS) {
+        static CreateWorldSpace(scene: Scene, size: Size, options: { id?: string, position?: Vector3, rotation?: Quaternion, renderScaleFactor?: number, sideOrientation?: number, cachingStrategy?: number, enableInteraction?: boolean}): Canvas2D {
+
+            let cs = options && options.cachingStrategy || Canvas2D.CACHESTRATEGY_CANVAS;
+
+            if (cs !== Canvas2D.CACHESTRATEGY_CANVAS) {
                 throw new Error("Right now only the CACHESTRATEGY_CANVAS cache Strategy is supported for WorldSpace Canvas. More will come soon!");
                 throw new Error("Right now only the CACHESTRATEGY_CANVAS cache Strategy is supported for WorldSpace Canvas. More will come soon!");
             }
             }
 
 
@@ -90,16 +96,14 @@
             //    throw new Error("CACHESTRATEGY_DONTCACHE cache Strategy can't be used for WorldSpace Canvas");
             //    throw new Error("CACHESTRATEGY_DONTCACHE cache Strategy can't be used for WorldSpace Canvas");
             //}
             //}
 
 
-            if (!sideOrientation) {
-                sideOrientation = Mesh.DEFAULTSIDE;
-            }
-
+            let id = options && options.id || null;
+            let rsf = options && options.renderScaleFactor || 1;
             let c = new Canvas2D();
             let c = new Canvas2D();
-            c.setupCanvas(scene, name, new Size(size.width*renderScaleFactor, size.height*renderScaleFactor), false, cachingStrategy, enableInteraction);
+            c.setupCanvas(scene, id, new Size(size.width * rsf, size.height * rsf), false, cs, options && options.enableInteraction || true);
 
 
-            let plane = new WorldSpaceCanvas2d(name, scene, c);
-            let vertexData = VertexData.CreatePlane({ width: size.width/2, height: size.height/2, sideOrientation: sideOrientation });
-            let mtl = new StandardMaterial(name + "_Material", scene);
+            let plane = new WorldSpaceCanvas2D(id, scene, c);
+            let vertexData = VertexData.CreatePlane({ width: size.width / 2, height: size.height / 2, sideOrientation: options && options.sideOrientation || Mesh.DEFAULTSIDE });
+            let mtl = new StandardMaterial(id + "_Material", scene);
 
 
             c.applyCachedTexture(vertexData, mtl);
             c.applyCachedTexture(vertexData, mtl);
             vertexData.applyToMesh(plane, false);
             vertexData.applyToMesh(plane, false);
@@ -107,8 +111,8 @@
             mtl.specularColor = new Color3(0, 0, 0);
             mtl.specularColor = new Color3(0, 0, 0);
             mtl.disableLighting =true;
             mtl.disableLighting =true;
             mtl.useAlphaFromDiffuseTexture = true;
             mtl.useAlphaFromDiffuseTexture = true;
-            plane.position = position;
-            plane.rotationQuaternion = rotation;
+            plane.position = options && options.position || Vector3.Zero();
+            plane.rotationQuaternion = options && options.rotation || Quaternion.Identity();
             plane.material = mtl;
             plane.material = mtl;
             c._worldSpaceNode = plane;
             c._worldSpaceNode = plane;
 
 
@@ -127,7 +131,7 @@
             this._capturedPointers = new StringDictionary<Prim2DBase>();
             this._capturedPointers = new StringDictionary<Prim2DBase>();
             this._pickStartingPosition = Vector2.Zero();
             this._pickStartingPosition = Vector2.Zero();
 
 
-            this.setupGroup2D(this, null, name, Vector2.Zero(), size, this._cachingStrategy===Canvas2D.CACHESTRATEGY_ALLGROUPS ? Group2D.GROUPCACHEBEHAVIOR_DONTCACHEOVERRIDE : Group2D.GROUPCACHEBEHAVIOR_FOLLOWCACHESTRATEGY);
+            this.setupGroup2D(this, null, name, Vector2.Zero(), null, size, this._cachingStrategy===Canvas2D.CACHESTRATEGY_ALLGROUPS ? Group2D.GROUPCACHEBEHAVIOR_DONTCACHEOVERRIDE : Group2D.GROUPCACHEBEHAVIOR_FOLLOWCACHESTRATEGY);
 
 
             this._hierarchyLevelMaxSiblingCount = 100;
             this._hierarchyLevelMaxSiblingCount = 100;
             this._hierarchyDepthOffset = 0;
             this._hierarchyDepthOffset = 0;
@@ -142,7 +146,7 @@
             });
             });
 
 
             if (cachingstrategy !== Canvas2D.CACHESTRATEGY_TOPLEVELGROUPS) {
             if (cachingstrategy !== Canvas2D.CACHESTRATEGY_TOPLEVELGROUPS) {
-                this._background = Rectangle2D.Create(this, "###CANVAS BACKGROUND###", 0, 0, size.width, size.height);
+                this._background = Rectangle2D.Create(this, { id: "###CANVAS BACKGROUND###", width: size.width, height: size.height});
                 this._background.isPickable = false;
                 this._background.isPickable = false;
                 this._background.origin = Vector2.Zero();
                 this._background.origin = Vector2.Zero();
                 this._background.levelVisible = false;
                 this._background.levelVisible = false;
@@ -257,6 +261,11 @@
            
            
         private static _interInfo = new IntersectInfo2D();
         private static _interInfo = new IntersectInfo2D();
         private _handlePointerEventForInteraction(eventData: PointerInfoPre, eventState: EventState) {
         private _handlePointerEventForInteraction(eventData: PointerInfoPre, eventState: EventState) {
+            // Dispose check
+            if (this.isDisposed) {
+                return;
+            }
+
             // Update the this._primPointerInfo structure we'll send to observers using the PointerEvent data
             // Update the this._primPointerInfo structure we'll send to observers using the PointerEvent data
             this._updatePointerInfo(eventData);
             this._updatePointerInfo(eventData);
 
 
@@ -640,7 +649,7 @@
         /**
         /**
          * Only valid for World Space Canvas, returns the scene node that display the canvas
          * Only valid for World Space Canvas, returns the scene node that display the canvas
          */
          */
-        public get worldSpaceCanvasNode(): WorldSpaceCanvas2d {
+        public get worldSpaceCanvasNode(): WorldSpaceCanvas2D {
             return this._worldSpaceNode;
             return this._worldSpaceNode;
         }
         }
 
 
@@ -757,7 +766,7 @@
         private _actualOverPrimitive: PrimitiveIntersectedInfo;
         private _actualOverPrimitive: PrimitiveIntersectedInfo;
         private _capturedPointers: StringDictionary<Prim2DBase>;
         private _capturedPointers: StringDictionary<Prim2DBase>;
         private _scenePrePointerObserver: Observer<PointerInfoPre>;
         private _scenePrePointerObserver: Observer<PointerInfoPre>;
-        private _worldSpaceNode: WorldSpaceCanvas2d;
+        private _worldSpaceNode: WorldSpaceCanvas2D;
         private _mapCounter = 0;
         private _mapCounter = 0;
         private _background: Rectangle2D;
         private _background: Rectangle2D;
         private _scene: Scene;
         private _scene: Scene;
@@ -774,6 +783,10 @@
 
 
         public _renderingSize: Size;
         public _renderingSize: Size;
 
 
+        protected onPrimBecomesDirty() {
+            this._addPrimToDirtyList(this);
+        }
+
         private _updateCanvasState() {
         private _updateCanvasState() {
             // Check if the update has already been made for this render Frame
             // Check if the update has already been made for this render Frame
             if (this.scene.getRenderId() === this._updateRenderId) {
             if (this.scene.getRenderId() === this._updateRenderId) {
@@ -877,14 +890,14 @@
                 // Special case if the canvas is entirely cached: create a group that will have a single sprite it will be rendered specifically at the very end of the rendering process
                 // Special case if the canvas is entirely cached: create a group that will have a single sprite it will be rendered specifically at the very end of the rendering process
                 if (this._cachingStrategy === Canvas2D.CACHESTRATEGY_CANVAS) {
                 if (this._cachingStrategy === Canvas2D.CACHESTRATEGY_CANVAS) {
                     this._cachedCanvasGroup = Group2D._createCachedCanvasGroup(this);
                     this._cachedCanvasGroup = Group2D._createCachedCanvasGroup(this);
-                    let sprite = Sprite2D.Create(this._cachedCanvasGroup, "__cachedCanvasSprite__", 0, 0, map, node.contentSize, node.pos);
+                    let sprite = Sprite2D.Create(this._cachedCanvasGroup, map, {id: "__cachedCanvasSprite__", spriteSize:node.contentSize, spriteLocation:node.pos});
                     sprite.zOrder = 1;
                     sprite.zOrder = 1;
                     sprite.origin = Vector2.Zero();
                     sprite.origin = Vector2.Zero();
                 }
                 }
 
 
                 // Create a Sprite that will be used to render this cache, the "__cachedSpriteOfGroup__" starting id is a hack to bypass exception throwing in case of the Canvas doesn't normally allows direct primitives
                 // Create a Sprite that will be used to render this cache, the "__cachedSpriteOfGroup__" starting id is a hack to bypass exception throwing in case of the Canvas doesn't normally allows direct primitives
                 else {
                 else {
-                    let sprite = Sprite2D.Create(parent, `__cachedSpriteOfGroup__${group.id}`, group.position.x, group.position.y, map, node.contentSize, node.pos, false);
+                    let sprite = Sprite2D.Create(parent, map, {id:`__cachedSpriteOfGroup__${group.id}`, x: group.position.x, y: group.position.y, spriteSize:node.contentSize, spriteLocation:node.pos});
                     sprite.origin = group.origin.clone();
                     sprite.origin = group.origin.clone();
                     res.sprite = sprite;
                     res.sprite = sprite;
                 }
                 }

+ 306 - 0
src/Canvas2d/babylon.ellipse2d.js

@@ -0,0 +1,306 @@
+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 __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
+    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
+    if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
+    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
+    return c > 3 && r && Object.defineProperty(target, key, r), r;
+};
+var BABYLON;
+(function (BABYLON) {
+    var Ellipse2DRenderCache = (function (_super) {
+        __extends(Ellipse2DRenderCache, _super);
+        function Ellipse2DRenderCache(engine, modelKey, isTransparent) {
+            _super.call(this, engine, modelKey, isTransparent);
+        }
+        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;
+            }
+            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);
+            }
+            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) {
+                    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);
+                    }
+                    engine.updateAndBindInstancesBuffer(instanceInfo._instancesPartsBuffer[partIndex], null, this.instancingFillAttributes);
+                    engine.draw(true, 0, this.fillIndicesCount, count);
+                    engine.unbindInstanceAttributes();
+                }
+                else {
+                    for (var i = 0; i < count; i++) {
+                        this.setupUniforms(this.effectFill, partIndex, instanceInfo._instancesPartsData[partIndex], 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) {
+                    if (!this.instancingBorderAttributes) {
+                        this.instancingBorderAttributes = this.loadInstancingAttributes(BABYLON.Shape2D.SHAPE2D_BORDERPARTID, this.effectBorder);
+                    }
+                    engine.updateAndBindInstancesBuffer(instanceInfo._instancesPartsBuffer[partIndex], null, this.instancingBorderAttributes);
+                    engine.draw(true, 0, this.borderIndicesCount, count);
+                    engine.unbindInstanceAttributes();
+                }
+                else {
+                    for (var i = 0; i < count; i++) {
+                        this.setupUniforms(this.effectBorder, partIndex, instanceInfo._instancesPartsData[partIndex], i);
+                        engine.draw(true, 0, this.borderIndicesCount);
+                    }
+                }
+            }
+            if (this.isTransparent) {
+                engine.setAlphaMode(cur);
+            }
+            if (this.effectFill && this.effectBorder) {
+                engine.setDepthFunction(depthFunction);
+            }
+            return true;
+        };
+        Ellipse2DRenderCache.prototype.dispose = function () {
+            if (!_super.prototype.dispose.call(this)) {
+                return false;
+            }
+            if (this.fillVB) {
+                this._engine._releaseBuffer(this.fillVB);
+                this.fillVB = null;
+            }
+            if (this.fillIB) {
+                this._engine._releaseBuffer(this.fillIB);
+                this.fillIB = null;
+            }
+            if (this.effectFill) {
+                this._engine._releaseEffect(this.effectFill);
+                this.effectFill = null;
+            }
+            if (this.borderVB) {
+                this._engine._releaseBuffer(this.borderVB);
+                this.borderVB = null;
+            }
+            if (this.borderIB) {
+                this._engine._releaseBuffer(this.borderIB);
+                this.borderIB = null;
+            }
+            if (this.effectBorder) {
+                this._engine._releaseEffect(this.effectBorder);
+                this.effectBorder = null;
+            }
+            return true;
+        };
+        return Ellipse2DRenderCache;
+    }(BABYLON.ModelRenderCache));
+    BABYLON.Ellipse2DRenderCache = Ellipse2DRenderCache;
+    var Ellipse2DInstanceData = (function (_super) {
+        __extends(Ellipse2DInstanceData, _super);
+        function Ellipse2DInstanceData(partId) {
+            _super.call(this, partId, 1);
+        }
+        Object.defineProperty(Ellipse2DInstanceData.prototype, "properties", {
+            get: function () {
+                return null;
+            },
+            enumerable: true,
+            configurable: true
+        });
+        __decorate([
+            BABYLON.instanceData()
+        ], Ellipse2DInstanceData.prototype, "properties", null);
+        return Ellipse2DInstanceData;
+    }(BABYLON.Shape2DInstanceData));
+    BABYLON.Ellipse2DInstanceData = Ellipse2DInstanceData;
+    var Ellipse2D = (function (_super) {
+        __extends(Ellipse2D, _super);
+        function Ellipse2D() {
+            _super.apply(this, arguments);
+        }
+        Object.defineProperty(Ellipse2D.prototype, "actualSize", {
+            get: function () {
+                return this.size;
+            },
+            enumerable: true,
+            configurable: true
+        });
+        Object.defineProperty(Ellipse2D.prototype, "size", {
+            get: function () {
+                return this._size;
+            },
+            set: function (value) {
+                this._size = value;
+            },
+            enumerable: true,
+            configurable: true
+        });
+        Object.defineProperty(Ellipse2D.prototype, "subdivisions", {
+            get: function () {
+                return this._subdivisions;
+            },
+            set: function (value) {
+                this._subdivisions = value;
+            },
+            enumerable: true,
+            configurable: true
+        });
+        Ellipse2D.prototype.levelIntersect = function (intersectInfo) {
+            var x = intersectInfo._localPickPosition.x;
+            var y = intersectInfo._localPickPosition.y;
+            var w = this.size.width / 2;
+            var h = this.size.height / 2;
+            return ((x * x) / (w * w) + (y * y) / (h * h)) <= 1;
+        };
+        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);
+            this.size = size;
+            this.subdivisions = subdivisions;
+        };
+        /**
+         * Create an Ellipse 2D Shape primitive
+         * @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
+         *  - 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
+         *  - 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.
+         */
+        Ellipse2D.Create = function (parent, options) {
+            BABYLON.Prim2DBase.CheckParent(parent);
+            var fill;
+            if (options && options.fill !== undefined) {
+                fill = options.fill;
+            }
+            else {
+                fill = BABYLON.Canvas2D.GetSolidColorBrushFromHex("#FFFFFFFF");
+            }
+            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);
+            return renderCache;
+        };
+        Ellipse2D.prototype.setupModelRenderCache = function (modelRenderCache) {
+            var renderCache = modelRenderCache;
+            var engine = this.owner.engine;
+            // Need to create WebGL resources for fill part?
+            if (this.fill) {
+                var vbSize = this.subdivisions + 1;
+                var vb = new Float32Array(vbSize);
+                for (var i = 0; i < vbSize; i++) {
+                    vb[i] = i;
+                }
+                renderCache.fillVB = engine.createVertexBuffer(vb);
+                var triCount = vbSize - 1;
+                var ib = new Float32Array(triCount * 3);
+                for (var i = 0; i < triCount; i++) {
+                    ib[i * 3 + 0] = 0;
+                    ib[i * 3 + 2] = i + 1;
+                    ib[i * 3 + 1] = i + 2;
+                }
+                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: "ellipse2d", fragment: "ellipse2d" }, ei.attributes, ei.uniforms, [], ei.defines, null);
+            }
+            // Need to create WebGL resource for border part?
+            if (this.border) {
+                var vbSize = this.subdivisions * 2;
+                var vb = new Float32Array(vbSize);
+                for (var i = 0; i < vbSize; i++) {
+                    vb[i] = i;
+                }
+                renderCache.borderVB = engine.createVertexBuffer(vb);
+                var triCount = vbSize;
+                var rs = triCount / 2;
+                var ib = new Float32Array(triCount * 3);
+                for (var i = 0; i < rs; i++) {
+                    var r0 = i;
+                    var r1 = (i + 1) % rs;
+                    ib[i * 6 + 0] = rs + r1;
+                    ib[i * 6 + 1] = rs + r0;
+                    ib[i * 6 + 2] = r0;
+                    ib[i * 6 + 3] = r1;
+                    ib[i * 6 + 4] = rs + r1;
+                    ib[i * 6 + 5] = r0;
+                }
+                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);
+            }
+            return renderCache;
+        };
+        Ellipse2D.prototype.createInstanceDataParts = function () {
+            var res = new Array();
+            if (this.border) {
+                res.push(new Ellipse2DInstanceData(BABYLON.Shape2D.SHAPE2D_BORDERPARTID));
+            }
+            if (this.fill) {
+                res.push(new Ellipse2DInstanceData(BABYLON.Shape2D.SHAPE2D_FILLPARTID));
+            }
+            return res;
+        };
+        Ellipse2D.prototype.refreshInstanceDataPart = function (part) {
+            if (!_super.prototype.refreshInstanceDataPart.call(this, part)) {
+                return false;
+            }
+            if (part.id === BABYLON.Shape2D.SHAPE2D_BORDERPARTID) {
+                var d = part;
+                var size = this.size;
+                d.properties = new BABYLON.Vector3(size.width, size.height, this.subdivisions);
+            }
+            else if (part.id === BABYLON.Shape2D.SHAPE2D_FILLPARTID) {
+                var d = part;
+                var size = this.size;
+                d.properties = new BABYLON.Vector3(size.width, size.height, this.subdivisions);
+            }
+            return true;
+        };
+        __decorate([
+            BABYLON.instanceLevelProperty(BABYLON.Shape2D.SHAPE2D_PROPCOUNT + 1, function (pi) { return Ellipse2D.sizeProperty = pi; }, false, true)
+        ], Ellipse2D.prototype, "size", null);
+        __decorate([
+            BABYLON.modelLevelProperty(BABYLON.Shape2D.SHAPE2D_PROPCOUNT + 2, function (pi) { return Ellipse2D.subdivisionsProperty = pi; })
+        ], Ellipse2D.prototype, "subdivisions", null);
+        Ellipse2D = __decorate([
+            BABYLON.className("Ellipse2D")
+        ], Ellipse2D);
+        return Ellipse2D;
+    }(BABYLON.Shape2D));
+    BABYLON.Ellipse2D = Ellipse2D;
+})(BABYLON || (BABYLON = {}));

+ 321 - 0
src/Canvas2d/babylon.ellipse2d.ts

@@ -0,0 +1,321 @@
+module BABYLON {
+    export class Ellipse2DRenderCache extends ModelRenderCache {
+        fillVB: WebGLBuffer;
+        fillIB: WebGLBuffer;
+        fillIndicesCount: number;
+        instancingFillAttributes: InstancingAttributeInfo[];
+        effectFill: Effect;
+
+        borderVB: WebGLBuffer;
+        borderIB: WebGLBuffer;
+        borderIndicesCount: number;
+        instancingBorderAttributes: InstancingAttributeInfo[];
+        effectBorder: Effect;
+
+        constructor(engine: Engine, modelKey: string, isTransparent: boolean) {
+            super(engine, modelKey, isTransparent);
+        }
+
+        render(instanceInfo: GroupInstanceInfo, context: Render2DContext): boolean {
+            // Do nothing if the shader is still loading/preparing 
+            if ((this.effectFill && !this.effectFill.isReady()) || (this.effectBorder && !this.effectBorder.isReady())) {
+                return false;
+            }
+
+            var engine = instanceInfo._owner.owner.engine;
+
+            let depthFunction = 0;
+            if (this.effectFill && this.effectBorder) {
+                depthFunction = engine.getDepthFunction();
+                engine.setDepthFunctionToLessOrEqual();
+            }
+
+            var cur: number;
+            if (this.isTransparent) {
+                cur = engine.getAlphaMode();
+                engine.setAlphaMode(Engine.ALPHA_COMBINE);
+            }
+
+            if (this.effectFill) {
+                let partIndex = instanceInfo._partIndexFromId.get(Shape2D.SHAPE2D_FILLPARTID.toString());
+
+                engine.enableEffect(this.effectFill);
+                engine.bindBuffersDirectly(this.fillVB, this.fillIB, [1], 4, this.effectFill);
+                let count = instanceInfo._instancesPartsData[partIndex].usedElementCount;
+                if (instanceInfo._owner.owner.supportInstancedArray) {
+                    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(Shape2D.SHAPE2D_FILLPARTID, this.effectFill);
+                    }
+
+                    engine.updateAndBindInstancesBuffer(instanceInfo._instancesPartsBuffer[partIndex], null, this.instancingFillAttributes);
+                    engine.draw(true, 0, this.fillIndicesCount, count);
+                    engine.unbindInstanceAttributes();
+                } else {
+                    for (let i = 0; i < count; i++) {
+                        this.setupUniforms(this.effectFill, partIndex, instanceInfo._instancesPartsData[partIndex], i);
+                        engine.draw(true, 0, this.fillIndicesCount);                        
+                    }
+                }
+            }
+
+            if (this.effectBorder) {
+                let partIndex = instanceInfo._partIndexFromId.get(Shape2D.SHAPE2D_BORDERPARTID.toString());
+
+                engine.enableEffect(this.effectBorder);
+                engine.bindBuffersDirectly(this.borderVB, this.borderIB, [1], 4, this.effectBorder);
+                let count = instanceInfo._instancesPartsData[partIndex].usedElementCount;
+                if (instanceInfo._owner.owner.supportInstancedArray) {
+                    if (!this.instancingBorderAttributes) {
+                        this.instancingBorderAttributes = this.loadInstancingAttributes(Shape2D.SHAPE2D_BORDERPARTID, this.effectBorder);
+                    }
+
+                    engine.updateAndBindInstancesBuffer(instanceInfo._instancesPartsBuffer[partIndex], null, this.instancingBorderAttributes);
+                    engine.draw(true, 0, this.borderIndicesCount, count);
+                    engine.unbindInstanceAttributes();
+                } else {
+                    for (let i = 0; i < count; i++) {
+                        this.setupUniforms(this.effectBorder, partIndex, instanceInfo._instancesPartsData[partIndex], i);
+                        engine.draw(true, 0, this.borderIndicesCount);
+                    }
+                }
+            }
+
+            if (this.isTransparent) {
+                engine.setAlphaMode(cur);
+            }
+
+            if (this.effectFill && this.effectBorder) {
+                engine.setDepthFunction(depthFunction);
+            }
+            return true;
+        }
+
+        public dispose(): boolean {
+            if (!super.dispose()) {
+                return false;
+            }
+
+            if (this.fillVB) {
+                this._engine._releaseBuffer(this.fillVB);
+                this.fillVB = null;
+            }
+
+            if (this.fillIB) {
+                this._engine._releaseBuffer(this.fillIB);
+                this.fillIB = null;
+            }
+
+            if (this.effectFill) {
+                this._engine._releaseEffect(this.effectFill);
+                this.effectFill = null;
+            }
+
+            if (this.borderVB) {
+                this._engine._releaseBuffer(this.borderVB);
+                this.borderVB = null;
+            }
+
+            if (this.borderIB) {
+                this._engine._releaseBuffer(this.borderIB);
+                this.borderIB = null;
+            }
+
+            if (this.effectBorder) {
+                this._engine._releaseEffect(this.effectBorder);
+                this.effectBorder = null;
+            }
+
+            return true;
+        }
+    }
+
+    export class Ellipse2DInstanceData extends Shape2DInstanceData {
+        constructor(partId: number) {
+            super(partId, 1);
+        }
+
+        @instanceData()
+        get properties(): Vector3 {
+            return null;
+        }
+    }
+
+    @className("Ellipse2D")
+    export class Ellipse2D extends Shape2D {
+
+        public static sizeProperty: Prim2DPropInfo;
+        public static subdivisionsProperty: Prim2DPropInfo;
+
+        public get actualSize(): Size {
+            return this.size;
+        }
+
+        @instanceLevelProperty(Shape2D.SHAPE2D_PROPCOUNT + 1, pi => Ellipse2D.sizeProperty = pi, false, true)
+        public get size(): Size {
+            return this._size;
+        }
+
+        public set size(value: Size) {
+            this._size = value;
+        }
+
+        @modelLevelProperty(Shape2D.SHAPE2D_PROPCOUNT + 2, pi => Ellipse2D.subdivisionsProperty = pi)
+        public get subdivisions(): number {
+            return this._subdivisions;
+        }
+
+        public set subdivisions(value: number) {
+            this._subdivisions = value;
+        }
+
+        protected levelIntersect(intersectInfo: IntersectInfo2D): boolean {
+            let x = intersectInfo._localPickPosition.x;
+            let y = intersectInfo._localPickPosition.y;
+            let w = this.size.width/2;
+            let h = this.size.height/2;
+            return ((x * x) / (w * w) + (y * y) / (h * h)) <= 1;
+        }
+
+        protected updateLevelBoundingInfo() {
+            BoundingInfo2D.CreateFromSizeToRef(this.size, this._levelBoundingInfo, this.origin);
+        }
+
+        protected setupEllipse2D(owner: Canvas2D, parent: Prim2DBase, id: string, position: Vector2, origin: Vector2, size: Size, subdivisions: number=64, fill?: IBrush2D, border?: IBrush2D, borderThickness: number = 1) {
+            this.setupShape2D(owner, parent, id, position, origin, true, fill, border, borderThickness);
+            this.size = size;
+            this.subdivisions = subdivisions;
+        }
+
+        /**
+         * Create an Ellipse 2D Shape primitive
+         * @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
+         *  - 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
+         *  - 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.
+         */
+        public static Create(parent: Prim2DBase, options: { id?: string, x?: number, y?: number, origin?: Vector2, width?: number, height?: number, subdivisions?: number, fill?: IBrush2D, border?: IBrush2D, borderThickness?: number }): Ellipse2D {
+            Prim2DBase.CheckParent(parent);
+
+            let fill: IBrush2D;
+            if (options && options.fill !== undefined) {
+                fill = options.fill;
+            } else {
+                fill = Canvas2D.GetSolidColorBrushFromHex("#FFFFFFFF");
+            }
+
+            let ellipse = new Ellipse2D();
+            ellipse.setupEllipse2D(parent.owner, parent, options && options.id || null, new Vector2(options && options.x || 0, options && options.y || 0), options && options.origin || null, new Size(options && options.width || 10, options && options.height || 10), options && options.subdivisions || 64, fill, options && options.border || null, options && options.borderThickness || 1);
+            return ellipse;
+        }
+
+        protected createModelRenderCache(modelKey: string, isTransparent: boolean): ModelRenderCache {
+            let renderCache = new Ellipse2DRenderCache(this.owner.engine, modelKey, isTransparent);
+            return renderCache;
+        }
+
+        protected setupModelRenderCache(modelRenderCache: ModelRenderCache) {
+            let renderCache = <Ellipse2DRenderCache>modelRenderCache;
+            let engine = this.owner.engine;
+
+            // Need to create WebGL resources for fill part?
+            if (this.fill) {
+                let vbSize = this.subdivisions + 1;
+                let vb = new Float32Array(vbSize);
+                for (let i = 0; i < vbSize; i++) {
+                    vb[i] = i;
+                }
+                renderCache.fillVB = engine.createVertexBuffer(vb);
+
+                let triCount = vbSize - 1;
+                let ib = new Float32Array(triCount * 3);
+                for (let i = 0; i < triCount; i++) {
+                    ib[i * 3 + 0] = 0;
+                    ib[i * 3 + 2] = i + 1;
+                    ib[i * 3 + 1] = i + 2;
+                }
+                ib[triCount * 3 - 2] = 1;
+
+                renderCache.fillIB = engine.createIndexBuffer(ib);
+                renderCache.fillIndicesCount = triCount * 3;
+
+                let ei = this.getDataPartEffectInfo(Shape2D.SHAPE2D_FILLPARTID, ["index"]);
+                renderCache.effectFill = engine.createEffect({ vertex: "ellipse2d", fragment: "ellipse2d" }, ei.attributes, ei.uniforms, [], ei.defines, null);
+            }
+
+            // Need to create WebGL resource for border part?
+            if (this.border) {
+                let vbSize = this.subdivisions * 2;
+                let vb = new Float32Array(vbSize);
+                for (let i = 0; i < vbSize; i++) {
+                    vb[i] = i;
+                }
+                renderCache.borderVB = engine.createVertexBuffer(vb);
+
+                let triCount = vbSize;
+                let rs = triCount / 2;
+                let ib = new Float32Array(triCount * 3);
+                for (let i = 0; i < rs; i++) {
+                    let r0 = i;
+                    let r1 = (i + 1) % rs;
+
+                    ib[i * 6 + 0] = rs + r1;
+                    ib[i * 6 + 1] = rs + r0;
+                    ib[i * 6 + 2] = r0;
+
+                    ib[i * 6 + 3] = r1;
+                    ib[i * 6 + 4] = rs + r1;
+                    ib[i * 6 + 5] = r0;
+                }
+
+                renderCache.borderIB = engine.createIndexBuffer(ib);
+                renderCache.borderIndicesCount = (triCount* 3);
+
+                let ei = this.getDataPartEffectInfo(Shape2D.SHAPE2D_BORDERPARTID, ["index"]);
+                renderCache.effectBorder = engine.createEffect({ vertex: "ellipse2d", fragment: "ellipse2d" }, ei.attributes, ei.uniforms, [], ei.defines, null);
+            }
+
+            return renderCache;
+        }
+
+
+        protected createInstanceDataParts(): InstanceDataBase[] {
+            var res = new Array<InstanceDataBase>();
+            if (this.border) {
+                res.push(new Ellipse2DInstanceData(Shape2D.SHAPE2D_BORDERPARTID));
+            }
+            if (this.fill) {
+                res.push(new Ellipse2DInstanceData(Shape2D.SHAPE2D_FILLPARTID));
+            }
+            return res;
+        }
+
+        protected refreshInstanceDataPart(part: InstanceDataBase): boolean {
+            if (!super.refreshInstanceDataPart(part)) {
+                return false;
+            }
+            if (part.id === Shape2D.SHAPE2D_BORDERPARTID) {
+                let d = <Ellipse2DInstanceData>part;
+                let size = this.size;
+                d.properties = new Vector3(size.width, size.height, this.subdivisions);
+            }
+            else if (part.id === Shape2D.SHAPE2D_FILLPARTID) {
+                let d = <Ellipse2DInstanceData>part;
+                let size = this.size;
+                d.properties = new Vector3(size.width, size.height, this.subdivisions);
+            }
+            return true;
+        }
+
+        private _size: Size;
+        private _subdivisions: number;
+    }
+}

+ 21 - 11
src/Canvas2d/babylon.group2d.js

@@ -22,16 +22,25 @@ var BABYLON;
             this._childrenRenderableGroups = new Array();
             this._childrenRenderableGroups = new Array();
             this._renderGroupInstancesInfo = new BABYLON.StringDictionary();
             this._renderGroupInstancesInfo = new BABYLON.StringDictionary();
         }
         }
-        Group2D.CreateGroup2D = function (parent, id, position, size, cacheBehabior) {
-            if (cacheBehabior === void 0) { cacheBehabior = Group2D.GROUPCACHEBEHAVIOR_FOLLOWCACHESTRATEGY; }
+        /**
+         * 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]
+         *  - 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.
+         *  - cacheBehavior: Define how the group should behave regarding the Canvas's cache strategy, default is Group2D.GROUPCACHEBEHAVIOR_FOLLOWCACHESTRATEGY
+         */
+        Group2D.CreateGroup2D = function (parent, options) {
             BABYLON.Prim2DBase.CheckParent(parent);
             BABYLON.Prim2DBase.CheckParent(parent);
             var g = new Group2D();
             var g = new Group2D();
-            g.setupGroup2D(parent.owner, parent, id, position, size, cacheBehabior);
+            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);
             return g;
             return g;
         };
         };
         Group2D._createCachedCanvasGroup = function (owner) {
         Group2D._createCachedCanvasGroup = function (owner) {
             var g = new Group2D();
             var g = new Group2D();
-            g.setupGroup2D(owner, null, "__cachedCanvasGroup__", BABYLON.Vector2.Zero());
+            g.setupGroup2D(owner, null, "__cachedCanvasGroup__", BABYLON.Vector2.Zero(), null);
             g.origin = BABYLON.Vector2.Zero();
             g.origin = BABYLON.Vector2.Zero();
             return g;
             return g;
         };
         };
@@ -76,10 +85,10 @@ var BABYLON;
             }
             }
             return true;
             return true;
         };
         };
-        Group2D.prototype.setupGroup2D = function (owner, parent, id, position, size, cacheBehavior) {
+        Group2D.prototype.setupGroup2D = function (owner, parent, id, position, origin, size, cacheBehavior) {
             if (cacheBehavior === void 0) { cacheBehavior = Group2D.GROUPCACHEBEHAVIOR_FOLLOWCACHESTRATEGY; }
             if (cacheBehavior === void 0) { cacheBehavior = Group2D.GROUPCACHEBEHAVIOR_FOLLOWCACHESTRATEGY; }
             this._cacheBehavior = cacheBehavior;
             this._cacheBehavior = cacheBehavior;
-            this.setupPrim2DBase(owner, parent, id, position);
+            this.setupPrim2DBase(owner, parent, id, position, origin);
             this.size = size;
             this.size = size;
             this._viewportPosition = BABYLON.Vector2.Zero();
             this._viewportPosition = BABYLON.Vector2.Zero();
         };
         };
@@ -247,6 +256,7 @@ var BABYLON;
                         }
                         }
                     });
                     });
                     // Everything is updated, clear the dirty list
                     // Everything is updated, clear the dirty list
+                    this._primDirtyList.forEach(function (p) { return p._resetPropertiesDirty(); });
                     this._primDirtyList.splice(0);
                     this._primDirtyList.splice(0);
                 }
                 }
             }
             }
@@ -273,7 +283,7 @@ var BABYLON;
                     var curVP = engine.setDirectViewport(this._viewportPosition.x, this._viewportPosition.y, this._viewportSize.width, this._viewportSize.height);
                     var curVP = engine.setDirectViewport(this._viewportPosition.x, this._viewportPosition.y, this._viewportSize.width, this._viewportSize.height);
                 }
                 }
                 // For each different model of primitive to render
                 // For each different model of primitive to render
-                var totalRenderCount = 0;
+                var totalRenderCount_1 = 0;
                 this._renderGroupInstancesInfo.forEach(function (k, v) {
                 this._renderGroupInstancesInfo.forEach(function (k, v) {
                     // This part will pack the dynamicfloatarray and update the instanced array WebGLBufffer
                     // This part will pack the dynamicfloatarray and update the instanced array WebGLBufffer
                     // Skip it if instanced arrays are not supported
                     // Skip it if instanced arrays are not supported
@@ -282,7 +292,7 @@ var BABYLON;
                             // If the instances of the model was changed, pack the data
                             // If the instances of the model was changed, pack the data
                             var array = v._instancesPartsData[i];
                             var array = v._instancesPartsData[i];
                             var instanceData_1 = array.pack();
                             var instanceData_1 = array.pack();
-                            totalRenderCount += array.usedElementCount;
+                            totalRenderCount_1 += array.usedElementCount;
                             // Compute the size the instance buffer should have
                             // Compute the size the instance buffer should have
                             var neededSize = array.usedElementCount * array.stride * 4;
                             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
                             // Check if we have to (re)create the instancesBuffer because there's none or the size is too small
@@ -300,12 +310,12 @@ var BABYLON;
                                 // Update the WebGL buffer to match the new content of the instances data
                                 // 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.bindBuffer(engine._gl.ARRAY_BUFFER, v._instancesPartsBuffer[i]);
                                 engine._gl.bufferSubData(engine._gl.ARRAY_BUFFER, 0, instanceData_1);
                                 engine._gl.bufferSubData(engine._gl.ARRAY_BUFFER, 0, instanceData_1);
-                                v._dirtyInstancesData = false;
                             }
                             }
                         }
                         }
+                        v._dirtyInstancesData = false;
                     }
                     }
                     // Submit render only if we have something to render (everything may be hidden and the floatarray empty)
                     // Submit render only if we have something to render (everything may be hidden and the floatarray empty)
-                    if (!_this.owner.supportInstancedArray || totalRenderCount > 0) {
+                    if (!_this.owner.supportInstancedArray || totalRenderCount_1 > 0) {
                         // render all the instances of this model, if the render method returns true then our instances are no longer dirty
                         // 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._modelCache.render(v, context);
                         // Update dirty flag/related
                         // Update dirty flag/related
@@ -460,6 +470,6 @@ var BABYLON;
             BABYLON.className("Group2D")
             BABYLON.className("Group2D")
         ], Group2D);
         ], Group2D);
         return Group2D;
         return Group2D;
-    })(BABYLON.Prim2DBase);
+    }(BABYLON.Prim2DBase));
     BABYLON.Group2D = Group2D;
     BABYLON.Group2D = Group2D;
 })(BABYLON || (BABYLON = {}));
 })(BABYLON || (BABYLON = {}));

+ 17 - 6
src/Canvas2d/babylon.group2d.ts

@@ -32,17 +32,27 @@
             this._renderGroupInstancesInfo = new StringDictionary<GroupInstanceInfo>();
             this._renderGroupInstancesInfo = new StringDictionary<GroupInstanceInfo>();
         }
         }
 
 
-        static CreateGroup2D(parent: Prim2DBase, id: string, position: Vector2, size?: Size, cacheBehabior: number = Group2D.GROUPCACHEBEHAVIOR_FOLLOWCACHESTRATEGY): Group2D {
+        /**
+         * 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]
+         *  - 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.
+         *  - cacheBehavior: Define how the group should behave regarding the Canvas's cache strategy, default is Group2D.GROUPCACHEBEHAVIOR_FOLLOWCACHESTRATEGY
+         */
+        static CreateGroup2D(parent: Prim2DBase, options: { id?: string, position?: Vector2; origin?: Vector2, size?: Size, cacheBehavior?: number}): Group2D {
             Prim2DBase.CheckParent(parent);
             Prim2DBase.CheckParent(parent);
             var g = new Group2D();
             var g = new Group2D();
-            g.setupGroup2D(parent.owner, parent, id, position, size, cacheBehabior);
+            g.setupGroup2D(parent.owner, parent, options && options.id || null, options && options.position || Vector2.Zero(), options && options.origin || null, options && options.size || null, options && options.cacheBehavior || Group2D.GROUPCACHEBEHAVIOR_FOLLOWCACHESTRATEGY);
 
 
             return g;
             return g;
         }
         }
 
 
         static _createCachedCanvasGroup(owner: Canvas2D): Group2D {
         static _createCachedCanvasGroup(owner: Canvas2D): Group2D {
             var g = new Group2D();
             var g = new Group2D();
-            g.setupGroup2D(owner, null, "__cachedCanvasGroup__", Vector2.Zero());
+            g.setupGroup2D(owner, null, "__cachedCanvasGroup__", Vector2.Zero(), null);
             g.origin = Vector2.Zero();
             g.origin = Vector2.Zero();
             return g;
             return g;
             
             
@@ -98,9 +108,9 @@
             return true;
             return true;
         }
         }
 
 
-        protected setupGroup2D(owner: Canvas2D, parent: Prim2DBase, id: string, position: Vector2, size?: Size, cacheBehavior: number = Group2D.GROUPCACHEBEHAVIOR_FOLLOWCACHESTRATEGY) {
+        protected setupGroup2D(owner: Canvas2D, parent: Prim2DBase, id: string, position: Vector2, origin: Vector2, size?: Size, cacheBehavior: number = Group2D.GROUPCACHEBEHAVIOR_FOLLOWCACHESTRATEGY) {
             this._cacheBehavior = cacheBehavior;
             this._cacheBehavior = cacheBehavior;
-            this.setupPrim2DBase(owner, parent, id, position);
+            this.setupPrim2DBase(owner, parent, id, position, origin);
             this.size = size;
             this.size = size;
             this._viewportPosition = Vector2.Zero();
             this._viewportPosition = Vector2.Zero();
         }
         }
@@ -278,6 +288,7 @@
                     });
                     });
 
 
                     // Everything is updated, clear the dirty list
                     // Everything is updated, clear the dirty list
+                    this._primDirtyList.forEach(p => p._resetPropertiesDirty());
                     this._primDirtyList.splice(0);
                     this._primDirtyList.splice(0);
                 }
                 }
             }
             }
@@ -337,9 +348,9 @@
                                 engine._gl.bindBuffer(engine._gl.ARRAY_BUFFER, v._instancesPartsBuffer[i]);
                                 engine._gl.bindBuffer(engine._gl.ARRAY_BUFFER, v._instancesPartsBuffer[i]);
                                 engine._gl.bufferSubData(engine._gl.ARRAY_BUFFER, 0, instanceData);
                                 engine._gl.bufferSubData(engine._gl.ARRAY_BUFFER, 0, instanceData);
 
 
-                                v._dirtyInstancesData = false;
                             }
                             }
                         }
                         }
+                        v._dirtyInstancesData = false;
                     }
                     }
 
 
                     // Submit render only if we have something to render (everything may be hidden and the floatarray empty)
                     // Submit render only if we have something to render (everything may be hidden and the floatarray empty)

+ 991 - 0
src/Canvas2d/babylon.lines2d.js

@@ -0,0 +1,991 @@
+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 __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
+    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
+    if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
+    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
+    return c > 3 && r && Object.defineProperty(target, key, r), r;
+};
+var BABYLON;
+(function (BABYLON) {
+    var Lines2DRenderCache = (function (_super) {
+        __extends(Lines2DRenderCache, _super);
+        function Lines2DRenderCache(engine, modelKey, isTransparent) {
+            _super.call(this, engine, modelKey, isTransparent);
+        }
+        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;
+            }
+            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);
+            }
+            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) {
+                    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);
+                    }
+                    engine.updateAndBindInstancesBuffer(instanceInfo._instancesPartsBuffer[partIndex], null, this.instancingFillAttributes);
+                    engine.draw(true, 0, this.fillIndicesCount, count);
+                    engine.unbindInstanceAttributes();
+                }
+                else {
+                    for (var i = 0; i < count; i++) {
+                        this.setupUniforms(this.effectFill, partIndex, instanceInfo._instancesPartsData[partIndex], 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) {
+                    if (!this.instancingBorderAttributes) {
+                        this.instancingBorderAttributes = this.loadInstancingAttributes(BABYLON.Shape2D.SHAPE2D_BORDERPARTID, this.effectBorder);
+                    }
+                    engine.updateAndBindInstancesBuffer(instanceInfo._instancesPartsBuffer[partIndex], null, this.instancingBorderAttributes);
+                    engine.draw(true, 0, this.borderIndicesCount, count);
+                    engine.unbindInstanceAttributes();
+                }
+                else {
+                    for (var i = 0; i < count; i++) {
+                        this.setupUniforms(this.effectBorder, partIndex, instanceInfo._instancesPartsData[partIndex], i);
+                        engine.draw(true, 0, this.borderIndicesCount);
+                    }
+                }
+            }
+            if (this.isTransparent) {
+                engine.setAlphaMode(cur);
+            }
+            if (this.effectFill && this.effectBorder) {
+                engine.setDepthFunction(depthFunction);
+            }
+            return true;
+        };
+        Lines2DRenderCache.prototype.dispose = function () {
+            if (!_super.prototype.dispose.call(this)) {
+                return false;
+            }
+            if (this.fillVB) {
+                this._engine._releaseBuffer(this.fillVB);
+                this.fillVB = null;
+            }
+            if (this.fillIB) {
+                this._engine._releaseBuffer(this.fillIB);
+                this.fillIB = null;
+            }
+            if (this.effectFill) {
+                this._engine._releaseEffect(this.effectFill);
+                this.effectFill = null;
+            }
+            if (this.borderVB) {
+                this._engine._releaseBuffer(this.borderVB);
+                this.borderVB = null;
+            }
+            if (this.borderIB) {
+                this._engine._releaseBuffer(this.borderIB);
+                this.borderIB = null;
+            }
+            if (this.effectBorder) {
+                this._engine._releaseEffect(this.effectBorder);
+                this.effectBorder = null;
+            }
+            return true;
+        };
+        return Lines2DRenderCache;
+    }(BABYLON.ModelRenderCache));
+    BABYLON.Lines2DRenderCache = Lines2DRenderCache;
+    var Lines2DInstanceData = (function (_super) {
+        __extends(Lines2DInstanceData, _super);
+        function Lines2DInstanceData(partId) {
+            _super.call(this, partId, 1);
+        }
+        Object.defineProperty(Lines2DInstanceData.prototype, "boundingMin", {
+            get: function () {
+                return null;
+            },
+            enumerable: true,
+            configurable: true
+        });
+        Object.defineProperty(Lines2DInstanceData.prototype, "boundingMax", {
+            get: function () {
+                return null;
+            },
+            enumerable: true,
+            configurable: true
+        });
+        __decorate([
+            BABYLON.instanceData()
+        ], Lines2DInstanceData.prototype, "boundingMin", null);
+        __decorate([
+            BABYLON.instanceData()
+        ], Lines2DInstanceData.prototype, "boundingMax", null);
+        return Lines2DInstanceData;
+    }(BABYLON.Shape2DInstanceData));
+    BABYLON.Lines2DInstanceData = Lines2DInstanceData;
+    var Lines2D = (function (_super) {
+        __extends(Lines2D, _super);
+        function Lines2D() {
+            _super.apply(this, arguments);
+        }
+        Object.defineProperty(Lines2D, "NoCap", {
+            get: function () { return Lines2D._noCap; },
+            enumerable: true,
+            configurable: true
+        });
+        Object.defineProperty(Lines2D, "RoundCap", {
+            get: function () { return Lines2D._roundCap; },
+            enumerable: true,
+            configurable: true
+        });
+        Object.defineProperty(Lines2D, "TriangleCap", {
+            get: function () { return Lines2D._triangleCap; },
+            enumerable: true,
+            configurable: true
+        });
+        Object.defineProperty(Lines2D, "SquareAnchorCap", {
+            get: function () { return Lines2D._squareAnchorCap; },
+            enumerable: true,
+            configurable: true
+        });
+        Object.defineProperty(Lines2D, "RoundAnchorCap", {
+            get: function () { return Lines2D._roundAnchorCap; },
+            enumerable: true,
+            configurable: true
+        });
+        Object.defineProperty(Lines2D, "DiamondAnchorCap", {
+            get: function () { return Lines2D._diamondAnchorCap; },
+            enumerable: true,
+            configurable: true
+        });
+        Object.defineProperty(Lines2D, "ArrowCap", {
+            get: function () { return Lines2D._arrowCap; },
+            enumerable: true,
+            configurable: true
+        });
+        Object.defineProperty(Lines2D.prototype, "actualSize", {
+            get: function () {
+                return this.size;
+            },
+            enumerable: true,
+            configurable: true
+        });
+        Object.defineProperty(Lines2D.prototype, "points", {
+            get: function () {
+                return this._points;
+            },
+            set: function (value) {
+                this._points = value;
+                this._levelBoundingInfoDirty = true;
+            },
+            enumerable: true,
+            configurable: true
+        });
+        Object.defineProperty(Lines2D.prototype, "fillThickness", {
+            get: function () {
+                return this._fillThickness;
+            },
+            set: function (value) {
+                this._fillThickness = value;
+            },
+            enumerable: true,
+            configurable: true
+        });
+        Object.defineProperty(Lines2D.prototype, "closed", {
+            get: function () {
+                return this._closed;
+            },
+            set: function (value) {
+                this._closed = value;
+            },
+            enumerable: true,
+            configurable: true
+        });
+        Object.defineProperty(Lines2D.prototype, "startCap", {
+            get: function () {
+                return this._startCap;
+            },
+            set: function (value) {
+                this._startCap = value;
+            },
+            enumerable: true,
+            configurable: true
+        });
+        Object.defineProperty(Lines2D.prototype, "endCap", {
+            get: function () {
+                return this._endCap;
+            },
+            set: function (value) {
+                this._endCap = value;
+            },
+            enumerable: true,
+            configurable: true
+        });
+        Lines2D.prototype.levelIntersect = function (intersectInfo) {
+            var pl = this.points.length;
+            var l = this.closed ? pl + 1 : pl;
+            var originOffset = new BABYLON.Vector2(-0.5, -0.5);
+            var p = intersectInfo._localPickPosition;
+            var prevA = this.transformPointWithOrigin(this._contour[0], originOffset);
+            var prevB = this.transformPointWithOrigin(this._contour[1], originOffset);
+            for (var i = 1; i < l; i++) {
+                var curA = this.transformPointWithOrigin(this._contour[(i % pl) * 2 + 0], originOffset);
+                var curB = this.transformPointWithOrigin(this._contour[(i % pl) * 2 + 1], originOffset);
+                if (BABYLON.Vector2.PointInTriangle(p, prevA, prevB, curA)) {
+                    return true;
+                }
+                if (BABYLON.Vector2.PointInTriangle(p, curA, prevB, curB)) {
+                    return true;
+                }
+                prevA = curA;
+                prevB = curB;
+            }
+            return false;
+        };
+        Object.defineProperty(Lines2D.prototype, "size", {
+            get: function () {
+                return this._size;
+            },
+            enumerable: true,
+            configurable: true
+        });
+        Object.defineProperty(Lines2D.prototype, "boundingMin", {
+            get: function () {
+                return this._boundingMin;
+            },
+            enumerable: true,
+            configurable: true
+        });
+        Object.defineProperty(Lines2D.prototype, "boundingMax", {
+            get: function () {
+                return this._boundingMax;
+            },
+            enumerable: true,
+            configurable: true
+        });
+        Lines2D.prototype.getUsedShaderCategories = function (dataPart) {
+            var res = _super.prototype.getUsedShaderCategories.call(this, dataPart);
+            // Remove the BORDER category, we don't use it in the VertexShader
+            var i = res.indexOf(BABYLON.Shape2D.SHAPE2D_CATEGORY_BORDER);
+            if (i !== -1) {
+                res.splice(i, 1);
+            }
+            return res;
+        };
+        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);
+            this.fillThickness = fillThickness;
+            this.startCap = startCap;
+            this.endCap = endCap;
+            this.points = points;
+            this.closed = closed;
+            this._size = BABYLON.Size.Zero();
+            this._boundingMin = BABYLON.Vector2.Zero();
+            this._boundingMax = BABYLON.Vector2.Zero();
+        };
+        /**
+         * Create an 2D Lines Shape primitive. The defined lines may be opened or closed (see below)
+         * @param parent the parent primitive, must be a valid primitive (or the Canvas)
+         * @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
+         *  - 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.
+         *  - Draw a cap of the given type at the start of the first line, you can't define a Cap if the Lines2D is closed. Default is Lines2D.NoCap.
+         *  - Draw a cap of the given type at the end of the last line, you can't define a Cap if the Lines2D is closed. Default is Lines2D.NoCap.
+         *  - 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.
+         */
+        Lines2D.Create = function (parent, points, options) {
+            BABYLON.Prim2DBase.CheckParent(parent);
+            var fill;
+            if (options && options.fill !== undefined) {
+                fill = options.fill;
+            }
+            else {
+                fill = BABYLON.Canvas2D.GetSolidColorBrushFromHex("#FFFFFFFF");
+            }
+            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);
+            return renderCache;
+        };
+        Lines2D.prototype.setupModelRenderCache = function (modelRenderCache) {
+            var _this = this;
+            var renderCache = modelRenderCache;
+            var engine = this.owner.engine;
+            // Init min/max because their being computed here
+            this.boundingMin = new BABYLON.Vector2(Number.MAX_VALUE, Number.MAX_VALUE);
+            this.boundingMax = new BABYLON.Vector2(Number.MIN_VALUE, Number.MIN_VALUE);
+            var perp = function (v, res) {
+                res.x = v.y;
+                res.y = -v.x;
+            };
+            var direction = function (a, b, res) {
+                a.subtractToRef(b, res);
+                res.normalize();
+            };
+            var tps = BABYLON.Vector2.Zero();
+            var computeMiter = function (tangent, miter, a, b) {
+                a.addToRef(b, tangent);
+                tangent.normalize();
+                miter.x = -tangent.y;
+                miter.y = tangent.x;
+                tps.x = -a.y;
+                tps.y = a.x;
+                return 1 / BABYLON.Vector2.Dot(miter, tps);
+            };
+            var intersect = function (x1, y1, x2, y2, x3, y3, x4, y4) {
+                var d = (x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4);
+                if (d === 0)
+                    return false;
+                var xi = ((x3 - x4) * (x1 * y2 - y1 * x2) - (x1 - x2) * (x3 * y4 - y3 * x4)) / d; // Intersection point is xi/yi, just in case...
+                //let yi = ((y3 - y4) * (x1 * y2 - y1 * x2) - (y1 - y2) * (x3 * y4 - y3 * x4)) / d; // That's why I left it commented
+                if (xi < Math.min(x1, x2) || xi > Math.max(x1, x2))
+                    return false;
+                if (xi < Math.min(x3, x4) || xi > Math.max(x3, x4))
+                    return false;
+                return true;
+            };
+            var startDir = BABYLON.Vector2.Zero();
+            var endDir = BABYLON.Vector2.Zero();
+            var updateMinMax = function (array, offset) {
+                if (offset >= array.length) {
+                    return;
+                }
+                _this._boundingMin.x = Math.min(_this._boundingMin.x, array[offset]);
+                _this._boundingMax.x = Math.max(_this._boundingMax.x, array[offset]);
+                _this._boundingMin.y = Math.min(_this._boundingMin.y, array[offset + 1]);
+                _this._boundingMax.y = Math.max(_this._boundingMax.y, array[offset + 1]);
+            };
+            var store = function (array, contour, index, max, p, n, halfThickness, borderThickness, detectFlip) {
+                var borderMode = borderThickness != null && !isNaN(borderThickness);
+                var off = index * (borderMode ? 8 : 4);
+                // Mandatory because we'll be out of bound in case of closed line, for the very last point (which is a duplicate of the first that we don't store in the vb)
+                if (off >= array.length) {
+                    return;
+                }
+                // Store start/end normal, we need it for the cap construction
+                if (index === 0) {
+                    perp(n, startDir);
+                }
+                else if (index === max - 1) {
+                    perp(n, endDir);
+                    endDir.x *= -1;
+                    endDir.y *= -1;
+                }
+                var swap = false;
+                array[off + 0] = p.x + n.x * halfThickness;
+                array[off + 1] = p.y + n.y * halfThickness;
+                array[off + 2] = p.x + n.x * -halfThickness;
+                array[off + 3] = p.y + n.y * -halfThickness;
+                updateMinMax(array, off);
+                updateMinMax(array, off + 2);
+                // If an index is given we check if the two segments formed between [index+0;detectFlip+0] and [index+2;detectFlip+2] intersect themselves.
+                // It should not be the case, they should be parallel, so if they cross, we switch the order of storage to ensure we'll have parallel lines
+                if (detectFlip !== undefined) {
+                    // Flip if intersect
+                    var flipOff = detectFlip * (borderMode ? 8 : 4);
+                    if (intersect(array[off + 0], array[off + 1], array[flipOff + 0], array[flipOff + 1], array[off + 2], array[off + 3], array[flipOff + 2], array[flipOff + 3])) {
+                        swap = true;
+                        var tps_1 = array[off + 0];
+                        array[off + 0] = array[off + 2];
+                        array[off + 2] = tps_1;
+                        tps_1 = array[off + 1];
+                        array[off + 1] = array[off + 3];
+                        array[off + 3] = tps_1;
+                    }
+                }
+                if (borderMode) {
+                    var t = halfThickness + borderThickness;
+                    array[off + 4] = p.x + n.x * (swap ? -t : t);
+                    array[off + 5] = p.y + n.y * (swap ? -t : t);
+                    array[off + 6] = p.x + n.x * (swap ? t : -t);
+                    array[off + 7] = p.y + n.y * (swap ? t : -t);
+                    updateMinMax(array, off + 4);
+                    updateMinMax(array, off + 6);
+                }
+                if (contour) {
+                    off += borderMode ? 4 : 0;
+                    contour.push(new BABYLON.Vector2(array[off + 0], array[off + 1]));
+                    contour.push(new BABYLON.Vector2(array[off + 2], array[off + 3]));
+                }
+            };
+            var sd = Lines2D._roundCapSubDiv;
+            var getCapSize = function (type, border) {
+                if (border === void 0) { border = false; }
+                // If no array given, we call this to get the size
+                var vbsize = 0, ibsize = 0;
+                switch (type) {
+                    case Lines2D.NoCap:
+                        // If the line is not close and we're computing border, we add the size to generate the edge border
+                        if (!_this.closed && border) {
+                            vbsize = 4;
+                            ibsize = 6;
+                        }
+                        else {
+                            vbsize = ibsize = 0;
+                        }
+                        break;
+                    case Lines2D.RoundCap:
+                        if (border) {
+                            vbsize = sd;
+                            ibsize = (sd - 2) * 3;
+                        }
+                        else {
+                            vbsize = (sd / 2) + 1;
+                            ibsize = (sd / 2) * 3;
+                        }
+                        break;
+                    case Lines2D.ArrowCap:
+                        if (border) {
+                            vbsize = 12;
+                            ibsize = 24;
+                        }
+                        else {
+                            vbsize = 3;
+                            ibsize = 3;
+                        }
+                        break;
+                    case Lines2D.TriangleCap:
+                        if (border) {
+                            vbsize = 6;
+                            ibsize = 12;
+                        }
+                        else {
+                            vbsize = 3;
+                            ibsize = 3;
+                        }
+                        break;
+                    case Lines2D.DiamondAnchorCap:
+                        if (border) {
+                            vbsize = 10;
+                            ibsize = 24;
+                        }
+                        else {
+                            vbsize = 5;
+                            ibsize = 9;
+                        }
+                        break;
+                    case Lines2D.SquareAnchorCap:
+                        if (border) {
+                            vbsize = 12;
+                            ibsize = 30;
+                        }
+                        else {
+                            vbsize = 4;
+                            ibsize = 6;
+                        }
+                        break;
+                    case Lines2D.RoundAnchorCap:
+                        if (border) {
+                            vbsize = sd * 2;
+                            ibsize = (sd - 1) * 6;
+                        }
+                        else {
+                            vbsize = sd + 1;
+                            ibsize = (sd + 1) * 3;
+                        }
+                        break;
+                }
+                return { vbsize: vbsize * 2, ibsize: ibsize };
+            };
+            var v = BABYLON.Vector2.Zero();
+            var storeVertex = function (vb, baseOffset, index, basePos, rotation, vertex) {
+                var c = Math.cos(rotation);
+                var s = Math.sin(rotation);
+                v.x = (c * vertex.x) + (-s * vertex.y) + basePos.x;
+                v.y = (s * vertex.x) + (c * vertex.y) + basePos.y;
+                var offset = baseOffset + (index * 2);
+                vb[offset + 0] = v.x;
+                vb[offset + 1] = v.y;
+                updateMinMax(vb, offset);
+                return (baseOffset + index * 2) / 2;
+            };
+            var storeIndex = function (ib, baseOffset, index, vertexIndex) {
+                ib[baseOffset + index] = vertexIndex;
+            };
+            var buildCap = function (vb, vbi, ib, ibi, pos, thickness, borderThickness, type, capDir) {
+                // Compute the transformation from the direction of the cap to build relative to our default orientation [1;0] (our cap are by default pointing toward right, horizontal
+                var dir = new BABYLON.Vector2(1, 0);
+                var angle = Math.atan2(capDir.y, capDir.x) - Math.atan2(dir.y, dir.x);
+                var ht = thickness / 2;
+                var t = thickness;
+                var borderMode = borderThickness != null;
+                var bt = borderThickness;
+                switch (type) {
+                    case Lines2D.NoCap:
+                        if (borderMode && !_this.closed) {
+                            var vi = 0;
+                            var ii = 0;
+                            var v1 = storeVertex(vb, vbi, vi++, pos, angle, new BABYLON.Vector2(0, ht + bt));
+                            var v2 = storeVertex(vb, vbi, vi++, pos, angle, new BABYLON.Vector2(bt, ht + bt));
+                            var v3 = storeVertex(vb, vbi, vi++, pos, angle, new BABYLON.Vector2(bt, -(ht + bt)));
+                            var v4 = storeVertex(vb, vbi, vi++, pos, angle, new BABYLON.Vector2(0, -(ht + bt)));
+                            storeIndex(ib, ibi, ii++, v1);
+                            storeIndex(ib, ibi, ii++, v2);
+                            storeIndex(ib, ibi, ii++, v3);
+                            storeIndex(ib, ibi, ii++, v1);
+                            storeIndex(ib, ibi, ii++, v3);
+                            storeIndex(ib, ibi, ii++, v4);
+                        }
+                        break;
+                    case Lines2D.ArrowCap:
+                        ht *= 2;
+                    case Lines2D.TriangleCap:
+                        {
+                            if (borderMode) {
+                                var f = type === Lines2D.TriangleCap ? bt : Math.sqrt(bt * bt * 2);
+                                var v1 = storeVertex(vb, vbi, 0, pos, angle, new BABYLON.Vector2(0, ht));
+                                var v2 = storeVertex(vb, vbi, 1, pos, angle, new BABYLON.Vector2(ht, 0));
+                                var v3 = storeVertex(vb, vbi, 2, pos, angle, new BABYLON.Vector2(0, -ht));
+                                var v4 = storeVertex(vb, vbi, 3, pos, angle, new BABYLON.Vector2(0, ht + f));
+                                var v5 = storeVertex(vb, vbi, 4, pos, angle, new BABYLON.Vector2(ht + f, 0));
+                                var v6 = storeVertex(vb, vbi, 5, pos, angle, new BABYLON.Vector2(0, -(ht + f)));
+                                var ii = 0;
+                                storeIndex(ib, ibi, ii++, v1);
+                                storeIndex(ib, ibi, ii++, v4);
+                                storeIndex(ib, ibi, ii++, v5);
+                                storeIndex(ib, ibi, ii++, v1);
+                                storeIndex(ib, ibi, ii++, v5);
+                                storeIndex(ib, ibi, ii++, v2);
+                                storeIndex(ib, ibi, ii++, v6);
+                                storeIndex(ib, ibi, ii++, v3);
+                                storeIndex(ib, ibi, ii++, v2);
+                                storeIndex(ib, ibi, ii++, v6);
+                                storeIndex(ib, ibi, ii++, v2);
+                                storeIndex(ib, ibi, ii++, v5);
+                                if (type === Lines2D.ArrowCap) {
+                                    var rht = thickness / 2;
+                                    var v7 = storeVertex(vb, vbi, 6, pos, angle, new BABYLON.Vector2(0, rht + bt));
+                                    var v8 = storeVertex(vb, vbi, 7, pos, angle, new BABYLON.Vector2(-bt, rht + bt));
+                                    var v9 = storeVertex(vb, vbi, 8, pos, angle, new BABYLON.Vector2(-bt, ht + f));
+                                    var v10 = storeVertex(vb, vbi, 9, pos, angle, new BABYLON.Vector2(0, -(rht + bt)));
+                                    var v11 = storeVertex(vb, vbi, 10, pos, angle, new BABYLON.Vector2(-bt, -(rht + bt)));
+                                    var v12 = storeVertex(vb, vbi, 11, pos, angle, new BABYLON.Vector2(-bt, -(ht + f)));
+                                    storeIndex(ib, ibi, ii++, v7);
+                                    storeIndex(ib, ibi, ii++, v8);
+                                    storeIndex(ib, ibi, ii++, v9);
+                                    storeIndex(ib, ibi, ii++, v7);
+                                    storeIndex(ib, ibi, ii++, v9);
+                                    storeIndex(ib, ibi, ii++, v4);
+                                    storeIndex(ib, ibi, ii++, v10);
+                                    storeIndex(ib, ibi, ii++, v12);
+                                    storeIndex(ib, ibi, ii++, v11);
+                                    storeIndex(ib, ibi, ii++, v10);
+                                    storeIndex(ib, ibi, ii++, v6);
+                                    storeIndex(ib, ibi, ii++, v12);
+                                }
+                            }
+                            else {
+                                var v1 = storeVertex(vb, vbi, 0, pos, angle, new BABYLON.Vector2(0, ht));
+                                var v2 = storeVertex(vb, vbi, 1, pos, angle, new BABYLON.Vector2(ht, 0));
+                                var v3 = storeVertex(vb, vbi, 2, pos, angle, new BABYLON.Vector2(0, -ht));
+                                storeIndex(ib, ibi, 0, v1);
+                                storeIndex(ib, ibi, 1, v2);
+                                storeIndex(ib, ibi, 2, v3);
+                            }
+                            break;
+                        }
+                    case Lines2D.RoundCap:
+                        {
+                            if (borderMode) {
+                                var curA = -Math.PI / 2;
+                                var incA = Math.PI / (sd / 2 - 1);
+                                var ii = 0;
+                                for (var i = 0; i < (sd / 2); i++) {
+                                    var v1 = storeVertex(vb, vbi, i * 2 + 0, pos, angle, new BABYLON.Vector2(Math.cos(curA) * ht, Math.sin(curA) * ht));
+                                    var v2 = storeVertex(vb, vbi, i * 2 + 1, pos, angle, new BABYLON.Vector2(Math.cos(curA) * (ht + bt), Math.sin(curA) * (ht + bt)));
+                                    if (i > 0) {
+                                        storeIndex(ib, ibi, ii++, v1 - 2);
+                                        storeIndex(ib, ibi, ii++, v2 - 2);
+                                        storeIndex(ib, ibi, ii++, v2);
+                                        storeIndex(ib, ibi, ii++, v1 - 2);
+                                        storeIndex(ib, ibi, ii++, v2);
+                                        storeIndex(ib, ibi, ii++, v1);
+                                    }
+                                    curA += incA;
+                                }
+                            }
+                            else {
+                                var c = storeVertex(vb, vbi, 0, pos, angle, new BABYLON.Vector2(0, 0));
+                                var curA = -Math.PI / 2;
+                                var incA = Math.PI / (sd / 2 - 1);
+                                storeVertex(vb, vbi, 1, pos, angle, new BABYLON.Vector2(Math.cos(curA) * ht, Math.sin(curA) * ht));
+                                curA += incA;
+                                for (var i = 1; i < (sd / 2); i++) {
+                                    var v2 = storeVertex(vb, vbi, i + 1, pos, angle, new BABYLON.Vector2(Math.cos(curA) * ht, Math.sin(curA) * ht));
+                                    storeIndex(ib, ibi, i * 3 + 0, c);
+                                    storeIndex(ib, ibi, i * 3 + 1, v2 - 1);
+                                    storeIndex(ib, ibi, i * 3 + 2, v2);
+                                    curA += incA;
+                                }
+                            }
+                            break;
+                        }
+                    case Lines2D.SquareAnchorCap:
+                        {
+                            var vi = 0;
+                            var v1 = storeVertex(vb, vbi, vi++, pos, angle, new BABYLON.Vector2(0, t));
+                            var v2 = storeVertex(vb, vbi, vi++, pos, angle, new BABYLON.Vector2(t * 2, t));
+                            var v3 = storeVertex(vb, vbi, vi++, pos, angle, new BABYLON.Vector2(t * 2, -t));
+                            var v4 = storeVertex(vb, vbi, vi++, pos, angle, new BABYLON.Vector2(0, -t));
+                            if (borderMode) {
+                                var v5 = storeVertex(vb, vbi, vi++, pos, angle, new BABYLON.Vector2(0, ht + bt));
+                                var v6 = storeVertex(vb, vbi, vi++, pos, angle, new BABYLON.Vector2(-bt, ht + bt));
+                                var v7 = storeVertex(vb, vbi, vi++, pos, angle, new BABYLON.Vector2(-bt, t + bt));
+                                var v8 = storeVertex(vb, vbi, vi++, pos, angle, new BABYLON.Vector2(t * 2 + bt, t + bt));
+                                var v9 = storeVertex(vb, vbi, vi++, pos, angle, new BABYLON.Vector2(t * 2 + bt, -(t + bt)));
+                                var v10 = storeVertex(vb, vbi, vi++, pos, angle, new BABYLON.Vector2(-bt, -(t + bt)));
+                                var v11 = storeVertex(vb, vbi, vi++, pos, angle, new BABYLON.Vector2(-bt, -(ht + bt)));
+                                var v12 = storeVertex(vb, vbi, vi++, pos, angle, new BABYLON.Vector2(0, -(ht + bt)));
+                                var ii = 0;
+                                storeIndex(ib, ibi, ii++, v6);
+                                storeIndex(ib, ibi, ii++, v1);
+                                storeIndex(ib, ibi, ii++, v5);
+                                storeIndex(ib, ibi, ii++, v6);
+                                storeIndex(ib, ibi, ii++, v7);
+                                storeIndex(ib, ibi, ii++, v1);
+                                storeIndex(ib, ibi, ii++, v1);
+                                storeIndex(ib, ibi, ii++, v7);
+                                storeIndex(ib, ibi, ii++, v8);
+                                storeIndex(ib, ibi, ii++, v1);
+                                storeIndex(ib, ibi, ii++, v8);
+                                storeIndex(ib, ibi, ii++, v2);
+                                storeIndex(ib, ibi, ii++, v2);
+                                storeIndex(ib, ibi, ii++, v8);
+                                storeIndex(ib, ibi, ii++, v9);
+                                storeIndex(ib, ibi, ii++, v2);
+                                storeIndex(ib, ibi, ii++, v9);
+                                storeIndex(ib, ibi, ii++, v3);
+                                storeIndex(ib, ibi, ii++, v3);
+                                storeIndex(ib, ibi, ii++, v9);
+                                storeIndex(ib, ibi, ii++, v10);
+                                storeIndex(ib, ibi, ii++, v3);
+                                storeIndex(ib, ibi, ii++, v10);
+                                storeIndex(ib, ibi, ii++, v4);
+                                storeIndex(ib, ibi, ii++, v10);
+                                storeIndex(ib, ibi, ii++, v11);
+                                storeIndex(ib, ibi, ii++, v4);
+                                storeIndex(ib, ibi, ii++, v11);
+                                storeIndex(ib, ibi, ii++, v12);
+                                storeIndex(ib, ibi, ii++, v4);
+                            }
+                            else {
+                                storeIndex(ib, ibi, 0, v1);
+                                storeIndex(ib, ibi, 1, v2);
+                                storeIndex(ib, ibi, 2, v3);
+                                storeIndex(ib, ibi, 3, v1);
+                                storeIndex(ib, ibi, 4, v3);
+                                storeIndex(ib, ibi, 5, v4);
+                            }
+                            break;
+                        }
+                    case Lines2D.RoundAnchorCap:
+                        {
+                            var cpos = Math.sqrt(t * t - ht * ht);
+                            var center = new BABYLON.Vector2(cpos, 0);
+                            var curA = BABYLON.Tools.ToRadians(-150);
+                            var incA = BABYLON.Tools.ToRadians(300) / (sd - 1);
+                            if (borderMode) {
+                                var ii = 0;
+                                for (var i = 0; i < sd; i++) {
+                                    var v1 = storeVertex(vb, vbi, i * 2 + 0, pos, angle, new BABYLON.Vector2(cpos + Math.cos(curA) * t, Math.sin(curA) * t));
+                                    var v2 = storeVertex(vb, vbi, i * 2 + 1, pos, angle, new BABYLON.Vector2(cpos + Math.cos(curA) * (t + bt), Math.sin(curA) * (t + bt)));
+                                    if (i > 0) {
+                                        storeIndex(ib, ibi, ii++, v1 - 2);
+                                        storeIndex(ib, ibi, ii++, v2 - 2);
+                                        storeIndex(ib, ibi, ii++, v2);
+                                        storeIndex(ib, ibi, ii++, v1 - 2);
+                                        storeIndex(ib, ibi, ii++, v2);
+                                        storeIndex(ib, ibi, ii++, v1);
+                                    }
+                                    curA += incA;
+                                }
+                            }
+                            else {
+                                var c = storeVertex(vb, vbi, 0, pos, angle, center);
+                                storeVertex(vb, vbi, 1, pos, angle, new BABYLON.Vector2(cpos + Math.cos(curA) * t, Math.sin(curA) * t));
+                                curA += incA;
+                                for (var i = 1; i < sd; i++) {
+                                    var v2 = storeVertex(vb, vbi, i + 1, pos, angle, new BABYLON.Vector2(cpos + Math.cos(curA) * t, Math.sin(curA) * t));
+                                    storeIndex(ib, ibi, i * 3 + 0, c);
+                                    storeIndex(ib, ibi, i * 3 + 1, v2 - 1);
+                                    storeIndex(ib, ibi, i * 3 + 2, v2);
+                                    curA += incA;
+                                }
+                                storeIndex(ib, ibi, sd * 3 + 0, c);
+                                storeIndex(ib, ibi, sd * 3 + 1, c + 1);
+                                storeIndex(ib, ibi, sd * 3 + 2, c + sd);
+                            }
+                            break;
+                        }
+                    case Lines2D.DiamondAnchorCap:
+                        {
+                            var vi = 0;
+                            var v1 = storeVertex(vb, vbi, vi++, pos, angle, new BABYLON.Vector2(0, ht));
+                            var v2 = storeVertex(vb, vbi, vi++, pos, angle, new BABYLON.Vector2(ht, t));
+                            var v3 = storeVertex(vb, vbi, vi++, pos, angle, new BABYLON.Vector2(ht * 3, 0));
+                            var v4 = storeVertex(vb, vbi, vi++, pos, angle, new BABYLON.Vector2(ht, -t));
+                            var v5 = storeVertex(vb, vbi, vi++, pos, angle, new BABYLON.Vector2(0, -ht));
+                            if (borderMode) {
+                                var f = Math.sqrt(bt * bt * 2);
+                                var v6 = storeVertex(vb, vbi, vi++, pos, angle, new BABYLON.Vector2(-f, ht));
+                                var v7 = storeVertex(vb, vbi, vi++, pos, angle, new BABYLON.Vector2(ht, t + f));
+                                var v8 = storeVertex(vb, vbi, vi++, pos, angle, new BABYLON.Vector2(ht * 3 + f, 0));
+                                var v9 = storeVertex(vb, vbi, vi++, pos, angle, new BABYLON.Vector2(ht, -(t + f)));
+                                var v10 = storeVertex(vb, vbi, vi++, pos, angle, new BABYLON.Vector2(-f, -ht));
+                                var ii = 0;
+                                storeIndex(ib, ibi, ii++, v6);
+                                storeIndex(ib, ibi, ii++, v7);
+                                storeIndex(ib, ibi, ii++, v1);
+                                storeIndex(ib, ibi, ii++, v1);
+                                storeIndex(ib, ibi, ii++, v7);
+                                storeIndex(ib, ibi, ii++, v2);
+                                storeIndex(ib, ibi, ii++, v2);
+                                storeIndex(ib, ibi, ii++, v7);
+                                storeIndex(ib, ibi, ii++, v8);
+                                storeIndex(ib, ibi, ii++, v2);
+                                storeIndex(ib, ibi, ii++, v8);
+                                storeIndex(ib, ibi, ii++, v3);
+                                storeIndex(ib, ibi, ii++, v3);
+                                storeIndex(ib, ibi, ii++, v8);
+                                storeIndex(ib, ibi, ii++, v9);
+                                storeIndex(ib, ibi, ii++, v3);
+                                storeIndex(ib, ibi, ii++, v9);
+                                storeIndex(ib, ibi, ii++, v4);
+                                storeIndex(ib, ibi, ii++, v4);
+                                storeIndex(ib, ibi, ii++, v9);
+                                storeIndex(ib, ibi, ii++, v10);
+                                storeIndex(ib, ibi, ii++, v4);
+                                storeIndex(ib, ibi, ii++, v10);
+                                storeIndex(ib, ibi, ii++, v5);
+                            }
+                            else {
+                                storeIndex(ib, ibi, 0, v1);
+                                storeIndex(ib, ibi, 1, v2);
+                                storeIndex(ib, ibi, 2, v3);
+                                storeIndex(ib, ibi, 3, v1);
+                                storeIndex(ib, ibi, 4, v3);
+                                storeIndex(ib, ibi, 5, v5);
+                                storeIndex(ib, ibi, 6, v5);
+                                storeIndex(ib, ibi, 7, v3);
+                                storeIndex(ib, ibi, 8, v4);
+                            }
+                            break;
+                        }
+                }
+                return null;
+            };
+            var buildLine = function (vb, contour, ht, bt) {
+                var lineA = BABYLON.Vector2.Zero();
+                var lineB = BABYLON.Vector2.Zero();
+                var tangent = BABYLON.Vector2.Zero();
+                var miter = BABYLON.Vector2.Zero();
+                var curNormal = null;
+                if (_this.closed) {
+                    _this.points.push(_this.points[0]);
+                }
+                var total = _this.points.length;
+                for (var i = 1; i < total; i++) {
+                    var last = _this.points[i - 1];
+                    var cur = _this.points[i];
+                    var next = (i < (_this.points.length - 1)) ? _this.points[i + 1] : null;
+                    direction(cur, last, lineA);
+                    if (!curNormal) {
+                        curNormal = BABYLON.Vector2.Zero();
+                        perp(lineA, curNormal);
+                    }
+                    if (i === 1) {
+                        store(vb, contour, 0, total, _this.points[0], curNormal, ht, bt);
+                    }
+                    if (!next) {
+                        perp(lineA, curNormal);
+                        store(vb, contour, i, total, _this.points[i], curNormal, ht, bt, i - 1);
+                    }
+                    else {
+                        direction(next, cur, lineB);
+                        var miterLen = computeMiter(tangent, miter, lineA, lineB);
+                        store(vb, contour, i, total, _this.points[i], miter, miterLen * ht, miterLen * bt, i - 1);
+                    }
+                }
+                if (_this.points.length > 2 && _this.closed) {
+                    var last2 = _this.points[total - 2];
+                    var cur2 = _this.points[0];
+                    var next2 = _this.points[1];
+                    direction(cur2, last2, lineA);
+                    direction(next2, cur2, lineB);
+                    perp(lineA, curNormal);
+                    var miterLen2 = computeMiter(tangent, miter, lineA, lineB);
+                    store(vb, null, 0, total, _this.points[0], miter, miterLen2 * ht, miterLen2 * bt, 1);
+                    // Patch contour
+                    if (contour) {
+                        var off = (bt == null) ? 0 : 4;
+                        contour[0].x = vb[off + 0];
+                        contour[0].y = vb[off + 1];
+                        contour[1].x = vb[off + 2];
+                        contour[1].y = vb[off + 3];
+                    }
+                }
+                // Remove the point we added at the beginning
+                if (_this.closed) {
+                    _this.points.splice(total - 1);
+                }
+            };
+            var contour = new Array();
+            // Need to create WebGL resources for fill part?
+            if (this.fill) {
+                var startCapInfo = getCapSize(this.startCap);
+                var endCapInfo = getCapSize(this.endCap);
+                var count = this.points.length;
+                var vbSize = (count * 2 * 2) + startCapInfo.vbsize + endCapInfo.vbsize;
+                var vb = new Float32Array(vbSize);
+                var ht = this.fillThickness / 2;
+                var total = this.points.length;
+                buildLine(vb, this.border ? null : contour, ht);
+                var max = total * 2;
+                var triCount = (count - (this.closed ? 0 : 1)) * 2;
+                var ib = new Float32Array(triCount * 3 + startCapInfo.ibsize + endCapInfo.ibsize);
+                for (var i = 0; i < triCount; i += 2) {
+                    ib[i * 3 + 0] = i + 0;
+                    ib[i * 3 + 1] = i + 1;
+                    ib[i * 3 + 2] = (i + 2) % max;
+                    ib[i * 3 + 3] = i + 1;
+                    ib[i * 3 + 4] = (i + 3) % max;
+                    ib[i * 3 + 5] = (i + 2) % max;
+                }
+                buildCap(vb, count * 2 * 2, ib, triCount * 3, this.points[0], this.fillThickness, null, this.startCap, startDir);
+                buildCap(vb, (count * 2 * 2) + startCapInfo.vbsize, ib, (triCount * 3) + startCapInfo.ibsize, this.points[total - 1], this.fillThickness, null, this.endCap, endDir);
+                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);
+            }
+            // Need to create WebGL resources for border part?
+            if (this.border) {
+                var startCapInfo = getCapSize(this.startCap, true);
+                var endCapInfo = getCapSize(this.endCap, true);
+                var count = this.points.length;
+                var vbSize = (count * 2 * 2 * 2) + startCapInfo.vbsize + endCapInfo.vbsize;
+                var vb = new Float32Array(vbSize);
+                var ht = this.fillThickness / 2;
+                var bt = this.borderThickness;
+                var total = this.points.length;
+                buildLine(vb, contour, ht, bt);
+                var max = total * 2 * 2;
+                var triCount = (count - (this.closed ? 0 : 1)) * 2 * 2;
+                var ib = new Float32Array(triCount * 3 + startCapInfo.ibsize + endCapInfo.ibsize);
+                for (var i = 0; i < triCount; i += 4) {
+                    ib[i * 3 + 0] = i + 0;
+                    ib[i * 3 + 1] = i + 2;
+                    ib[i * 3 + 2] = (i + 6) % max;
+                    ib[i * 3 + 3] = i + 0;
+                    ib[i * 3 + 4] = (i + 6) % max;
+                    ib[i * 3 + 5] = (i + 4) % max;
+                    ib[i * 3 + 6] = i + 3;
+                    ib[i * 3 + 7] = i + 1;
+                    ib[i * 3 + 8] = (i + 5) % max;
+                    ib[i * 3 + 9] = i + 3;
+                    ib[i * 3 + 10] = (i + 5) % max;
+                    ib[i * 3 + 11] = (i + 7) % max;
+                }
+                buildCap(vb, count * 2 * 2 * 2, ib, triCount * 3, this.points[0], this.fillThickness, this.borderThickness, this.startCap, startDir);
+                buildCap(vb, (count * 2 * 2 * 2) + startCapInfo.vbsize, ib, (triCount * 3) + startCapInfo.ibsize, this.points[total - 1], this.fillThickness, this.borderThickness, this.endCap, endDir);
+                renderCache.borderVB = engine.createVertexBuffer(vb);
+                renderCache.borderIB = engine.createIndexBuffer(ib);
+                renderCache.borderIndicesCount = ib.length;
+                var ei = this.getDataPartEffectInfo(BABYLON.Shape2D.SHAPE2D_BORDERPARTID, ["position"]);
+                renderCache.effectBorder = engine.createEffect({ vertex: "lines2d", fragment: "lines2d" }, ei.attributes, ei.uniforms, [], ei.defines, null);
+            }
+            this._contour = contour;
+            var bs = this._boundingMax.subtract(this._boundingMin);
+            this._size.width = bs.x;
+            this._size.height = bs.y;
+            return renderCache;
+        };
+        Lines2D.prototype.createInstanceDataParts = function () {
+            var res = new Array();
+            if (this.border) {
+                res.push(new Lines2DInstanceData(BABYLON.Shape2D.SHAPE2D_BORDERPARTID));
+            }
+            if (this.fill) {
+                res.push(new Lines2DInstanceData(BABYLON.Shape2D.SHAPE2D_FILLPARTID));
+            }
+            return res;
+        };
+        Lines2D.prototype.refreshInstanceDataPart = function (part) {
+            if (!_super.prototype.refreshInstanceDataPart.call(this, part)) {
+                return false;
+            }
+            if (part.id === BABYLON.Shape2D.SHAPE2D_BORDERPARTID) {
+                var d = part;
+                d.boundingMin = this.boundingMin;
+                d.boundingMax = this.boundingMax;
+            }
+            else if (part.id === BABYLON.Shape2D.SHAPE2D_FILLPARTID) {
+                var d = part;
+                d.boundingMin = this.boundingMin;
+                d.boundingMax = this.boundingMax;
+            }
+            return true;
+        };
+        Lines2D._noCap = 0;
+        Lines2D._roundCap = 1;
+        Lines2D._triangleCap = 2;
+        Lines2D._squareAnchorCap = 3;
+        Lines2D._roundAnchorCap = 4;
+        Lines2D._diamondAnchorCap = 5;
+        Lines2D._arrowCap = 6;
+        Lines2D._roundCapSubDiv = 36;
+        __decorate([
+            BABYLON.modelLevelProperty(BABYLON.Shape2D.SHAPE2D_PROPCOUNT + 1, function (pi) { return Lines2D.pointsProperty = pi; })
+        ], Lines2D.prototype, "points", null);
+        __decorate([
+            BABYLON.modelLevelProperty(BABYLON.Shape2D.SHAPE2D_PROPCOUNT + 2, function (pi) { return Lines2D.fillThicknessProperty = pi; })
+        ], Lines2D.prototype, "fillThickness", null);
+        __decorate([
+            BABYLON.modelLevelProperty(BABYLON.Shape2D.SHAPE2D_PROPCOUNT + 3, function (pi) { return Lines2D.closedProperty = pi; })
+        ], Lines2D.prototype, "closed", null);
+        __decorate([
+            BABYLON.modelLevelProperty(BABYLON.Shape2D.SHAPE2D_PROPCOUNT + 4, function (pi) { return Lines2D.startCapProperty = pi; })
+        ], Lines2D.prototype, "startCap", null);
+        __decorate([
+            BABYLON.modelLevelProperty(BABYLON.Shape2D.SHAPE2D_PROPCOUNT + 5, function (pi) { return Lines2D.endCapProperty = pi; })
+        ], Lines2D.prototype, "endCap", null);
+        Lines2D = __decorate([
+            BABYLON.className("Lines2D")
+        ], Lines2D);
+        return Lines2D;
+    }(BABYLON.Shape2D));
+    BABYLON.Lines2D = Lines2D;
+})(BABYLON || (BABYLON = {}));

+ 973 - 0
src/Canvas2d/babylon.lines2d.ts

@@ -0,0 +1,973 @@
+module BABYLON {
+    export class Lines2DRenderCache extends ModelRenderCache {
+        fillVB: WebGLBuffer;
+        fillIB: WebGLBuffer;
+        fillIndicesCount: number;
+        instancingFillAttributes: InstancingAttributeInfo[];
+        effectFill: Effect;
+
+        borderVB: WebGLBuffer;
+        borderIB: WebGLBuffer;
+        borderIndicesCount: number;
+        instancingBorderAttributes: InstancingAttributeInfo[];
+        effectBorder: Effect;
+
+        constructor(engine: Engine, modelKey: string, isTransparent: boolean) {
+            super(engine, modelKey, isTransparent);
+        }
+
+        render(instanceInfo: GroupInstanceInfo, context: Render2DContext): boolean {
+            // Do nothing if the shader is still loading/preparing 
+            if ((this.effectFill && !this.effectFill.isReady()) || (this.effectBorder && !this.effectBorder.isReady())) {
+                return false;
+            }
+
+            var engine = instanceInfo._owner.owner.engine;
+
+            let depthFunction = 0;
+            if (this.effectFill && this.effectBorder) {
+                depthFunction = engine.getDepthFunction();
+                engine.setDepthFunctionToLessOrEqual();
+            }
+
+            var cur: number;
+            if (this.isTransparent) {
+                cur = engine.getAlphaMode();
+                engine.setAlphaMode(Engine.ALPHA_COMBINE);
+            }
+
+            if (this.effectFill) {
+                let partIndex = instanceInfo._partIndexFromId.get(Shape2D.SHAPE2D_FILLPARTID.toString());
+             
+                engine.enableEffect(this.effectFill);
+                engine.bindBuffersDirectly(this.fillVB, this.fillIB, [2], 2*4, this.effectFill);
+                let count = instanceInfo._instancesPartsData[partIndex].usedElementCount;
+                if (instanceInfo._owner.owner.supportInstancedArray) {
+                    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(Shape2D.SHAPE2D_FILLPARTID, this.effectFill);
+                    }
+
+                    engine.updateAndBindInstancesBuffer(instanceInfo._instancesPartsBuffer[partIndex], null, this.instancingFillAttributes);
+                    engine.draw(true, 0, this.fillIndicesCount, count);
+                    engine.unbindInstanceAttributes();
+                } else {
+                    for (let i = 0; i < count; i++) {
+                        this.setupUniforms(this.effectFill, partIndex, instanceInfo._instancesPartsData[partIndex], i);
+                        engine.draw(true, 0, this.fillIndicesCount);                        
+                    }
+                }
+            }
+
+            if (this.effectBorder) {
+                let partIndex = instanceInfo._partIndexFromId.get(Shape2D.SHAPE2D_BORDERPARTID.toString());
+
+                engine.enableEffect(this.effectBorder);
+                engine.bindBuffersDirectly(this.borderVB, this.borderIB, [2], 2 * 4, this.effectBorder);
+                let count = instanceInfo._instancesPartsData[partIndex].usedElementCount;
+                if (instanceInfo._owner.owner.supportInstancedArray) {
+                    if (!this.instancingBorderAttributes) {
+                        this.instancingBorderAttributes = this.loadInstancingAttributes(Shape2D.SHAPE2D_BORDERPARTID, this.effectBorder);
+                    }
+
+                    engine.updateAndBindInstancesBuffer(instanceInfo._instancesPartsBuffer[partIndex], null, this.instancingBorderAttributes);
+                    engine.draw(true, 0, this.borderIndicesCount, count);
+                    engine.unbindInstanceAttributes();
+                } else {
+                    for (let i = 0; i < count; i++) {
+                        this.setupUniforms(this.effectBorder, partIndex, instanceInfo._instancesPartsData[partIndex], i);
+                        engine.draw(true, 0, this.borderIndicesCount);
+                    }
+                }
+            }
+
+            if (this.isTransparent) {
+                engine.setAlphaMode(cur);
+            }
+
+            if (this.effectFill && this.effectBorder) {
+                engine.setDepthFunction(depthFunction);
+            }
+            return true;
+        }
+
+        public dispose(): boolean {
+            if (!super.dispose()) {
+                return false;
+            }
+
+            if (this.fillVB) {
+                this._engine._releaseBuffer(this.fillVB);
+                this.fillVB = null;
+            }
+
+            if (this.fillIB) {
+                this._engine._releaseBuffer(this.fillIB);
+                this.fillIB = null;
+            }
+
+            if (this.effectFill) {
+                this._engine._releaseEffect(this.effectFill);
+                this.effectFill = null;
+            }
+
+            if (this.borderVB) {
+                this._engine._releaseBuffer(this.borderVB);
+                this.borderVB = null;
+            }
+
+            if (this.borderIB) {
+                this._engine._releaseBuffer(this.borderIB);
+                this.borderIB = null;
+            }
+
+            if (this.effectBorder) {
+                this._engine._releaseEffect(this.effectBorder);
+                this.effectBorder = null;
+            }
+
+            return true;
+        }
+    }
+
+    export class Lines2DInstanceData extends Shape2DInstanceData {
+        constructor(partId: number) {
+            super(partId, 1);
+        }
+
+        @instanceData()
+        get boundingMin(): Vector2 {
+            return null;
+        }
+
+        @instanceData()
+        get boundingMax(): Vector2 {
+            return null;
+        }
+    }
+
+    @className("Lines2D")
+    export class Lines2D extends Shape2D {
+        static get NoCap            () { return Lines2D._noCap;            }
+        static get RoundCap         () { return Lines2D._roundCap;         }
+        static get TriangleCap      () { return Lines2D._triangleCap;      }
+        static get SquareAnchorCap  () { return Lines2D._squareAnchorCap;  }
+        static get RoundAnchorCap   () { return Lines2D._roundAnchorCap;   }
+        static get DiamondAnchorCap () { return Lines2D._diamondAnchorCap; }
+        static get ArrowCap         () { return Lines2D._arrowCap;         }
+
+        public static pointsProperty: Prim2DPropInfo;
+        public static fillThicknessProperty: Prim2DPropInfo;
+        public static closedProperty: Prim2DPropInfo;
+        public static startCapProperty: Prim2DPropInfo;
+        public static endCapProperty: Prim2DPropInfo;
+
+        public get actualSize(): Size {
+            return this.size;
+        }
+
+        @modelLevelProperty(Shape2D.SHAPE2D_PROPCOUNT + 1, pi => Lines2D.pointsProperty = pi)
+        public get points(): Vector2[] {
+            return this._points;
+        }
+
+        public set points(value: Vector2[]) {
+            this._points = value;
+            this._levelBoundingInfoDirty = true;
+        }
+
+        @modelLevelProperty(Shape2D.SHAPE2D_PROPCOUNT + 2, pi => Lines2D.fillThicknessProperty = pi)
+        public get fillThickness(): number {
+            return this._fillThickness;
+        }
+
+        public set fillThickness(value: number) {
+            this._fillThickness = value;
+        }
+
+        @modelLevelProperty(Shape2D.SHAPE2D_PROPCOUNT + 3, pi => Lines2D.closedProperty = pi)
+        public get closed(): boolean {
+            return this._closed;
+        }
+
+        public set closed(value: boolean) {
+            this._closed = value;
+        }
+
+        @modelLevelProperty(Shape2D.SHAPE2D_PROPCOUNT + 4, pi => Lines2D.startCapProperty = pi)
+        public get startCap(): number {
+            return this._startCap;
+        }
+
+        public set startCap(value: number) {
+            this._startCap = value;
+        }
+
+        @modelLevelProperty(Shape2D.SHAPE2D_PROPCOUNT + 5, pi => Lines2D.endCapProperty = pi)
+        public get endCap(): number {
+            return this._endCap;
+        }
+
+        public set endCap(value: number) {
+            this._endCap = value;
+        }
+
+        protected levelIntersect(intersectInfo: IntersectInfo2D): boolean {
+            let pl = this.points.length;
+            let l = this.closed ? pl + 1 : pl;
+
+            let originOffset = new Vector2(-0.5, -0.5);
+            let p = intersectInfo._localPickPosition;
+
+            let prevA = this.transformPointWithOrigin(this._contour[0], originOffset);
+            let prevB = this.transformPointWithOrigin(this._contour[1], originOffset);
+            for (let i = 1; i < l; i++) {
+                let curA = this.transformPointWithOrigin(this._contour[(i % pl) * 2 + 0], originOffset);
+                let curB = this.transformPointWithOrigin(this._contour[(i % pl) * 2 + 1], originOffset);
+
+                if (Vector2.PointInTriangle(p, prevA, prevB, curA)) {
+                    return true;
+                }
+                if (Vector2.PointInTriangle(p, curA, prevB, curB)) {
+                    return true;
+                }
+
+                prevA = curA;
+                prevB = curB;
+            }
+            return false;
+        }
+
+        protected get size(): Size {
+            return this._size;
+        }
+
+        protected get boundingMin(): Vector2 {
+            return this._boundingMin;
+        }
+
+        protected get boundingMax(): Vector2 {
+            return this._boundingMax;
+        }
+
+        protected getUsedShaderCategories(dataPart: InstanceDataBase): string[] {
+            let res = super.getUsedShaderCategories(dataPart);
+
+            // Remove the BORDER category, we don't use it in the VertexShader
+            let i = res.indexOf(Shape2D.SHAPE2D_CATEGORY_BORDER);
+            if (i !== -1) {
+                res.splice(i, 1);
+            }
+            return res;
+        }
+
+        protected updateLevelBoundingInfo() {
+            BoundingInfo2D.CreateFromSizeToRef(this.size, this._levelBoundingInfo, this.origin);
+        }
+
+        protected setupLines2D(owner: Canvas2D, parent: Prim2DBase, id: string, position: Vector2, origin: Vector2, points: Vector2[], fillThickness: number, startCap: number, endCap: number, fill: IBrush2D, border: IBrush2D, borderThickness: number, closed: boolean) {
+            this.setupShape2D(owner, parent, id, position, origin, true, fill, border, borderThickness);
+            this.fillThickness = fillThickness;
+            this.startCap = startCap;
+            this.endCap = endCap;
+            this.points = points;
+            this.closed = closed;
+            this._size = Size.Zero();
+            this._boundingMin = Vector2.Zero();
+            this._boundingMax = Vector2.Zero();
+        }
+
+        /**
+         * Create an 2D Lines Shape primitive. The defined lines may be opened or closed (see below)
+         * @param parent the parent primitive, must be a valid primitive (or the Canvas)
+         * @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
+         *  - 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.
+         *  - Draw a cap of the given type at the start of the first line, you can't define a Cap if the Lines2D is closed. Default is Lines2D.NoCap.
+         *  - Draw a cap of the given type at the end of the last line, you can't define a Cap if the Lines2D is closed. Default is Lines2D.NoCap.
+         *  - 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.
+         */
+        public static Create(parent: Prim2DBase, points: Vector2[], options: { id?: string, x?: number, y?: number, origin?: Vector2, fillThickness?: number, closed?: boolean, startCap?: number, endCap?: number, fill?: IBrush2D, border?: IBrush2D, borderThickness?: number }): Lines2D {
+            Prim2DBase.CheckParent(parent);
+
+            let fill: IBrush2D;
+            if (options && options.fill !== undefined) {
+                fill = options.fill;
+            } else {
+                fill = Canvas2D.GetSolidColorBrushFromHex("#FFFFFFFF");
+            }
+
+            let lines = new Lines2D();
+            lines.setupLines2D(parent.owner, parent, options && options.id || null, new 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;
+        }
+
+        protected createModelRenderCache(modelKey: string, isTransparent: boolean): ModelRenderCache {
+            let renderCache = new Lines2DRenderCache(this.owner.engine, modelKey, isTransparent);
+            return renderCache;
+        }
+
+        protected setupModelRenderCache(modelRenderCache: ModelRenderCache) {
+            let renderCache = <Lines2DRenderCache>modelRenderCache;
+            let engine = this.owner.engine;
+
+            // Init min/max because their being computed here
+            this.boundingMin = new Vector2(Number.MAX_VALUE, Number.MAX_VALUE);
+            this.boundingMax = new Vector2(Number.MIN_VALUE, Number.MIN_VALUE);
+
+            let perp = (v: Vector2, res: Vector2) => {
+                res.x = v.y;
+                res.y = -v.x;
+            };
+
+            let direction = (a: Vector2, b: Vector2, res: Vector2) => {
+                a.subtractToRef(b, res);
+                res.normalize();
+            }
+
+            let tps = Vector2.Zero();
+            let computeMiter = (tangent: Vector2, miter: Vector2, a: Vector2, b: Vector2): number => {
+                a.addToRef(b, tangent);
+                tangent.normalize();
+
+                miter.x = -tangent.y;
+                miter.y = tangent.x;
+
+                tps.x = -a.y;
+                tps.y = a.x;
+
+                return 1 / Vector2.Dot(miter, tps);
+            }
+
+            let intersect = (x1: number, y1: number, x2: number, y2: number, x3: number, y3: number, x4: number, y4: number): boolean => {
+                let d = (x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4);
+                if (d === 0) return false;
+
+                let xi = ((x3 - x4) * (x1 * y2 - y1 * x2) - (x1 - x2) * (x3 * y4 - y3 * x4)) / d;   // Intersection point is xi/yi, just in case...
+                //let yi = ((y3 - y4) * (x1 * y2 - y1 * x2) - (y1 - y2) * (x3 * y4 - y3 * x4)) / d; // That's why I left it commented
+
+                if (xi < Math.min(x1, x2) || xi > Math.max(x1, x2)) return false;
+                if (xi < Math.min(x3, x4) || xi > Math.max(x3, x4)) return false;
+                return true;
+            }
+
+            let startDir: Vector2 = Vector2.Zero();
+            let endDir: Vector2 = Vector2.Zero();
+
+            let updateMinMax = (array: Float32Array, offset: number) => {
+                if (offset >= array.length) {
+                    return;
+                }
+                this._boundingMin.x = Math.min(this._boundingMin.x, array[offset]);
+                this._boundingMax.x = Math.max(this._boundingMax.x, array[offset]);
+                this._boundingMin.y = Math.min(this._boundingMin.y, array[offset+1]);
+                this._boundingMax.y = Math.max(this._boundingMax.y, array[offset+1]);
+            }
+
+            let store = (array: Float32Array, contour: Vector2[], index: number, max: number, p: Vector2, n: Vector2, halfThickness: number, borderThickness: number, detectFlip?: number) => {
+                let borderMode = borderThickness != null && !isNaN(borderThickness);
+                let off = index * (borderMode ? 8 : 4);
+
+                // Mandatory because we'll be out of bound in case of closed line, for the very last point (which is a duplicate of the first that we don't store in the vb)
+                if (off >= array.length) {
+                    return;
+                }
+
+                // Store start/end normal, we need it for the cap construction
+                if (index === 0) {
+                    perp(n, startDir);
+                } else if (index === max - 1) {
+                    perp(n, endDir);
+                    endDir.x *= -1;
+                    endDir.y *= -1;
+                }
+
+                let swap = false;
+
+                array[off + 0] = p.x + n.x * halfThickness;
+                array[off + 1] = p.y + n.y * halfThickness;
+                array[off + 2] = p.x + n.x * -halfThickness;
+                array[off + 3] = p.y + n.y * -halfThickness;
+
+                updateMinMax(array, off);
+                updateMinMax(array, off + 2);
+
+                // If an index is given we check if the two segments formed between [index+0;detectFlip+0] and [index+2;detectFlip+2] intersect themselves.
+                // It should not be the case, they should be parallel, so if they cross, we switch the order of storage to ensure we'll have parallel lines
+                if (detectFlip !== undefined) {
+                    // Flip if intersect
+                    let flipOff = detectFlip * (borderMode ? 8 : 4);
+                    if (intersect(array[off + 0], array[off + 1], array[flipOff + 0], array[flipOff + 1], array[off + 2], array[off + 3], array[flipOff + 2], array[flipOff + 3])) {
+                        swap = true;
+                        let tps = array[off + 0];
+                        array[off + 0] = array[off + 2];
+                        array[off + 2] = tps;
+
+                        tps = array[off + 1];
+                        array[off + 1] = array[off + 3];
+                        array[off + 3] = tps;
+                    }
+                }
+
+                if (borderMode) {
+                    let t = halfThickness + borderThickness;
+                    array[off + 4] = p.x + n.x * (swap ? -t : t);
+                    array[off + 5] = p.y + n.y * (swap ? -t : t);
+                    array[off + 6] = p.x + n.x * (swap ? t : -t);
+                    array[off + 7] = p.y + n.y * (swap ? t : -t);
+
+                    updateMinMax(array, off + 4);
+                    updateMinMax(array, off + 6);
+                }
+
+                if (contour) {
+                    off += borderMode ? 4 : 0;
+                    contour.push(new Vector2(array[off + 0], array[off + 1]));
+                    contour.push(new Vector2(array[off + 2], array[off + 3]));
+                }
+            }
+
+            let sd = Lines2D._roundCapSubDiv;
+            let getCapSize = (type: number, border: boolean = false): { vbsize: number; ibsize: number } => {
+                // If no array given, we call this to get the size
+                let vbsize: number = 0, ibsize: number = 0;
+                switch (type) {
+                    case Lines2D.NoCap:
+                        // If the line is not close and we're computing border, we add the size to generate the edge border
+                        if (!this.closed && border) {
+                            vbsize = 4;
+                            ibsize = 6;
+                        } else {
+                            vbsize = ibsize = 0;
+                        }
+                        break;
+                    case Lines2D.RoundCap:
+                        if (border) {
+                            vbsize = sd;
+                            ibsize = (sd-2) * 3;
+                        } else {
+                            vbsize = (sd / 2) + 1;
+                            ibsize = (sd / 2) * 3;
+                        }
+                        break;
+                    case Lines2D.ArrowCap:
+                        if (border) {
+                            vbsize = 12;
+                            ibsize = 24;
+                        } else {
+                            vbsize = 3;
+                            ibsize = 3;
+                        }
+                        break;
+                    case Lines2D.TriangleCap:
+                        if (border) {
+                            vbsize = 6;
+                            ibsize = 12;
+                        } else {
+                            vbsize = 3;
+                            ibsize = 3;
+                        }
+                        break;
+                    case Lines2D.DiamondAnchorCap:
+                        if (border) {
+                            vbsize = 10;
+                            ibsize = 24;
+                        } else {
+                            vbsize = 5;
+                            ibsize = 9;
+                        }
+                        break;
+                    case Lines2D.SquareAnchorCap:
+                        if (border) {
+                            vbsize = 12;
+                            ibsize = 30;
+                        } else {
+                            vbsize = 4;
+                            ibsize = 6;
+                        }
+                        break;
+                    case Lines2D.RoundAnchorCap:
+                        if (border) {
+                            vbsize = sd*2;
+                            ibsize = (sd - 1) * 6;
+                        } else {
+                            vbsize = sd + 1;
+                            ibsize = (sd + 1) * 3;
+                        }
+                        break;
+                }
+
+                return { vbsize: vbsize*2, ibsize: ibsize };
+            }
+
+            let v = Vector2.Zero();
+            let storeVertex = (vb: Float32Array, baseOffset: number, index: number, basePos: Vector2, rotation: number, vertex: Vector2): number => {
+                let c = Math.cos(rotation);
+                let s = Math.sin(rotation);
+
+                v.x = (c * vertex.x) + (-s * vertex.y) + basePos.x;
+                v.y = (s * vertex.x) + ( c * vertex.y) + basePos.y;
+                let offset = baseOffset + (index*2);
+                vb[offset + 0] = v.x;
+                vb[offset + 1] = v.y;
+
+                updateMinMax(vb, offset);
+                return (baseOffset + index*2) / 2;
+            }
+
+            let storeIndex = (ib: Float32Array, baseOffset: number, index: number, vertexIndex: number) => {
+                ib[baseOffset + index] = vertexIndex;
+            }
+
+            let buildCap = (vb: Float32Array, vbi: number, ib: Float32Array, ibi: number, pos: Vector2, thickness: number, borderThickness: number, type: number, capDir: Vector2): { vbsize: number; ibsize: number } => {
+
+                // Compute the transformation from the direction of the cap to build relative to our default orientation [1;0] (our cap are by default pointing toward right, horizontal
+                let dir = new Vector2(1, 0);
+                let angle = Math.atan2(capDir.y, capDir.x) - Math.atan2(dir.y, dir.x);
+
+                let ht = thickness / 2;
+                let t = thickness;
+                let borderMode = borderThickness != null;
+                let bt = borderThickness;
+                switch (type) {
+                    case Lines2D.NoCap:
+                        if (borderMode && !this.closed) {
+                            let vi = 0;
+                            let ii = 0;
+                            let v1 = storeVertex(vb, vbi, vi++, pos, angle, new Vector2(0, ht + bt));
+                            let v2 = storeVertex(vb, vbi, vi++, pos, angle, new Vector2(bt, ht + bt));
+                            let v3 = storeVertex(vb, vbi, vi++, pos, angle, new Vector2(bt, -(ht + bt)));
+                            let v4 = storeVertex(vb, vbi, vi++, pos, angle, new Vector2(0, -(ht + bt)));
+
+                            storeIndex(ib, ibi, ii++, v1); storeIndex(ib, ibi, ii++, v2); storeIndex(ib, ibi, ii++, v3);
+                            storeIndex(ib, ibi, ii++, v1); storeIndex(ib, ibi, ii++, v3); storeIndex(ib, ibi, ii++, v4);
+                        }
+                        break;
+                    case Lines2D.ArrowCap:
+                        ht *= 2;
+                    case Lines2D.TriangleCap:
+                    {
+                        if (borderMode) {
+                            let f = type===Lines2D.TriangleCap ? bt : Math.sqrt(bt * bt * 2);
+                            let v1 = storeVertex(vb, vbi, 0, pos, angle, new Vector2(0, ht));
+                            let v2 = storeVertex(vb, vbi, 1, pos, angle, new Vector2(ht, 0));
+                            let v3 = storeVertex(vb, vbi, 2, pos, angle, new Vector2(0, -ht));
+                            let v4 = storeVertex(vb, vbi, 3, pos, angle, new Vector2(0, ht+f));
+                            let v5 = storeVertex(vb, vbi, 4, pos, angle, new Vector2(ht+f, 0));
+                            let v6 = storeVertex(vb, vbi, 5, pos, angle, new Vector2(0, -(ht+f)));
+
+                            let ii = 0;
+                            storeIndex(ib, ibi, ii++, v1);  storeIndex(ib, ibi, ii++, v4);  storeIndex(ib, ibi, ii++, v5);
+                            storeIndex(ib, ibi, ii++, v1);  storeIndex(ib, ibi, ii++, v5);  storeIndex(ib, ibi, ii++, v2);
+                            storeIndex(ib, ibi, ii++, v6);  storeIndex(ib, ibi, ii++, v3);  storeIndex(ib, ibi, ii++, v2);
+                            storeIndex(ib, ibi, ii++, v6);  storeIndex(ib, ibi, ii++, v2);  storeIndex(ib, ibi, ii++, v5);
+
+                            if (type === Lines2D.ArrowCap) {
+                                let rht = thickness / 2;
+                                let v7 = storeVertex(vb, vbi, 6, pos, angle, new Vector2(0, rht+bt));
+                                let v8 = storeVertex(vb, vbi, 7, pos, angle, new Vector2(-bt, rht+bt));
+                                let v9 = storeVertex(vb, vbi, 8, pos, angle, new Vector2(-bt, ht+f));
+
+                                let v10 = storeVertex(vb, vbi, 9, pos, angle, new Vector2(0, -(rht+bt)));
+                                let v11 = storeVertex(vb, vbi, 10, pos, angle, new Vector2(-bt, -(rht+bt)));
+                                let v12 = storeVertex(vb, vbi, 11, pos, angle, new Vector2(-bt, -(ht+f)));
+
+                                storeIndex(ib, ibi, ii++, v7);  storeIndex(ib, ibi, ii++, v8);  storeIndex(ib, ibi, ii++, v9);
+                                storeIndex(ib, ibi, ii++, v7);  storeIndex(ib, ibi, ii++, v9);  storeIndex(ib, ibi, ii++, v4);
+                                storeIndex(ib, ibi, ii++, v10); storeIndex(ib, ibi, ii++, v12); storeIndex(ib, ibi, ii++, v11);
+                                storeIndex(ib, ibi, ii++, v10); storeIndex(ib, ibi, ii++, v6);  storeIndex(ib, ibi, ii++, v12);
+                            }
+                        } else {
+                            let v1 = storeVertex(vb, vbi, 0, pos, angle, new Vector2(0, ht));
+                            let v2 = storeVertex(vb, vbi, 1, pos, angle, new Vector2(ht, 0));
+                            let v3 = storeVertex(vb, vbi, 2, pos, angle, new Vector2(0, -ht));
+
+                            storeIndex(ib, ibi, 0, v1);
+                            storeIndex(ib, ibi, 1, v2);
+                            storeIndex(ib, ibi, 2, v3);
+                        }
+                        break;
+                    }
+                    case Lines2D.RoundCap:
+                    {
+                        if (borderMode) {
+                            let curA = -Math.PI / 2;
+                            let incA = Math.PI / (sd / 2 - 1);
+                            let ii = 0;
+
+                            for (let i = 0; i < (sd / 2); i++) {
+                                let v1 = storeVertex(vb, vbi, i*2 + 0, pos, angle, new Vector2(Math.cos(curA) * ht, Math.sin(curA) * ht));
+                                let v2 = storeVertex(vb, vbi, i*2 + 1, pos, angle, new Vector2(Math.cos(curA) * (ht+bt), Math.sin(curA) * (ht+bt)));
+
+                                if (i > 0) {
+                                    storeIndex(ib, ibi, ii++, v1 - 2);
+                                    storeIndex(ib, ibi, ii++, v2 - 2);
+                                    storeIndex(ib, ibi, ii++, v2);
+
+                                    storeIndex(ib, ibi, ii++, v1 - 2);
+                                    storeIndex(ib, ibi, ii++, v2);
+                                    storeIndex(ib, ibi, ii++, v1);
+                                }
+                                curA += incA;
+                            }
+                        } else {
+                            let c = storeVertex(vb, vbi, 0, pos, angle, new Vector2(0, 0));
+                            let curA = -Math.PI / 2;
+                            let incA = Math.PI / (sd / 2 - 1);
+
+                            storeVertex(vb, vbi, 1, pos, angle, new Vector2(Math.cos(curA) * ht, Math.sin(curA) * ht));
+                            curA += incA;
+                            for (let i = 1; i < (sd / 2); i++) {
+                                let v2 = storeVertex(vb, vbi, i + 1, pos, angle, new Vector2(Math.cos(curA) * ht, Math.sin(curA) * ht));
+
+                                storeIndex(ib, ibi, i * 3 + 0, c);
+                                storeIndex(ib, ibi, i * 3 + 1, v2 - 1);
+                                storeIndex(ib, ibi, i * 3 + 2, v2);
+                                curA += incA;
+                            }
+                        }
+                        break;
+                    }
+                    case Lines2D.SquareAnchorCap:
+                    {
+                        let vi = 0;
+                        let v1 = storeVertex(vb, vbi, vi++, pos, angle, new Vector2(0, t));
+                        let v2 = storeVertex(vb, vbi, vi++, pos, angle, new Vector2(t * 2, t));
+                        let v3 = storeVertex(vb, vbi, vi++, pos, angle, new Vector2(t * 2, -t));
+                        let v4 = storeVertex(vb, vbi, vi++, pos, angle, new Vector2(0, -t));
+
+                        if (borderMode) {
+                            let v5 = storeVertex(vb, vbi, vi++, pos, angle, new Vector2(0, ht+bt));
+                            let v6 = storeVertex(vb, vbi, vi++, pos, angle, new Vector2(-bt, ht+bt));
+                            let v7 = storeVertex(vb, vbi, vi++, pos, angle, new Vector2(-bt, t + bt));
+                            let v8 = storeVertex(vb, vbi, vi++, pos, angle, new Vector2(t * 2 + bt, t + bt));
+
+                            let v9 =  storeVertex(vb, vbi, vi++, pos, angle, new Vector2(t * 2 + bt, -(t+bt)));
+                            let v10 = storeVertex(vb, vbi, vi++, pos, angle, new Vector2(-bt, -(t + bt)));
+                            let v11 = storeVertex(vb, vbi, vi++, pos, angle, new Vector2(-bt, -(ht+bt)));
+                            let v12 = storeVertex(vb, vbi, vi++, pos, angle, new Vector2(0, -(ht+bt)));
+
+                            let ii = 0;
+                            storeIndex(ib, ibi, ii++, v6);  storeIndex(ib, ibi, ii++, v1);  storeIndex(ib, ibi, ii++, v5);
+                            storeIndex(ib, ibi, ii++, v6);  storeIndex(ib, ibi, ii++, v7);  storeIndex(ib, ibi, ii++, v1);
+                            storeIndex(ib, ibi, ii++, v1);  storeIndex(ib, ibi, ii++, v7);  storeIndex(ib, ibi, ii++, v8);
+                            storeIndex(ib, ibi, ii++, v1);  storeIndex(ib, ibi, ii++, v8);  storeIndex(ib, ibi, ii++, v2);
+                            storeIndex(ib, ibi, ii++, v2);  storeIndex(ib, ibi, ii++, v8);  storeIndex(ib, ibi, ii++, v9);
+                            storeIndex(ib, ibi, ii++, v2);  storeIndex(ib, ibi, ii++, v9);  storeIndex(ib, ibi, ii++, v3);
+                            storeIndex(ib, ibi, ii++, v3);  storeIndex(ib, ibi, ii++, v9);  storeIndex(ib, ibi, ii++, v10);
+                            storeIndex(ib, ibi, ii++, v3);  storeIndex(ib, ibi, ii++, v10); storeIndex(ib, ibi, ii++, v4);
+                            storeIndex(ib, ibi, ii++, v10); storeIndex(ib, ibi, ii++, v11); storeIndex(ib, ibi, ii++, v4);
+                            storeIndex(ib, ibi, ii++, v11); storeIndex(ib, ibi, ii++, v12); storeIndex(ib, ibi, ii++, v4);
+
+                        } else {
+                            storeIndex(ib, ibi, 0, v1);
+                            storeIndex(ib, ibi, 1, v2);
+                            storeIndex(ib, ibi, 2, v3);
+
+                            storeIndex(ib, ibi, 3, v1);
+                            storeIndex(ib, ibi, 4, v3);
+                            storeIndex(ib, ibi, 5, v4);
+                        }
+                        break;
+                    }
+                    case Lines2D.RoundAnchorCap:
+                    {
+                        let cpos = Math.sqrt(t * t - ht * ht);
+                        let center = new Vector2(cpos, 0);
+                        let curA = Tools.ToRadians(-150);
+                        let incA = Tools.ToRadians(300) / (sd - 1);
+
+                        if (borderMode) {
+                            let ii = 0;
+
+                            for (let i = 0; i < sd; i++) {
+                                let v1 = storeVertex(vb, vbi, i * 2 + 0, pos, angle, new Vector2(cpos + Math.cos(curA) * t, Math.sin(curA) * t));
+                                let v2 = storeVertex(vb, vbi, i * 2 + 1, pos, angle, new Vector2(cpos + Math.cos(curA) * (t + bt), Math.sin(curA) * (t + bt)));
+
+                                if (i > 0) {
+                                    storeIndex(ib, ibi, ii++, v1 - 2);
+                                    storeIndex(ib, ibi, ii++, v2 - 2);
+                                    storeIndex(ib, ibi, ii++, v2);
+
+                                    storeIndex(ib, ibi, ii++, v1 - 2);
+                                    storeIndex(ib, ibi, ii++, v2);
+                                    storeIndex(ib, ibi, ii++, v1);
+                                }
+                                curA += incA;
+                            }
+                        } else {
+                            let c = storeVertex(vb, vbi, 0, pos, angle, center);
+                            storeVertex(vb, vbi, 1, pos, angle, new Vector2(cpos + Math.cos(curA) * t, Math.sin(curA) * t));
+                            curA += incA;
+                            for (let i = 1; i < sd; i++) {
+                                let v2 = storeVertex(vb, vbi, i + 1, pos, angle, new Vector2(cpos + Math.cos(curA) * t, Math.sin(curA) * t));
+
+                                storeIndex(ib, ibi, i * 3 + 0, c);
+                                storeIndex(ib, ibi, i * 3 + 1, v2 - 1);
+                                storeIndex(ib, ibi, i * 3 + 2, v2);
+                                curA += incA;
+                            }
+                            storeIndex(ib, ibi, sd * 3 + 0, c);
+                            storeIndex(ib, ibi, sd * 3 + 1, c + 1);
+                            storeIndex(ib, ibi, sd * 3 + 2, c + sd);
+                        }
+                        break;
+                    }
+                    case Lines2D.DiamondAnchorCap:
+                    {
+                        let vi = 0;
+                        let v1 = storeVertex(vb, vbi, vi++, pos, angle, new Vector2(0, ht));
+                        let v2 = storeVertex(vb, vbi, vi++, pos, angle, new Vector2(ht, t));
+                        let v3 = storeVertex(vb, vbi, vi++, pos, angle, new Vector2(ht * 3, 0));
+                        let v4 = storeVertex(vb, vbi, vi++, pos, angle, new Vector2(ht, -t));
+                        let v5 = storeVertex(vb, vbi, vi++, pos, angle, new Vector2(0, -ht));
+
+                        if (borderMode) {
+                            let f = Math.sqrt(bt * bt * 2);
+                            let v6 = storeVertex(vb, vbi, vi++, pos, angle, new Vector2(-f,ht));
+                            let v7 = storeVertex(vb, vbi, vi++, pos, angle, new Vector2(ht,t+f));
+                            let v8 = storeVertex(vb, vbi, vi++, pos, angle, new Vector2(ht*3+f,0));
+                            let v9 = storeVertex(vb, vbi, vi++, pos, angle, new Vector2(ht,-(t+f)));
+                            let v10 = storeVertex(vb, vbi, vi++, pos, angle, new Vector2(-f, -ht));
+
+                            let ii = 0;
+                            storeIndex(ib, ibi, ii++, v6); storeIndex(ib, ibi, ii++, v7); storeIndex(ib, ibi, ii++, v1);
+                            storeIndex(ib, ibi, ii++, v1); storeIndex(ib, ibi, ii++, v7); storeIndex(ib, ibi, ii++, v2);
+
+                            storeIndex(ib, ibi, ii++, v2); storeIndex(ib, ibi, ii++, v7); storeIndex(ib, ibi, ii++, v8);
+                            storeIndex(ib, ibi, ii++, v2); storeIndex(ib, ibi, ii++, v8); storeIndex(ib, ibi, ii++, v3);
+
+                            storeIndex(ib, ibi, ii++, v3); storeIndex(ib, ibi, ii++, v8); storeIndex(ib, ibi, ii++, v9);
+                            storeIndex(ib, ibi, ii++, v3); storeIndex(ib, ibi, ii++, v9); storeIndex(ib, ibi, ii++, v4);
+
+                            storeIndex(ib, ibi, ii++, v4); storeIndex(ib, ibi, ii++, v9); storeIndex(ib, ibi, ii++, v10);
+                            storeIndex(ib, ibi, ii++, v4); storeIndex(ib, ibi, ii++, v10); storeIndex(ib, ibi, ii++, v5);
+
+                        } else {
+                            storeIndex(ib, ibi, 0, v1); storeIndex(ib, ibi, 1, v2); storeIndex(ib, ibi, 2, v3);
+                            storeIndex(ib, ibi, 3, v1); storeIndex(ib, ibi, 4, v3); storeIndex(ib, ibi, 5, v5);
+                            storeIndex(ib, ibi, 6, v5); storeIndex(ib, ibi, 7, v3); storeIndex(ib, ibi, 8, v4);
+                        }
+                        break;
+                    }
+                }
+
+                return null;
+            }
+
+            let buildLine = (vb: Float32Array, contour: Vector2[], ht: number, bt?: number) => {
+                let lineA = Vector2.Zero();
+                let lineB = Vector2.Zero();
+                let tangent = Vector2.Zero();
+                let miter = Vector2.Zero();
+                let curNormal: Vector2 = null;
+
+                if (this.closed) {
+                    this.points.push(this.points[0]);
+                }
+
+                var total = this.points.length;
+                for (let i = 1; i < total; i++) {
+                    let last = this.points[i - 1];
+                    let cur = this.points[i];
+                    let next = (i < (this.points.length - 1)) ? this.points[i + 1] : null;
+
+                    direction(cur, last, lineA);
+                    if (!curNormal) {
+                        curNormal = Vector2.Zero();
+                        perp(lineA, curNormal);
+                    }
+
+                    if (i === 1) {
+                        store(vb, contour, 0, total, this.points[0], curNormal, ht, bt);
+                    }
+
+                    if (!next) {
+                        perp(lineA, curNormal);
+                        store(vb, contour, i, total, this.points[i], curNormal, ht, bt, i - 1);
+                    } else {
+                        direction(next, cur, lineB);
+
+                        var miterLen = computeMiter(tangent, miter, lineA, lineB);
+                        store(vb, contour, i, total, this.points[i], miter, miterLen*ht, miterLen*bt, i - 1);
+                    }
+                }
+
+                if (this.points.length > 2 && this.closed) {
+                    let last2 = this.points[total - 2];
+                    let cur2 = this.points[0];
+                    let next2 = this.points[1];
+
+                    direction(cur2, last2, lineA);
+                    direction(next2, cur2, lineB);
+                    perp(lineA, curNormal);
+
+                    var miterLen2 = computeMiter(tangent, miter, lineA, lineB);
+                    store(vb, null, 0, total, this.points[0], miter, miterLen2 * ht, miterLen2 * bt, 1);
+
+                    // Patch contour
+                    if (contour) {
+                        let off = (bt == null) ? 0 : 4;
+                        contour[0].x = vb[off + 0];
+                        contour[0].y = vb[off + 1];
+                        contour[1].x = vb[off + 2];
+                        contour[1].y = vb[off + 3];
+                    }
+                }
+
+                // Remove the point we added at the beginning
+                if (this.closed) {
+                    this.points.splice(total - 1);
+                }
+            }
+
+            let contour = new Array<Vector2>();
+
+            // Need to create WebGL resources for fill part?
+            if (this.fill) {
+                let startCapInfo = getCapSize(this.startCap);
+                let endCapInfo = getCapSize(this.endCap);
+                let count = this.points.length;
+                let vbSize = (count * 2 * 2) + startCapInfo.vbsize + endCapInfo.vbsize;
+                let vb = new Float32Array(vbSize);
+                let ht = this.fillThickness / 2;
+                let total = this.points.length;
+
+                buildLine(vb, this.border ? null : contour, ht);
+
+                let max = total * 2;
+                let triCount = (count - (this.closed ? 0 : 1)) * 2;
+                let ib = new Float32Array(triCount * 3 + startCapInfo.ibsize + endCapInfo.ibsize);
+                for (let i = 0; i < triCount; i+=2) {
+                    ib[i * 3 + 0] = i + 0;
+                    ib[i * 3 + 1] = i + 1;
+                    ib[i * 3 + 2] = (i + 2) % max;
+
+                    ib[i * 3 + 3] = i + 1;
+                    ib[i * 3 + 4] = (i + 3) % max;
+                    ib[i * 3 + 5] = (i + 2) % max;
+                }
+
+                buildCap(vb, count * 2 * 2, ib, triCount * 3, this.points[0], this.fillThickness, null, this.startCap, startDir);
+                buildCap(vb, (count * 2 * 2) + startCapInfo.vbsize, ib, (triCount * 3) + startCapInfo.ibsize, this.points[total - 1], this.fillThickness, null, this.endCap, endDir);
+
+                renderCache.fillVB = engine.createVertexBuffer(vb);
+                renderCache.fillIB = engine.createIndexBuffer(ib);
+                renderCache.fillIndicesCount = ib.length;
+
+                let ei = this.getDataPartEffectInfo(Shape2D.SHAPE2D_FILLPARTID, ["position"]);
+                renderCache.effectFill = engine.createEffect({ vertex: "lines2d", fragment: "lines2d" }, ei.attributes, ei.uniforms, [], ei.defines, null);
+            }
+
+            // Need to create WebGL resources for border part?
+            if (this.border) {
+                let startCapInfo = getCapSize(this.startCap, true);
+                let endCapInfo = getCapSize(this.endCap, true);
+                let count = this.points.length;
+                let vbSize = (count * 2 * 2 * 2) + startCapInfo.vbsize + endCapInfo.vbsize;
+                let vb = new Float32Array(vbSize);
+                let ht = this.fillThickness / 2;
+                let bt = this.borderThickness;
+                let total = this.points.length;
+
+                buildLine(vb, contour, ht, bt);
+
+                let max = total * 2 * 2;
+                let triCount = (count - (this.closed ? 0 : 1)) * 2 * 2;
+                let ib = new Float32Array(triCount * 3 + startCapInfo.ibsize + endCapInfo.ibsize);
+                for (let i = 0; i < triCount; i += 4) {
+                    ib[i * 3 + 0] = i + 0;
+                    ib[i * 3 + 1] = i + 2;
+                    ib[i * 3 + 2] = (i + 6) % max;
+
+                    ib[i * 3 + 3] = i + 0;
+                    ib[i * 3 + 4] = (i + 6) % max;
+                    ib[i * 3 + 5] = (i + 4) % max;
+
+                    ib[i * 3 + 6] = i + 3;
+                    ib[i * 3 + 7] = i + 1;
+                    ib[i * 3 + 8] = (i + 5) % max;
+
+                    ib[i * 3 + 9] = i + 3;
+                    ib[i * 3 + 10] = (i + 5) % max;
+                    ib[i * 3 + 11] = (i + 7) % max;
+                }
+
+                buildCap(vb, count * 2 * 2 * 2, ib, triCount * 3, this.points[0], this.fillThickness, this.borderThickness, this.startCap, startDir);
+                buildCap(vb, (count * 2 * 2 * 2) + startCapInfo.vbsize, ib, (triCount * 3) + startCapInfo.ibsize, this.points[total - 1], this.fillThickness, this.borderThickness, this.endCap, endDir);
+
+                renderCache.borderVB = engine.createVertexBuffer(vb);
+                renderCache.borderIB = engine.createIndexBuffer(ib);
+                renderCache.borderIndicesCount = ib.length;
+
+                let ei = this.getDataPartEffectInfo(Shape2D.SHAPE2D_BORDERPARTID, ["position"]);
+                renderCache.effectBorder = engine.createEffect({ vertex: "lines2d", fragment: "lines2d" }, ei.attributes, ei.uniforms, [], ei.defines, null);
+            }
+
+            this._contour = contour;
+            let bs = this._boundingMax.subtract(this._boundingMin);
+            this._size.width = bs.x;
+            this._size.height = bs.y;
+            return renderCache;
+        }
+
+
+        protected createInstanceDataParts(): InstanceDataBase[] {
+            var res = new Array<InstanceDataBase>();
+            if (this.border) {
+                res.push(new Lines2DInstanceData(Shape2D.SHAPE2D_BORDERPARTID));
+            }
+            if (this.fill) {
+                res.push(new Lines2DInstanceData(Shape2D.SHAPE2D_FILLPARTID));
+            }
+            return res;
+        }
+
+        protected refreshInstanceDataPart(part: InstanceDataBase): boolean {
+            if (!super.refreshInstanceDataPart(part)) {
+                return false;
+            }
+            if (part.id === Shape2D.SHAPE2D_BORDERPARTID) {
+                let d = <Lines2DInstanceData>part;
+                d.boundingMin = this.boundingMin;
+                d.boundingMax = this.boundingMax;
+            }
+            else if (part.id === Shape2D.SHAPE2D_FILLPARTID) {
+                let d = <Lines2DInstanceData>part;
+                d.boundingMin = this.boundingMin;
+                d.boundingMax = this.boundingMax;
+            }
+            return true;
+        }
+
+        private static _noCap            = 0;
+        private static _roundCap         = 1;
+        private static _triangleCap      = 2;
+        private static _squareAnchorCap  = 3;
+        private static _roundAnchorCap   = 4;
+        private static _diamondAnchorCap = 5;
+        private static _arrowCap         = 6;
+
+        private static _roundCapSubDiv = 36;
+
+        private _boundingMin: Vector2;
+        private _boundingMax: Vector2;
+        private _size: Size;
+        private _contour: Vector2[];
+
+        private _closed: boolean;
+        private _startCap: number;
+        private _endCap: number;
+        private _fillThickness: number;
+        private _points: Vector2[];
+
+
+    }
+}

+ 2 - 2
src/Canvas2d/babylon.modelRenderCache.js

@@ -31,7 +31,7 @@ var BABYLON;
             return true;
             return true;
         };
         };
         return GroupInstanceInfo;
         return GroupInstanceInfo;
-    })();
+    }());
     BABYLON.GroupInstanceInfo = GroupInstanceInfo;
     BABYLON.GroupInstanceInfo = GroupInstanceInfo;
     var ModelRenderCache = (function () {
     var ModelRenderCache = (function () {
         function ModelRenderCache(engine, modelKey, isTransparent) {
         function ModelRenderCache(engine, modelKey, isTransparent) {
@@ -178,6 +178,6 @@ var BABYLON;
         ModelRenderCache.v3 = BABYLON.Vector3.Zero();
         ModelRenderCache.v3 = BABYLON.Vector3.Zero();
         ModelRenderCache.v4 = BABYLON.Vector4.Zero();
         ModelRenderCache.v4 = BABYLON.Vector4.Zero();
         return ModelRenderCache;
         return ModelRenderCache;
-    })();
+    }());
     BABYLON.ModelRenderCache = ModelRenderCache;
     BABYLON.ModelRenderCache = ModelRenderCache;
 })(BABYLON || (BABYLON = {}));
 })(BABYLON || (BABYLON = {}));

+ 1 - 1
src/Canvas2d/babylon.modelRenderCache.ts

@@ -1,6 +1,6 @@
 module BABYLON {
 module BABYLON {
     export const enum ShaderDataType {
     export const enum ShaderDataType {
-        Vector2, Vector3, Vector4, Matrix, float, Color3, Color4
+        Vector2, Vector3, Vector4, Matrix, float, Color3, Color4, Size
     }
     }
 
 
     export class GroupInstanceInfo {
     export class GroupInstanceInfo {

+ 9 - 9
src/Canvas2d/babylon.prim2dBase.js

@@ -15,7 +15,7 @@ var BABYLON;
         function Render2DContext() {
         function Render2DContext() {
         }
         }
         return Render2DContext;
         return Render2DContext;
-    })();
+    }());
     BABYLON.Render2DContext = Render2DContext;
     BABYLON.Render2DContext = Render2DContext;
     /**
     /**
      * This class store information for the pointerEventObservable Observable.
      * This class store information for the pointerEventObservable Observable.
@@ -175,7 +175,7 @@ var BABYLON;
         PrimitivePointerInfo._pointerLostCapture = 0x0200;
         PrimitivePointerInfo._pointerLostCapture = 0x0200;
         PrimitivePointerInfo._mouseWheelPrecision = 3.0;
         PrimitivePointerInfo._mouseWheelPrecision = 3.0;
         return PrimitivePointerInfo;
         return PrimitivePointerInfo;
-    })();
+    }());
     BABYLON.PrimitivePointerInfo = PrimitivePointerInfo;
     BABYLON.PrimitivePointerInfo = PrimitivePointerInfo;
     /**
     /**
      * Stores information about a Primitive that was intersected
      * Stores information about a Primitive that was intersected
@@ -186,7 +186,7 @@ var BABYLON;
             this.intersectionLocation = intersectionLocation;
             this.intersectionLocation = intersectionLocation;
         }
         }
         return PrimitiveIntersectedInfo;
         return PrimitiveIntersectedInfo;
-    })();
+    }());
     BABYLON.PrimitiveIntersectedInfo = PrimitiveIntersectedInfo;
     BABYLON.PrimitiveIntersectedInfo = PrimitiveIntersectedInfo;
     /**
     /**
      * Main class used for the Primitive Intersection API
      * Main class used for the Primitive Intersection API
@@ -223,14 +223,14 @@ var BABYLON;
             }
             }
         };
         };
         return IntersectInfo2D;
         return IntersectInfo2D;
-    })();
+    }());
     BABYLON.IntersectInfo2D = IntersectInfo2D;
     BABYLON.IntersectInfo2D = IntersectInfo2D;
     var Prim2DBase = (function (_super) {
     var Prim2DBase = (function (_super) {
         __extends(Prim2DBase, _super);
         __extends(Prim2DBase, _super);
         function Prim2DBase() {
         function Prim2DBase() {
             _super.apply(this, arguments);
             _super.apply(this, arguments);
         }
         }
-        Prim2DBase.prototype.setupPrim2DBase = function (owner, parent, id, position, isVisible) {
+        Prim2DBase.prototype.setupPrim2DBase = function (owner, parent, id, position, origin, isVisible) {
             if (isVisible === void 0) { isVisible = true; }
             if (isVisible === void 0) { isVisible = true; }
             if (!(this instanceof BABYLON.Group2D) && !(this instanceof BABYLON.Sprite2D && id !== null && id.indexOf("__cachedSpriteOfGroup__") === 0) && (owner.cachingStrategy === BABYLON.Canvas2D.CACHESTRATEGY_TOPLEVELGROUPS) && (parent === owner)) {
             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");
                 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");
@@ -265,7 +265,7 @@ var BABYLON;
             this.rotation = 0;
             this.rotation = 0;
             this.scale = 1;
             this.scale = 1;
             this.levelVisible = isVisible;
             this.levelVisible = isVisible;
-            this.origin = new BABYLON.Vector2(0.5, 0.5);
+            this.origin = origin || new BABYLON.Vector2(0.5, 0.5);
         };
         };
         Object.defineProperty(Prim2DBase.prototype, "actionManager", {
         Object.defineProperty(Prim2DBase.prototype, "actionManager", {
             get: function () {
             get: function () {
@@ -696,8 +696,8 @@ var BABYLON;
             }
             }
         };
         };
         Prim2DBase.prototype.updateGlobalTransVisOf = function (list, recurse) {
         Prim2DBase.prototype.updateGlobalTransVisOf = function (list, recurse) {
-            for (var _i = 0; _i < list.length; _i++) {
-                var cur = list[_i];
+            for (var _i = 0, list_1 = list; _i < list_1.length; _i++) {
+                var cur = list_1[_i];
                 cur.updateGlobalTransVis(recurse);
                 cur.updateGlobalTransVis(recurse);
             }
             }
         };
         };
@@ -778,6 +778,6 @@ var BABYLON;
             BABYLON.className("Prim2DBase")
             BABYLON.className("Prim2DBase")
         ], Prim2DBase);
         ], Prim2DBase);
         return Prim2DBase;
         return Prim2DBase;
-    })(BABYLON.SmartPropertyPrim);
+    }(BABYLON.SmartPropertyPrim));
     BABYLON.Prim2DBase = Prim2DBase;
     BABYLON.Prim2DBase = Prim2DBase;
 })(BABYLON || (BABYLON = {}));
 })(BABYLON || (BABYLON = {}));

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

@@ -296,7 +296,7 @@
     export class Prim2DBase extends SmartPropertyPrim {
     export class Prim2DBase extends SmartPropertyPrim {
         static PRIM2DBASE_PROPCOUNT: number = 10;
         static PRIM2DBASE_PROPCOUNT: number = 10;
 
 
-        protected setupPrim2DBase(owner: Canvas2D, parent: Prim2DBase, id: string, position: Vector2, isVisible: boolean = true) {
+        protected setupPrim2DBase(owner: Canvas2D, parent: Prim2DBase, id: string, position: Vector2, origin: Vector2, isVisible: boolean = true) {
             if (!(this instanceof Group2D) && !(this instanceof Sprite2D && id !== null && id.indexOf("__cachedSpriteOfGroup__") === 0) && (owner.cachingStrategy === Canvas2D.CACHESTRATEGY_TOPLEVELGROUPS) && (parent === owner)) {
             if (!(this instanceof Group2D) && !(this instanceof Sprite2D && id !== null && id.indexOf("__cachedSpriteOfGroup__") === 0) && (owner.cachingStrategy === 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");
                 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");
             }
             }
@@ -333,7 +333,7 @@
             this.rotation = 0;
             this.rotation = 0;
             this.scale = 1;
             this.scale = 1;
             this.levelVisible = isVisible;
             this.levelVisible = isVisible;
-            this.origin = new Vector2(0.5, 0.5);
+            this.origin = origin || new Vector2(0.5, 0.5);
         }
         }
 
 
 
 

+ 34 - 22
src/Canvas2d/babylon.rectangle2d.js

@@ -35,7 +35,7 @@ var BABYLON;
             if (this.effectFill) {
             if (this.effectFill) {
                 var partIndex = instanceInfo._partIndexFromId.get(BABYLON.Shape2D.SHAPE2D_FILLPARTID.toString());
                 var partIndex = instanceInfo._partIndexFromId.get(BABYLON.Shape2D.SHAPE2D_FILLPARTID.toString());
                 engine.enableEffect(this.effectFill);
                 engine.enableEffect(this.effectFill);
-                engine.bindBuffers(this.fillVB, this.fillIB, [1], 4, this.effectFill);
+                engine.bindBuffersDirectly(this.fillVB, this.fillIB, [1], 4, this.effectFill);
                 var count = instanceInfo._instancesPartsData[partIndex].usedElementCount;
                 var count = instanceInfo._instancesPartsData[partIndex].usedElementCount;
                 if (instanceInfo._owner.owner.supportInstancedArray) {
                 if (instanceInfo._owner.owner.supportInstancedArray) {
                     if (!this.instancingFillAttributes) {
                     if (!this.instancingFillAttributes) {
@@ -44,7 +44,7 @@ var BABYLON;
                     }
                     }
                     engine.updateAndBindInstancesBuffer(instanceInfo._instancesPartsBuffer[partIndex], null, this.instancingFillAttributes);
                     engine.updateAndBindInstancesBuffer(instanceInfo._instancesPartsBuffer[partIndex], null, this.instancingFillAttributes);
                     engine.draw(true, 0, this.fillIndicesCount, count);
                     engine.draw(true, 0, this.fillIndicesCount, count);
-                    engine.unBindInstancesBuffer(instanceInfo._instancesPartsBuffer[partIndex], this.instancingFillAttributes);
+                    engine.unbindInstanceAttributes();
                 }
                 }
                 else {
                 else {
                     for (var i = 0; i < count; i++) {
                     for (var i = 0; i < count; i++) {
@@ -56,7 +56,7 @@ var BABYLON;
             if (this.effectBorder) {
             if (this.effectBorder) {
                 var partIndex = instanceInfo._partIndexFromId.get(BABYLON.Shape2D.SHAPE2D_BORDERPARTID.toString());
                 var partIndex = instanceInfo._partIndexFromId.get(BABYLON.Shape2D.SHAPE2D_BORDERPARTID.toString());
                 engine.enableEffect(this.effectBorder);
                 engine.enableEffect(this.effectBorder);
-                engine.bindBuffers(this.borderVB, this.borderIB, [1], 4, this.effectBorder);
+                engine.bindBuffersDirectly(this.borderVB, this.borderIB, [1], 4, this.effectBorder);
                 var count = instanceInfo._instancesPartsData[partIndex].usedElementCount;
                 var count = instanceInfo._instancesPartsData[partIndex].usedElementCount;
                 if (instanceInfo._owner.owner.supportInstancedArray) {
                 if (instanceInfo._owner.owner.supportInstancedArray) {
                     if (!this.instancingBorderAttributes) {
                     if (!this.instancingBorderAttributes) {
@@ -64,7 +64,7 @@ var BABYLON;
                     }
                     }
                     engine.updateAndBindInstancesBuffer(instanceInfo._instancesPartsBuffer[partIndex], null, this.instancingBorderAttributes);
                     engine.updateAndBindInstancesBuffer(instanceInfo._instancesPartsBuffer[partIndex], null, this.instancingBorderAttributes);
                     engine.draw(true, 0, this.borderIndicesCount, count);
                     engine.draw(true, 0, this.borderIndicesCount, count);
-                    engine.unBindInstancesBuffer(instanceInfo._instancesPartsBuffer[partIndex], this.instancingBorderAttributes);
+                    engine.unbindInstanceAttributes();
                 }
                 }
                 else {
                 else {
                     for (var i = 0; i < count; i++) {
                     for (var i = 0; i < count; i++) {
@@ -112,7 +112,7 @@ var BABYLON;
             return true;
             return true;
         };
         };
         return Rectangle2DRenderCache;
         return Rectangle2DRenderCache;
-    })(BABYLON.ModelRenderCache);
+    }(BABYLON.ModelRenderCache));
     BABYLON.Rectangle2DRenderCache = Rectangle2DRenderCache;
     BABYLON.Rectangle2DRenderCache = Rectangle2DRenderCache;
     var Rectangle2DInstanceData = (function (_super) {
     var Rectangle2DInstanceData = (function (_super) {
         __extends(Rectangle2DInstanceData, _super);
         __extends(Rectangle2DInstanceData, _super);
@@ -130,7 +130,7 @@ var BABYLON;
             BABYLON.instanceData()
             BABYLON.instanceData()
         ], Rectangle2DInstanceData.prototype, "properties", null);
         ], Rectangle2DInstanceData.prototype, "properties", null);
         return Rectangle2DInstanceData;
         return Rectangle2DInstanceData;
-    })(BABYLON.Shape2DInstanceData);
+    }(BABYLON.Shape2DInstanceData));
     BABYLON.Rectangle2DInstanceData = Rectangle2DInstanceData;
     BABYLON.Rectangle2DInstanceData = Rectangle2DInstanceData;
     var Rectangle2D = (function (_super) {
     var Rectangle2D = (function (_super) {
         __extends(Rectangle2D, _super);
         __extends(Rectangle2D, _super);
@@ -187,29 +187,41 @@ var BABYLON;
         Rectangle2D.prototype.updateLevelBoundingInfo = function () {
         Rectangle2D.prototype.updateLevelBoundingInfo = function () {
             BABYLON.BoundingInfo2D.CreateFromSizeToRef(this.size, this._levelBoundingInfo, this.origin);
             BABYLON.BoundingInfo2D.CreateFromSizeToRef(this.size, this._levelBoundingInfo, this.origin);
         };
         };
-        Rectangle2D.prototype.setupRectangle2D = function (owner, parent, id, position, size, roundRadius, fill, border, borderThickness) {
+        Rectangle2D.prototype.setupRectangle2D = function (owner, parent, id, position, origin, size, roundRadius, fill, border, borderThickness) {
             if (roundRadius === void 0) { roundRadius = 0; }
             if (roundRadius === void 0) { roundRadius = 0; }
             if (borderThickness === void 0) { borderThickness = 1; }
             if (borderThickness === void 0) { borderThickness = 1; }
-            this.setupShape2D(owner, parent, id, position, true, fill, border, borderThickness);
+            this.setupShape2D(owner, parent, id, position, origin, true, fill, border, borderThickness);
             this.size = size;
             this.size = size;
             this.notRounded = !roundRadius;
             this.notRounded = !roundRadius;
             this.roundRadius = roundRadius;
             this.roundRadius = roundRadius;
         };
         };
-        Rectangle2D.Create = function (parent, id, x, y, width, height, fill, border) {
+        /**
+         * Create an Rectangle 2D Shape primitive. May be a sharp rectangle (with sharp corners), or a rounded one.
+         * @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
+         *  - 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
+         *  - 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.
+         */
+        Rectangle2D.Create = function (parent, options) {
             BABYLON.Prim2DBase.CheckParent(parent);
             BABYLON.Prim2DBase.CheckParent(parent);
             var rect = new Rectangle2D();
             var rect = new Rectangle2D();
-            rect.setupRectangle2D(parent.owner, parent, id, new BABYLON.Vector2(x, y), new BABYLON.Size(width, height), null);
-            rect.fill = fill;
-            rect.border = border;
-            return rect;
-        };
-        Rectangle2D.CreateRounded = function (parent, id, x, y, width, height, roundRadius, fill, border) {
-            if (roundRadius === void 0) { roundRadius = 0; }
-            BABYLON.Prim2DBase.CheckParent(parent);
-            var rect = new Rectangle2D();
-            rect.setupRectangle2D(parent.owner, parent, id, new BABYLON.Vector2(x, y), new BABYLON.Size(width, height), roundRadius);
-            rect.fill = fill || BABYLON.Canvas2D.GetSolidColorBrushFromHex("#FFFFFFFF");
-            rect.border = border;
+            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;
+            }
+            else {
+                rect.fill = BABYLON.Canvas2D.GetSolidColorBrushFromHex("#FFFFFFFF");
+            }
+            rect.border = options && options.border || null;
+            rect.borderThickness = options && options.borderThickness || 1;
             return rect;
             return rect;
         };
         };
         Rectangle2D.prototype.createModelRenderCache = function (modelKey, isTransparent) {
         Rectangle2D.prototype.createModelRenderCache = function (modelKey, isTransparent) {
@@ -312,6 +324,6 @@ var BABYLON;
             BABYLON.className("Rectangle2D")
             BABYLON.className("Rectangle2D")
         ], Rectangle2D);
         ], Rectangle2D);
         return Rectangle2D;
         return Rectangle2D;
-    })(BABYLON.Shape2D);
+    }(BABYLON.Shape2D));
     BABYLON.Rectangle2D = Rectangle2D;
     BABYLON.Rectangle2D = Rectangle2D;
 })(BABYLON || (BABYLON = {}));
 })(BABYLON || (BABYLON = {}));

+ 30 - 19
src/Canvas2d/babylon.rectangle2d.ts

@@ -40,7 +40,7 @@
                 let partIndex = instanceInfo._partIndexFromId.get(Shape2D.SHAPE2D_FILLPARTID.toString());
                 let partIndex = instanceInfo._partIndexFromId.get(Shape2D.SHAPE2D_FILLPARTID.toString());
 
 
                 engine.enableEffect(this.effectFill);
                 engine.enableEffect(this.effectFill);
-                engine.bindBuffers(this.fillVB, this.fillIB, [1], 4, this.effectFill);
+                engine.bindBuffersDirectly(this.fillVB, this.fillIB, [1], 4, this.effectFill);
                 let count = instanceInfo._instancesPartsData[partIndex].usedElementCount;
                 let count = instanceInfo._instancesPartsData[partIndex].usedElementCount;
                 if (instanceInfo._owner.owner.supportInstancedArray) {
                 if (instanceInfo._owner.owner.supportInstancedArray) {
                     if (!this.instancingFillAttributes) {
                     if (!this.instancingFillAttributes) {
@@ -50,7 +50,7 @@
 
 
                     engine.updateAndBindInstancesBuffer(instanceInfo._instancesPartsBuffer[partIndex], null, this.instancingFillAttributes);
                     engine.updateAndBindInstancesBuffer(instanceInfo._instancesPartsBuffer[partIndex], null, this.instancingFillAttributes);
                     engine.draw(true, 0, this.fillIndicesCount, count);
                     engine.draw(true, 0, this.fillIndicesCount, count);
-                    engine.unBindInstancesBuffer(instanceInfo._instancesPartsBuffer[partIndex], this.instancingFillAttributes);
+                    engine.unbindInstanceAttributes();
                 } else {
                 } else {
                     for (let i = 0; i < count; i++) {
                     for (let i = 0; i < count; i++) {
                         this.setupUniforms(this.effectFill, partIndex, instanceInfo._instancesPartsData[partIndex], i);
                         this.setupUniforms(this.effectFill, partIndex, instanceInfo._instancesPartsData[partIndex], i);
@@ -63,7 +63,7 @@
                 let partIndex = instanceInfo._partIndexFromId.get(Shape2D.SHAPE2D_BORDERPARTID.toString());
                 let partIndex = instanceInfo._partIndexFromId.get(Shape2D.SHAPE2D_BORDERPARTID.toString());
 
 
                 engine.enableEffect(this.effectBorder);
                 engine.enableEffect(this.effectBorder);
-                engine.bindBuffers(this.borderVB, this.borderIB, [1], 4, this.effectBorder);
+                engine.bindBuffersDirectly(this.borderVB, this.borderIB, [1], 4, this.effectBorder);
                 let count = instanceInfo._instancesPartsData[partIndex].usedElementCount;
                 let count = instanceInfo._instancesPartsData[partIndex].usedElementCount;
                 if (instanceInfo._owner.owner.supportInstancedArray) {
                 if (instanceInfo._owner.owner.supportInstancedArray) {
                     if (!this.instancingBorderAttributes) {
                     if (!this.instancingBorderAttributes) {
@@ -72,7 +72,7 @@
 
 
                     engine.updateAndBindInstancesBuffer(instanceInfo._instancesPartsBuffer[partIndex], null, this.instancingBorderAttributes);
                     engine.updateAndBindInstancesBuffer(instanceInfo._instancesPartsBuffer[partIndex], null, this.instancingBorderAttributes);
                     engine.draw(true, 0, this.borderIndicesCount, count);
                     engine.draw(true, 0, this.borderIndicesCount, count);
-                    engine.unBindInstancesBuffer(instanceInfo._instancesPartsBuffer[partIndex], this.instancingBorderAttributes);
+                    engine.unbindInstanceAttributes();
                 } else {
                 } else {
                     for (let i = 0; i < count; i++) {
                     for (let i = 0; i < count; i++) {
                         this.setupUniforms(this.effectBorder, partIndex, instanceInfo._instancesPartsData[partIndex], i);
                         this.setupUniforms(this.effectBorder, partIndex, instanceInfo._instancesPartsData[partIndex], i);
@@ -195,30 +195,41 @@
             BoundingInfo2D.CreateFromSizeToRef(this.size, this._levelBoundingInfo, this.origin);
             BoundingInfo2D.CreateFromSizeToRef(this.size, this._levelBoundingInfo, this.origin);
         }
         }
 
 
-        protected setupRectangle2D(owner: Canvas2D, parent: Prim2DBase, id: string, position: Vector2, size: Size, roundRadius = 0, fill?: IBrush2D, border?: IBrush2D, borderThickness: number = 1) {
-            this.setupShape2D(owner, parent, id, position, true, fill, border, borderThickness);
+        protected setupRectangle2D(owner: Canvas2D, parent: Prim2DBase, id: string, position: Vector2, origin: Vector2, size: Size, roundRadius = 0, fill?: IBrush2D, border?: IBrush2D, borderThickness: number = 1) {
+            this.setupShape2D(owner, parent, id, position, origin, true, fill, border, borderThickness);
             this.size = size;
             this.size = size;
             this.notRounded = !roundRadius;
             this.notRounded = !roundRadius;
             this.roundRadius = roundRadius;
             this.roundRadius = roundRadius;
         }
         }
 
 
-        public static Create(parent: Prim2DBase, id: string, x: number, y: number, width: number, height: number, fill?: IBrush2D, border?: IBrush2D): Rectangle2D {
+        /**
+         * Create an Rectangle 2D Shape primitive. May be a sharp rectangle (with sharp corners), or a rounded one.
+         * @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
+         *  - 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
+         *  - 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.
+         */
+        public static Create(parent: Prim2DBase, options: { id?: string, x?: number, y?: number, origin?: Vector2, width?: number, height?: number, roundRadius?: number, fill?: IBrush2D, border?: IBrush2D, borderThickness?: number}): Rectangle2D {
             Prim2DBase.CheckParent(parent);
             Prim2DBase.CheckParent(parent);
 
 
             let rect = new Rectangle2D();
             let rect = new Rectangle2D();
-            rect.setupRectangle2D(parent.owner, parent, id, new Vector2(x, y), new Size(width, height), null);
-            rect.fill = fill;
-            rect.border = border;
-            return rect;
-        }
-
-        public static CreateRounded(parent: Prim2DBase, id: string, x: number, y: number, width: number, height: number, roundRadius = 0, fill?: IBrush2D, border?: IBrush2D): Rectangle2D {
-            Prim2DBase.CheckParent(parent);
+            rect.setupRectangle2D(parent.owner, parent, options && options.id || null, new Vector2(options && options.x || 0, options && options.y || 0), options && options.origin || null, new Size(options && options.width || 10, options && options.height || 10), options && options.roundRadius || 0);
 
 
-            let rect = new Rectangle2D();
-            rect.setupRectangle2D(parent.owner, parent, id, new Vector2(x, y), new Size(width, height), roundRadius);
-            rect.fill = fill || Canvas2D.GetSolidColorBrushFromHex("#FFFFFFFF");
-            rect.border = border;
+            if (options && options.fill !== undefined) {
+                rect.fill = options.fill;
+            } else {
+                rect.fill = Canvas2D.GetSolidColorBrushFromHex("#FFFFFFFF");                
+            }
+            rect.border = options && options.border || null;
+            rect.borderThickness = options && options.borderThickness || 1;
             return rect;
             return rect;
         }
         }
 
 

+ 48 - 12
src/Canvas2d/babylon.renderablePrim2d.js

@@ -27,7 +27,7 @@ var BABYLON;
             }
             }
         };
         };
         InstanceClassInfo.prototype.getInstancingAttributeInfos = function (effect, categories) {
         InstanceClassInfo.prototype.getInstancingAttributeInfos = function (effect, categories) {
-            var catInline = categories.join(";");
+            var catInline = ";" + categories.join(";") + ";";
             var res = new Array();
             var res = new Array();
             var curInfo = this;
             var curInfo = this;
             while (curInfo) {
             while (curInfo) {
@@ -73,10 +73,9 @@ var BABYLON;
             return curOffset;
             return curOffset;
         };
         };
         return InstanceClassInfo;
         return InstanceClassInfo;
-    })();
+    }());
     BABYLON.InstanceClassInfo = InstanceClassInfo;
     BABYLON.InstanceClassInfo = InstanceClassInfo;
     var InstancePropInfo = (function () {
     var InstancePropInfo = (function () {
-        //uniformLocation: WebGLUniformLocation;
         function InstancePropInfo() {
         function InstancePropInfo() {
             this.instanceOffset = new BABYLON.StringDictionary();
             this.instanceOffset = new BABYLON.StringDictionary();
         }
         }
@@ -114,6 +113,11 @@ var BABYLON;
                 this.dataType = 6 /* Color4 */;
                 this.dataType = 6 /* Color4 */;
                 return;
                 return;
             }
             }
+            if (val instanceof BABYLON.Size) {
+                this.size = 8;
+                this.dataType = 7 /* Size */;
+                return;
+            }
             return;
             return;
         };
         };
         InstancePropInfo.prototype.writeData = function (array, offset, val) {
         InstancePropInfo.prototype.writeData = function (array, offset, val) {
@@ -173,10 +177,17 @@ var BABYLON;
                         }
                         }
                         break;
                         break;
                     }
                     }
+                case 7 /* Size */:
+                    {
+                        var s = val;
+                        array[offset + 0] = s.width;
+                        array[offset + 1] = s.height;
+                        break;
+                    }
             }
             }
         };
         };
         return InstancePropInfo;
         return InstancePropInfo;
-    })();
+    }());
     BABYLON.InstancePropInfo = InstancePropInfo;
     BABYLON.InstancePropInfo = InstancePropInfo;
     function instanceData(category, shaderAttributeName) {
     function instanceData(category, shaderAttributeName) {
         return function (target, propName, descriptor) {
         return function (target, propName, descriptor) {
@@ -191,11 +202,19 @@ var BABYLON;
             info = new InstancePropInfo();
             info = new InstancePropInfo();
             info.attributeName = shaderAttributeName;
             info.attributeName = shaderAttributeName;
             info.category = category || null;
             info.category = category || null;
+            if (info.category) {
+                info.delimitedCategory = ";" + info.category + ";";
+            }
             node.levelContent.add(instanceDataName, info);
             node.levelContent.add(instanceDataName, info);
             descriptor.get = function () {
             descriptor.get = function () {
                 return null;
                 return null;
             };
             };
             descriptor.set = function (val) {
             descriptor.set = function (val) {
+                // Check that we're not trying to set a property that belongs to a category that is not allowed (current)
+                // Quit if it's the case, otherwise we could overwrite data somewhere...
+                if (info.category && InstanceClassInfo._CurCategories.indexOf(info.delimitedCategory) === -1) {
+                    return;
+                }
                 if (!info.size) {
                 if (!info.size) {
                     info.setSize(val);
                     info.setSize(val);
                     node.classContent.mapProperty(info, true);
                     node.classContent.mapProperty(info, true);
@@ -300,7 +319,7 @@ var BABYLON;
             instanceData()
             instanceData()
         ], InstanceDataBase.prototype, "origin", null);
         ], InstanceDataBase.prototype, "origin", null);
         return InstanceDataBase;
         return InstanceDataBase;
-    })();
+    }());
     BABYLON.InstanceDataBase = InstanceDataBase;
     BABYLON.InstanceDataBase = InstanceDataBase;
     var RenderablePrim2D = (function (_super) {
     var RenderablePrim2D = (function (_super) {
         __extends(RenderablePrim2D, _super);
         __extends(RenderablePrim2D, _super);
@@ -317,8 +336,8 @@ var BABYLON;
             enumerable: true,
             enumerable: true,
             configurable: true
             configurable: true
         });
         });
-        RenderablePrim2D.prototype.setupRenderablePrim2D = function (owner, parent, id, position, isVisible) {
-            this.setupPrim2DBase(owner, parent, id, position);
+        RenderablePrim2D.prototype.setupRenderablePrim2D = function (owner, parent, id, position, origin, isVisible) {
+            this.setupPrim2DBase(owner, parent, id, position, origin);
             this._isTransparent = false;
             this._isTransparent = false;
         };
         };
         RenderablePrim2D.prototype.dispose = function () {
         RenderablePrim2D.prototype.dispose = function () {
@@ -382,8 +401,8 @@ var BABYLON;
                     var usedCatList = new Array();
                     var usedCatList = new Array();
                     var partIdList = new Array();
                     var partIdList = new Array();
                     var joinedUsedCatList = new Array();
                     var joinedUsedCatList = new Array();
-                    for (var _i = 0; _i < parts.length; _i++) {
-                        var dataPart = parts[_i];
+                    for (var _i = 0, parts_1 = parts; _i < parts_1.length; _i++) {
+                        var dataPart = parts_1[_i];
                         var cat = this.getUsedShaderCategories(dataPart);
                         var cat = this.getUsedShaderCategories(dataPart);
                         var cti = dataPart.getClassTreeInfo();
                         var cti = dataPart.getClassTreeInfo();
                         // Make sure the instance is visible other the properties won't be set and their size/offset wont be computed
                         // Make sure the instance is visible other the properties won't be set and their size/offset wont be computed
@@ -391,7 +410,7 @@ var BABYLON;
                         this.isVisible = true;
                         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.
                         // 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]));
                         //console.log("Build Prop Layout for " + Tools.getClassName(this._instanceDataParts[0]));
-                        var joinCat = cat.join(";");
+                        var joinCat = ";" + cat.join(";") + ";";
                         joinedUsedCatList.push(joinCat);
                         joinedUsedCatList.push(joinCat);
                         InstanceClassInfo._CurCategories = joinCat;
                         InstanceClassInfo._CurCategories = joinCat;
                         var obj = this.beforeRefreshForLayoutConstruction(dataPart);
                         var obj = this.beforeRefreshForLayoutConstruction(dataPart);
@@ -432,7 +451,7 @@ var BABYLON;
                         gii._partIndexFromId.add(this._modelRenderCache._partIdList[j].toString(), j);
                         gii._partIndexFromId.add(this._modelRenderCache._partIdList[j].toString(), j);
                         for (var _a = 0, _b = this._instanceDataParts; _a < _b.length; _a++) {
                         for (var _a = 0, _b = this._instanceDataParts; _a < _b.length; _a++) {
                             var part = _b[_a];
                             var part = _b[_a];
-                            gii._instancesPartsUsedShaderCategories[gii._partIndexFromId.get(part.id.toString())] = this.getUsedShaderCategories(part).join(";");
+                            gii._instancesPartsUsedShaderCategories[gii._partIndexFromId.get(part.id.toString())] = ";" + this.getUsedShaderCategories(part).join(";") + ";";
                         }
                         }
                     }
                     }
                 }
                 }
@@ -477,6 +496,23 @@ var BABYLON;
                 this._visibilityChanged = false; // Reset the flag as we've handled the case
                 this._visibilityChanged = false; // Reset the flag as we've handled the case
             }
             }
         };
         };
+        /**
+         * Transform a given point using the Primitive's origin setting.
+         * This method requires the Primitive's actualSize to be accurate
+         * @param p the point to transform
+         * @param originOffset an offset applied on the current origin before performing the transformation. Depending on which frame of reference your data is expressed you may have to apply a offset. (if you data is expressed from the bottom/left, no offset is required. If it's expressed from the center the a [-0.5;-0.5] offset has to be applied.
+         * @param res an allocated Vector2 that will receive the transformed content
+         */
+        RenderablePrim2D.prototype.transformPointWithOriginByRef = function (p, originOffset, res) {
+            var actualSize = this.actualSize;
+            res.x = p.x - ((this.origin.x + (originOffset ? originOffset.x : 0)) * actualSize.width);
+            res.y = p.y - ((this.origin.y + (originOffset ? originOffset.y : 0)) * actualSize.height);
+        };
+        RenderablePrim2D.prototype.transformPointWithOrigin = function (p, originOffset) {
+            var res = new BABYLON.Vector2(0, 0);
+            this.transformPointWithOriginByRef(p, originOffset, res);
+            return res;
+        };
         RenderablePrim2D.prototype.getDataPartEffectInfo = function (dataPartId, vertexBufferAttributes) {
         RenderablePrim2D.prototype.getDataPartEffectInfo = function (dataPartId, vertexBufferAttributes) {
             var dataPart = BABYLON.Tools.first(this._instanceDataParts, function (i) { return i.id === dataPartId; });
             var dataPart = BABYLON.Tools.first(this._instanceDataParts, function (i) { return i.id === dataPartId; });
             if (!dataPart) {
             if (!dataPart) {
@@ -571,6 +607,6 @@ var BABYLON;
             BABYLON.className("RenderablePrim2D")
             BABYLON.className("RenderablePrim2D")
         ], RenderablePrim2D);
         ], RenderablePrim2D);
         return RenderablePrim2D;
         return RenderablePrim2D;
-    })(BABYLON.Prim2DBase);
+    }(BABYLON.Prim2DBase));
     BABYLON.RenderablePrim2D = RenderablePrim2D;
     BABYLON.RenderablePrim2D = RenderablePrim2D;
 })(BABYLON || (BABYLON = {}));
 })(BABYLON || (BABYLON = {}));

+ 46 - 6
src/Canvas2d/babylon.renderablePrim2d.ts

@@ -19,7 +19,7 @@
         }
         }
 
 
         getInstancingAttributeInfos(effect: Effect, categories: string[]): InstancingAttributeInfo[] {
         getInstancingAttributeInfos(effect: Effect, categories: string[]): InstancingAttributeInfo[] {
-            let catInline = categories.join(";");
+            let catInline = ";" + categories.join(";") + ";";
             let res = new Array<InstancingAttributeInfo>();
             let res = new Array<InstancingAttributeInfo>();
             let curInfo: InstanceClassInfo = this;
             let curInfo: InstanceClassInfo = this;
             while (curInfo) {
             while (curInfo) {
@@ -82,6 +82,8 @@
         dataType: ShaderDataType;
         dataType: ShaderDataType;
         //uniformLocation: WebGLUniformLocation;
         //uniformLocation: WebGLUniformLocation;
 
 
+        delimitedCategory: string;
+
         constructor() {
         constructor() {
             this.instanceOffset = new StringDictionary<number>();
             this.instanceOffset = new StringDictionary<number>();
         }
         }
@@ -120,7 +122,11 @@
                 this.dataType = ShaderDataType.Color4;
                 this.dataType = ShaderDataType.Color4;
                 return;
                 return;
             }
             }
-            return;
+            if (val instanceof Size) {
+                this.size = 8;
+                this.dataType = ShaderDataType.Size;
+                return;
+            }            return;
         }
         }
 
 
         writeData(array: Float32Array, offset: number, val) {
         writeData(array: Float32Array, offset: number, val) {
@@ -180,6 +186,13 @@
                         }
                         }
                         break;
                         break;
                     }
                     }
+                case ShaderDataType.Size:
+                    {
+                        let s = <Size>val;
+                        array[offset + 0] = s.width;
+                        array[offset + 1] = s.height;
+                        break;
+                    }
             }
             }
         }
         }
     }
     }
@@ -201,6 +214,9 @@
             info = new InstancePropInfo();
             info = new InstancePropInfo();
             info.attributeName = shaderAttributeName;
             info.attributeName = shaderAttributeName;
             info.category = category || null;
             info.category = category || null;
+            if (info.category) {
+                info.delimitedCategory = ";" + info.category + ";";
+            }
 
 
             node.levelContent.add(instanceDataName, info);
             node.levelContent.add(instanceDataName, info);
 
 
@@ -209,6 +225,11 @@
             }
             }
 
 
             descriptor.set = function (val) {
             descriptor.set = function (val) {
+                // Check that we're not trying to set a property that belongs to a category that is not allowed (current)
+                // Quit if it's the case, otherwise we could overwrite data somewhere...
+                if (info.category && InstanceClassInfo._CurCategories.indexOf(info.delimitedCategory) === -1) {
+                    return;
+                }
                 if (!info.size) {
                 if (!info.size) {
                     info.setSize(val);
                     info.setSize(val);
                     node.classContent.mapProperty(info, true);
                     node.classContent.mapProperty(info, true);
@@ -322,8 +343,8 @@
             this._isTransparent = value;
             this._isTransparent = value;
         }
         }
 
 
-        setupRenderablePrim2D(owner: Canvas2D, parent: Prim2DBase, id: string, position: Vector2, isVisible: boolean) {
-            this.setupPrim2DBase(owner, parent, id, position);
+        setupRenderablePrim2D(owner: Canvas2D, parent: Prim2DBase, id: string, position: Vector2, origin: Vector2, isVisible: boolean) {
+            this.setupPrim2DBase(owner, parent, id, position, origin);
             this._isTransparent = false;
             this._isTransparent = false;
         }
         }
 
 
@@ -408,7 +429,7 @@
                         this.isVisible = true;
                         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.
                         // 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]));
                         //console.log("Build Prop Layout for " + Tools.getClassName(this._instanceDataParts[0]));
-                        let joinCat = cat.join(";");
+                        let joinCat = ";" + cat.join(";") + ";";
                         joinedUsedCatList.push(joinCat);
                         joinedUsedCatList.push(joinCat);
                         InstanceClassInfo._CurCategories = joinCat;
                         InstanceClassInfo._CurCategories = joinCat;
                         let obj = this.beforeRefreshForLayoutConstruction(dataPart);
                         let obj = this.beforeRefreshForLayoutConstruction(dataPart);
@@ -451,7 +472,7 @@
                         gii._partIndexFromId.add(this._modelRenderCache._partIdList[j].toString(), j);
                         gii._partIndexFromId.add(this._modelRenderCache._partIdList[j].toString(), j);
 
 
                         for (let part of this._instanceDataParts) {
                         for (let part of this._instanceDataParts) {
-                            gii._instancesPartsUsedShaderCategories[gii._partIndexFromId.get(part.id.toString())] = this.getUsedShaderCategories(part).join(";");
+                            gii._instancesPartsUsedShaderCategories[gii._partIndexFromId.get(part.id.toString())] = ";" + this.getUsedShaderCategories(part).join(";") + ";";
                         }
                         }
                     }
                     }
                 }
                 }
@@ -506,6 +527,25 @@
             }
             }
         }
         }
 
 
+        /**
+         * Transform a given point using the Primitive's origin setting.
+         * This method requires the Primitive's actualSize to be accurate
+         * @param p the point to transform
+         * @param originOffset an offset applied on the current origin before performing the transformation. Depending on which frame of reference your data is expressed you may have to apply a offset. (if you data is expressed from the bottom/left, no offset is required. If it's expressed from the center the a [-0.5;-0.5] offset has to be applied.
+         * @param res an allocated Vector2 that will receive the transformed content
+         */
+        protected transformPointWithOriginByRef(p: Vector2, originOffset:Vector2, res: Vector2) {
+            let actualSize = this.actualSize;
+            res.x = p.x - ((this.origin.x + (originOffset ? originOffset.x : 0)) * actualSize.width);
+            res.y = p.y - ((this.origin.y + (originOffset ? originOffset.y : 0)) * actualSize.height);
+        }
+
+        protected transformPointWithOrigin(p: Vector2, originOffset: Vector2): Vector2 {
+            let res = new Vector2(0, 0);
+            this.transformPointWithOriginByRef(p, originOffset, res);
+            return res;
+        }
+
         protected getDataPartEffectInfo(dataPartId: number, vertexBufferAttributes: string[]): { attributes: string[], uniforms: string[], defines: string } {
         protected getDataPartEffectInfo(dataPartId: number, vertexBufferAttributes: string[]): { attributes: string[], uniforms: string[], defines: string } {
             let dataPart = Tools.first(this._instanceDataParts, i => i.id === dataPartId);
             let dataPart = Tools.first(this._instanceDataParts, i => i.id === dataPartId);
             if (!dataPart) {
             if (!dataPart) {

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

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

+ 2 - 4
src/Canvas2d/babylon.shape2d.ts

@@ -44,8 +44,8 @@
             this._borderThickness = value;
             this._borderThickness = value;
         }
         }
 
 
-        setupShape2D(owner: Canvas2D, parent: Prim2DBase, id: string, position: Vector2, isVisible: boolean, fill: IBrush2D, border: IBrush2D, borderThickness: number = 1.0) {
-            this.setupRenderablePrim2D(owner, parent, id, position, isVisible);
+        setupShape2D(owner: Canvas2D, parent: Prim2DBase, id: string, position: Vector2, origin: Vector2, isVisible: boolean, fill: IBrush2D, border: IBrush2D, borderThickness: number = 1.0) {
+            this.setupRenderablePrim2D(owner, parent, id, position, origin, isVisible);
             this.border = border;
             this.border = border;
             this.fill = fill;
             this.fill = fill;
             this.borderThickness = borderThickness;
             this.borderThickness = borderThickness;
@@ -123,8 +123,6 @@
                         d.borderGradientTY = ty;
                         d.borderGradientTY = ty;
                     }
                     }
                 }
                 }
-
-
             }
             }
 
 
             return true;
             return true;

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

@@ -10,7 +10,7 @@ var BABYLON;
         function Prim2DClassInfo() {
         function Prim2DClassInfo() {
         }
         }
         return Prim2DClassInfo;
         return Prim2DClassInfo;
-    })();
+    }());
     BABYLON.Prim2DClassInfo = Prim2DClassInfo;
     BABYLON.Prim2DClassInfo = Prim2DClassInfo;
     var Prim2DPropInfo = (function () {
     var Prim2DPropInfo = (function () {
         function Prim2DPropInfo() {
         function Prim2DPropInfo() {
@@ -19,13 +19,13 @@ var BABYLON;
         Prim2DPropInfo.PROPKIND_INSTANCE = 2;
         Prim2DPropInfo.PROPKIND_INSTANCE = 2;
         Prim2DPropInfo.PROPKIND_DYNAMIC = 3;
         Prim2DPropInfo.PROPKIND_DYNAMIC = 3;
         return Prim2DPropInfo;
         return Prim2DPropInfo;
-    })();
+    }());
     BABYLON.Prim2DPropInfo = Prim2DPropInfo;
     BABYLON.Prim2DPropInfo = Prim2DPropInfo;
     var PropertyChangedInfo = (function () {
     var PropertyChangedInfo = (function () {
         function PropertyChangedInfo() {
         function PropertyChangedInfo() {
         }
         }
         return PropertyChangedInfo;
         return PropertyChangedInfo;
-    })();
+    }());
     BABYLON.PropertyChangedInfo = PropertyChangedInfo;
     BABYLON.PropertyChangedInfo = PropertyChangedInfo;
     var ClassTreeInfo = (function () {
     var ClassTreeInfo = (function () {
         function ClassTreeInfo(baseClass, type, classContentFactory) {
         function ClassTreeInfo(baseClass, type, classContentFactory) {
@@ -62,13 +62,13 @@ var BABYLON;
         Object.defineProperty(ClassTreeInfo.prototype, "fullContent", {
         Object.defineProperty(ClassTreeInfo.prototype, "fullContent", {
             get: function () {
             get: function () {
                 if (!this._fullContent) {
                 if (!this._fullContent) {
-                    var dic = new BABYLON.StringDictionary();
+                    var dic_1 = new BABYLON.StringDictionary();
                     var curLevel = this;
                     var curLevel = this;
                     while (curLevel) {
                     while (curLevel) {
-                        curLevel.levelContent.forEach(function (k, v) { return dic.add(k, v); });
+                        curLevel.levelContent.forEach(function (k, v) { return dic_1.add(k, v); });
                         curLevel = curLevel._baseClass;
                         curLevel = curLevel._baseClass;
                     }
                     }
-                    this._fullContent = dic;
+                    this._fullContent = dic_1;
                 }
                 }
                 return this._fullContent;
                 return this._fullContent;
             },
             },
@@ -128,7 +128,7 @@ var BABYLON;
             return dic;
             return dic;
         };
         };
         return ClassTreeInfo;
         return ClassTreeInfo;
-    })();
+    }());
     BABYLON.ClassTreeInfo = ClassTreeInfo;
     BABYLON.ClassTreeInfo = ClassTreeInfo;
     var SmartPropertyPrim = (function () {
     var SmartPropertyPrim = (function () {
         function SmartPropertyPrim() {
         function SmartPropertyPrim() {
@@ -190,6 +190,16 @@ var BABYLON;
                 propDic.forEach(function (k, v) {
                 propDic.forEach(function (k, v) {
                     if (v.kind === Prim2DPropInfo.PROPKIND_MODEL) {
                     if (v.kind === Prim2DPropInfo.PROPKIND_MODEL) {
                         var propVal = _this[v.name];
                         var propVal = _this[v.name];
+                        // Special case, array, this WON'T WORK IN ALL CASES, all entries have to be of the same type and it must be a BJS well known one
+                        if (propVal && propVal.constructor === Array) {
+                            var firstVal = propVal[0];
+                            if (!firstVal) {
+                                propVal = 0;
+                            }
+                            else {
+                                propVal = BABYLON.Tools.hashCodeFromStream(BABYLON.Tools.arrayOrStringFeeder(propVal));
+                            }
+                        }
                         modelKey += v.name + ":" + ((propVal != null) ? ((v.typeLevelCompare) ? BABYLON.Tools.getClassName(propVal) : propVal.toString()) : "[null]") + ";";
                         modelKey += v.name + ":" + ((propVal != null) ? ((v.typeLevelCompare) ? BABYLON.Tools.getClassName(propVal) : propVal.toString()) : "[null]") + ";";
                     }
                     }
                 });
                 });
@@ -350,6 +360,9 @@ var BABYLON;
             this._instanceDirtyFlags &= ~flags;
             this._instanceDirtyFlags &= ~flags;
             return this._instanceDirtyFlags;
             return this._instanceDirtyFlags;
         };
         };
+        SmartPropertyPrim.prototype._resetPropertiesDirty = function () {
+            this._instanceDirtyFlags = 0;
+        };
         Object.defineProperty(SmartPropertyPrim.prototype, "levelBoundingInfo", {
         Object.defineProperty(SmartPropertyPrim.prototype, "levelBoundingInfo", {
             /**
             /**
              * Retrieve the boundingInfo for this Primitive, computed based on the primitive itself and NOT its children
              * Retrieve the boundingInfo for this Primitive, computed based on the primitive itself and NOT its children
@@ -406,7 +419,7 @@ var BABYLON;
             BABYLON.className("SmartPropertyPrim")
             BABYLON.className("SmartPropertyPrim")
         ], SmartPropertyPrim);
         ], SmartPropertyPrim);
         return SmartPropertyPrim;
         return SmartPropertyPrim;
-    })();
+    }());
     BABYLON.SmartPropertyPrim = SmartPropertyPrim;
     BABYLON.SmartPropertyPrim = SmartPropertyPrim;
     function modelLevelProperty(propId, piStore, typeLevelCompare, dirtyBoundingInfo) {
     function modelLevelProperty(propId, piStore, typeLevelCompare, dirtyBoundingInfo) {
         if (typeLevelCompare === void 0) { typeLevelCompare = false; }
         if (typeLevelCompare === void 0) { typeLevelCompare = false; }

+ 16 - 1
src/Canvas2d/babylon.smartPropertyPrim.ts

@@ -205,6 +205,17 @@
             propDic.forEach((k, v) => {
             propDic.forEach((k, v) => {
                 if (v.kind === Prim2DPropInfo.PROPKIND_MODEL) {
                 if (v.kind === Prim2DPropInfo.PROPKIND_MODEL) {
                     let propVal = this[v.name];
                     let propVal = this[v.name];
+
+                    // Special case, array, this WON'T WORK IN ALL CASES, all entries have to be of the same type and it must be a BJS well known one
+                    if (propVal && propVal.constructor === Array) {
+                        let firstVal = propVal[0];
+                        if (!firstVal) {
+                            propVal = 0;
+                        } else {
+                            propVal = Tools.hashCodeFromStream(Tools.arrayOrStringFeeder(propVal));
+                        }
+                    }
+
                     modelKey += v.name + ":" + ((propVal != null) ? ((v.typeLevelCompare) ? Tools.getClassName(propVal) : propVal.toString()) : "[null]") + ";";
                     modelKey += v.name + ":" + ((propVal != null) ? ((v.typeLevelCompare) ? Tools.getClassName(propVal) : propVal.toString()) : "[null]") + ";";
                 }
                 }
             });
             });
@@ -383,6 +394,10 @@
             return this._instanceDirtyFlags;
             return this._instanceDirtyFlags;
         }
         }
 
 
+        public _resetPropertiesDirty() {
+            this._instanceDirtyFlags = 0;
+        }
+
         /**
         /**
          * Retrieve the boundingInfo for this Primitive, computed based on the primitive itself and NOT its children
          * Retrieve the boundingInfo for this Primitive, computed based on the primitive itself and NOT its children
          * @returns {} 
          * @returns {} 
@@ -445,8 +460,8 @@
 
 
         private _modelKey; string;
         private _modelKey; string;
         private _propInfo: StringDictionary<Prim2DPropInfo>;
         private _propInfo: StringDictionary<Prim2DPropInfo>;
-        private _levelBoundingInfoDirty: boolean;
         private _isDisposed: boolean;
         private _isDisposed: boolean;
+        protected _levelBoundingInfoDirty: boolean;
         protected _levelBoundingInfo: BoundingInfo2D;
         protected _levelBoundingInfo: BoundingInfo2D;
         protected _boundingInfo: BoundingInfo2D;
         protected _boundingInfo: BoundingInfo2D;
         protected _modelDirty: boolean;
         protected _modelDirty: boolean;

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

@@ -25,7 +25,7 @@ var BABYLON;
             var engine = instanceInfo._owner.owner.engine;
             var engine = instanceInfo._owner.owner.engine;
             engine.enableEffect(this.effect);
             engine.enableEffect(this.effect);
             this.effect.setTexture("diffuseSampler", this.texture);
             this.effect.setTexture("diffuseSampler", this.texture);
-            engine.bindBuffers(this.vb, this.ib, [1], 4, this.effect);
+            engine.bindBuffersDirectly(this.vb, this.ib, [1], 4, this.effect);
             var cur = engine.getAlphaMode();
             var cur = engine.getAlphaMode();
             engine.setAlphaMode(BABYLON.Engine.ALPHA_COMBINE);
             engine.setAlphaMode(BABYLON.Engine.ALPHA_COMBINE);
             var count = instanceInfo._instancesPartsData[0].usedElementCount;
             var count = instanceInfo._instancesPartsData[0].usedElementCount;
@@ -35,7 +35,7 @@ var BABYLON;
                 }
                 }
                 engine.updateAndBindInstancesBuffer(instanceInfo._instancesPartsBuffer[0], null, this.instancingAttributes);
                 engine.updateAndBindInstancesBuffer(instanceInfo._instancesPartsBuffer[0], null, this.instancingAttributes);
                 engine.draw(true, 0, 6, count);
                 engine.draw(true, 0, 6, count);
-                engine.unBindInstancesBuffer(instanceInfo._instancesPartsBuffer[0], this.instancingAttributes);
+                engine.unbindInstanceAttributes();
             }
             }
             else {
             else {
                 for (var i = 0; i < count; i++) {
                 for (var i = 0; i < count; i++) {
@@ -69,7 +69,7 @@ var BABYLON;
             return true;
             return true;
         };
         };
         return Sprite2DRenderCache;
         return Sprite2DRenderCache;
-    })(BABYLON.ModelRenderCache);
+    }(BABYLON.ModelRenderCache));
     BABYLON.Sprite2DRenderCache = Sprite2DRenderCache;
     BABYLON.Sprite2DRenderCache = Sprite2DRenderCache;
     var Sprite2DInstanceData = (function (_super) {
     var Sprite2DInstanceData = (function (_super) {
         __extends(Sprite2DInstanceData, _super);
         __extends(Sprite2DInstanceData, _super);
@@ -127,7 +127,7 @@ var BABYLON;
             BABYLON.instanceData()
             BABYLON.instanceData()
         ], Sprite2DInstanceData.prototype, "invertY", null);
         ], Sprite2DInstanceData.prototype, "invertY", null);
         return Sprite2DInstanceData;
         return Sprite2DInstanceData;
-    })(BABYLON.InstanceDataBase);
+    }(BABYLON.InstanceDataBase));
     BABYLON.Sprite2DInstanceData = Sprite2DInstanceData;
     BABYLON.Sprite2DInstanceData = Sprite2DInstanceData;
     var Sprite2D = (function (_super) {
     var Sprite2D = (function (_super) {
         __extends(Sprite2D, _super);
         __extends(Sprite2D, _super);
@@ -205,27 +205,43 @@ 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
             // 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;
             return true;
         };
         };
-        Sprite2D.prototype.setupSprite2D = function (owner, parent, id, position, texture, spriteSize, spriteLocation, invertY) {
-            this.setupRenderablePrim2D(owner, parent, id, position, true);
+        Sprite2D.prototype.setupSprite2D = function (owner, parent, id, position, origin, texture, spriteSize, spriteLocation, invertY) {
+            this.setupRenderablePrim2D(owner, parent, id, position, origin, true);
             this.texture = texture;
             this.texture = texture;
             this.texture.wrapU = BABYLON.Texture.CLAMP_ADDRESSMODE;
             this.texture.wrapU = BABYLON.Texture.CLAMP_ADDRESSMODE;
             this.texture.wrapV = BABYLON.Texture.CLAMP_ADDRESSMODE;
             this.texture.wrapV = BABYLON.Texture.CLAMP_ADDRESSMODE;
-            this.spriteSize = spriteSize;
-            this.spriteLocation = spriteLocation;
+            this.spriteSize = spriteSize || null;
+            this.spriteLocation = spriteLocation || new BABYLON.Vector2(0, 0);
             this.spriteFrame = 0;
             this.spriteFrame = 0;
             this.invertY = invertY;
             this.invertY = invertY;
             this._isTransparent = true;
             this._isTransparent = true;
+            if (!this.spriteSize) {
+                var s = texture.getSize();
+                this.spriteSize = new BABYLON.Size(s.width, s.height);
+            }
         };
         };
-        Sprite2D.Create = function (parent, id, x, y, texture, spriteSize, spriteLocation, invertY) {
-            if (invertY === void 0) { invertY = false; }
+        /**
+         * Create an 2D Sprite primitive
+         * @param parent the parent primitive, must be a valid primitive (or the Canvas)
+         * @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
+         *  - 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.
+         */
+        Sprite2D.Create = function (parent, texture, options) {
             BABYLON.Prim2DBase.CheckParent(parent);
             BABYLON.Prim2DBase.CheckParent(parent);
             var sprite = new Sprite2D();
             var sprite = new Sprite2D();
-            sprite.setupSprite2D(parent.owner, parent, id, new BABYLON.Vector2(x, y), texture, spriteSize, spriteLocation, invertY);
+            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);
             return sprite;
             return sprite;
         };
         };
         Sprite2D._createCachedCanvasSprite = function (owner, texture, size, pos) {
         Sprite2D._createCachedCanvasSprite = function (owner, texture, size, pos) {
             var sprite = new Sprite2D();
             var sprite = new Sprite2D();
-            sprite.setupSprite2D(owner, null, "__cachedCanvasSprite__", new BABYLON.Vector2(0, 0), texture, size, pos, false);
+            sprite.setupSprite2D(owner, null, "__cachedCanvasSprite__", new BABYLON.Vector2(0, 0), null, texture, size, pos, false);
             return sprite;
             return sprite;
         };
         };
         Sprite2D.prototype.createModelRenderCache = function (modelKey, isTransparent) {
         Sprite2D.prototype.createModelRenderCache = function (modelKey, isTransparent) {
@@ -264,7 +280,7 @@ var BABYLON;
             }
             }
             if (part.id === Sprite2D.SPRITE2D_MAINPARTID) {
             if (part.id === Sprite2D.SPRITE2D_MAINPARTID) {
                 var d = this._instanceDataParts[0];
                 var d = this._instanceDataParts[0];
-                var ts = this.texture.getSize();
+                var ts = this.texture.getBaseSize();
                 var sl = this.spriteLocation;
                 var sl = this.spriteLocation;
                 var ss = this.spriteSize;
                 var ss = this.spriteSize;
                 d.topLeftUV = new BABYLON.Vector2(sl.x / ts.width, sl.y / ts.height);
                 d.topLeftUV = new BABYLON.Vector2(sl.x / ts.width, sl.y / ts.height);
@@ -296,6 +312,6 @@ var BABYLON;
             BABYLON.className("Sprite2D")
             BABYLON.className("Sprite2D")
         ], Sprite2D);
         ], Sprite2D);
         return Sprite2D;
         return Sprite2D;
-    })(BABYLON.RenderablePrim2D);
+    }(BABYLON.RenderablePrim2D));
     BABYLON.Sprite2D = Sprite2D;
     BABYLON.Sprite2D = Sprite2D;
 })(BABYLON || (BABYLON = {}));
 })(BABYLON || (BABYLON = {}));

+ 28 - 10
src/Canvas2d/babylon.sprite2d.ts

@@ -18,7 +18,7 @@
 
 
             engine.enableEffect(this.effect);
             engine.enableEffect(this.effect);
             this.effect.setTexture("diffuseSampler", this.texture);
             this.effect.setTexture("diffuseSampler", this.texture);
-            engine.bindBuffers(this.vb, this.ib, [1], 4, this.effect);
+            engine.bindBuffersDirectly(this.vb, this.ib, [1], 4, this.effect);
 
 
             var cur = engine.getAlphaMode();
             var cur = engine.getAlphaMode();
             engine.setAlphaMode(Engine.ALPHA_COMBINE);
             engine.setAlphaMode(Engine.ALPHA_COMBINE);
@@ -29,7 +29,7 @@
                 }
                 }
                 engine.updateAndBindInstancesBuffer(instanceInfo._instancesPartsBuffer[0], null, this.instancingAttributes);
                 engine.updateAndBindInstancesBuffer(instanceInfo._instancesPartsBuffer[0], null, this.instancingAttributes);
                 engine.draw(true, 0, 6, count);
                 engine.draw(true, 0, 6, count);
-                engine.unBindInstancesBuffer(instanceInfo._instancesPartsBuffer[0], this.instancingAttributes);
+                engine.unbindInstanceAttributes();
             } else {
             } else {
                 for (let i = 0; i < count; i++) {
                 for (let i = 0; i < count; i++) {
                     this.setupUniforms(this.effect, 0, instanceInfo._instancesPartsData[0], i);
                     this.setupUniforms(this.effect, 0, instanceInfo._instancesPartsData[0], i);
@@ -179,30 +179,48 @@
             return true;
             return true;
         }
         }
 
 
-        protected setupSprite2D(owner: Canvas2D, parent: Prim2DBase, id: string, position: Vector2, texture: Texture, spriteSize: Size, spriteLocation: Vector2, invertY: boolean) {
-            this.setupRenderablePrim2D(owner, parent, id, position, true);
+        protected setupSprite2D(owner: Canvas2D, parent: Prim2DBase, id: string, position: Vector2, origin: Vector2, texture: Texture, spriteSize: Size, spriteLocation: Vector2, invertY: boolean) {
+            this.setupRenderablePrim2D(owner, parent, id, position, origin, true);
             this.texture = texture;
             this.texture = texture;
             this.texture.wrapU = Texture.CLAMP_ADDRESSMODE;
             this.texture.wrapU = Texture.CLAMP_ADDRESSMODE;
             this.texture.wrapV = Texture.CLAMP_ADDRESSMODE;
             this.texture.wrapV = Texture.CLAMP_ADDRESSMODE;
-            this.spriteSize = spriteSize;
-            this.spriteLocation = spriteLocation;
+            this.spriteSize = spriteSize || null;
+            this.spriteLocation = spriteLocation || new Vector2(0,0);
             this.spriteFrame = 0;
             this.spriteFrame = 0;
             this.invertY = invertY;
             this.invertY = invertY;
             this._isTransparent = true;
             this._isTransparent = true;
+
+            if (!this.spriteSize) {
+                var s = texture.getSize();
+                this.spriteSize = new Size(s.width, s.height);
+            }
         }
         }
 
 
-        public static Create(parent: Prim2DBase, id: string, x: number, y: number, texture: Texture, spriteSize: Size, spriteLocation: Vector2, invertY: boolean = false): Sprite2D {
+        /**
+         * Create an 2D Sprite primitive
+         * @param parent the parent primitive, must be a valid primitive (or the Canvas)
+         * @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
+         *  - 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.
+         */
+        public static Create(parent: Prim2DBase, texture: Texture, options: { id?: string, x?: number, y?: number, origin?: Vector2, spriteSize?: Size, spriteLocation?: Vector2, invertY?: boolean}): Sprite2D {
             Prim2DBase.CheckParent(parent);
             Prim2DBase.CheckParent(parent);
 
 
             let sprite = new Sprite2D();
             let sprite = new Sprite2D();
-            sprite.setupSprite2D(parent.owner, parent, id, new Vector2(x, y), texture, spriteSize, spriteLocation, invertY);
+            sprite.setupSprite2D(parent.owner, parent, options && options.id || null, new 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);
             return sprite;
             return sprite;
         }
         }
 
 
         static _createCachedCanvasSprite(owner: Canvas2D, texture: MapTexture, size: Size, pos: Vector2): Sprite2D {
         static _createCachedCanvasSprite(owner: Canvas2D, texture: MapTexture, size: Size, pos: Vector2): Sprite2D {
 
 
             let sprite = new Sprite2D();
             let sprite = new Sprite2D();
-            sprite.setupSprite2D(owner, null, "__cachedCanvasSprite__", new Vector2(0, 0), texture, size, pos, false);
+            sprite.setupSprite2D(owner, null, "__cachedCanvasSprite__", new Vector2(0, 0), null, texture, size, pos, false);
 
 
             return sprite;
             return sprite;
         }
         }
@@ -253,7 +271,7 @@
 
 
             if (part.id === Sprite2D.SPRITE2D_MAINPARTID) {
             if (part.id === Sprite2D.SPRITE2D_MAINPARTID) {
                 let d = <Sprite2DInstanceData>this._instanceDataParts[0];
                 let d = <Sprite2DInstanceData>this._instanceDataParts[0];
-                let ts = this.texture.getSize();
+                let ts = this.texture.getBaseSize();
                 let sl = this.spriteLocation;
                 let sl = this.spriteLocation;
                 let ss = this.spriteSize;
                 let ss = this.spriteSize;
                 d.topLeftUV = new Vector2(sl.x / ts.width, sl.y / ts.height);
                 d.topLeftUV = new Vector2(sl.x / ts.width, sl.y / ts.height);

文件差異過大導致無法顯示
+ 25 - 12
src/Canvas2d/babylon.text2d.js


+ 22 - 6
src/Canvas2d/babylon.text2d.ts

@@ -22,7 +22,7 @@
 
 
             engine.enableEffect(this.effect);
             engine.enableEffect(this.effect);
             this.effect.setTexture("diffuseSampler", this.fontTexture);
             this.effect.setTexture("diffuseSampler", this.fontTexture);
-            engine.bindBuffers(this.vb, this.ib, [1], 4, this.effect);
+            engine.bindBuffersDirectly(this.vb, this.ib, [1], 4, this.effect);
 
 
             var cur = engine.getAlphaMode();
             var cur = engine.getAlphaMode();
             engine.setAlphaMode(Engine.ALPHA_ADD);
             engine.setAlphaMode(Engine.ALPHA_ADD);
@@ -30,7 +30,7 @@
             if (instanceInfo._owner.owner.supportInstancedArray) {
             if (instanceInfo._owner.owner.supportInstancedArray) {
                 engine.updateAndBindInstancesBuffer(instanceInfo._instancesPartsBuffer[0], null, this.instancingAttributes);
                 engine.updateAndBindInstancesBuffer(instanceInfo._instancesPartsBuffer[0], null, this.instancingAttributes);
                 engine.draw(true, 0, 6, count);
                 engine.draw(true, 0, 6, count);
-                engine.unBindInstancesBuffer(instanceInfo._instancesPartsBuffer[0], this.instancingAttributes);
+                engine.unbindInstanceAttributes();
             } else {
             } else {
                 for (let i = 0; i < count; i++) {
                 for (let i = 0; i < count; i++) {
                     this.setupUniforms(this.effect, 0, instanceInfo._instancesPartsData[0], i);
                     this.setupUniforms(this.effect, 0, instanceInfo._instancesPartsData[0], i);
@@ -216,8 +216,8 @@
             BoundingInfo2D.CreateFromSizeToRef(this.actualSize, this._levelBoundingInfo, this.origin);
             BoundingInfo2D.CreateFromSizeToRef(this.actualSize, this._levelBoundingInfo, this.origin);
         }
         }
 
 
-        protected setupText2D(owner: Canvas2D, parent: Prim2DBase, id: string, position: Vector2, fontName: string, text: string, areaSize: Size, defaultFontColor: Color4, vAlign, hAlign, tabulationSize: number) {
-            this.setupRenderablePrim2D(owner, parent, id, position, true);
+        protected setupText2D(owner: Canvas2D, parent: Prim2DBase, id: string, position: Vector2, origin: Vector2, fontName: string, text: string, areaSize: Size, defaultFontColor: Color4, vAlign, hAlign, tabulationSize: number) {
+            this.setupRenderablePrim2D(owner, parent, id, position, origin, true);
 
 
             this.fontName = fontName;
             this.fontName = fontName;
             this.defaultFontColor = defaultFontColor;
             this.defaultFontColor = defaultFontColor;
@@ -229,11 +229,27 @@
             this._isTransparent = true;
             this._isTransparent = true;
         }
         }
 
 
-        public static Create(parent: Prim2DBase, id: string, x: number, y: number, fontName: string, text: string, defaultFontColor?: Color4, areaSize?: Size, vAlign = Text2D.TEXT2D_VALIGN_TOP, hAlign = Text2D.TEXT2D_HALIGN_LEFT, tabulationSize: number = 4): Text2D {
+        /**
+         * Create a Text primitive
+         * @param parent the parent primitive, must be a valid primitive (or the Canvas)
+         * @param text the text to display
+         * 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
+         *  - origin: define the normalized origin point location, default [0.5;0.5]
+         *  - fontName: the name/size/style of the font to use, following the CSS notation. Default is "12pt Arial".
+         *  - defaultColor: the color by default to apply on each letter of the text to display, default is plain white.
+         *  - areaSize: the size of the area in which to display the text, default is auto-fit from text content.
+         *  - vAlign: vertical alignment (areaSize must be specified), default is Text2D.TEXT2D_VALIGN_CENTER
+         *  - hAlign: horizontal alignment (areaSize must be specified), default is Text2D.TEXT2D_HALIGN_CENTER
+         *  - tabulationSize: number of space character to insert when a tabulation is encountered, default is 4
+         */
+        public static Create(parent: Prim2DBase, text: string, options?: { id?: string, x?: number, y?: number, origin?:Vector2, fontName?: string, defaultFontColor?: Color4, areaSize?: Size, vAlign?: number, hAlign?: number, tabulationSize?: number}): Text2D {
             Prim2DBase.CheckParent(parent);
             Prim2DBase.CheckParent(parent);
 
 
             let text2d = new Text2D();
             let text2d = new Text2D();
-            text2d.setupText2D(parent.owner, parent, id, new Vector2(x, y), fontName, text, areaSize, defaultFontColor || new Color4(0,0,0,1), vAlign, hAlign, tabulationSize);
+            text2d.setupText2D(parent.owner, parent, options && options.id || null, new Vector2(options && options.x || 0, options && options.y || 0), options && options.origin || null, options && options.fontName || "12pt Arial", text, options && options.areaSize, options && options.defaultFontColor || new Color4(1, 1, 1, 1), options && options.vAlign || Text2D.TEXT2D_VALIGN_CENTER, options && options.hAlign || Text2D.TEXT2D_HALIGN_CENTER, options && options.tabulationSize || 4);
             return text2d;
             return text2d;
         }
         }
 
 

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

@@ -8,20 +8,20 @@ var BABYLON;
     /**
     /**
      * This is the class that is used to display a World Space Canvas into a scene
      * This is the class that is used to display a World Space Canvas into a scene
      */
      */
-    var WorldSpaceCanvas2d = (function (_super) {
-        __extends(WorldSpaceCanvas2d, _super);
-        function WorldSpaceCanvas2d(name, scene, canvas) {
+    var WorldSpaceCanvas2D = (function (_super) {
+        __extends(WorldSpaceCanvas2D, _super);
+        function WorldSpaceCanvas2D(name, scene, canvas) {
             _super.call(this, name, scene);
             _super.call(this, name, scene);
             this._canvas = canvas;
             this._canvas = canvas;
         }
         }
-        WorldSpaceCanvas2d.prototype.dispose = function () {
+        WorldSpaceCanvas2D.prototype.dispose = function () {
             _super.prototype.dispose.call(this);
             _super.prototype.dispose.call(this);
             if (this._canvas) {
             if (this._canvas) {
                 this._canvas.dispose();
                 this._canvas.dispose();
                 this._canvas = null;
                 this._canvas = null;
             }
             }
         };
         };
-        return WorldSpaceCanvas2d;
-    })(BABYLON.Mesh);
-    BABYLON.WorldSpaceCanvas2d = WorldSpaceCanvas2d;
+        return WorldSpaceCanvas2D;
+    }(BABYLON.Mesh));
+    BABYLON.WorldSpaceCanvas2D = WorldSpaceCanvas2D;
 })(BABYLON || (BABYLON = {}));
 })(BABYLON || (BABYLON = {}));

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

@@ -2,7 +2,7 @@
     /**
     /**
      * This is the class that is used to display a World Space Canvas into a scene
      * This is the class that is used to display a World Space Canvas into a scene
      */
      */
-    export class WorldSpaceCanvas2d extends Mesh {
+    export class WorldSpaceCanvas2D extends Mesh {
         constructor(name: string, scene: Scene, canvas: Canvas2D) {
         constructor(name: string, scene: Scene, canvas: Canvas2D) {
             super(name, scene);
             super(name, scene);
 
 

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

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

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

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

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

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

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

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

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

@@ -83,6 +83,6 @@ var BABYLON;
             }
             }
         };
         };
         return Octree;
         return Octree;
-    })();
+    }());
     BABYLON.Octree = Octree;
     BABYLON.Octree = Octree;
 })(BABYLON || (BABYLON = {}));
 })(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);
             BABYLON.Octree._CreateBlocks(this._minPoint, this._maxPoint, this.entries, this._capacity, this._depth, this._maxDepth, this, this._creationFunc);
         };
         };
         return OctreeBlock;
         return OctreeBlock;
-    })();
+    }());
     BABYLON.OctreeBlock = OctreeBlock;
     BABYLON.OctreeBlock = OctreeBlock;
 })(BABYLON || (BABYLON = {}));
 })(BABYLON || (BABYLON = {}));

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

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

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

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

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

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

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

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

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

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

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

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

+ 13 - 11
src/Layer/babylon.layer.js

@@ -6,8 +6,7 @@ var BABYLON;
             this.scale = new BABYLON.Vector2(1, 1);
             this.scale = new BABYLON.Vector2(1, 1);
             this.offset = new BABYLON.Vector2(0, 0);
             this.offset = new BABYLON.Vector2(0, 0);
             this.alphaBlendingMode = BABYLON.Engine.ALPHA_COMBINE;
             this.alphaBlendingMode = BABYLON.Engine.ALPHA_COMBINE;
-            this._vertexDeclaration = [2];
-            this._vertexStrideSize = 2 * 4;
+            this._vertexBuffers = {};
             // Events
             // Events
             /**
             /**
             * An event triggered when the layer is disposed.
             * An event triggered when the layer is disposed.
@@ -29,13 +28,15 @@ var BABYLON;
             this.color = color === undefined ? new BABYLON.Color4(1, 1, 1, 1) : color;
             this.color = color === undefined ? new BABYLON.Color4(1, 1, 1, 1) : color;
             this._scene = scene;
             this._scene = scene;
             this._scene.layers.push(this);
             this._scene.layers.push(this);
+            var engine = scene.getEngine();
             // VBO
             // VBO
             var vertices = [];
             var vertices = [];
             vertices.push(1, 1);
             vertices.push(1, 1);
             vertices.push(-1, 1);
             vertices.push(-1, 1);
             vertices.push(-1, -1);
             vertices.push(-1, -1);
             vertices.push(1, -1);
             vertices.push(1, -1);
-            this._vertexBuffer = scene.getEngine().createVertexBuffer(vertices);
+            var vertexBuffer = new BABYLON.VertexBuffer(engine, vertices, BABYLON.VertexBuffer.PositionKind, false, false, 2);
+            this._vertexBuffers[BABYLON.VertexBuffer.PositionKind] = vertexBuffer;
             // Indices
             // Indices
             var indices = [];
             var indices = [];
             indices.push(0);
             indices.push(0);
@@ -44,10 +45,10 @@ var BABYLON;
             indices.push(0);
             indices.push(0);
             indices.push(2);
             indices.push(2);
             indices.push(3);
             indices.push(3);
-            this._indexBuffer = scene.getEngine().createIndexBuffer(indices);
+            this._indexBuffer = engine.createIndexBuffer(indices);
             // Effects
             // Effects
-            this._effect = this._scene.getEngine().createEffect("layer", ["position"], ["textureMatrix", "color", "scale", "offset"], ["textureSampler"], "");
-            this._alphaTestEffect = this._scene.getEngine().createEffect("layer", ["position"], ["textureMatrix", "color", "scale", "offset"], ["textureSampler"], "#define ALPHATEST");
+            this._effect = engine.createEffect("layer", [BABYLON.VertexBuffer.PositionKind], ["textureMatrix", "color", "scale", "offset"], ["textureSampler"], "");
+            this._alphaTestEffect = engine.createEffect("layer", [BABYLON.VertexBuffer.PositionKind], ["textureMatrix", "color", "scale", "offset"], ["textureSampler"], "#define ALPHATEST");
         }
         }
         Object.defineProperty(Layer.prototype, "onDispose", {
         Object.defineProperty(Layer.prototype, "onDispose", {
             set: function (callback) {
             set: function (callback) {
@@ -98,7 +99,7 @@ var BABYLON;
             currentEffect.setVector2("offset", this.offset);
             currentEffect.setVector2("offset", this.offset);
             currentEffect.setVector2("scale", this.scale);
             currentEffect.setVector2("scale", this.scale);
             // VBOs
             // VBOs
-            engine.bindBuffers(this._vertexBuffer, this._indexBuffer, this._vertexDeclaration, this._vertexStrideSize, currentEffect);
+            engine.bindBuffers(this._vertexBuffers, this._indexBuffer, currentEffect);
             // Draw order
             // Draw order
             if (!this._alphaTestEffect) {
             if (!this._alphaTestEffect) {
                 engine.setAlphaMode(this.alphaBlendingMode);
                 engine.setAlphaMode(this.alphaBlendingMode);
@@ -111,9 +112,10 @@ var BABYLON;
             this.onAfterRenderObservable.notifyObservers(this);
             this.onAfterRenderObservable.notifyObservers(this);
         };
         };
         Layer.prototype.dispose = function () {
         Layer.prototype.dispose = function () {
-            if (this._vertexBuffer) {
-                this._scene.getEngine()._releaseBuffer(this._vertexBuffer);
-                this._vertexBuffer = null;
+            var vertexBuffer = this._vertexBuffers[BABYLON.VertexBuffer.PositionKind];
+            if (vertexBuffer) {
+                vertexBuffer.dispose();
+                this._vertexBuffers[BABYLON.VertexBuffer.PositionKind] = null;
             }
             }
             if (this._indexBuffer) {
             if (this._indexBuffer) {
                 this._scene.getEngine()._releaseBuffer(this._indexBuffer);
                 this._scene.getEngine()._releaseBuffer(this._indexBuffer);
@@ -133,6 +135,6 @@ var BABYLON;
             this.onBeforeRenderObservable.clear();
             this.onBeforeRenderObservable.clear();
         };
         };
         return Layer;
         return Layer;
-    })();
+    }());
     BABYLON.Layer = Layer;
     BABYLON.Layer = Layer;
 })(BABYLON || (BABYLON = {}));
 })(BABYLON || (BABYLON = {}));

+ 0 - 0
src/Layer/babylon.layer.ts


部分文件因文件數量過多而無法顯示