David Catuhe 9 лет назад
Родитель
Сommit
8220f1520a
100 измененных файлов с 20921 добавлено и 20921 удалено
  1. 88 88
      src/Actions/babylon.action.ts
  2. 115 115
      src/Actions/babylon.condition.ts
  3. 207 207
      src/Actions/babylon.directActions.ts
  4. 56 56
      src/Actions/babylon.interpolateValueAction.ts
  5. 130 130
      src/Animations/babylon.animatable.ts
  6. 188 188
      src/Animations/babylon.easing.ts
  7. 127 127
      src/Audio/babylon.analyser.ts
  8. 84 84
      src/Audio/babylon.audioEngine.ts
  9. 113 113
      src/Audio/babylon.soundtrack.ts
  10. 91 91
      src/Bones/babylon.bone.ts
  11. 49 49
      src/Cameras/VR/babylon.vrDeviceOrientationCamera.ts
  12. 80 80
      src/Cameras/VR/babylon.webVRCamera.ts
  13. 36 36
      src/Cameras/babylon.anaglyphCamera.js
  14. 671 671
      src/Cameras/babylon.arcRotateCamera.ts
  15. 77 77
      src/Cameras/babylon.deviceOrientationCamera.ts
  16. 107 107
      src/Cameras/babylon.followCamera.ts
  17. 50 50
      src/Cameras/babylon.gamepadCamera.ts
  18. 43 43
      src/Cameras/babylon.stereoscopicCameras.ts
  19. 314 314
      src/Cameras/babylon.targetCamera.ts
  20. 49 49
      src/Cameras/babylon.virtualJoysticksCamera.ts
  21. 345 345
      src/Collisions/babylon.collider.ts
  22. 418 418
      src/Collisions/babylon.collisionCoordinator.ts
  23. 291 291
      src/Collisions/babylon.collisionWorker.ts
  24. 82 82
      src/Collisions/babylon.pickingInfo.ts
  25. 109 109
      src/Culling/Octrees/babylon.octree.ts
  26. 134 134
      src/Culling/Octrees/babylon.octreeBlock.ts
  27. 177 177
      src/Culling/babylon.boundingBox.ts
  28. 109 109
      src/Culling/babylon.boundingInfo.ts
  29. 63 63
      src/Culling/babylon.boundingSphere.ts
  30. 767 767
      src/Debug/babylon.debugLayer.ts
  31. 104 104
      src/Layer/babylon.layer.ts
  32. 25 25
      src/LensFlare/babylon.lensFlare.ts
  33. 147 147
      src/Lights/babylon.directionalLight.ts
  34. 42 42
      src/Lights/babylon.hemisphericLight.ts
  35. 94 94
      src/Lights/babylon.pointLight.ts
  36. 99 99
      src/Lights/babylon.spotLight.ts
  37. 205 205
      src/Loading/babylon.sceneLoader.ts
  38. 133 133
      src/Materials/Textures/Procedurals/babylon.customProceduralTexture.ts
  39. 322 322
      src/Materials/Textures/Procedurals/babylon.proceduralTexture.ts
  40. 103 103
      src/Materials/Textures/babylon.dynamicTexture.ts
  41. 62 62
      src/Materials/Textures/babylon.mirrorTexture.ts
  42. 36 36
      src/Materials/Textures/babylon.rawTexture.ts
  43. 278 278
      src/Materials/Textures/babylon.renderTargetTexture.ts
  44. 57 57
      src/Materials/Textures/babylon.videoTexture.ts
  45. 510 510
      src/Materials/babylon.effect.ts
  46. 295 295
      src/Materials/babylon.shaderMaterial.ts
  47. 321 321
      src/Math/babylon.math.SIMD.ts
  48. 3618 3618
      src/Math/babylon.math.ts
  49. 1062 1062
      src/Mesh/babylon.abstractMesh.ts
  50. 609 609
      src/Mesh/babylon.csg.ts
  51. 37 37
      src/Mesh/babylon.groundMesh.ts
  52. 67 67
      src/Mesh/babylon.linesMesh.ts
  53. 802 802
      src/Mesh/babylon.meshBuilder.ts
  54. 5 5
      src/Mesh/babylon.meshLODLevel.ts
  55. 764 764
      src/Mesh/babylon.meshSimplification.ts
  56. 273 273
      src/Mesh/babylon.polygonMesh.ts
  57. 192 192
      src/Mesh/babylon.subMesh.ts
  58. 193 193
      src/Mesh/babylon.vertexBuffer.ts
  59. 24 24
      src/Particles/babylon.particle.ts
  60. 44 44
      src/Particles/babylon.solidParticle.ts
  61. 636 636
      src/Particles/babylon.solidParticleSystem.ts
  62. 489 489
      src/Physics/Plugins/babylon.cannonJSPlugin.ts
  63. 412 412
      src/Physics/Plugins/babylon.oimoJSPlugin.ts
  64. 116 116
      src/Physics/babylon.physicsEngine.ts
  65. 218 218
      src/PostProcess/RenderPipeline/babylon.postProcessRenderEffect.ts
  66. 58 58
      src/PostProcess/RenderPipeline/babylon.postProcessRenderPass.ts
  67. 180 180
      src/PostProcess/RenderPipeline/babylon.postProcessRenderPipeline.ts
  68. 96 96
      src/PostProcess/RenderPipeline/babylon.postProcessRenderPipelineManager.ts
  69. 6 6
      src/PostProcess/babylon.anaglyphPostProcess.ts
  70. 6 6
      src/PostProcess/babylon.blackAndWhitePostProcess.ts
  71. 12 12
      src/PostProcess/babylon.blurPostProcess.ts
  72. 32 32
      src/PostProcess/babylon.colorCorrectionPostProcess.ts
  73. 21 21
      src/PostProcess/babylon.convolutionPostProcess.ts
  74. 6 6
      src/PostProcess/babylon.displayPassPostProcess.ts
  75. 10 10
      src/PostProcess/babylon.filterPostProcess.ts
  76. 17 17
      src/PostProcess/babylon.fxaaPostProcess.ts
  77. 450 450
      src/PostProcess/babylon.hdrRenderingPipeline.ts
  78. 278 278
      src/PostProcess/babylon.lensRenderingPipeline.ts
  79. 6 6
      src/PostProcess/babylon.passPostProcess.ts
  80. 159 159
      src/PostProcess/babylon.postProcess.ts
  81. 153 153
      src/PostProcess/babylon.postProcessManager.ts
  82. 28 28
      src/PostProcess/babylon.refractionPostProcess.ts
  83. 240 240
      src/PostProcess/babylon.ssaoRenderingPipeline.ts
  84. 19 19
      src/PostProcess/babylon.stereoscopicInterlacePostProcess.ts
  85. 40 40
      src/PostProcess/babylon.tonemapPostProcess.ts
  86. 394 394
      src/PostProcess/babylon.volumetricLightScatteringPostProcess.ts
  87. 41 41
      src/PostProcess/babylon.vrDistortionCorrectionPostProcess.ts
  88. 93 93
      src/Probes/babylon.reflectionProbe.ts
  89. 101 101
      src/Rendering/babylon.boundingBoxRenderer.ts
  90. 155 155
      src/Rendering/babylon.depthRenderer.ts
  91. 296 296
      src/Rendering/babylon.edgesRenderer.ts
  92. 102 102
      src/Rendering/babylon.outlineRenderer.ts
  93. 112 112
      src/Rendering/babylon.renderingGroup.ts
  94. 139 139
      src/Rendering/babylon.renderingManager.ts
  95. 16 16
      src/Shaders/anaglyph.fragment.fx
  96. 10 10
      src/Shaders/blackAndWhite.fragment.fx
  97. 36 36
      src/Shaders/blur.fragment.fx
  98. 39 39
      src/Shaders/chromaticAberration.fragment.fx
  99. 6 6
      src/Shaders/color.fragment.fx
  100. 0 0
      src/Shaders/color.vertex.fx

+ 88 - 88
src/Actions/babylon.action.ts

@@ -1,89 +1,89 @@
-module BABYLON {
-    export class Action {
-        public trigger: number;
-        public _actionManager: ActionManager;
-
-        private _nextActiveAction: Action;
-        private _child: Action;
-        private _condition: Condition;
-        private _triggerParameter: any;
-
-        constructor(public triggerOptions: any, condition?: Condition) {
-
-            if (triggerOptions.parameter) {
-                this.trigger = triggerOptions.trigger;
-                this._triggerParameter = triggerOptions.parameter;
-            } else {
-                this.trigger = triggerOptions;
-            }
-
-            this._nextActiveAction = this;
-            this._condition = condition;
-        }
-
-        // Methods
-        public _prepare(): void {
-        }
-
-        public getTriggerParameter(): any {
-            return this._triggerParameter;
-        }
-
-        public _executeCurrent(evt: ActionEvent): void {
-            if (this._nextActiveAction._condition) {
-                var condition = this._nextActiveAction._condition;
-                var currentRenderId = this._actionManager.getScene().getRenderId();
-
-                // We cache the current evaluation for the current frame
-                if (condition._evaluationId === currentRenderId) {
-                    if (!condition._currentResult) {
-                        return;
-                    }
-                } else {
-                    condition._evaluationId = currentRenderId;
-
-                    if (!condition.isValid()) {
-                        condition._currentResult = false;
-                        return;
-                    }
-
-                    condition._currentResult = true;
-                }
-            }
-
-            this._nextActiveAction.execute(evt);
-
-            if (this._nextActiveAction._child) {
-
-                if (!this._nextActiveAction._child._actionManager) {
-                    this._nextActiveAction._child._actionManager = this._actionManager;
-                }
-
-                this._nextActiveAction = this._nextActiveAction._child;
-            } else {
-                this._nextActiveAction = this;
-            }
-        }
-
-        public execute(evt: ActionEvent): void {
-
-        }
-
-        public then(action: Action): Action {
-            this._child = action;
-
-            action._actionManager = this._actionManager;
-            action._prepare();
-
-            return action;
-        }
-
-        public _getProperty(propertyPath: string): string {
-            return this._actionManager._getProperty(propertyPath);
-        }
-
-        public _getEffectiveTarget(target: any, propertyPath: string): any {
-            return this._actionManager._getEffectiveTarget(target, propertyPath);
-        }
-    }
+module BABYLON {
+    export class Action {
+        public trigger: number;
+        public _actionManager: ActionManager;
+
+        private _nextActiveAction: Action;
+        private _child: Action;
+        private _condition: Condition;
+        private _triggerParameter: any;
+
+        constructor(public triggerOptions: any, condition?: Condition) {
+
+            if (triggerOptions.parameter) {
+                this.trigger = triggerOptions.trigger;
+                this._triggerParameter = triggerOptions.parameter;
+            } else {
+                this.trigger = triggerOptions;
+            }
+
+            this._nextActiveAction = this;
+            this._condition = condition;
+        }
+
+        // Methods
+        public _prepare(): void {
+        }
+
+        public getTriggerParameter(): any {
+            return this._triggerParameter;
+        }
+
+        public _executeCurrent(evt: ActionEvent): void {
+            if (this._nextActiveAction._condition) {
+                var condition = this._nextActiveAction._condition;
+                var currentRenderId = this._actionManager.getScene().getRenderId();
+
+                // We cache the current evaluation for the current frame
+                if (condition._evaluationId === currentRenderId) {
+                    if (!condition._currentResult) {
+                        return;
+                    }
+                } else {
+                    condition._evaluationId = currentRenderId;
+
+                    if (!condition.isValid()) {
+                        condition._currentResult = false;
+                        return;
+                    }
+
+                    condition._currentResult = true;
+                }
+            }
+
+            this._nextActiveAction.execute(evt);
+
+            if (this._nextActiveAction._child) {
+
+                if (!this._nextActiveAction._child._actionManager) {
+                    this._nextActiveAction._child._actionManager = this._actionManager;
+                }
+
+                this._nextActiveAction = this._nextActiveAction._child;
+            } else {
+                this._nextActiveAction = this;
+            }
+        }
+
+        public execute(evt: ActionEvent): void {
+
+        }
+
+        public then(action: Action): Action {
+            this._child = action;
+
+            action._actionManager = this._actionManager;
+            action._prepare();
+
+            return action;
+        }
+
+        public _getProperty(propertyPath: string): string {
+            return this._actionManager._getProperty(propertyPath);
+        }
+
+        public _getEffectiveTarget(target: any, propertyPath: string): any {
+            return this._actionManager._getEffectiveTarget(target, propertyPath);
+        }
+    }
 }

+ 115 - 115
src/Actions/babylon.condition.ts

@@ -1,116 +1,116 @@
-module BABYLON {
-    export class Condition {
-        public _actionManager: ActionManager;
-
-        public _evaluationId: number;
-        public _currentResult: boolean;
-
-        constructor(actionManager: ActionManager) {
-            this._actionManager = actionManager;
-        }
-
-        public isValid(): boolean {
-            return true;
-        }
-
-        public _getProperty(propertyPath: string): string {
-            return this._actionManager._getProperty(propertyPath);
-        }
-
-        public _getEffectiveTarget(target: any, propertyPath: string): any {
-            return this._actionManager._getEffectiveTarget(target, propertyPath);
-        }
-    }
-
-    export class ValueCondition extends Condition {
-        // Statics
-        private static _IsEqual = 0;
-        private static _IsDifferent = 1;
-        private static _IsGreater = 2;
-        private static _IsLesser = 3;
-
-        public static get IsEqual(): number {
-            return ValueCondition._IsEqual;
-        }
-
-        public static get IsDifferent(): number {
-            return ValueCondition._IsDifferent;
-        }
-
-        public static get IsGreater(): number {
-            return ValueCondition._IsGreater;
-        }
-
-        public static get IsLesser(): number {
-            return ValueCondition._IsLesser;
-        }
-
-        // Members
-        public _actionManager: ActionManager;
-
-        private _target: any;
-        private _property: string;
-
-        constructor(actionManager: ActionManager, target: any, public propertyPath: string, public value: any, public operator: number = ValueCondition.IsEqual) {
-            super(actionManager);
-
-            this._target = this._getEffectiveTarget(target, this.propertyPath);
-            this._property = this._getProperty(this.propertyPath);
-        }
-
-        // Methods
-        public isValid(): boolean {
-            switch (this.operator) {
-                case ValueCondition.IsGreater:
-                    return this._target[this._property] > this.value;
-                case ValueCondition.IsLesser:
-                    return this._target[this._property] < this.value;
-                case ValueCondition.IsEqual:
-                case ValueCondition.IsDifferent:
-                    var check: boolean;
-
-                    if (this.value.equals) {
-                        check = this.value.equals(this._target[this._property]);
-                    } else {
-                        check = this.value === this._target[this._property];
-                    }
-                    return this.operator === ValueCondition.IsEqual ? check : !check;
-            }
-
-            return false;
-        }
-    }
-
-    export class PredicateCondition extends Condition {
-        // Members
-        public _actionManager: ActionManager;
-
-
-        constructor(actionManager: ActionManager, public predicate: () => boolean) {
-            super(actionManager);
-        }
-
-        public isValid(): boolean {
-            return this.predicate();
-        }
-    }
-
-    export class StateCondition extends Condition {
-        // Members
-        public _actionManager: ActionManager;
-
-        private _target: any;
-
-        constructor(actionManager: ActionManager, target: any, public value: string) {
-            super(actionManager);
-
-            this._target = target;
-        }
-
-        // Methods
-        public isValid(): boolean {
-            return this._target.state === this.value;
-        }
-    }
-
+module BABYLON {
+    export class Condition {
+        public _actionManager: ActionManager;
+
+        public _evaluationId: number;
+        public _currentResult: boolean;
+
+        constructor(actionManager: ActionManager) {
+            this._actionManager = actionManager;
+        }
+
+        public isValid(): boolean {
+            return true;
+        }
+
+        public _getProperty(propertyPath: string): string {
+            return this._actionManager._getProperty(propertyPath);
+        }
+
+        public _getEffectiveTarget(target: any, propertyPath: string): any {
+            return this._actionManager._getEffectiveTarget(target, propertyPath);
+        }
+    }
+
+    export class ValueCondition extends Condition {
+        // Statics
+        private static _IsEqual = 0;
+        private static _IsDifferent = 1;
+        private static _IsGreater = 2;
+        private static _IsLesser = 3;
+
+        public static get IsEqual(): number {
+            return ValueCondition._IsEqual;
+        }
+
+        public static get IsDifferent(): number {
+            return ValueCondition._IsDifferent;
+        }
+
+        public static get IsGreater(): number {
+            return ValueCondition._IsGreater;
+        }
+
+        public static get IsLesser(): number {
+            return ValueCondition._IsLesser;
+        }
+
+        // Members
+        public _actionManager: ActionManager;
+
+        private _target: any;
+        private _property: string;
+
+        constructor(actionManager: ActionManager, target: any, public propertyPath: string, public value: any, public operator: number = ValueCondition.IsEqual) {
+            super(actionManager);
+
+            this._target = this._getEffectiveTarget(target, this.propertyPath);
+            this._property = this._getProperty(this.propertyPath);
+        }
+
+        // Methods
+        public isValid(): boolean {
+            switch (this.operator) {
+                case ValueCondition.IsGreater:
+                    return this._target[this._property] > this.value;
+                case ValueCondition.IsLesser:
+                    return this._target[this._property] < this.value;
+                case ValueCondition.IsEqual:
+                case ValueCondition.IsDifferent:
+                    var check: boolean;
+
+                    if (this.value.equals) {
+                        check = this.value.equals(this._target[this._property]);
+                    } else {
+                        check = this.value === this._target[this._property];
+                    }
+                    return this.operator === ValueCondition.IsEqual ? check : !check;
+            }
+
+            return false;
+        }
+    }
+
+    export class PredicateCondition extends Condition {
+        // Members
+        public _actionManager: ActionManager;
+
+
+        constructor(actionManager: ActionManager, public predicate: () => boolean) {
+            super(actionManager);
+        }
+
+        public isValid(): boolean {
+            return this.predicate();
+        }
+    }
+
+    export class StateCondition extends Condition {
+        // Members
+        public _actionManager: ActionManager;
+
+        private _target: any;
+
+        constructor(actionManager: ActionManager, target: any, public value: string) {
+            super(actionManager);
+
+            this._target = target;
+        }
+
+        // Methods
+        public isValid(): boolean {
+            return this._target.state === this.value;
+        }
+    }
+
 }

+ 207 - 207
src/Actions/babylon.directActions.ts

@@ -1,208 +1,208 @@
-module BABYLON {
-    export class SwitchBooleanAction extends Action {
-        private _target: any;
-        private _property: string;
-
-        constructor(triggerOptions: any, target: any, public propertyPath: string, condition?: Condition) {
-            super(triggerOptions, condition);
-            this._target = target;
-        }
-
-        public _prepare(): void {
-            this._target = this._getEffectiveTarget(this._target, this.propertyPath);
-            this._property = this._getProperty(this.propertyPath);
-        }
-
-        public execute(): void {
-            this._target[this._property] = !this._target[this._property];
-        }
-    }
-
-    export class SetStateAction extends Action {
-        private _target: any;
-
-        constructor(triggerOptions: any, target: any, public value: string, condition?: Condition) {
-            super(triggerOptions, condition);
-            this._target = target;
-        }
-
-        public execute(): void {
-            this._target.state = this.value;
-        }
-    }
-
-    export class SetValueAction extends Action {
-        private _target: any;
-        private _property: string;
-
-        constructor(triggerOptions: any, target: any, public propertyPath: string, public value: any, condition?: Condition) {
-            super(triggerOptions, condition);
-            this._target = target;
-        }
-
-        public _prepare(): void {
-            this._target = this._getEffectiveTarget(this._target, this.propertyPath);
-            this._property = this._getProperty(this.propertyPath);
-        }
-
-        public execute(): void {
-            this._target[this._property] = this.value;
-        }
-    }
-
-    export class IncrementValueAction extends Action {
-        private _target: any;
-        private _property: string;
-
-        constructor(triggerOptions: any, target: any, public propertyPath: string, public value: any, condition?: Condition) {
-            super(triggerOptions, condition);
-            this._target = target;
-        }
-
-        public _prepare(): void {
-            this._target = this._getEffectiveTarget(this._target, this.propertyPath);
-            this._property = this._getProperty(this.propertyPath);
-
-            if (typeof this._target[this._property] !== "number") {
-                Tools.Warn("Warning: IncrementValueAction can only be used with number values");
-            }
-        }
-
-        public execute(): void {
-            this._target[this._property] += this.value;
-        }
-    }
-
-    export class PlayAnimationAction extends Action {
-        private _target: any;
-
-        constructor(triggerOptions: any, target: any, public from: number, public to: number, public loop?: boolean, condition?: Condition) {
-            super(triggerOptions, condition);
-            this._target = target;
-        }
-
-        public _prepare(): void {
-        }
-
-        public execute(): void {
-            var scene = this._actionManager.getScene();
-            scene.beginAnimation(this._target, this.from, this.to, this.loop);
-        }
-    }
-
-    export class StopAnimationAction extends Action {
-        private _target: any;
-
-        constructor(triggerOptions: any, target: any, condition?: Condition) {
-            super(triggerOptions, condition);
-            this._target = target;
-        }
-
-        public _prepare(): void {           
-        }
-
-        public execute(): void {
-            var scene = this._actionManager.getScene();
-            scene.stopAnimation(this._target);
-        }
-    }
-
-    export class DoNothingAction extends Action {
-        constructor(triggerOptions: any = ActionManager.NothingTrigger, condition?: Condition) {
-            super(triggerOptions, condition);
-        }
-
-        public execute(): void {
-        }
-    }
-
-    export class CombineAction extends Action {
-        constructor(triggerOptions: any, public children: Action[], condition?: Condition) {
-            super(triggerOptions, condition);
-        }
-
-        public _prepare(): void {
-            for (var index = 0; index < this.children.length; index++) {
-                this.children[index]._actionManager = this._actionManager;
-                this.children[index]._prepare();
-            }
-        }
-
-        public execute(evt: ActionEvent): void {
-            for (var index = 0; index < this.children.length; index++) {
-                this.children[index].execute(evt);
-            }
-        }
-    }
-
-    export class ExecuteCodeAction extends Action {
-        constructor(triggerOptions: any, public func: (evt: ActionEvent) => void, condition?: Condition) {
-            super(triggerOptions, condition);
-        }
-
-        public execute(evt: ActionEvent): void {
-            this.func(evt);
-        }
-    }
-
-    export class SetParentAction extends Action {
-        private _parent: any;
-        private _target: any;
-
-        constructor(triggerOptions: any, target: any, parent: any, condition?: Condition) {
-            super(triggerOptions, condition);
-            this._target = target;
-            this._parent = parent;
-        }
-
-        public _prepare(): void {
-        }
-
-        public execute(): void {
-            if (this._target.parent === this._parent) {
-                return;
-            }
-
-            var invertParentWorldMatrix = this._parent.getWorldMatrix().clone();
-            invertParentWorldMatrix.invert();
-
-            this._target.position = Vector3.TransformCoordinates(this._target.position, invertParentWorldMatrix);
-
-            this._target.parent = this._parent;
-        }
-    }
-
-    export class PlaySoundAction extends Action {
-        private _sound: Sound;
-
-        constructor(triggerOptions: any, sound: Sound, condition?: Condition) {
-            super(triggerOptions, condition);
-            this._sound = sound;
-        }
-
-        public _prepare(): void {
-        }
-
-        public execute(): void {
-            if (this._sound !== undefined)
-                this._sound.play();
-        }
-    }
-
-    export class StopSoundAction extends Action {
-        private _sound: Sound;
-
-        constructor(triggerOptions: any, sound: Sound, condition?: Condition) {
-            super(triggerOptions, condition);
-            this._sound = sound;
-        }
-
-        public _prepare(): void {
-        }
-
-        public execute(): void {
-            if (this._sound !== undefined)
-                this._sound.stop();
-        }
-    }
+module BABYLON {
+    export class SwitchBooleanAction extends Action {
+        private _target: any;
+        private _property: string;
+
+        constructor(triggerOptions: any, target: any, public propertyPath: string, condition?: Condition) {
+            super(triggerOptions, condition);
+            this._target = target;
+        }
+
+        public _prepare(): void {
+            this._target = this._getEffectiveTarget(this._target, this.propertyPath);
+            this._property = this._getProperty(this.propertyPath);
+        }
+
+        public execute(): void {
+            this._target[this._property] = !this._target[this._property];
+        }
+    }
+
+    export class SetStateAction extends Action {
+        private _target: any;
+
+        constructor(triggerOptions: any, target: any, public value: string, condition?: Condition) {
+            super(triggerOptions, condition);
+            this._target = target;
+        }
+
+        public execute(): void {
+            this._target.state = this.value;
+        }
+    }
+
+    export class SetValueAction extends Action {
+        private _target: any;
+        private _property: string;
+
+        constructor(triggerOptions: any, target: any, public propertyPath: string, public value: any, condition?: Condition) {
+            super(triggerOptions, condition);
+            this._target = target;
+        }
+
+        public _prepare(): void {
+            this._target = this._getEffectiveTarget(this._target, this.propertyPath);
+            this._property = this._getProperty(this.propertyPath);
+        }
+
+        public execute(): void {
+            this._target[this._property] = this.value;
+        }
+    }
+
+    export class IncrementValueAction extends Action {
+        private _target: any;
+        private _property: string;
+
+        constructor(triggerOptions: any, target: any, public propertyPath: string, public value: any, condition?: Condition) {
+            super(triggerOptions, condition);
+            this._target = target;
+        }
+
+        public _prepare(): void {
+            this._target = this._getEffectiveTarget(this._target, this.propertyPath);
+            this._property = this._getProperty(this.propertyPath);
+
+            if (typeof this._target[this._property] !== "number") {
+                Tools.Warn("Warning: IncrementValueAction can only be used with number values");
+            }
+        }
+
+        public execute(): void {
+            this._target[this._property] += this.value;
+        }
+    }
+
+    export class PlayAnimationAction extends Action {
+        private _target: any;
+
+        constructor(triggerOptions: any, target: any, public from: number, public to: number, public loop?: boolean, condition?: Condition) {
+            super(triggerOptions, condition);
+            this._target = target;
+        }
+
+        public _prepare(): void {
+        }
+
+        public execute(): void {
+            var scene = this._actionManager.getScene();
+            scene.beginAnimation(this._target, this.from, this.to, this.loop);
+        }
+    }
+
+    export class StopAnimationAction extends Action {
+        private _target: any;
+
+        constructor(triggerOptions: any, target: any, condition?: Condition) {
+            super(triggerOptions, condition);
+            this._target = target;
+        }
+
+        public _prepare(): void {           
+        }
+
+        public execute(): void {
+            var scene = this._actionManager.getScene();
+            scene.stopAnimation(this._target);
+        }
+    }
+
+    export class DoNothingAction extends Action {
+        constructor(triggerOptions: any = ActionManager.NothingTrigger, condition?: Condition) {
+            super(triggerOptions, condition);
+        }
+
+        public execute(): void {
+        }
+    }
+
+    export class CombineAction extends Action {
+        constructor(triggerOptions: any, public children: Action[], condition?: Condition) {
+            super(triggerOptions, condition);
+        }
+
+        public _prepare(): void {
+            for (var index = 0; index < this.children.length; index++) {
+                this.children[index]._actionManager = this._actionManager;
+                this.children[index]._prepare();
+            }
+        }
+
+        public execute(evt: ActionEvent): void {
+            for (var index = 0; index < this.children.length; index++) {
+                this.children[index].execute(evt);
+            }
+        }
+    }
+
+    export class ExecuteCodeAction extends Action {
+        constructor(triggerOptions: any, public func: (evt: ActionEvent) => void, condition?: Condition) {
+            super(triggerOptions, condition);
+        }
+
+        public execute(evt: ActionEvent): void {
+            this.func(evt);
+        }
+    }
+
+    export class SetParentAction extends Action {
+        private _parent: any;
+        private _target: any;
+
+        constructor(triggerOptions: any, target: any, parent: any, condition?: Condition) {
+            super(triggerOptions, condition);
+            this._target = target;
+            this._parent = parent;
+        }
+
+        public _prepare(): void {
+        }
+
+        public execute(): void {
+            if (this._target.parent === this._parent) {
+                return;
+            }
+
+            var invertParentWorldMatrix = this._parent.getWorldMatrix().clone();
+            invertParentWorldMatrix.invert();
+
+            this._target.position = Vector3.TransformCoordinates(this._target.position, invertParentWorldMatrix);
+
+            this._target.parent = this._parent;
+        }
+    }
+
+    export class PlaySoundAction extends Action {
+        private _sound: Sound;
+
+        constructor(triggerOptions: any, sound: Sound, condition?: Condition) {
+            super(triggerOptions, condition);
+            this._sound = sound;
+        }
+
+        public _prepare(): void {
+        }
+
+        public execute(): void {
+            if (this._sound !== undefined)
+                this._sound.play();
+        }
+    }
+
+    export class StopSoundAction extends Action {
+        private _sound: Sound;
+
+        constructor(triggerOptions: any, sound: Sound, condition?: Condition) {
+            super(triggerOptions, condition);
+            this._sound = sound;
+        }
+
+        public _prepare(): void {
+        }
+
+        public execute(): void {
+            if (this._sound !== undefined)
+                this._sound.stop();
+        }
+    }
 } 

+ 56 - 56
src/Actions/babylon.interpolateValueAction.ts

@@ -1,57 +1,57 @@
-module BABYLON {
-    export class InterpolateValueAction extends Action {
-        private _target: any;
-        private _property: string;
-
-        constructor(triggerOptions: any, target: any, public propertyPath: string, public value: any, public duration: number = 1000, condition?: Condition, public stopOtherAnimations?: boolean, public onInterpolationDone?: () => void) {
-            super(triggerOptions, condition);
-
-            this._target = target;
-        }
-
-        public _prepare(): void {
-            this._target = this._getEffectiveTarget(this._target, this.propertyPath);
-            this._property = this._getProperty(this.propertyPath);
-        }
-
-        public execute(): void {
-            var scene = this._actionManager.getScene();
-            var keys = [
-                {
-                    frame: 0,
-                    value: this._target[this._property]
-                }, {
-                    frame: 100,
-                    value: this.value
-                }
-            ];
-
-            var dataType: number;
-
-            if (typeof this.value === "number") {
-                dataType = Animation.ANIMATIONTYPE_FLOAT;
-            } else if (this.value instanceof Color3) {
-                dataType = Animation.ANIMATIONTYPE_COLOR3;
-            } else if (this.value instanceof Vector3) {
-                dataType = Animation.ANIMATIONTYPE_VECTOR3;
-            } else if (this.value instanceof Matrix) {
-                dataType = Animation.ANIMATIONTYPE_MATRIX;
-            } else if (this.value instanceof Quaternion) {
-                dataType = Animation.ANIMATIONTYPE_QUATERNION;
-            } else {
-                Tools.Warn("InterpolateValueAction: Unsupported type (" + typeof this.value + ")");
-                return;
-            }
-
-            var animation = new Animation("InterpolateValueAction", this._property, 100 * (1000.0 / this.duration), dataType, Animation.ANIMATIONLOOPMODE_CONSTANT);
-
-            animation.setKeys(keys);
-
-            if (this.stopOtherAnimations) {
-                scene.stopAnimation(this._target);
-            }
-
-            scene.beginDirectAnimation(this._target, [animation], 0, 100, false, 1, this.onInterpolationDone);
-        }
-    }
+module BABYLON {
+    export class InterpolateValueAction extends Action {
+        private _target: any;
+        private _property: string;
+
+        constructor(triggerOptions: any, target: any, public propertyPath: string, public value: any, public duration: number = 1000, condition?: Condition, public stopOtherAnimations?: boolean, public onInterpolationDone?: () => void) {
+            super(triggerOptions, condition);
+
+            this._target = target;
+        }
+
+        public _prepare(): void {
+            this._target = this._getEffectiveTarget(this._target, this.propertyPath);
+            this._property = this._getProperty(this.propertyPath);
+        }
+
+        public execute(): void {
+            var scene = this._actionManager.getScene();
+            var keys = [
+                {
+                    frame: 0,
+                    value: this._target[this._property]
+                }, {
+                    frame: 100,
+                    value: this.value
+                }
+            ];
+
+            var dataType: number;
+
+            if (typeof this.value === "number") {
+                dataType = Animation.ANIMATIONTYPE_FLOAT;
+            } else if (this.value instanceof Color3) {
+                dataType = Animation.ANIMATIONTYPE_COLOR3;
+            } else if (this.value instanceof Vector3) {
+                dataType = Animation.ANIMATIONTYPE_VECTOR3;
+            } else if (this.value instanceof Matrix) {
+                dataType = Animation.ANIMATIONTYPE_MATRIX;
+            } else if (this.value instanceof Quaternion) {
+                dataType = Animation.ANIMATIONTYPE_QUATERNION;
+            } else {
+                Tools.Warn("InterpolateValueAction: Unsupported type (" + typeof this.value + ")");
+                return;
+            }
+
+            var animation = new Animation("InterpolateValueAction", this._property, 100 * (1000.0 / this.duration), dataType, Animation.ANIMATIONLOOPMODE_CONSTANT);
+
+            animation.setKeys(keys);
+
+            if (this.stopOtherAnimations) {
+                scene.stopAnimation(this._target);
+            }
+
+            scene.beginDirectAnimation(this._target, [animation], 0, 100, false, 1, this.onInterpolationDone);
+        }
+    }
 } 

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

@@ -1,131 +1,131 @@
-module BABYLON {
-    export class Animatable {
-        private _localDelayOffset: number;
-        private _pausedDelay: number;
-        private _animations = new Array<Animation>();
-        private _paused = false;
-        private _scene: Scene;
-
-        public animationStarted = false;
-
-        constructor(scene: Scene, public target, public fromFrame: number = 0, public toFrame: number = 100, public loopAnimation: boolean = false, public speedRatio: number = 1.0, public onAnimationEnd?, animations?: any) {
-            if (animations) {
-                this.appendAnimations(target, animations);
-            }
-
-            this._scene = scene;
-            scene._activeAnimatables.push(this);
-        }
-
-        // Methods
-        public getAnimations(): Animation[] {
-            return this._animations;
-        }
-
-        public appendAnimations(target: any, animations: Animation[]): void {
-            for (var index = 0; index < animations.length; index++) {
-                var animation = animations[index];
-
-                animation._target = target;
-                this._animations.push(animation);
-            }
-        }
-
-        public getAnimationByTargetProperty(property: string) {
-            var animations = this._animations;
-
-            for (var index = 0; index < animations.length; index++) {
-                if (animations[index].targetProperty === property) {
-                    return animations[index];
-                }
-            }
-
-            return null;
-        }
-
-        public reset(): void {
-            var animations = this._animations;
-
-            for (var index = 0; index < animations.length; index++) {
-                animations[index].reset();
-            }
-
-            this._localDelayOffset = null;
-            this._pausedDelay = null;
-
-        }
-
-        public goToFrame(frame: number): void {
-            var animations = this._animations;
-
-            for (var index = 0; index < animations.length; index++) {
-                animations[index].goToFrame(frame);
-            }
-        }
-
-        public pause(): void {
-            if (this._paused) {
-                return;
-            }
-            this._paused = true;
-        }
-
-        public restart(): void {
-            this._paused = false;
-        }
-
-        public stop(): void {
-            var index = this._scene._activeAnimatables.indexOf(this);
-
-            if (index > -1) {
-                this._scene._activeAnimatables.splice(index, 1);
-            }
-
-            if (this.onAnimationEnd) {
-                this.onAnimationEnd();
-            }
-        }
-
-        public _animate(delay: number): boolean {
-            if (this._paused) {
-                this.animationStarted = false;
-                if (!this._pausedDelay) {
-                    this._pausedDelay = delay;
-                }
-                return true;
-            }
-
-            if (!this._localDelayOffset) {
-                this._localDelayOffset = delay;
-            } else if (this._pausedDelay) {
-                this._localDelayOffset += delay - this._pausedDelay;
-                this._pausedDelay = null;
-            }
-
-            // Animating
-            var running = false;
-            var animations = this._animations;
-            var index: number;
-
-            for (index = 0; index < animations.length; index++) {
-                var animation = animations[index];
-                var isRunning = animation.animate(delay - this._localDelayOffset, this.fromFrame, this.toFrame, this.loopAnimation, this.speedRatio);
-                running = running || isRunning;
-            }
-
-            this.animationStarted = running;
-
-            if (!running) {
-                // Remove from active animatables
-                index = this._scene._activeAnimatables.indexOf(this);
-                this._scene._activeAnimatables.splice(index, 1);
-            }
-
-            if (!running && this.onAnimationEnd) {
-                this.onAnimationEnd();
-            }
-
-            return running;
-        }
-    }
+module BABYLON {
+    export class Animatable {
+        private _localDelayOffset: number;
+        private _pausedDelay: number;
+        private _animations = new Array<Animation>();
+        private _paused = false;
+        private _scene: Scene;
+
+        public animationStarted = false;
+
+        constructor(scene: Scene, public target, public fromFrame: number = 0, public toFrame: number = 100, public loopAnimation: boolean = false, public speedRatio: number = 1.0, public onAnimationEnd?, animations?: any) {
+            if (animations) {
+                this.appendAnimations(target, animations);
+            }
+
+            this._scene = scene;
+            scene._activeAnimatables.push(this);
+        }
+
+        // Methods
+        public getAnimations(): Animation[] {
+            return this._animations;
+        }
+
+        public appendAnimations(target: any, animations: Animation[]): void {
+            for (var index = 0; index < animations.length; index++) {
+                var animation = animations[index];
+
+                animation._target = target;
+                this._animations.push(animation);
+            }
+        }
+
+        public getAnimationByTargetProperty(property: string) {
+            var animations = this._animations;
+
+            for (var index = 0; index < animations.length; index++) {
+                if (animations[index].targetProperty === property) {
+                    return animations[index];
+                }
+            }
+
+            return null;
+        }
+
+        public reset(): void {
+            var animations = this._animations;
+
+            for (var index = 0; index < animations.length; index++) {
+                animations[index].reset();
+            }
+
+            this._localDelayOffset = null;
+            this._pausedDelay = null;
+
+        }
+
+        public goToFrame(frame: number): void {
+            var animations = this._animations;
+
+            for (var index = 0; index < animations.length; index++) {
+                animations[index].goToFrame(frame);
+            }
+        }
+
+        public pause(): void {
+            if (this._paused) {
+                return;
+            }
+            this._paused = true;
+        }
+
+        public restart(): void {
+            this._paused = false;
+        }
+
+        public stop(): void {
+            var index = this._scene._activeAnimatables.indexOf(this);
+
+            if (index > -1) {
+                this._scene._activeAnimatables.splice(index, 1);
+            }
+
+            if (this.onAnimationEnd) {
+                this.onAnimationEnd();
+            }
+        }
+
+        public _animate(delay: number): boolean {
+            if (this._paused) {
+                this.animationStarted = false;
+                if (!this._pausedDelay) {
+                    this._pausedDelay = delay;
+                }
+                return true;
+            }
+
+            if (!this._localDelayOffset) {
+                this._localDelayOffset = delay;
+            } else if (this._pausedDelay) {
+                this._localDelayOffset += delay - this._pausedDelay;
+                this._pausedDelay = null;
+            }
+
+            // Animating
+            var running = false;
+            var animations = this._animations;
+            var index: number;
+
+            for (index = 0; index < animations.length; index++) {
+                var animation = animations[index];
+                var isRunning = animation.animate(delay - this._localDelayOffset, this.fromFrame, this.toFrame, this.loopAnimation, this.speedRatio);
+                running = running || isRunning;
+            }
+
+            this.animationStarted = running;
+
+            if (!running) {
+                // Remove from active animatables
+                index = this._scene._activeAnimatables.indexOf(this);
+                this._scene._activeAnimatables.splice(index, 1);
+            }
+
+            if (!running && this.onAnimationEnd) {
+                this.onAnimationEnd();
+            }
+
+            return running;
+        }
+    }
 } 

+ 188 - 188
src/Animations/babylon.easing.ts

@@ -1,188 +1,188 @@
-module BABYLON {
-
-    export interface IEasingFunction {
-        ease(gradient: number): number;
-    }
-
-    export class EasingFunction implements IEasingFunction {
-        //Statics
-        private static _EASINGMODE_EASEIN = 0;
-        private static _EASINGMODE_EASEOUT = 1;
-        private static _EASINGMODE_EASEINOUT = 2;
-
-        public static get EASINGMODE_EASEIN(): number {
-            return EasingFunction._EASINGMODE_EASEIN;
-        }
-
-        public static get EASINGMODE_EASEOUT(): number {
-            return EasingFunction._EASINGMODE_EASEOUT;
-        }
-
-        public static get EASINGMODE_EASEINOUT(): number {
-            return EasingFunction._EASINGMODE_EASEINOUT;
-        }
-
-        // Properties
-        private _easingMode = EasingFunction.EASINGMODE_EASEIN;
-
-        public setEasingMode(easingMode: number) {
-            var n = Math.min(Math.max(easingMode, 0), 2);
-            this._easingMode = n;
-        }
-        public getEasingMode(): number {
-            return this._easingMode;
-        }
-
-        public easeInCore(gradient: number): number {
-            throw new Error('You must implement this method');
-        }
-
-        public ease(gradient: number): number {
-            switch (this._easingMode) {
-                case EasingFunction.EASINGMODE_EASEIN:
-                    return this.easeInCore(gradient);
-                case EasingFunction.EASINGMODE_EASEOUT:
-                    return (1 - this.easeInCore(1 - gradient));
-            }
-
-            if (gradient >= 0.5) {
-                return (((1 - this.easeInCore((1 - gradient) * 2)) * 0.5) + 0.5);
-            }
-
-            return (this.easeInCore(gradient * 2) * 0.5);
-        }
-
-    }
-
-    export class CircleEase extends EasingFunction implements IEasingFunction {
-        public easeInCore(gradient: number): number {
-            gradient = Math.max(0, Math.min(1, gradient));
-            return (1.0 - Math.sqrt(1.0 - (gradient * gradient)));
-        }
-    }
-
-    export class BackEase extends EasingFunction implements IEasingFunction {
-        constructor(public amplitude: number = 1) {
-            super();
-        }
-
-        public easeInCore(gradient: number): number {
-            var num = Math.max(0, this.amplitude);
-            return (Math.pow(gradient, 3.0) - ((gradient * num) * Math.sin(3.1415926535897931 * gradient)));
-        }
-    }
-
-    export class BounceEase extends EasingFunction implements IEasingFunction {
-        constructor(public bounces: number= 3, public bounciness: number= 2) {
-            super();
-        }
-
-        public easeInCore(gradient: number): number {
-            var y = Math.max(0.0, this.bounces);
-            var bounciness = this.bounciness;
-            if (bounciness <= 1.0) {
-                bounciness = 1.001;
-            }
-            var num9 = Math.pow(bounciness, y);
-            var num5 = 1.0 - bounciness;
-            var num4 = ((1.0 - num9) / num5) + (num9 * 0.5);
-            var num15 = gradient * num4;
-            var num65 = Math.log((-num15 * (1.0 - bounciness)) + 1.0) / Math.log(bounciness);
-            var num3 = Math.floor(num65);
-            var num13 = num3 + 1.0;
-            var num8 = (1.0 - Math.pow(bounciness, num3)) / (num5 * num4);
-            var num12 = (1.0 - Math.pow(bounciness, num13)) / (num5 * num4);
-            var num7 = (num8 + num12) * 0.5;
-            var num6 = gradient - num7;
-            var num2 = num7 - num8;
-            return (((-Math.pow(1.0 / bounciness, y - num3) / (num2 * num2)) * (num6 - num2)) * (num6 + num2));
-        }
-    }
-
-    export class CubicEase extends EasingFunction implements IEasingFunction {
-        public easeInCore(gradient: number): number {
-            return (gradient * gradient * gradient);
-        }
-    }
-
-    export class ElasticEase extends EasingFunction implements IEasingFunction {
-        constructor(public oscillations: number= 3, public springiness: number= 3) {
-            super();
-        }
-
-        public easeInCore(gradient: number): number {
-            var num2;
-            var num3 = Math.max(0.0, this.oscillations);
-            var num = Math.max(0.0, this.springiness);
-
-            if (num == 0) {
-                num2 = gradient;
-            }else {
-                num2 = (Math.exp(num * gradient) - 1.0) / (Math.exp(num) - 1.0);
-            }
-            return (num2 * Math.sin(((6.2831853071795862 * num3) + 1.5707963267948966) * gradient));
-        }
-    }
-
-    export class ExponentialEase  extends EasingFunction implements IEasingFunction {
-        constructor(public exponent: number= 2) {
-            super();
-        }
-
-        public easeInCore(gradient: number): number {
-            if (this.exponent <= 0) {
-                return gradient;
-            }
-
-            return ((Math.exp(this.exponent * gradient) - 1.0) / (Math.exp(this.exponent) - 1.0));
-        }
-    }
-
-    export class PowerEase  extends EasingFunction implements IEasingFunction {
-        constructor(public power: number= 2) {
-            super();
-        }
-
-        public easeInCore(gradient: number): number {
-            var y = Math.max(0.0, this.power);
-            return Math.pow(gradient, y);
-        }
-    }
-
-    export class QuadraticEase extends EasingFunction implements IEasingFunction {
-        public easeInCore(gradient: number): number {
-            return (gradient * gradient);
-
-           
-
-        }
-    }
-
-    export class QuarticEase extends EasingFunction implements IEasingFunction {
-        public easeInCore(gradient: number): number {
-            return (gradient * gradient * gradient * gradient);
-        }
-    }
-
-    export class QuinticEase extends EasingFunction implements IEasingFunction {
-        public easeInCore(gradient: number): number {
-            return (gradient * gradient * gradient * gradient * gradient);
-        }
-    }
-
-    export class SineEase  extends EasingFunction implements IEasingFunction {
-        public easeInCore(gradient: number): number {
-            return (1.0 - Math.sin(1.5707963267948966 * (1.0 - gradient)));
-        }
-    }
-
-    export class BezierCurveEase extends EasingFunction implements IEasingFunction {
-        constructor(public x1: number= 0, public y1: number= 0, public x2: number= 1, public y2: number= 1) {
-            super();
-        }
-
-        public easeInCore(gradient: number): number {
-            return BezierCurve.interpolate(gradient, this.x1, this.y1, this.x2, this.y2);
-        }
-    }
-}
+module BABYLON {
+
+    export interface IEasingFunction {
+        ease(gradient: number): number;
+    }
+
+    export class EasingFunction implements IEasingFunction {
+        //Statics
+        private static _EASINGMODE_EASEIN = 0;
+        private static _EASINGMODE_EASEOUT = 1;
+        private static _EASINGMODE_EASEINOUT = 2;
+
+        public static get EASINGMODE_EASEIN(): number {
+            return EasingFunction._EASINGMODE_EASEIN;
+        }
+
+        public static get EASINGMODE_EASEOUT(): number {
+            return EasingFunction._EASINGMODE_EASEOUT;
+        }
+
+        public static get EASINGMODE_EASEINOUT(): number {
+            return EasingFunction._EASINGMODE_EASEINOUT;
+        }
+
+        // Properties
+        private _easingMode = EasingFunction.EASINGMODE_EASEIN;
+
+        public setEasingMode(easingMode: number) {
+            var n = Math.min(Math.max(easingMode, 0), 2);
+            this._easingMode = n;
+        }
+        public getEasingMode(): number {
+            return this._easingMode;
+        }
+
+        public easeInCore(gradient: number): number {
+            throw new Error('You must implement this method');
+        }
+
+        public ease(gradient: number): number {
+            switch (this._easingMode) {
+                case EasingFunction.EASINGMODE_EASEIN:
+                    return this.easeInCore(gradient);
+                case EasingFunction.EASINGMODE_EASEOUT:
+                    return (1 - this.easeInCore(1 - gradient));
+            }
+
+            if (gradient >= 0.5) {
+                return (((1 - this.easeInCore((1 - gradient) * 2)) * 0.5) + 0.5);
+            }
+
+            return (this.easeInCore(gradient * 2) * 0.5);
+        }
+
+    }
+
+    export class CircleEase extends EasingFunction implements IEasingFunction {
+        public easeInCore(gradient: number): number {
+            gradient = Math.max(0, Math.min(1, gradient));
+            return (1.0 - Math.sqrt(1.0 - (gradient * gradient)));
+        }
+    }
+
+    export class BackEase extends EasingFunction implements IEasingFunction {
+        constructor(public amplitude: number = 1) {
+            super();
+        }
+
+        public easeInCore(gradient: number): number {
+            var num = Math.max(0, this.amplitude);
+            return (Math.pow(gradient, 3.0) - ((gradient * num) * Math.sin(3.1415926535897931 * gradient)));
+        }
+    }
+
+    export class BounceEase extends EasingFunction implements IEasingFunction {
+        constructor(public bounces: number= 3, public bounciness: number= 2) {
+            super();
+        }
+
+        public easeInCore(gradient: number): number {
+            var y = Math.max(0.0, this.bounces);
+            var bounciness = this.bounciness;
+            if (bounciness <= 1.0) {
+                bounciness = 1.001;
+            }
+            var num9 = Math.pow(bounciness, y);
+            var num5 = 1.0 - bounciness;
+            var num4 = ((1.0 - num9) / num5) + (num9 * 0.5);
+            var num15 = gradient * num4;
+            var num65 = Math.log((-num15 * (1.0 - bounciness)) + 1.0) / Math.log(bounciness);
+            var num3 = Math.floor(num65);
+            var num13 = num3 + 1.0;
+            var num8 = (1.0 - Math.pow(bounciness, num3)) / (num5 * num4);
+            var num12 = (1.0 - Math.pow(bounciness, num13)) / (num5 * num4);
+            var num7 = (num8 + num12) * 0.5;
+            var num6 = gradient - num7;
+            var num2 = num7 - num8;
+            return (((-Math.pow(1.0 / bounciness, y - num3) / (num2 * num2)) * (num6 - num2)) * (num6 + num2));
+        }
+    }
+
+    export class CubicEase extends EasingFunction implements IEasingFunction {
+        public easeInCore(gradient: number): number {
+            return (gradient * gradient * gradient);
+        }
+    }
+
+    export class ElasticEase extends EasingFunction implements IEasingFunction {
+        constructor(public oscillations: number= 3, public springiness: number= 3) {
+            super();
+        }
+
+        public easeInCore(gradient: number): number {
+            var num2;
+            var num3 = Math.max(0.0, this.oscillations);
+            var num = Math.max(0.0, this.springiness);
+
+            if (num == 0) {
+                num2 = gradient;
+            }else {
+                num2 = (Math.exp(num * gradient) - 1.0) / (Math.exp(num) - 1.0);
+            }
+            return (num2 * Math.sin(((6.2831853071795862 * num3) + 1.5707963267948966) * gradient));
+        }
+    }
+
+    export class ExponentialEase  extends EasingFunction implements IEasingFunction {
+        constructor(public exponent: number= 2) {
+            super();
+        }
+
+        public easeInCore(gradient: number): number {
+            if (this.exponent <= 0) {
+                return gradient;
+            }
+
+            return ((Math.exp(this.exponent * gradient) - 1.0) / (Math.exp(this.exponent) - 1.0));
+        }
+    }
+
+    export class PowerEase  extends EasingFunction implements IEasingFunction {
+        constructor(public power: number= 2) {
+            super();
+        }
+
+        public easeInCore(gradient: number): number {
+            var y = Math.max(0.0, this.power);
+            return Math.pow(gradient, y);
+        }
+    }
+
+    export class QuadraticEase extends EasingFunction implements IEasingFunction {
+        public easeInCore(gradient: number): number {
+            return (gradient * gradient);
+
+           
+
+        }
+    }
+
+    export class QuarticEase extends EasingFunction implements IEasingFunction {
+        public easeInCore(gradient: number): number {
+            return (gradient * gradient * gradient * gradient);
+        }
+    }
+
+    export class QuinticEase extends EasingFunction implements IEasingFunction {
+        public easeInCore(gradient: number): number {
+            return (gradient * gradient * gradient * gradient * gradient);
+        }
+    }
+
+    export class SineEase  extends EasingFunction implements IEasingFunction {
+        public easeInCore(gradient: number): number {
+            return (1.0 - Math.sin(1.5707963267948966 * (1.0 - gradient)));
+        }
+    }
+
+    export class BezierCurveEase extends EasingFunction implements IEasingFunction {
+        constructor(public x1: number= 0, public y1: number= 0, public x2: number= 1, public y2: number= 1) {
+            super();
+        }
+
+        public easeInCore(gradient: number): number {
+            return BezierCurve.interpolate(gradient, this.x1, this.y1, this.x2, this.y2);
+        }
+    }
+}

+ 127 - 127
src/Audio/babylon.analyser.ts

@@ -1,128 +1,128 @@
-module BABYLON {
-    export class Analyser {
-        public SMOOTHING = 0.75;
-        public FFT_SIZE = 512;
-        public BARGRAPHAMPLITUDE = 256;
-        public DEBUGCANVASPOS = { x: 20, y: 20 };
-        public DEBUGCANVASSIZE = { width: 320, height: 200 }
-
-        private _byteFreqs: Uint8Array;
-        private _byteTime: Uint8Array;
-        private _floatFreqs: Float32Array;
-        private _webAudioAnalyser: AnalyserNode;
-        private _debugCanvas: HTMLCanvasElement;
-        private _debugCanvasContext: CanvasRenderingContext2D;
-        private _scene: Scene;
-        private _registerFunc;
-        private _audioEngine: AudioEngine;
-
-        constructor(scene: Scene) {
-            this._scene = scene;
-            this._audioEngine = Engine.audioEngine;
-            if (this._audioEngine.canUseWebAudio) {
-                this._webAudioAnalyser = this._audioEngine.audioContext.createAnalyser();
-                this._webAudioAnalyser.minDecibels = -140;
-                this._webAudioAnalyser.maxDecibels = 0;
-                this._byteFreqs = new Uint8Array(this._webAudioAnalyser.frequencyBinCount);
-                this._byteTime = new Uint8Array(this._webAudioAnalyser.frequencyBinCount);
-                this._floatFreqs = new Float32Array(this._webAudioAnalyser.frequencyBinCount);
-            }
-        }
-
-        public getFrequencyBinCount(): number {
-            if (this._audioEngine.canUseWebAudio) {
-                return this._webAudioAnalyser.frequencyBinCount;
-            }
-            else {
-                return 0;
-            }
-        }
-
-        public getByteFrequencyData(): Uint8Array {
-            if (this._audioEngine.canUseWebAudio) {
-                this._webAudioAnalyser.smoothingTimeConstant = this.SMOOTHING;
-                this._webAudioAnalyser.fftSize = this.FFT_SIZE;
-                this._webAudioAnalyser.getByteFrequencyData(this._byteFreqs);
-            }
-            return this._byteFreqs;
-        }
-
-        public getByteTimeDomainData(): Uint8Array {
-            if (this._audioEngine.canUseWebAudio) {
-                this._webAudioAnalyser.smoothingTimeConstant = this.SMOOTHING;
-                this._webAudioAnalyser.fftSize = this.FFT_SIZE;
-                this._webAudioAnalyser.getByteTimeDomainData(this._byteTime);
-            }
-            return this._byteTime;
-        }
-
-        public getFloatFrequencyData(): Uint8Array {
-            if (this._audioEngine.canUseWebAudio) {
-                this._webAudioAnalyser.smoothingTimeConstant = this.SMOOTHING;
-                this._webAudioAnalyser.fftSize = this.FFT_SIZE;
-                this._webAudioAnalyser.getFloatFrequencyData(this._floatFreqs);
-            }
-            return this._floatFreqs;
-        }
-
-        public drawDebugCanvas() {
-            if (this._audioEngine.canUseWebAudio) {
-                if (!this._debugCanvas) {
-                    this._debugCanvas = document.createElement("canvas");
-                    this._debugCanvas.width = this.DEBUGCANVASSIZE.width;
-                    this._debugCanvas.height = this.DEBUGCANVASSIZE.height;
-                    this._debugCanvas.style.position = "absolute";
-                    this._debugCanvas.style.top = this.DEBUGCANVASPOS.y + "px" ;
-                    this._debugCanvas.style.left = this.DEBUGCANVASPOS.x + "px" ;
-                    this._debugCanvasContext = this._debugCanvas.getContext("2d");
-                    document.body.appendChild(this._debugCanvas);
-                    this._registerFunc = () => {
-                        this.drawDebugCanvas();
-                    };
-                    this._scene.registerBeforeRender(this._registerFunc);
-                }
-                if (this._registerFunc) {
-                    var workingArray = this.getByteFrequencyData();
-
-                    this._debugCanvasContext.fillStyle = 'rgb(0, 0, 0)';
-                    this._debugCanvasContext.fillRect(0, 0, this.DEBUGCANVASSIZE.width, this.DEBUGCANVASSIZE.height);
-
-                    // Draw the frequency domain chart.
-                    for (var i = 0; i < this.getFrequencyBinCount(); i++) {
-                        var value = workingArray[i];
-                        var percent = value / this.BARGRAPHAMPLITUDE;
-                        var height = this.DEBUGCANVASSIZE.height * percent;
-                        var offset = this.DEBUGCANVASSIZE.height - height - 1;
-                        var barWidth = this.DEBUGCANVASSIZE.width / this.getFrequencyBinCount();
-                        var hue = i / this.getFrequencyBinCount() * 360;
-                        this._debugCanvasContext.fillStyle = 'hsl(' + hue + ', 100%, 50%)';
-                        this._debugCanvasContext.fillRect(i * barWidth, offset, barWidth, height);
-                    }
-                }
-            }
-        }
-
-        public stopDebugCanvas() {
-            if (this._debugCanvas) {
-                this._scene.unregisterBeforeRender(this._registerFunc);
-                this._registerFunc = null;
-                document.body.removeChild(this._debugCanvas);
-                this._debugCanvas = null;
-                this._debugCanvasContext = null;
-            }
-        }
-
-        public connectAudioNodes(inputAudioNode: AudioNode, outputAudioNode: AudioNode) {
-            if (this._audioEngine.canUseWebAudio) {
-                inputAudioNode.connect(this._webAudioAnalyser);
-                this._webAudioAnalyser.connect(outputAudioNode);
-            }
-        }
-
-        public dispose() {
-            if (this._audioEngine.canUseWebAudio) {
-                this._webAudioAnalyser.disconnect();
-            }
-        }
-    }
+module BABYLON {
+    export class Analyser {
+        public SMOOTHING = 0.75;
+        public FFT_SIZE = 512;
+        public BARGRAPHAMPLITUDE = 256;
+        public DEBUGCANVASPOS = { x: 20, y: 20 };
+        public DEBUGCANVASSIZE = { width: 320, height: 200 }
+
+        private _byteFreqs: Uint8Array;
+        private _byteTime: Uint8Array;
+        private _floatFreqs: Float32Array;
+        private _webAudioAnalyser: AnalyserNode;
+        private _debugCanvas: HTMLCanvasElement;
+        private _debugCanvasContext: CanvasRenderingContext2D;
+        private _scene: Scene;
+        private _registerFunc;
+        private _audioEngine: AudioEngine;
+
+        constructor(scene: Scene) {
+            this._scene = scene;
+            this._audioEngine = Engine.audioEngine;
+            if (this._audioEngine.canUseWebAudio) {
+                this._webAudioAnalyser = this._audioEngine.audioContext.createAnalyser();
+                this._webAudioAnalyser.minDecibels = -140;
+                this._webAudioAnalyser.maxDecibels = 0;
+                this._byteFreqs = new Uint8Array(this._webAudioAnalyser.frequencyBinCount);
+                this._byteTime = new Uint8Array(this._webAudioAnalyser.frequencyBinCount);
+                this._floatFreqs = new Float32Array(this._webAudioAnalyser.frequencyBinCount);
+            }
+        }
+
+        public getFrequencyBinCount(): number {
+            if (this._audioEngine.canUseWebAudio) {
+                return this._webAudioAnalyser.frequencyBinCount;
+            }
+            else {
+                return 0;
+            }
+        }
+
+        public getByteFrequencyData(): Uint8Array {
+            if (this._audioEngine.canUseWebAudio) {
+                this._webAudioAnalyser.smoothingTimeConstant = this.SMOOTHING;
+                this._webAudioAnalyser.fftSize = this.FFT_SIZE;
+                this._webAudioAnalyser.getByteFrequencyData(this._byteFreqs);
+            }
+            return this._byteFreqs;
+        }
+
+        public getByteTimeDomainData(): Uint8Array {
+            if (this._audioEngine.canUseWebAudio) {
+                this._webAudioAnalyser.smoothingTimeConstant = this.SMOOTHING;
+                this._webAudioAnalyser.fftSize = this.FFT_SIZE;
+                this._webAudioAnalyser.getByteTimeDomainData(this._byteTime);
+            }
+            return this._byteTime;
+        }
+
+        public getFloatFrequencyData(): Uint8Array {
+            if (this._audioEngine.canUseWebAudio) {
+                this._webAudioAnalyser.smoothingTimeConstant = this.SMOOTHING;
+                this._webAudioAnalyser.fftSize = this.FFT_SIZE;
+                this._webAudioAnalyser.getFloatFrequencyData(this._floatFreqs);
+            }
+            return this._floatFreqs;
+        }
+
+        public drawDebugCanvas() {
+            if (this._audioEngine.canUseWebAudio) {
+                if (!this._debugCanvas) {
+                    this._debugCanvas = document.createElement("canvas");
+                    this._debugCanvas.width = this.DEBUGCANVASSIZE.width;
+                    this._debugCanvas.height = this.DEBUGCANVASSIZE.height;
+                    this._debugCanvas.style.position = "absolute";
+                    this._debugCanvas.style.top = this.DEBUGCANVASPOS.y + "px" ;
+                    this._debugCanvas.style.left = this.DEBUGCANVASPOS.x + "px" ;
+                    this._debugCanvasContext = this._debugCanvas.getContext("2d");
+                    document.body.appendChild(this._debugCanvas);
+                    this._registerFunc = () => {
+                        this.drawDebugCanvas();
+                    };
+                    this._scene.registerBeforeRender(this._registerFunc);
+                }
+                if (this._registerFunc) {
+                    var workingArray = this.getByteFrequencyData();
+
+                    this._debugCanvasContext.fillStyle = 'rgb(0, 0, 0)';
+                    this._debugCanvasContext.fillRect(0, 0, this.DEBUGCANVASSIZE.width, this.DEBUGCANVASSIZE.height);
+
+                    // Draw the frequency domain chart.
+                    for (var i = 0; i < this.getFrequencyBinCount(); i++) {
+                        var value = workingArray[i];
+                        var percent = value / this.BARGRAPHAMPLITUDE;
+                        var height = this.DEBUGCANVASSIZE.height * percent;
+                        var offset = this.DEBUGCANVASSIZE.height - height - 1;
+                        var barWidth = this.DEBUGCANVASSIZE.width / this.getFrequencyBinCount();
+                        var hue = i / this.getFrequencyBinCount() * 360;
+                        this._debugCanvasContext.fillStyle = 'hsl(' + hue + ', 100%, 50%)';
+                        this._debugCanvasContext.fillRect(i * barWidth, offset, barWidth, height);
+                    }
+                }
+            }
+        }
+
+        public stopDebugCanvas() {
+            if (this._debugCanvas) {
+                this._scene.unregisterBeforeRender(this._registerFunc);
+                this._registerFunc = null;
+                document.body.removeChild(this._debugCanvas);
+                this._debugCanvas = null;
+                this._debugCanvasContext = null;
+            }
+        }
+
+        public connectAudioNodes(inputAudioNode: AudioNode, outputAudioNode: AudioNode) {
+            if (this._audioEngine.canUseWebAudio) {
+                inputAudioNode.connect(this._webAudioAnalyser);
+                this._webAudioAnalyser.connect(outputAudioNode);
+            }
+        }
+
+        public dispose() {
+            if (this._audioEngine.canUseWebAudio) {
+                this._webAudioAnalyser.disconnect();
+            }
+        }
+    }
 }

+ 84 - 84
src/Audio/babylon.audioEngine.ts

@@ -1,84 +1,84 @@
-module BABYLON {
-    export class AudioEngine {
-        private _audioContext: AudioContext = null;
-        private _audioContextInitialized = false;
-        public canUseWebAudio: boolean = false;
-        public masterGain: GainNode;
-
-        private _connectedAnalyser: Analyser;
-        public WarnedWebAudioUnsupported: boolean = false;
-
-        public get audioContext(): AudioContext {
-            if (!this._audioContextInitialized) {
-                this._initializeAudioContext();
-            }
-            return this._audioContext;
-        }
-
-        constructor() {
-            if (typeof window.AudioContext !== 'undefined' || typeof window.webkitAudioContext !== 'undefined') {
-                window.AudioContext = window.AudioContext || window.webkitAudioContext;
-                this.canUseWebAudio = true;
-            }
-        }
-
-        private _initializeAudioContext() {
-            try {
-                if (this.canUseWebAudio) {
-                    this._audioContext = new AudioContext();
-                    // create a global volume gain node 
-                    this.masterGain = this._audioContext.createGain();
-                    this.masterGain.gain.value = 1;
-                    this.masterGain.connect(this._audioContext.destination);
-                    this._audioContextInitialized = true;
-                }
-            }
-            catch (e) {
-                this.canUseWebAudio = false;
-                Tools.Error("Web Audio: " + e.message);
-            }
-        }
-
-        public dispose() {
-            if (this.canUseWebAudio && this._audioContextInitialized) {
-                if (this._connectedAnalyser) {
-                    this._connectedAnalyser.stopDebugCanvas();
-                    this._connectedAnalyser.dispose();
-                    this.masterGain.disconnect();
-                    this.masterGain.connect(this._audioContext.destination);
-                    this._connectedAnalyser = null;
-                }
-                this.masterGain.gain.value = 1;
-            }
-            this.WarnedWebAudioUnsupported = false;
-        }
-
-        public getGlobalVolume(): number {
-            if (this.canUseWebAudio && this._audioContextInitialized) {
-                return this.masterGain.gain.value;
-            }
-            else {
-                return -1;
-            }
-        }
-
-        public setGlobalVolume(newVolume: number) {
-            if (this.canUseWebAudio && this._audioContextInitialized) {
-                this.masterGain.gain.value = newVolume;
-            }
-        }
-
-        public connectToAnalyser(analyser: Analyser) {
-            if (this._connectedAnalyser) {
-                this._connectedAnalyser.stopDebugCanvas();
-            }
-            if (this.canUseWebAudio && this._audioContextInitialized) {
-                this._connectedAnalyser = analyser;
-                this.masterGain.disconnect();
-                this._connectedAnalyser.connectAudioNodes(this.masterGain, this._audioContext.destination);
-            }
-        }
-    }
-}
-
-
+module BABYLON {
+    export class AudioEngine {
+        private _audioContext: AudioContext = null;
+        private _audioContextInitialized = false;
+        public canUseWebAudio: boolean = false;
+        public masterGain: GainNode;
+
+        private _connectedAnalyser: Analyser;
+        public WarnedWebAudioUnsupported: boolean = false;
+
+        public get audioContext(): AudioContext {
+            if (!this._audioContextInitialized) {
+                this._initializeAudioContext();
+            }
+            return this._audioContext;
+        }
+
+        constructor() {
+            if (typeof window.AudioContext !== 'undefined' || typeof window.webkitAudioContext !== 'undefined') {
+                window.AudioContext = window.AudioContext || window.webkitAudioContext;
+                this.canUseWebAudio = true;
+            }
+        }
+
+        private _initializeAudioContext() {
+            try {
+                if (this.canUseWebAudio) {
+                    this._audioContext = new AudioContext();
+                    // create a global volume gain node 
+                    this.masterGain = this._audioContext.createGain();
+                    this.masterGain.gain.value = 1;
+                    this.masterGain.connect(this._audioContext.destination);
+                    this._audioContextInitialized = true;
+                }
+            }
+            catch (e) {
+                this.canUseWebAudio = false;
+                Tools.Error("Web Audio: " + e.message);
+            }
+        }
+
+        public dispose() {
+            if (this.canUseWebAudio && this._audioContextInitialized) {
+                if (this._connectedAnalyser) {
+                    this._connectedAnalyser.stopDebugCanvas();
+                    this._connectedAnalyser.dispose();
+                    this.masterGain.disconnect();
+                    this.masterGain.connect(this._audioContext.destination);
+                    this._connectedAnalyser = null;
+                }
+                this.masterGain.gain.value = 1;
+            }
+            this.WarnedWebAudioUnsupported = false;
+        }
+
+        public getGlobalVolume(): number {
+            if (this.canUseWebAudio && this._audioContextInitialized) {
+                return this.masterGain.gain.value;
+            }
+            else {
+                return -1;
+            }
+        }
+
+        public setGlobalVolume(newVolume: number) {
+            if (this.canUseWebAudio && this._audioContextInitialized) {
+                this.masterGain.gain.value = newVolume;
+            }
+        }
+
+        public connectToAnalyser(analyser: Analyser) {
+            if (this._connectedAnalyser) {
+                this._connectedAnalyser.stopDebugCanvas();
+            }
+            if (this.canUseWebAudio && this._audioContextInitialized) {
+                this._connectedAnalyser = analyser;
+                this.masterGain.disconnect();
+                this._connectedAnalyser.connectAudioNodes(this.masterGain, this._audioContext.destination);
+            }
+        }
+    }
+}
+
+

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

@@ -1,114 +1,114 @@
-module BABYLON {
-    export class SoundTrack {
-        private _outputAudioNode: GainNode;
-        private _inputAudioNode: AudioNode;
-        private _trackConvolver: ConvolverNode;
-        private _scene: Scene;
-        public id: number = -1;
-        public soundCollection: Array<Sound>;
-        private _isMainTrack: boolean = false;
-        private _connectedAnalyser: Analyser;
-        private _options;
-        private _isInitialized = false;
-
-        constructor(scene: Scene, options?: any) {
-            this._scene = scene;
-            this.soundCollection = new Array();
-            this._options = options;
-
-            if (!this._isMainTrack) {
-                this._scene.soundTracks.push(this);
-                this.id = this._scene.soundTracks.length - 1;
-            }
-        }
-
-        private _initializeSoundTrackAudioGraph() {
-            if (Engine.audioEngine.canUseWebAudio) {
-                this._outputAudioNode = Engine.audioEngine.audioContext.createGain();
-                this._outputAudioNode.connect(Engine.audioEngine.masterGain);
-
-                if (this._options) {
-                    if (this._options.volume) { this._outputAudioNode.gain.value = this._options.volume; }
-                    if (this._options.mainTrack) { this._isMainTrack = this._options.mainTrack; }
-                }
-
-                this._isInitialized = true;
-            }
-        }
-
-        public dispose() {
-            if (Engine.audioEngine.canUseWebAudio) {
-                if (this._connectedAnalyser) {
-                    this._connectedAnalyser.stopDebugCanvas();
-                }
-                while (this.soundCollection.length) {
-                    this.soundCollection[0].dispose();
-                }
-                if (this._outputAudioNode) {
-                    this._outputAudioNode.disconnect();
-                }
-                this._outputAudioNode = null;
-            }
-        }
-
-        public AddSound(sound: Sound) {
-            if (!this._isInitialized) {
-                this._initializeSoundTrackAudioGraph();
-            }
-            if (Engine.audioEngine.canUseWebAudio) {
-                sound.connectToSoundTrackAudioNode(this._outputAudioNode);
-            }
-            if (sound.soundTrackId) {
-                if (sound.soundTrackId === -1) {
-                    this._scene.mainSoundTrack.RemoveSound(sound);
-                }
-                else {
-                    this._scene.soundTracks[sound.soundTrackId].RemoveSound(sound);
-                }
-            }
-
-            this.soundCollection.push(sound);
-            sound.soundTrackId = this.id;
-        }
-
-        public RemoveSound(sound: Sound) {
-            var index = this.soundCollection.indexOf(sound);
-            if (index !== -1) {
-                this.soundCollection.splice(index, 1);
-            }
-        }
-
-        public setVolume(newVolume: number) {
-            if (Engine.audioEngine.canUseWebAudio) {
-                this._outputAudioNode.gain.value = newVolume;
-            }
-        }
-
-        public switchPanningModelToHRTF() {
-            if (Engine.audioEngine.canUseWebAudio) {
-                for (var i = 0; i < this.soundCollection.length; i++) {
-                    this.soundCollection[i].switchPanningModelToHRTF();
-                }
-            }
-        }
-
-        public switchPanningModelToEqualPower() {
-            if (Engine.audioEngine.canUseWebAudio) {
-                for (var i = 0; i < this.soundCollection.length; i++) {
-                    this.soundCollection[i].switchPanningModelToEqualPower();
-                }
-            }
-        }
-
-        public connectToAnalyser(analyser: Analyser) {
-            if (this._connectedAnalyser) {
-                this._connectedAnalyser.stopDebugCanvas();
-            }
-            this._connectedAnalyser = analyser;
-            if (Engine.audioEngine.canUseWebAudio) {
-                this._outputAudioNode.disconnect();
-                this._connectedAnalyser.connectAudioNodes(this._outputAudioNode, Engine.audioEngine.masterGain);
-            }
-        }
-    }
+module BABYLON {
+    export class SoundTrack {
+        private _outputAudioNode: GainNode;
+        private _inputAudioNode: AudioNode;
+        private _trackConvolver: ConvolverNode;
+        private _scene: Scene;
+        public id: number = -1;
+        public soundCollection: Array<Sound>;
+        private _isMainTrack: boolean = false;
+        private _connectedAnalyser: Analyser;
+        private _options;
+        private _isInitialized = false;
+
+        constructor(scene: Scene, options?: any) {
+            this._scene = scene;
+            this.soundCollection = new Array();
+            this._options = options;
+
+            if (!this._isMainTrack) {
+                this._scene.soundTracks.push(this);
+                this.id = this._scene.soundTracks.length - 1;
+            }
+        }
+
+        private _initializeSoundTrackAudioGraph() {
+            if (Engine.audioEngine.canUseWebAudio) {
+                this._outputAudioNode = Engine.audioEngine.audioContext.createGain();
+                this._outputAudioNode.connect(Engine.audioEngine.masterGain);
+
+                if (this._options) {
+                    if (this._options.volume) { this._outputAudioNode.gain.value = this._options.volume; }
+                    if (this._options.mainTrack) { this._isMainTrack = this._options.mainTrack; }
+                }
+
+                this._isInitialized = true;
+            }
+        }
+
+        public dispose() {
+            if (Engine.audioEngine.canUseWebAudio) {
+                if (this._connectedAnalyser) {
+                    this._connectedAnalyser.stopDebugCanvas();
+                }
+                while (this.soundCollection.length) {
+                    this.soundCollection[0].dispose();
+                }
+                if (this._outputAudioNode) {
+                    this._outputAudioNode.disconnect();
+                }
+                this._outputAudioNode = null;
+            }
+        }
+
+        public AddSound(sound: Sound) {
+            if (!this._isInitialized) {
+                this._initializeSoundTrackAudioGraph();
+            }
+            if (Engine.audioEngine.canUseWebAudio) {
+                sound.connectToSoundTrackAudioNode(this._outputAudioNode);
+            }
+            if (sound.soundTrackId) {
+                if (sound.soundTrackId === -1) {
+                    this._scene.mainSoundTrack.RemoveSound(sound);
+                }
+                else {
+                    this._scene.soundTracks[sound.soundTrackId].RemoveSound(sound);
+                }
+            }
+
+            this.soundCollection.push(sound);
+            sound.soundTrackId = this.id;
+        }
+
+        public RemoveSound(sound: Sound) {
+            var index = this.soundCollection.indexOf(sound);
+            if (index !== -1) {
+                this.soundCollection.splice(index, 1);
+            }
+        }
+
+        public setVolume(newVolume: number) {
+            if (Engine.audioEngine.canUseWebAudio) {
+                this._outputAudioNode.gain.value = newVolume;
+            }
+        }
+
+        public switchPanningModelToHRTF() {
+            if (Engine.audioEngine.canUseWebAudio) {
+                for (var i = 0; i < this.soundCollection.length; i++) {
+                    this.soundCollection[i].switchPanningModelToHRTF();
+                }
+            }
+        }
+
+        public switchPanningModelToEqualPower() {
+            if (Engine.audioEngine.canUseWebAudio) {
+                for (var i = 0; i < this.soundCollection.length; i++) {
+                    this.soundCollection[i].switchPanningModelToEqualPower();
+                }
+            }
+        }
+
+        public connectToAnalyser(analyser: Analyser) {
+            if (this._connectedAnalyser) {
+                this._connectedAnalyser.stopDebugCanvas();
+            }
+            this._connectedAnalyser = analyser;
+            if (Engine.audioEngine.canUseWebAudio) {
+                this._outputAudioNode.disconnect();
+                this._connectedAnalyser.connectAudioNodes(this._outputAudioNode, Engine.audioEngine.masterGain);
+            }
+        }
+    }
 }

+ 91 - 91
src/Bones/babylon.bone.ts

@@ -1,92 +1,92 @@
-module BABYLON {
-    export class Bone extends Node {
-        public children = new Array<Bone>();
-        public animations = new Array<Animation>();
-
-        private _skeleton: Skeleton;
-        private _matrix: Matrix;
-        private _baseMatrix: Matrix;
-        private _worldTransform = new Matrix();
-        private _absoluteTransform = new Matrix();
-        private _invertedAbsoluteTransform = new Matrix();
-        private _parent: Bone;
-
-        constructor(public name: string, skeleton: Skeleton, parentBone: Bone, matrix: Matrix) {
-            super(name, skeleton.getScene());
-            this._skeleton = skeleton;
-            this._matrix = matrix;
-            this._baseMatrix = matrix;
-
-            skeleton.bones.push(this);
-
-            if (parentBone) {
-                this._parent = parentBone;
-                parentBone.children.push(this);
-            } else {
-                this._parent = null;
-            }
-
-            this._updateDifferenceMatrix();
-        }
-
-        // Members
-        public getParent():Bone {
-            return this._parent;
-        }
-
-        public getLocalMatrix():Matrix {
-            return this._matrix;
-        }
-
-        public getBaseMatrix(): Matrix {
-            return this._baseMatrix;
-        }
-
-        public getWorldMatrix(): Matrix {
-            return this._worldTransform;
-        }
-
-        public getInvertedAbsoluteTransform(): Matrix {
-            return this._invertedAbsoluteTransform;
-        }
-
-        public getAbsoluteMatrix(): Matrix {
-            var matrix = this._matrix.clone();
-            var parent = this._parent;
-
-            while (parent) {
-                matrix = matrix.multiply(parent.getLocalMatrix());
-                parent = parent.getParent();
-            }
-
-            return matrix;
-        }
-
-        // Methods
-        public updateMatrix(matrix: Matrix): void {
-            this._matrix = matrix;
-            this._skeleton._markAsDirty();
-
-            this._updateDifferenceMatrix();
-        }
-
-        private _updateDifferenceMatrix(): void {
-            if (this._parent) {
-                this._matrix.multiplyToRef(this._parent._absoluteTransform, this._absoluteTransform);
-            } else {
-                this._absoluteTransform.copyFrom(this._matrix);
-            }
-
-            this._absoluteTransform.invertToRef(this._invertedAbsoluteTransform);
-
-            for (var index = 0; index < this.children.length; index++) {
-                this.children[index]._updateDifferenceMatrix();
-            }
-        }
-
-        public markAsDirty(): void {
-            this._currentRenderId++;
-            this._skeleton._markAsDirty();
-        }
-    }
+module BABYLON {
+    export class Bone extends Node {
+        public children = new Array<Bone>();
+        public animations = new Array<Animation>();
+
+        private _skeleton: Skeleton;
+        private _matrix: Matrix;
+        private _baseMatrix: Matrix;
+        private _worldTransform = new Matrix();
+        private _absoluteTransform = new Matrix();
+        private _invertedAbsoluteTransform = new Matrix();
+        private _parent: Bone;
+
+        constructor(public name: string, skeleton: Skeleton, parentBone: Bone, matrix: Matrix) {
+            super(name, skeleton.getScene());
+            this._skeleton = skeleton;
+            this._matrix = matrix;
+            this._baseMatrix = matrix;
+
+            skeleton.bones.push(this);
+
+            if (parentBone) {
+                this._parent = parentBone;
+                parentBone.children.push(this);
+            } else {
+                this._parent = null;
+            }
+
+            this._updateDifferenceMatrix();
+        }
+
+        // Members
+        public getParent():Bone {
+            return this._parent;
+        }
+
+        public getLocalMatrix():Matrix {
+            return this._matrix;
+        }
+
+        public getBaseMatrix(): Matrix {
+            return this._baseMatrix;
+        }
+
+        public getWorldMatrix(): Matrix {
+            return this._worldTransform;
+        }
+
+        public getInvertedAbsoluteTransform(): Matrix {
+            return this._invertedAbsoluteTransform;
+        }
+
+        public getAbsoluteMatrix(): Matrix {
+            var matrix = this._matrix.clone();
+            var parent = this._parent;
+
+            while (parent) {
+                matrix = matrix.multiply(parent.getLocalMatrix());
+                parent = parent.getParent();
+            }
+
+            return matrix;
+        }
+
+        // Methods
+        public updateMatrix(matrix: Matrix): void {
+            this._matrix = matrix;
+            this._skeleton._markAsDirty();
+
+            this._updateDifferenceMatrix();
+        }
+
+        private _updateDifferenceMatrix(): void {
+            if (this._parent) {
+                this._matrix.multiplyToRef(this._parent._absoluteTransform, this._absoluteTransform);
+            } else {
+                this._absoluteTransform.copyFrom(this._matrix);
+            }
+
+            this._absoluteTransform.invertToRef(this._invertedAbsoluteTransform);
+
+            for (var index = 0; index < this.children.length; index++) {
+                this.children[index]._updateDifferenceMatrix();
+            }
+        }
+
+        public markAsDirty(): void {
+            this._currentRenderId++;
+            this._skeleton._markAsDirty();
+        }
+    }
 } 

+ 49 - 49
src/Cameras/VR/babylon.vrDeviceOrientationCamera.ts

@@ -1,50 +1,50 @@
-module BABYLON {
-    export class VRDeviceOrientationFreeCamera extends FreeCamera {
-        public _alpha = 0;
-        public _beta = 0;
-        public _gamma = 0;
-    
-        private _offsetOrientation: { yaw: number; pitch: number; roll: number };
-        private _deviceOrientationHandler;
-
-        constructor(name: string, position: Vector3, scene: Scene, compensateDistortion = true) {
-            super(name, position, scene);
-
-            var metrics = VRCameraMetrics.GetDefault();
-            metrics.compensateDistortion = compensateDistortion;
-            this.setCameraRigMode(Camera.RIG_MODE_VR, { vrCameraMetrics: metrics });
-
-            this._deviceOrientationHandler = this._onOrientationEvent.bind(this);
-        }
-
-        public _onOrientationEvent(evt: DeviceOrientationEvent): void {
-            this._alpha = +evt.alpha|0;
-            this._beta = +evt.beta|0;
-            this._gamma = +evt.gamma|0;
-
-            if (this._gamma < 0) {
-                this._gamma = 90 + this._gamma;
-            }
-            else {
-                // Incline it in the correct angle.
-                this._gamma = 270 - this._gamma;
-            }
-
-            this.rotation.x = this._gamma / 180.0 * Math.PI;   
-            this.rotation.y = -this._alpha / 180.0 * Math.PI;   
-            this.rotation.z = this._beta / 180.0 * Math.PI;     
-        }
-
-        public attachControl(element: HTMLElement, noPreventDefault?: boolean): void {
-            super.attachControl(element, noPreventDefault);
-
-            window.addEventListener("deviceorientation", this._deviceOrientationHandler);
-        }
-
-        public detachControl(element: HTMLElement): void {
-            super.detachControl(element);
-
-            window.removeEventListener("deviceorientation", this._deviceOrientationHandler);
-        }
-    }
+module BABYLON {
+    export class VRDeviceOrientationFreeCamera extends FreeCamera {
+        public _alpha = 0;
+        public _beta = 0;
+        public _gamma = 0;
+    
+        private _offsetOrientation: { yaw: number; pitch: number; roll: number };
+        private _deviceOrientationHandler;
+
+        constructor(name: string, position: Vector3, scene: Scene, compensateDistortion = true) {
+            super(name, position, scene);
+
+            var metrics = VRCameraMetrics.GetDefault();
+            metrics.compensateDistortion = compensateDistortion;
+            this.setCameraRigMode(Camera.RIG_MODE_VR, { vrCameraMetrics: metrics });
+
+            this._deviceOrientationHandler = this._onOrientationEvent.bind(this);
+        }
+
+        public _onOrientationEvent(evt: DeviceOrientationEvent): void {
+            this._alpha = +evt.alpha|0;
+            this._beta = +evt.beta|0;
+            this._gamma = +evt.gamma|0;
+
+            if (this._gamma < 0) {
+                this._gamma = 90 + this._gamma;
+            }
+            else {
+                // Incline it in the correct angle.
+                this._gamma = 270 - this._gamma;
+            }
+
+            this.rotation.x = this._gamma / 180.0 * Math.PI;   
+            this.rotation.y = -this._alpha / 180.0 * Math.PI;   
+            this.rotation.z = this._beta / 180.0 * Math.PI;     
+        }
+
+        public attachControl(element: HTMLElement, noPreventDefault?: boolean): void {
+            super.attachControl(element, noPreventDefault);
+
+            window.addEventListener("deviceorientation", this._deviceOrientationHandler);
+        }
+
+        public detachControl(element: HTMLElement): void {
+            super.detachControl(element);
+
+            window.removeEventListener("deviceorientation", this._deviceOrientationHandler);
+        }
+    }
 }

+ 80 - 80
src/Cameras/VR/babylon.webVRCamera.ts

@@ -1,81 +1,81 @@
-declare var HMDVRDevice;
-declare var PositionSensorVRDevice;
-
-module BABYLON {
-    export class WebVRFreeCamera extends FreeCamera {
-        public _hmdDevice = null;
-        public _sensorDevice = null;
-        public _cacheState = null;
-        public _cacheQuaternion = new Quaternion();
-        public _cacheRotation = Vector3.Zero();
-        public _vrEnabled = false;
-
-        constructor(name: string, position: Vector3, scene: Scene, compensateDistortion = true) {
-            super(name, position, scene);
-            
-            var metrics = VRCameraMetrics.GetDefault();
-            metrics.compensateDistortion = compensateDistortion;
-            this.setCameraRigMode(Camera.RIG_MODE_VR, { vrCameraMetrics: metrics });
-
-            this._getWebVRDevices = this._getWebVRDevices.bind(this);
-        }
-
-        private _getWebVRDevices(devices: Array<any>): void {
-            var size = devices.length;
-            var i = 0;
-
-            // Reset devices.
-            this._sensorDevice = null;
-            this._hmdDevice = null;
-
-            // Search for a HmdDevice.
-            while (i < size && this._hmdDevice === null) {
-                if (devices[i] instanceof HMDVRDevice) {
-                    this._hmdDevice = devices[i];
-                }
-                i++;
-            }
-
-            i = 0;
-
-            while (i < size && this._sensorDevice === null) {
-                if (devices[i] instanceof PositionSensorVRDevice && (!this._hmdDevice || devices[i].hardwareUnitId === this._hmdDevice.hardwareUnitId)) {
-                    this._sensorDevice = devices[i];
-                }
-                i++;
-            }
-
-            this._vrEnabled = this._sensorDevice && this._hmdDevice ? true : false;
-        }
-
-        public _checkInputs(): void {
-            if (this._vrEnabled) {
-                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.z;
-                this.rotation.y = -this._cacheRotation.y;
-                this.rotation.z = this._cacheRotation.x;
-            }
-
-            super._checkInputs();
-        }
-
-        public attachControl(element: HTMLElement, noPreventDefault?: boolean): void {
-            super.attachControl(element, noPreventDefault);
-
-            if (navigator.getVRDevices) {
-                navigator.getVRDevices().then(this._getWebVRDevices);
-            }
-            else if (navigator.mozGetVRDevices) {
-                navigator.mozGetVRDevices(this._getWebVRDevices);
-            }
-        }
-
-        public detachControl(element: HTMLElement): void {
-            super.detachControl(element);
-            this._vrEnabled = false;
-        }
-    }
+declare var HMDVRDevice;
+declare var PositionSensorVRDevice;
+
+module BABYLON {
+    export class WebVRFreeCamera extends FreeCamera {
+        public _hmdDevice = null;
+        public _sensorDevice = null;
+        public _cacheState = null;
+        public _cacheQuaternion = new Quaternion();
+        public _cacheRotation = Vector3.Zero();
+        public _vrEnabled = false;
+
+        constructor(name: string, position: Vector3, scene: Scene, compensateDistortion = true) {
+            super(name, position, scene);
+            
+            var metrics = VRCameraMetrics.GetDefault();
+            metrics.compensateDistortion = compensateDistortion;
+            this.setCameraRigMode(Camera.RIG_MODE_VR, { vrCameraMetrics: metrics });
+
+            this._getWebVRDevices = this._getWebVRDevices.bind(this);
+        }
+
+        private _getWebVRDevices(devices: Array<any>): void {
+            var size = devices.length;
+            var i = 0;
+
+            // Reset devices.
+            this._sensorDevice = null;
+            this._hmdDevice = null;
+
+            // Search for a HmdDevice.
+            while (i < size && this._hmdDevice === null) {
+                if (devices[i] instanceof HMDVRDevice) {
+                    this._hmdDevice = devices[i];
+                }
+                i++;
+            }
+
+            i = 0;
+
+            while (i < size && this._sensorDevice === null) {
+                if (devices[i] instanceof PositionSensorVRDevice && (!this._hmdDevice || devices[i].hardwareUnitId === this._hmdDevice.hardwareUnitId)) {
+                    this._sensorDevice = devices[i];
+                }
+                i++;
+            }
+
+            this._vrEnabled = this._sensorDevice && this._hmdDevice ? true : false;
+        }
+
+        public _checkInputs(): void {
+            if (this._vrEnabled) {
+                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.z;
+                this.rotation.y = -this._cacheRotation.y;
+                this.rotation.z = this._cacheRotation.x;
+            }
+
+            super._checkInputs();
+        }
+
+        public attachControl(element: HTMLElement, noPreventDefault?: boolean): void {
+            super.attachControl(element, noPreventDefault);
+
+            if (navigator.getVRDevices) {
+                navigator.getVRDevices().then(this._getWebVRDevices);
+            }
+            else if (navigator.mozGetVRDevices) {
+                navigator.mozGetVRDevices(this._getWebVRDevices);
+            }
+        }
+
+        public detachControl(element: HTMLElement): void {
+            super.detachControl(element);
+            this._vrEnabled = false;
+        }
+    }
 }

+ 36 - 36
src/Cameras/babylon.anaglyphCamera.js

@@ -1,37 +1,37 @@
-var __extends = this.__extends || function (d, b) {
-    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
-    function __() { this.constructor = d; }
-    __.prototype = b.prototype;
-    d.prototype = new __();
-};
-var BABYLON;
-(function (BABYLON) {
-    var AnaglyphFreeCamera = (function (_super) {
-        __extends(AnaglyphFreeCamera, _super);
-        function AnaglyphFreeCamera(name, position, eyeSpace, scene) {
-            _super.call(this, name, position, scene);
-            this.setSubCameraMode(BABYLON.Camera.SUB_CAMERA_MODE_ANAGLYPH, eyeSpace);
-        }
-        return AnaglyphFreeCamera;
-    })(BABYLON.FreeCamera);
-    BABYLON.AnaglyphFreeCamera = AnaglyphFreeCamera;
-    var AnaglyphArcRotateCamera = (function (_super) {
-        __extends(AnaglyphArcRotateCamera, _super);
-        function AnaglyphArcRotateCamera(name, alpha, beta, radius, target, eyeSpace, scene) {
-            _super.call(this, name, alpha, beta, radius, target, scene);
-            this.setSubCameraMode(BABYLON.Camera.SUB_CAMERA_MODE_ANAGLYPH, eyeSpace);
-        }
-        return AnaglyphArcRotateCamera;
-    })(BABYLON.ArcRotateCamera);
-    BABYLON.AnaglyphArcRotateCamera = AnaglyphArcRotateCamera;
-    var AnaglyphGamepadCamera = (function (_super) {
-        __extends(AnaglyphGamepadCamera, _super);
-        function AnaglyphGamepadCamera(name, position, eyeSpace, scene) {
-            _super.call(this, name, position, scene);
-            this.setSubCameraMode(BABYLON.Camera.SUB_CAMERA_MODE_ANAGLYPH, eyeSpace);
-        }
-        return AnaglyphGamepadCamera;
-    })(BABYLON.GamepadCamera);
-    BABYLON.AnaglyphGamepadCamera = AnaglyphGamepadCamera;
-})(BABYLON || (BABYLON = {}));
+var __extends = this.__extends || function (d, b) {
+    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
+    function __() { this.constructor = d; }
+    __.prototype = b.prototype;
+    d.prototype = new __();
+};
+var BABYLON;
+(function (BABYLON) {
+    var AnaglyphFreeCamera = (function (_super) {
+        __extends(AnaglyphFreeCamera, _super);
+        function AnaglyphFreeCamera(name, position, eyeSpace, scene) {
+            _super.call(this, name, position, scene);
+            this.setSubCameraMode(BABYLON.Camera.SUB_CAMERA_MODE_ANAGLYPH, eyeSpace);
+        }
+        return AnaglyphFreeCamera;
+    })(BABYLON.FreeCamera);
+    BABYLON.AnaglyphFreeCamera = AnaglyphFreeCamera;
+    var AnaglyphArcRotateCamera = (function (_super) {
+        __extends(AnaglyphArcRotateCamera, _super);
+        function AnaglyphArcRotateCamera(name, alpha, beta, radius, target, eyeSpace, scene) {
+            _super.call(this, name, alpha, beta, radius, target, scene);
+            this.setSubCameraMode(BABYLON.Camera.SUB_CAMERA_MODE_ANAGLYPH, eyeSpace);
+        }
+        return AnaglyphArcRotateCamera;
+    })(BABYLON.ArcRotateCamera);
+    BABYLON.AnaglyphArcRotateCamera = AnaglyphArcRotateCamera;
+    var AnaglyphGamepadCamera = (function (_super) {
+        __extends(AnaglyphGamepadCamera, _super);
+        function AnaglyphGamepadCamera(name, position, eyeSpace, scene) {
+            _super.call(this, name, position, scene);
+            this.setSubCameraMode(BABYLON.Camera.SUB_CAMERA_MODE_ANAGLYPH, eyeSpace);
+        }
+        return AnaglyphGamepadCamera;
+    })(BABYLON.GamepadCamera);
+    BABYLON.AnaglyphGamepadCamera = AnaglyphGamepadCamera;
+})(BABYLON || (BABYLON = {}));
 //# sourceMappingURL=babylon.anaglyphCamera.js.map

Разница между файлами не показана из-за своего большого размера
+ 671 - 671
src/Cameras/babylon.arcRotateCamera.ts


+ 77 - 77
src/Cameras/babylon.deviceOrientationCamera.ts

@@ -1,78 +1,78 @@
-module BABYLON {
-    // We're mainly based on the logic defined into the FreeCamera code
-    export class DeviceOrientationCamera extends FreeCamera {
-        private _offsetX: number = null;
-        private _offsetY: number = null;
-        private _orientationGamma: number = 0;
-        private _orientationBeta: number = 0;
-        private _initialOrientationGamma: number = 0;
-        private _initialOrientationBeta: number = 0;
-        private _attachedCanvas: HTMLCanvasElement;
-        private _orientationChanged: (e: DeviceOrientationEvent) => any;
-
-        public angularSensibility: number = 10000.0;
-        public moveSensibility: number = 50.0;
-
-        constructor(name: string, position: Vector3, scene: Scene) {
-            super(name, position, scene);
-
-            window.addEventListener("resize", () => {
-                this._initialOrientationGamma = null;
-            }, false);
-        }
-
-        public attachControl(canvas: HTMLCanvasElement, noPreventDefault: boolean): void {
-            if (this._attachedCanvas) {
-                return;
-            }
-            this._attachedCanvas = canvas;
-
-            if (!this._orientationChanged) {
-                this._orientationChanged = (evt) => {
-
-                    if (!this._initialOrientationGamma) {
-                            this._initialOrientationGamma = evt.gamma;
-                            this._initialOrientationBeta = evt.beta;
-                    }
-
-                    this._orientationGamma = evt.gamma;
-                    this._orientationBeta = evt.beta;
- 
-                    this._offsetY = (this._initialOrientationBeta - this._orientationBeta);
-                    this._offsetX = (this._initialOrientationGamma - this._orientationGamma);
-                };
-            }
-
-            window.addEventListener("deviceorientation", this._orientationChanged);
-        }
-
-        public detachControl(canvas: HTMLCanvasElement): void {
-            if (this._attachedCanvas !== canvas) {
-                return;
-            }
-
-            window.removeEventListener("deviceorientation", this._orientationChanged);
-
-            this._attachedCanvas = null;
-            this._orientationGamma = 0;
-            this._orientationBeta = 0;
-            this._initialOrientationGamma = 0;
-            this._initialOrientationBeta = 0;
-        }
-
-        public _checkInputs(): void {
-            if (!this._offsetX) {
-                return;
-            }
-            this.cameraRotation.y -= this._offsetX / this.angularSensibility;
-
-            var speed = this._computeLocalCameraSpeed();
-            var direction = new Vector3(0, 0, speed * this._offsetY / this.moveSensibility);
-
-            Matrix.RotationYawPitchRollToRef(this.rotation.y, this.rotation.x, 0, this._cameraRotationMatrix);
-            this.cameraDirection.addInPlace(Vector3.TransformCoordinates(direction, this._cameraRotationMatrix));
-
-            super._checkInputs();
-        }
-    }
+module BABYLON {
+    // We're mainly based on the logic defined into the FreeCamera code
+    export class DeviceOrientationCamera extends FreeCamera {
+        private _offsetX: number = null;
+        private _offsetY: number = null;
+        private _orientationGamma: number = 0;
+        private _orientationBeta: number = 0;
+        private _initialOrientationGamma: number = 0;
+        private _initialOrientationBeta: number = 0;
+        private _attachedCanvas: HTMLCanvasElement;
+        private _orientationChanged: (e: DeviceOrientationEvent) => any;
+
+        public angularSensibility: number = 10000.0;
+        public moveSensibility: number = 50.0;
+
+        constructor(name: string, position: Vector3, scene: Scene) {
+            super(name, position, scene);
+
+            window.addEventListener("resize", () => {
+                this._initialOrientationGamma = null;
+            }, false);
+        }
+
+        public attachControl(canvas: HTMLCanvasElement, noPreventDefault: boolean): void {
+            if (this._attachedCanvas) {
+                return;
+            }
+            this._attachedCanvas = canvas;
+
+            if (!this._orientationChanged) {
+                this._orientationChanged = (evt) => {
+
+                    if (!this._initialOrientationGamma) {
+                            this._initialOrientationGamma = evt.gamma;
+                            this._initialOrientationBeta = evt.beta;
+                    }
+
+                    this._orientationGamma = evt.gamma;
+                    this._orientationBeta = evt.beta;
+ 
+                    this._offsetY = (this._initialOrientationBeta - this._orientationBeta);
+                    this._offsetX = (this._initialOrientationGamma - this._orientationGamma);
+                };
+            }
+
+            window.addEventListener("deviceorientation", this._orientationChanged);
+        }
+
+        public detachControl(canvas: HTMLCanvasElement): void {
+            if (this._attachedCanvas !== canvas) {
+                return;
+            }
+
+            window.removeEventListener("deviceorientation", this._orientationChanged);
+
+            this._attachedCanvas = null;
+            this._orientationGamma = 0;
+            this._orientationBeta = 0;
+            this._initialOrientationGamma = 0;
+            this._initialOrientationBeta = 0;
+        }
+
+        public _checkInputs(): void {
+            if (!this._offsetX) {
+                return;
+            }
+            this.cameraRotation.y -= this._offsetX / this.angularSensibility;
+
+            var speed = this._computeLocalCameraSpeed();
+            var direction = new Vector3(0, 0, speed * this._offsetY / this.moveSensibility);
+
+            Matrix.RotationYawPitchRollToRef(this.rotation.y, this.rotation.x, 0, this._cameraRotationMatrix);
+            this.cameraDirection.addInPlace(Vector3.TransformCoordinates(direction, this._cameraRotationMatrix));
+
+            super._checkInputs();
+        }
+    }
 }

+ 107 - 107
src/Cameras/babylon.followCamera.ts

@@ -1,107 +1,107 @@
-module BABYLON {
-    export class FollowCamera extends TargetCamera {
-
-        public radius: number = 12;
-        public rotationOffset: number = 0;
-        public heightOffset: number = 4;
-        public cameraAcceleration: number = 0.05;
-        public maxCameraSpeed: number = 20;
-        public target: AbstractMesh;
-
-        constructor(name: string, position: Vector3, scene: Scene) {
-            super(name, position, scene);
-        }
-
-        private getRadians(degrees): number {
-            return degrees * Math.PI / 180;
-        }
-
-        private follow(cameraTarget: AbstractMesh) {
-            if (!cameraTarget)
-                return;
-
-            var yRotation;
-            if (cameraTarget.rotationQuaternion) {
-                var rotMatrix = new Matrix();
-                cameraTarget.rotationQuaternion.toRotationMatrix(rotMatrix);
-                yRotation = Math.atan2(rotMatrix.m[8], rotMatrix.m[10]);
-            } else {
-                yRotation = cameraTarget.rotation.y;
-            }
-            var radians = this.getRadians(this.rotationOffset) + yRotation;
-            var targetX: number = cameraTarget.position.x + Math.sin(radians) * this.radius;
-
-            var targetZ: number = cameraTarget.position.z + Math.cos(radians) * this.radius;
-            var dx: number = targetX - this.position.x;
-            var dy: number = (cameraTarget.position.y + this.heightOffset) - this.position.y;
-            var dz: number = (targetZ) - this.position.z;
-            var vx: number = dx * this.cameraAcceleration * 2;//this is set to .05
-            var vy: number = dy * this.cameraAcceleration;
-            var vz: number = dz * this.cameraAcceleration * 2;
-
-            if (vx > this.maxCameraSpeed || vx < -this.maxCameraSpeed) {
-                vx = vx < 1 ? -this.maxCameraSpeed : this.maxCameraSpeed;
-            }
-
-            if (vy > this.maxCameraSpeed || vy < -this.maxCameraSpeed) {
-                vy = vy < 1 ? -this.maxCameraSpeed : this.maxCameraSpeed;
-            }
-
-            if (vz > this.maxCameraSpeed || vz < -this.maxCameraSpeed) {
-                vz = vz < 1 ? -this.maxCameraSpeed : this.maxCameraSpeed;
-            }
-
-            this.position = new Vector3(this.position.x + vx, this.position.y + vy, this.position.z + vz);
-            this.setTarget(cameraTarget.position);
-        }
-
-        public _checkInputs(): void {
-            super._checkInputs();
-            this.follow(this.target);
-        }
-
-        public serialize(): any {
-            var serializationObject = super.serialize();
-       
-            serializationObject.radius = this.radius;
-            serializationObject.heightOffset = this.heightOffset;
-            serializationObject.rotationOffset = this.rotationOffset;
-       
-            return serializationObject;
-        }
-    }
-
-    export class ArcFollowCamera extends TargetCamera {
-
-        private _cartesianCoordinates: Vector3 = Vector3.Zero();
-
-        constructor(name: string, public alpha: number, public beta: number, public radius: number, public target: AbstractMesh, scene: Scene) {
-            super(name, Vector3.Zero(), scene);
-            this.follow();
-        }
-
-        private follow(): void {
-            this._cartesianCoordinates.x = this.radius * Math.cos(this.alpha) * Math.cos(this.beta);
-            this._cartesianCoordinates.y = this.radius * Math.sin(this.beta);
-            this._cartesianCoordinates.z = this.radius * Math.sin(this.alpha) * Math.cos(this.beta);
-
-            this.position = this.target.position.add(this._cartesianCoordinates);
-            this.setTarget(this.target.position);
-        }
-
-        public _checkInputs(): void {
-            super._checkInputs();
-            this.follow();
-        }
-
-        public serialize(): any {
-            var serializationObject = super.serialize();
-
-            serializationObject.radius = this.radius;
-
-            return serializationObject;
-        }
-    }
-}
-
-
+module BABYLON {
+    export class FollowCamera extends TargetCamera {
+
+        public radius: number = 12;
+        public rotationOffset: number = 0;
+        public heightOffset: number = 4;
+        public cameraAcceleration: number = 0.05;
+        public maxCameraSpeed: number = 20;
+        public target: AbstractMesh;
+
+        constructor(name: string, position: Vector3, scene: Scene) {
+            super(name, position, scene);
+        }
+
+        private getRadians(degrees): number {
+            return degrees * Math.PI / 180;
+        }
+
+        private follow(cameraTarget: AbstractMesh) {
+            if (!cameraTarget)
+                return;
+
+            var yRotation;
+            if (cameraTarget.rotationQuaternion) {
+                var rotMatrix = new Matrix();
+                cameraTarget.rotationQuaternion.toRotationMatrix(rotMatrix);
+                yRotation = Math.atan2(rotMatrix.m[8], rotMatrix.m[10]);
+            } else {
+                yRotation = cameraTarget.rotation.y;
+            }
+            var radians = this.getRadians(this.rotationOffset) + yRotation;
+            var targetX: number = cameraTarget.position.x + Math.sin(radians) * this.radius;
+
+            var targetZ: number = cameraTarget.position.z + Math.cos(radians) * this.radius;
+            var dx: number = targetX - this.position.x;
+            var dy: number = (cameraTarget.position.y + this.heightOffset) - this.position.y;
+            var dz: number = (targetZ) - this.position.z;
+            var vx: number = dx * this.cameraAcceleration * 2;//this is set to .05
+            var vy: number = dy * this.cameraAcceleration;
+            var vz: number = dz * this.cameraAcceleration * 2;
+
+            if (vx > this.maxCameraSpeed || vx < -this.maxCameraSpeed) {
+                vx = vx < 1 ? -this.maxCameraSpeed : this.maxCameraSpeed;
+            }
+
+            if (vy > this.maxCameraSpeed || vy < -this.maxCameraSpeed) {
+                vy = vy < 1 ? -this.maxCameraSpeed : this.maxCameraSpeed;
+            }
+
+            if (vz > this.maxCameraSpeed || vz < -this.maxCameraSpeed) {
+                vz = vz < 1 ? -this.maxCameraSpeed : this.maxCameraSpeed;
+            }
+
+            this.position = new Vector3(this.position.x + vx, this.position.y + vy, this.position.z + vz);
+            this.setTarget(cameraTarget.position);
+        }
+
+        public _checkInputs(): void {
+            super._checkInputs();
+            this.follow(this.target);
+        }
+
+        public serialize(): any {
+            var serializationObject = super.serialize();
+       
+            serializationObject.radius = this.radius;
+            serializationObject.heightOffset = this.heightOffset;
+            serializationObject.rotationOffset = this.rotationOffset;
+       
+            return serializationObject;
+        }
+    }
+
+    export class ArcFollowCamera extends TargetCamera {
+
+        private _cartesianCoordinates: Vector3 = Vector3.Zero();
+
+        constructor(name: string, public alpha: number, public beta: number, public radius: number, public target: AbstractMesh, scene: Scene) {
+            super(name, Vector3.Zero(), scene);
+            this.follow();
+        }
+
+        private follow(): void {
+            this._cartesianCoordinates.x = this.radius * Math.cos(this.alpha) * Math.cos(this.beta);
+            this._cartesianCoordinates.y = this.radius * Math.sin(this.beta);
+            this._cartesianCoordinates.z = this.radius * Math.sin(this.alpha) * Math.cos(this.beta);
+
+            this.position = this.target.position.add(this._cartesianCoordinates);
+            this.setTarget(this.target.position);
+        }
+
+        public _checkInputs(): void {
+            super._checkInputs();
+            this.follow();
+        }
+
+        public serialize(): any {
+            var serializationObject = super.serialize();
+
+            serializationObject.radius = this.radius;
+
+            return serializationObject;
+        }
+    }
+}
+
+

+ 50 - 50
src/Cameras/babylon.gamepadCamera.ts

@@ -1,51 +1,51 @@
-module BABYLON {
-    // We're mainly based on the logic defined into the FreeCamera code
-    export class GamepadCamera extends FreeCamera {
-        private _gamepad: Gamepad;
-        private _gamepads: Gamepads;
-        public angularSensibility = 200;
-        public moveSensibility = 75;
-
-        constructor(name: string, position: Vector3, scene: Scene) {
-            super(name, position, scene);
-            this._gamepads = new Gamepads((gamepad: Gamepad) => { this._onNewGameConnected(gamepad); });
-        }
-
-        private _onNewGameConnected(gamepad: Gamepad) {
-            // Only the first gamepad can control the camera
-            if (gamepad.index === 0) {
-                this._gamepad = gamepad;
-            }
-        }
-
-        public _checkInputs(): void {
-            if (this._gamepad) {
-                var LSValues = this._gamepad.leftStick;
-                var normalizedLX = LSValues.x / this.moveSensibility;
-                var normalizedLY = LSValues.y / this.moveSensibility;
-                LSValues.x = Math.abs(normalizedLX) > 0.005 ? 0 + normalizedLX : 0;
-                LSValues.y = Math.abs(normalizedLY) > 0.005 ? 0 + normalizedLY : 0;
-
-                var RSValues = this._gamepad.rightStick;
-                var normalizedRX = RSValues.x / this.angularSensibility;
-                var normalizedRY = RSValues.y / this.angularSensibility;
-                RSValues.x = Math.abs(normalizedRX) > 0.001 ? 0 + normalizedRX : 0;
-                RSValues.y = Math.abs(normalizedRY) > 0.001 ? 0 + normalizedRY : 0;
-
-                var cameraTransform = Matrix.RotationYawPitchRoll(this.rotation.y, this.rotation.x, 0);
-
-                var speed = this._computeLocalCameraSpeed() * 50.0;
-                var deltaTransform = Vector3.TransformCoordinates(new Vector3(LSValues.x * speed, 0, -LSValues.y * speed), cameraTransform);
-                this.cameraDirection = this.cameraDirection.add(deltaTransform);
-                this.cameraRotation = this.cameraRotation.add(new Vector2(RSValues.y, RSValues.x));
-            }
-
-            super._checkInputs();
-        }
-
-        public dispose(): void {
-            this._gamepads.dispose();
-            super.dispose();
-        }
-    }
+module BABYLON {
+    // We're mainly based on the logic defined into the FreeCamera code
+    export class GamepadCamera extends FreeCamera {
+        private _gamepad: Gamepad;
+        private _gamepads: Gamepads;
+        public angularSensibility = 200;
+        public moveSensibility = 75;
+
+        constructor(name: string, position: Vector3, scene: Scene) {
+            super(name, position, scene);
+            this._gamepads = new Gamepads((gamepad: Gamepad) => { this._onNewGameConnected(gamepad); });
+        }
+
+        private _onNewGameConnected(gamepad: Gamepad) {
+            // Only the first gamepad can control the camera
+            if (gamepad.index === 0) {
+                this._gamepad = gamepad;
+            }
+        }
+
+        public _checkInputs(): void {
+            if (this._gamepad) {
+                var LSValues = this._gamepad.leftStick;
+                var normalizedLX = LSValues.x / this.moveSensibility;
+                var normalizedLY = LSValues.y / this.moveSensibility;
+                LSValues.x = Math.abs(normalizedLX) > 0.005 ? 0 + normalizedLX : 0;
+                LSValues.y = Math.abs(normalizedLY) > 0.005 ? 0 + normalizedLY : 0;
+
+                var RSValues = this._gamepad.rightStick;
+                var normalizedRX = RSValues.x / this.angularSensibility;
+                var normalizedRY = RSValues.y / this.angularSensibility;
+                RSValues.x = Math.abs(normalizedRX) > 0.001 ? 0 + normalizedRX : 0;
+                RSValues.y = Math.abs(normalizedRY) > 0.001 ? 0 + normalizedRY : 0;
+
+                var cameraTransform = Matrix.RotationYawPitchRoll(this.rotation.y, this.rotation.x, 0);
+
+                var speed = this._computeLocalCameraSpeed() * 50.0;
+                var deltaTransform = Vector3.TransformCoordinates(new Vector3(LSValues.x * speed, 0, -LSValues.y * speed), cameraTransform);
+                this.cameraDirection = this.cameraDirection.add(deltaTransform);
+                this.cameraRotation = this.cameraRotation.add(new Vector2(RSValues.y, RSValues.x));
+            }
+
+            super._checkInputs();
+        }
+
+        public dispose(): void {
+            this._gamepads.dispose();
+            super.dispose();
+        }
+    }
 }

+ 43 - 43
src/Cameras/babylon.stereoscopicCameras.ts

@@ -1,44 +1,44 @@
-module BABYLON {
-    export class AnaglyphFreeCamera extends FreeCamera {
-        constructor(name: string, position: Vector3, public interaxialDistance: number, scene: Scene) {
-            super(name, position, scene);
-            this.setCameraRigMode(Camera.RIG_MODE_STEREOSCOPIC_ANAGLYPH, { interaxialDistance: interaxialDistance });
-        }
-    }
-
-    export class AnaglyphArcRotateCamera extends ArcRotateCamera {
-        constructor(name: string, alpha: number, beta: number, radius: number, target, interaxialDistance: number, scene: Scene) {
-            super(name, alpha, beta, radius, target, scene);
-            this.setCameraRigMode(Camera.RIG_MODE_STEREOSCOPIC_ANAGLYPH, { interaxialDistance: interaxialDistance });
-        }
-    }
-
-    export class AnaglyphGamepadCamera extends GamepadCamera {
-        constructor(name: string, position: Vector3, interaxialDistance: number, scene: Scene) {
-            super(name, position, scene);
-            this.setCameraRigMode(Camera.RIG_MODE_STEREOSCOPIC_ANAGLYPH, { interaxialDistance: interaxialDistance });
-        }
-    }
-    
-    export class StereoscopicFreeCamera extends FreeCamera {
-        constructor(name: string, position: Vector3, interaxialDistance: number, isSideBySide: boolean, scene: Scene) {
-            super(name, position, scene);
-
-            this.setCameraRigMode(isSideBySide ? Camera.RIG_MODE_STEREOSCOPIC_SIDEBYSIDE_PARALLEL : Camera.RIG_MODE_STEREOSCOPIC_OVERUNDER, { interaxialDistance: interaxialDistance });
-        }
-    }
-
-    export class StereoscopicArcRotateCamera extends ArcRotateCamera {
-        constructor(name: string, alpha: number, beta: number, radius: number, target, interaxialDistance: number, isSideBySide: boolean, scene:Scene) {
-            super(name, alpha, beta, radius, target, scene);
-            this.setCameraRigMode(isSideBySide ? Camera.RIG_MODE_STEREOSCOPIC_SIDEBYSIDE_PARALLEL : Camera.RIG_MODE_STEREOSCOPIC_OVERUNDER, { interaxialDistance: interaxialDistance });
-        }
-    }
-
-    export class StereoscopicGamepadCamera extends GamepadCamera {
-        constructor(name: string, position: Vector3, interaxialDistance: number, isSideBySide: boolean, scene: Scene) {
-            super(name, position, scene);
-            this.setCameraRigMode(isSideBySide ? Camera.RIG_MODE_STEREOSCOPIC_SIDEBYSIDE_PARALLEL : Camera.RIG_MODE_STEREOSCOPIC_OVERUNDER, { interaxialDistance: interaxialDistance });
-        }
-    }
+module BABYLON {
+    export class AnaglyphFreeCamera extends FreeCamera {
+        constructor(name: string, position: Vector3, public interaxialDistance: number, scene: Scene) {
+            super(name, position, scene);
+            this.setCameraRigMode(Camera.RIG_MODE_STEREOSCOPIC_ANAGLYPH, { interaxialDistance: interaxialDistance });
+        }
+    }
+
+    export class AnaglyphArcRotateCamera extends ArcRotateCamera {
+        constructor(name: string, alpha: number, beta: number, radius: number, target, interaxialDistance: number, scene: Scene) {
+            super(name, alpha, beta, radius, target, scene);
+            this.setCameraRigMode(Camera.RIG_MODE_STEREOSCOPIC_ANAGLYPH, { interaxialDistance: interaxialDistance });
+        }
+    }
+
+    export class AnaglyphGamepadCamera extends GamepadCamera {
+        constructor(name: string, position: Vector3, interaxialDistance: number, scene: Scene) {
+            super(name, position, scene);
+            this.setCameraRigMode(Camera.RIG_MODE_STEREOSCOPIC_ANAGLYPH, { interaxialDistance: interaxialDistance });
+        }
+    }
+    
+    export class StereoscopicFreeCamera extends FreeCamera {
+        constructor(name: string, position: Vector3, interaxialDistance: number, isSideBySide: boolean, scene: Scene) {
+            super(name, position, scene);
+
+            this.setCameraRigMode(isSideBySide ? Camera.RIG_MODE_STEREOSCOPIC_SIDEBYSIDE_PARALLEL : Camera.RIG_MODE_STEREOSCOPIC_OVERUNDER, { interaxialDistance: interaxialDistance });
+        }
+    }
+
+    export class StereoscopicArcRotateCamera extends ArcRotateCamera {
+        constructor(name: string, alpha: number, beta: number, radius: number, target, interaxialDistance: number, isSideBySide: boolean, scene:Scene) {
+            super(name, alpha, beta, radius, target, scene);
+            this.setCameraRigMode(isSideBySide ? Camera.RIG_MODE_STEREOSCOPIC_SIDEBYSIDE_PARALLEL : Camera.RIG_MODE_STEREOSCOPIC_OVERUNDER, { interaxialDistance: interaxialDistance });
+        }
+    }
+
+    export class StereoscopicGamepadCamera extends GamepadCamera {
+        constructor(name: string, position: Vector3, interaxialDistance: number, isSideBySide: boolean, scene: Scene) {
+            super(name, position, scene);
+            this.setCameraRigMode(isSideBySide ? Camera.RIG_MODE_STEREOSCOPIC_SIDEBYSIDE_PARALLEL : Camera.RIG_MODE_STEREOSCOPIC_OVERUNDER, { interaxialDistance: interaxialDistance });
+        }
+    }
 } 

+ 314 - 314
src/Cameras/babylon.targetCamera.ts

@@ -1,315 +1,315 @@
-module BABYLON {
-    export class TargetCamera extends Camera {
-
-        public cameraDirection = new Vector3(0, 0, 0);
-        public cameraRotation = new Vector2(0, 0);
-        public rotation = new Vector3(0, 0, 0);
-
-        public speed = 2.0;
-        public noRotationConstraint = false;
-        public lockedTarget = null;
-
-        public _currentTarget = Vector3.Zero();
-        public _viewMatrix = Matrix.Zero();
-        public _camMatrix = Matrix.Zero();
-        public _cameraTransformMatrix = Matrix.Zero();
-        public _cameraRotationMatrix = Matrix.Zero();
-        private _rigCamTransformMatrix: Matrix;
-
-        public _referencePoint = new Vector3(0, 0, 1);
-        public _transformedReferencePoint = Vector3.Zero();
-        public _lookAtTemp = Matrix.Zero();
-        public _tempMatrix = Matrix.Zero();
-
-        public _reset: () => void;
-
-        public _waitingLockedTargetId: string;
-
-        constructor(name: string, position: Vector3, scene: Scene) {
-            super(name, position, scene);
-        }
-
-        public getFrontPosition(distance: number): Vector3 {
-            var direction = this.getTarget().subtract(this.position);
-            direction.normalize();
-            direction.scaleInPlace(distance);
-            return this.globalPosition.add(direction);
-        }
-
-        public _getLockedTargetPosition(): Vector3 {
-            if (!this.lockedTarget) {
-                return null;
-            }
-
-            return this.lockedTarget.position || this.lockedTarget;
-        }
-
-        // Cache
-        public _initCache() {
-            super._initCache();
-            this._cache.lockedTarget = new Vector3(Number.MAX_VALUE, Number.MAX_VALUE, Number.MAX_VALUE);
-            this._cache.rotation = new Vector3(Number.MAX_VALUE, Number.MAX_VALUE, Number.MAX_VALUE);
-        }
-
-        public _updateCache(ignoreParentClass?: boolean): void {
-            if (!ignoreParentClass) {
-                super._updateCache();
-            }
-
-            var lockedTargetPosition = this._getLockedTargetPosition();
-            if (!lockedTargetPosition) {
-                this._cache.lockedTarget = null;
-            }
-            else {
-                if (!this._cache.lockedTarget) {
-                    this._cache.lockedTarget = lockedTargetPosition.clone();
-                }
-                else {
-                    this._cache.lockedTarget.copyFrom(lockedTargetPosition);
-                }
-            }
-
-            this._cache.rotation.copyFrom(this.rotation);
-        }
-
-        // Synchronized
-        public _isSynchronizedViewMatrix(): boolean {
-            if (!super._isSynchronizedViewMatrix()) {
-                return false;
-            }
-
-            var lockedTargetPosition = this._getLockedTargetPosition();
-
-            return (this._cache.lockedTarget ? this._cache.lockedTarget.equals(lockedTargetPosition) : !lockedTargetPosition)
-                && this._cache.rotation.equals(this.rotation);
-        }
-
-        // Methods
-        public _computeLocalCameraSpeed(): number {
-            var engine = this.getEngine();
-            return this.speed * ((engine.getDeltaTime() / (engine.getFps() * 10.0)));
-        }
-
-        // Target
-        public setTarget(target: Vector3): void {
-            this.upVector.normalize();
-
-            Matrix.LookAtLHToRef(this.position, target, this.upVector, this._camMatrix);
-            this._camMatrix.invert();
-
-            this.rotation.x = Math.atan(this._camMatrix.m[6] / this._camMatrix.m[10]);
-
-            var vDir = target.subtract(this.position);
-
-            if (vDir.x >= 0.0) {
-                this.rotation.y = (-Math.atan(vDir.z / vDir.x) + Math.PI / 2.0);
-            } else {
-                this.rotation.y = (-Math.atan(vDir.z / vDir.x) - Math.PI / 2.0);
-            }
-
-            this.rotation.z = -Math.acos(Vector3.Dot(new Vector3(0, 1.0, 0), this.upVector));
-
-            if (isNaN(this.rotation.x)) {
-                this.rotation.x = 0;
-            }
-
-            if (isNaN(this.rotation.y)) {
-                this.rotation.y = 0;
-            }
-
-            if (isNaN(this.rotation.z)) {
-                this.rotation.z = 0;
-            }
-        }
-
-        public getTarget(): Vector3 {
-            return this._currentTarget;
-        }
-
-
-        public _decideIfNeedsToMove(): boolean {
-            return Math.abs(this.cameraDirection.x) > 0 || Math.abs(this.cameraDirection.y) > 0 || Math.abs(this.cameraDirection.z) > 0;
-        }
-
-        public _updatePosition(): void {
-            this.position.addInPlace(this.cameraDirection);
-        }
-        public _checkInputs(): void {
-            var needToMove = this._decideIfNeedsToMove();
-            var needToRotate = Math.abs(this.cameraRotation.x) > 0 || Math.abs(this.cameraRotation.y) > 0;
-
-            // Move
-            if (needToMove) {
-                this._updatePosition();
-            }
-
-            // Rotate
-            if (needToRotate) {
-                this.rotation.x += this.cameraRotation.x;
-                this.rotation.y += this.cameraRotation.y;
-
-
-                if (!this.noRotationConstraint) {
-                    var limit = (Math.PI / 2) * 0.95;
-
-
-                    if (this.rotation.x > limit)
-                        this.rotation.x = limit;
-                    if (this.rotation.x < -limit)
-                        this.rotation.x = -limit;
-                }
-            }
-
-            // Inertia
-            if (needToMove) {
-                if (Math.abs(this.cameraDirection.x) < Engine.Epsilon) {
-                    this.cameraDirection.x = 0;
-                }
-
-                if (Math.abs(this.cameraDirection.y) < Engine.Epsilon) {
-                    this.cameraDirection.y = 0;
-                }
-
-                if (Math.abs(this.cameraDirection.z) < Engine.Epsilon) {
-                    this.cameraDirection.z = 0;
-                }
-
-                this.cameraDirection.scaleInPlace(this.inertia);
-            }
-            if (needToRotate) {
-                if (Math.abs(this.cameraRotation.x) < Engine.Epsilon) {
-                    this.cameraRotation.x = 0;
-                }
-
-                if (Math.abs(this.cameraRotation.y) < Engine.Epsilon) {
-                    this.cameraRotation.y = 0;
-                }
-                this.cameraRotation.scaleInPlace(this.inertia);
-            }
-
-            super._checkInputs();
-        }
-
-
-        public _getViewMatrix(): Matrix {
-            if (!this.lockedTarget) {
-                // Compute
-                if (this.upVector.x !== 0 || this.upVector.y !== 1.0 || this.upVector.z !== 0) {
-                    Matrix.LookAtLHToRef(Vector3.Zero(), this._referencePoint, this.upVector, this._lookAtTemp);
-                    Matrix.RotationYawPitchRollToRef(this.rotation.y, this.rotation.x, this.rotation.z, this._cameraRotationMatrix);
-
-
-                    this._lookAtTemp.multiplyToRef(this._cameraRotationMatrix, this._tempMatrix);
-                    this._lookAtTemp.invert();
-                    this._tempMatrix.multiplyToRef(this._lookAtTemp, this._cameraRotationMatrix);
-                } else {
-                    Matrix.RotationYawPitchRollToRef(this.rotation.y, this.rotation.x, this.rotation.z, this._cameraRotationMatrix);
-                }
-
-                Vector3.TransformCoordinatesToRef(this._referencePoint, this._cameraRotationMatrix, this._transformedReferencePoint);
-
-                // Computing target and final matrix
-                this.position.addToRef(this._transformedReferencePoint, this._currentTarget);
-            } else {
-                this._currentTarget.copyFrom(this._getLockedTargetPosition());
-            }
-
-            Matrix.LookAtLHToRef(this.position, this._currentTarget, this.upVector, this._viewMatrix);
-            return this._viewMatrix;
-        }
-
-        public _getVRViewMatrix(): Matrix {
-            Matrix.RotationYawPitchRollToRef(this.rotation.y, this.rotation.x, this.rotation.z, this._cameraRotationMatrix);
-
-            Vector3.TransformCoordinatesToRef(this._referencePoint, this._cameraRotationMatrix, this._transformedReferencePoint);
-            Vector3.TransformNormalToRef(this.upVector, this._cameraRotationMatrix, this._cameraRigParams.vrActualUp);
-
-            // Computing target and final matrix
-            this.position.addToRef(this._transformedReferencePoint, this._currentTarget);
-
-            Matrix.LookAtLHToRef(this.position, this._currentTarget, this._cameraRigParams.vrActualUp, this._cameraRigParams.vrWorkMatrix);
-
-            this._cameraRigParams.vrWorkMatrix.multiplyToRef(this._cameraRigParams.vrPreViewMatrix, this._viewMatrix);
-            return this._viewMatrix;
-        }
-        
-        /**
-         * @override
-         * Override Camera.createRigCamera
-         */
-        public createRigCamera(name: string, cameraIndex: number): Camera {
-            if (this.cameraRigMode !== Camera.RIG_MODE_NONE) {
-                var rigCamera = new TargetCamera(name, this.position.clone(), this.getScene());
-                if (this.cameraRigMode === Camera.RIG_MODE_VR) {
-                    rigCamera._cameraRigParams = {};
-                    rigCamera._cameraRigParams.vrActualUp = new Vector3(0, 0, 0);
-                    rigCamera._getViewMatrix = rigCamera._getVRViewMatrix;
-                }
-                return rigCamera;
-            }
-            return null;
-        }
-        
-        /**
-         * @override
-         * Override Camera._updateRigCameras
-         */
-        public _updateRigCameras() {
-            switch (this.cameraRigMode) {
-                case Camera.RIG_MODE_STEREOSCOPIC_ANAGLYPH:
-                case Camera.RIG_MODE_STEREOSCOPIC_SIDEBYSIDE_PARALLEL:
-                case Camera.RIG_MODE_STEREOSCOPIC_SIDEBYSIDE_CROSSEYED:
-                case Camera.RIG_MODE_STEREOSCOPIC_OVERUNDER:
-                case Camera.RIG_MODE_VR:
-                    var camLeft = <TargetCamera> this._rigCameras[0];
-                    var camRight = <TargetCamera> this._rigCameras[1];
-
-                    if (this.cameraRigMode === Camera.RIG_MODE_VR) {
-                        camLeft.rotation.x = camRight.rotation.x = this.rotation.x;
-                        camLeft.rotation.y = camRight.rotation.y = this.rotation.y;
-                        camLeft.rotation.z = camRight.rotation.z = this.rotation.z;
-
-                        camLeft.position.copyFrom(this.position);
-                        camRight.position.copyFrom(this.position);
-
-                    } else {
-                        //provisionnaly using _cameraRigParams.stereoHalfAngle instead of calculations based on _cameraRigParams.interaxialDistance:
-                        this._getRigCamPosition(-this._cameraRigParams.stereoHalfAngle, camLeft.position);
-                        this._getRigCamPosition(this._cameraRigParams.stereoHalfAngle, camRight.position);
-
-                        camLeft.setTarget(this.getTarget());
-                        camRight.setTarget(this.getTarget());
-                    }
-                    break;
-            }
-            super._updateRigCameras();
-        }
-
-        private _getRigCamPosition(halfSpace: number, result: Vector3) {
-            if (!this._rigCamTransformMatrix) {
-                this._rigCamTransformMatrix = new Matrix();
-            }
-            var target = this.getTarget();
-            Matrix.Translation(-target.x, -target.y, -target.z).multiplyToRef(Matrix.RotationY(halfSpace), this._rigCamTransformMatrix);
-
-            this._rigCamTransformMatrix = this._rigCamTransformMatrix.multiply(Matrix.Translation(target.x, target.y, target.z));
-
-            Vector3.TransformCoordinatesToRef(this.position, this._rigCamTransformMatrix, result);
-        }
-
-        public serialize(): any {
-            var serializationObject = super.serialize();
-            serializationObject.speed = this.speed;
-
-            if (this.rotation) {
-                serializationObject.rotation = this.rotation.asArray();
-            }
-
-            if (this.lockedTarget && this.lockedTarget.id) {
-                serializationObject.lockedTargetId = this.lockedTarget.id;
-            }
-
-            return serializationObject;
-        }
-    }
+module BABYLON {
+    export class TargetCamera extends Camera {
+
+        public cameraDirection = new Vector3(0, 0, 0);
+        public cameraRotation = new Vector2(0, 0);
+        public rotation = new Vector3(0, 0, 0);
+
+        public speed = 2.0;
+        public noRotationConstraint = false;
+        public lockedTarget = null;
+
+        public _currentTarget = Vector3.Zero();
+        public _viewMatrix = Matrix.Zero();
+        public _camMatrix = Matrix.Zero();
+        public _cameraTransformMatrix = Matrix.Zero();
+        public _cameraRotationMatrix = Matrix.Zero();
+        private _rigCamTransformMatrix: Matrix;
+
+        public _referencePoint = new Vector3(0, 0, 1);
+        public _transformedReferencePoint = Vector3.Zero();
+        public _lookAtTemp = Matrix.Zero();
+        public _tempMatrix = Matrix.Zero();
+
+        public _reset: () => void;
+
+        public _waitingLockedTargetId: string;
+
+        constructor(name: string, position: Vector3, scene: Scene) {
+            super(name, position, scene);
+        }
+
+        public getFrontPosition(distance: number): Vector3 {
+            var direction = this.getTarget().subtract(this.position);
+            direction.normalize();
+            direction.scaleInPlace(distance);
+            return this.globalPosition.add(direction);
+        }
+
+        public _getLockedTargetPosition(): Vector3 {
+            if (!this.lockedTarget) {
+                return null;
+            }
+
+            return this.lockedTarget.position || this.lockedTarget;
+        }
+
+        // Cache
+        public _initCache() {
+            super._initCache();
+            this._cache.lockedTarget = new Vector3(Number.MAX_VALUE, Number.MAX_VALUE, Number.MAX_VALUE);
+            this._cache.rotation = new Vector3(Number.MAX_VALUE, Number.MAX_VALUE, Number.MAX_VALUE);
+        }
+
+        public _updateCache(ignoreParentClass?: boolean): void {
+            if (!ignoreParentClass) {
+                super._updateCache();
+            }
+
+            var lockedTargetPosition = this._getLockedTargetPosition();
+            if (!lockedTargetPosition) {
+                this._cache.lockedTarget = null;
+            }
+            else {
+                if (!this._cache.lockedTarget) {
+                    this._cache.lockedTarget = lockedTargetPosition.clone();
+                }
+                else {
+                    this._cache.lockedTarget.copyFrom(lockedTargetPosition);
+                }
+            }
+
+            this._cache.rotation.copyFrom(this.rotation);
+        }
+
+        // Synchronized
+        public _isSynchronizedViewMatrix(): boolean {
+            if (!super._isSynchronizedViewMatrix()) {
+                return false;
+            }
+
+            var lockedTargetPosition = this._getLockedTargetPosition();
+
+            return (this._cache.lockedTarget ? this._cache.lockedTarget.equals(lockedTargetPosition) : !lockedTargetPosition)
+                && this._cache.rotation.equals(this.rotation);
+        }
+
+        // Methods
+        public _computeLocalCameraSpeed(): number {
+            var engine = this.getEngine();
+            return this.speed * ((engine.getDeltaTime() / (engine.getFps() * 10.0)));
+        }
+
+        // Target
+        public setTarget(target: Vector3): void {
+            this.upVector.normalize();
+
+            Matrix.LookAtLHToRef(this.position, target, this.upVector, this._camMatrix);
+            this._camMatrix.invert();
+
+            this.rotation.x = Math.atan(this._camMatrix.m[6] / this._camMatrix.m[10]);
+
+            var vDir = target.subtract(this.position);
+
+            if (vDir.x >= 0.0) {
+                this.rotation.y = (-Math.atan(vDir.z / vDir.x) + Math.PI / 2.0);
+            } else {
+                this.rotation.y = (-Math.atan(vDir.z / vDir.x) - Math.PI / 2.0);
+            }
+
+            this.rotation.z = -Math.acos(Vector3.Dot(new Vector3(0, 1.0, 0), this.upVector));
+
+            if (isNaN(this.rotation.x)) {
+                this.rotation.x = 0;
+            }
+
+            if (isNaN(this.rotation.y)) {
+                this.rotation.y = 0;
+            }
+
+            if (isNaN(this.rotation.z)) {
+                this.rotation.z = 0;
+            }
+        }
+
+        public getTarget(): Vector3 {
+            return this._currentTarget;
+        }
+
+
+        public _decideIfNeedsToMove(): boolean {
+            return Math.abs(this.cameraDirection.x) > 0 || Math.abs(this.cameraDirection.y) > 0 || Math.abs(this.cameraDirection.z) > 0;
+        }
+
+        public _updatePosition(): void {
+            this.position.addInPlace(this.cameraDirection);
+        }
+        public _checkInputs(): void {
+            var needToMove = this._decideIfNeedsToMove();
+            var needToRotate = Math.abs(this.cameraRotation.x) > 0 || Math.abs(this.cameraRotation.y) > 0;
+
+            // Move
+            if (needToMove) {
+                this._updatePosition();
+            }
+
+            // Rotate
+            if (needToRotate) {
+                this.rotation.x += this.cameraRotation.x;
+                this.rotation.y += this.cameraRotation.y;
+
+
+                if (!this.noRotationConstraint) {
+                    var limit = (Math.PI / 2) * 0.95;
+
+
+                    if (this.rotation.x > limit)
+                        this.rotation.x = limit;
+                    if (this.rotation.x < -limit)
+                        this.rotation.x = -limit;
+                }
+            }
+
+            // Inertia
+            if (needToMove) {
+                if (Math.abs(this.cameraDirection.x) < Engine.Epsilon) {
+                    this.cameraDirection.x = 0;
+                }
+
+                if (Math.abs(this.cameraDirection.y) < Engine.Epsilon) {
+                    this.cameraDirection.y = 0;
+                }
+
+                if (Math.abs(this.cameraDirection.z) < Engine.Epsilon) {
+                    this.cameraDirection.z = 0;
+                }
+
+                this.cameraDirection.scaleInPlace(this.inertia);
+            }
+            if (needToRotate) {
+                if (Math.abs(this.cameraRotation.x) < Engine.Epsilon) {
+                    this.cameraRotation.x = 0;
+                }
+
+                if (Math.abs(this.cameraRotation.y) < Engine.Epsilon) {
+                    this.cameraRotation.y = 0;
+                }
+                this.cameraRotation.scaleInPlace(this.inertia);
+            }
+
+            super._checkInputs();
+        }
+
+
+        public _getViewMatrix(): Matrix {
+            if (!this.lockedTarget) {
+                // Compute
+                if (this.upVector.x !== 0 || this.upVector.y !== 1.0 || this.upVector.z !== 0) {
+                    Matrix.LookAtLHToRef(Vector3.Zero(), this._referencePoint, this.upVector, this._lookAtTemp);
+                    Matrix.RotationYawPitchRollToRef(this.rotation.y, this.rotation.x, this.rotation.z, this._cameraRotationMatrix);
+
+
+                    this._lookAtTemp.multiplyToRef(this._cameraRotationMatrix, this._tempMatrix);
+                    this._lookAtTemp.invert();
+                    this._tempMatrix.multiplyToRef(this._lookAtTemp, this._cameraRotationMatrix);
+                } else {
+                    Matrix.RotationYawPitchRollToRef(this.rotation.y, this.rotation.x, this.rotation.z, this._cameraRotationMatrix);
+                }
+
+                Vector3.TransformCoordinatesToRef(this._referencePoint, this._cameraRotationMatrix, this._transformedReferencePoint);
+
+                // Computing target and final matrix
+                this.position.addToRef(this._transformedReferencePoint, this._currentTarget);
+            } else {
+                this._currentTarget.copyFrom(this._getLockedTargetPosition());
+            }
+
+            Matrix.LookAtLHToRef(this.position, this._currentTarget, this.upVector, this._viewMatrix);
+            return this._viewMatrix;
+        }
+
+        public _getVRViewMatrix(): Matrix {
+            Matrix.RotationYawPitchRollToRef(this.rotation.y, this.rotation.x, this.rotation.z, this._cameraRotationMatrix);
+
+            Vector3.TransformCoordinatesToRef(this._referencePoint, this._cameraRotationMatrix, this._transformedReferencePoint);
+            Vector3.TransformNormalToRef(this.upVector, this._cameraRotationMatrix, this._cameraRigParams.vrActualUp);
+
+            // Computing target and final matrix
+            this.position.addToRef(this._transformedReferencePoint, this._currentTarget);
+
+            Matrix.LookAtLHToRef(this.position, this._currentTarget, this._cameraRigParams.vrActualUp, this._cameraRigParams.vrWorkMatrix);
+
+            this._cameraRigParams.vrWorkMatrix.multiplyToRef(this._cameraRigParams.vrPreViewMatrix, this._viewMatrix);
+            return this._viewMatrix;
+        }
+        
+        /**
+         * @override
+         * Override Camera.createRigCamera
+         */
+        public createRigCamera(name: string, cameraIndex: number): Camera {
+            if (this.cameraRigMode !== Camera.RIG_MODE_NONE) {
+                var rigCamera = new TargetCamera(name, this.position.clone(), this.getScene());
+                if (this.cameraRigMode === Camera.RIG_MODE_VR) {
+                    rigCamera._cameraRigParams = {};
+                    rigCamera._cameraRigParams.vrActualUp = new Vector3(0, 0, 0);
+                    rigCamera._getViewMatrix = rigCamera._getVRViewMatrix;
+                }
+                return rigCamera;
+            }
+            return null;
+        }
+        
+        /**
+         * @override
+         * Override Camera._updateRigCameras
+         */
+        public _updateRigCameras() {
+            switch (this.cameraRigMode) {
+                case Camera.RIG_MODE_STEREOSCOPIC_ANAGLYPH:
+                case Camera.RIG_MODE_STEREOSCOPIC_SIDEBYSIDE_PARALLEL:
+                case Camera.RIG_MODE_STEREOSCOPIC_SIDEBYSIDE_CROSSEYED:
+                case Camera.RIG_MODE_STEREOSCOPIC_OVERUNDER:
+                case Camera.RIG_MODE_VR:
+                    var camLeft = <TargetCamera> this._rigCameras[0];
+                    var camRight = <TargetCamera> this._rigCameras[1];
+
+                    if (this.cameraRigMode === Camera.RIG_MODE_VR) {
+                        camLeft.rotation.x = camRight.rotation.x = this.rotation.x;
+                        camLeft.rotation.y = camRight.rotation.y = this.rotation.y;
+                        camLeft.rotation.z = camRight.rotation.z = this.rotation.z;
+
+                        camLeft.position.copyFrom(this.position);
+                        camRight.position.copyFrom(this.position);
+
+                    } else {
+                        //provisionnaly using _cameraRigParams.stereoHalfAngle instead of calculations based on _cameraRigParams.interaxialDistance:
+                        this._getRigCamPosition(-this._cameraRigParams.stereoHalfAngle, camLeft.position);
+                        this._getRigCamPosition(this._cameraRigParams.stereoHalfAngle, camRight.position);
+
+                        camLeft.setTarget(this.getTarget());
+                        camRight.setTarget(this.getTarget());
+                    }
+                    break;
+            }
+            super._updateRigCameras();
+        }
+
+        private _getRigCamPosition(halfSpace: number, result: Vector3) {
+            if (!this._rigCamTransformMatrix) {
+                this._rigCamTransformMatrix = new Matrix();
+            }
+            var target = this.getTarget();
+            Matrix.Translation(-target.x, -target.y, -target.z).multiplyToRef(Matrix.RotationY(halfSpace), this._rigCamTransformMatrix);
+
+            this._rigCamTransformMatrix = this._rigCamTransformMatrix.multiply(Matrix.Translation(target.x, target.y, target.z));
+
+            Vector3.TransformCoordinatesToRef(this.position, this._rigCamTransformMatrix, result);
+        }
+
+        public serialize(): any {
+            var serializationObject = super.serialize();
+            serializationObject.speed = this.speed;
+
+            if (this.rotation) {
+                serializationObject.rotation = this.rotation.asArray();
+            }
+
+            if (this.lockedTarget && this.lockedTarget.id) {
+                serializationObject.lockedTargetId = this.lockedTarget.id;
+            }
+
+            return serializationObject;
+        }
+    }
 } 

+ 49 - 49
src/Cameras/babylon.virtualJoysticksCamera.ts

@@ -1,50 +1,50 @@
-module BABYLON {
-    // We're mainly based on the logic defined into the FreeCamera code
-    export class VirtualJoysticksCamera extends FreeCamera {
-        private _leftjoystick: VirtualJoystick;
-        private _rightjoystick: VirtualJoystick;
-
-        constructor(name: string, position: Vector3, scene: Scene) {
-            super(name, position, scene);
-            this._leftjoystick = new VirtualJoystick(true);
-            this._leftjoystick.setAxisForUpDown(JoystickAxis.Z);
-            this._leftjoystick.setAxisForLeftRight(JoystickAxis.X);
-            this._leftjoystick.setJoystickSensibility(0.15);
-            this._rightjoystick = new VirtualJoystick(false);
-            this._rightjoystick.setAxisForUpDown(JoystickAxis.X);
-            this._rightjoystick.setAxisForLeftRight(JoystickAxis.Y);
-            this._rightjoystick.reverseUpDown = true;
-            this._rightjoystick.setJoystickSensibility(0.05);
-            this._rightjoystick.setJoystickColor("yellow");
-        }
-
-        public getLeftJoystick(): VirtualJoystick {
-            return this._leftjoystick;
-        }
-
-        public getRightJoystick(): VirtualJoystick {
-            return this._rightjoystick;
-        }
-
-        public _checkInputs(): void {
-            var speed = this._computeLocalCameraSpeed() * 50;
-            var cameraTransform = Matrix.RotationYawPitchRoll(this.rotation.y, this.rotation.x, 0);
-            var deltaTransform = Vector3.TransformCoordinates(new Vector3(this._leftjoystick.deltaPosition.x * speed, this._leftjoystick.deltaPosition.y * speed, this._leftjoystick.deltaPosition.z * speed), cameraTransform);
-            this.cameraDirection = this.cameraDirection.add(deltaTransform);
-            this.cameraRotation = this.cameraRotation.addVector3(this._rightjoystick.deltaPosition);
-            if (!this._leftjoystick.pressed) {
-                this._leftjoystick.deltaPosition = this._leftjoystick.deltaPosition.scale(0.9);
-            }
-            if (!this._rightjoystick.pressed) {
-                this._rightjoystick.deltaPosition = this._rightjoystick.deltaPosition.scale(0.9);
-            }
-
-            super._checkInputs();
-        }
-
-        public dispose(): void {
-            this._leftjoystick.releaseCanvas();
-            super.dispose();
-        }
-    }
+module BABYLON {
+    // We're mainly based on the logic defined into the FreeCamera code
+    export class VirtualJoysticksCamera extends FreeCamera {
+        private _leftjoystick: VirtualJoystick;
+        private _rightjoystick: VirtualJoystick;
+
+        constructor(name: string, position: Vector3, scene: Scene) {
+            super(name, position, scene);
+            this._leftjoystick = new VirtualJoystick(true);
+            this._leftjoystick.setAxisForUpDown(JoystickAxis.Z);
+            this._leftjoystick.setAxisForLeftRight(JoystickAxis.X);
+            this._leftjoystick.setJoystickSensibility(0.15);
+            this._rightjoystick = new VirtualJoystick(false);
+            this._rightjoystick.setAxisForUpDown(JoystickAxis.X);
+            this._rightjoystick.setAxisForLeftRight(JoystickAxis.Y);
+            this._rightjoystick.reverseUpDown = true;
+            this._rightjoystick.setJoystickSensibility(0.05);
+            this._rightjoystick.setJoystickColor("yellow");
+        }
+
+        public getLeftJoystick(): VirtualJoystick {
+            return this._leftjoystick;
+        }
+
+        public getRightJoystick(): VirtualJoystick {
+            return this._rightjoystick;
+        }
+
+        public _checkInputs(): void {
+            var speed = this._computeLocalCameraSpeed() * 50;
+            var cameraTransform = Matrix.RotationYawPitchRoll(this.rotation.y, this.rotation.x, 0);
+            var deltaTransform = Vector3.TransformCoordinates(new Vector3(this._leftjoystick.deltaPosition.x * speed, this._leftjoystick.deltaPosition.y * speed, this._leftjoystick.deltaPosition.z * speed), cameraTransform);
+            this.cameraDirection = this.cameraDirection.add(deltaTransform);
+            this.cameraRotation = this.cameraRotation.addVector3(this._rightjoystick.deltaPosition);
+            if (!this._leftjoystick.pressed) {
+                this._leftjoystick.deltaPosition = this._leftjoystick.deltaPosition.scale(0.9);
+            }
+            if (!this._rightjoystick.pressed) {
+                this._rightjoystick.deltaPosition = this._rightjoystick.deltaPosition.scale(0.9);
+            }
+
+            super._checkInputs();
+        }
+
+        public dispose(): void {
+            this._leftjoystick.releaseCanvas();
+            super.dispose();
+        }
+    }
 }

+ 345 - 345
src/Collisions/babylon.collider.ts

@@ -1,346 +1,346 @@
-module BABYLON {
-    var intersectBoxAASphere = (boxMin: Vector3, boxMax: Vector3, sphereCenter: Vector3, sphereRadius: number): boolean => {
-        if (boxMin.x > sphereCenter.x + sphereRadius)
-            return false;
-
-        if (sphereCenter.x - sphereRadius > boxMax.x)
-            return false;
-
-        if (boxMin.y > sphereCenter.y + sphereRadius)
-            return false;
-
-        if (sphereCenter.y - sphereRadius > boxMax.y)
-            return false;
-
-        if (boxMin.z > sphereCenter.z + sphereRadius)
-            return false;
-
-        if (sphereCenter.z - sphereRadius > boxMax.z)
-            return false;
-
-        return true;
-    };
-
-    var getLowestRoot = (a: number, b: number, c: number, maxR: number) => {
-        var determinant = b * b - 4.0 * a * c;
-        var result = { root: 0, found: false };
-
-        if (determinant < 0)
-            return result;
-
-        var sqrtD = Math.sqrt(determinant);
-        var r1 = (-b - sqrtD) / (2.0 * a);
-        var r2 = (-b + sqrtD) / (2.0 * a);
-
-        if (r1 > r2) {
-            var temp = r2;
-            r2 = r1;
-            r1 = temp;
-        }
-
-        if (r1 > 0 && r1 < maxR) {
-            result.root = r1;
-            result.found = true;
-            return result;
-        }
-
-        if (r2 > 0 && r2 < maxR) {
-            result.root = r2;
-            result.found = true;
-            return result;
-        }
-
-        return result;
-    };
-
-    export class Collider {
-        public radius = new Vector3(1, 1, 1);
-        public retry = 0;
-        public velocity: Vector3;
-        public basePoint: Vector3;
-        public epsilon: number;
-        public collisionFound: boolean;
-        public velocityWorldLength: number;
-        public basePointWorld = Vector3.Zero();
-        public velocityWorld = Vector3.Zero();
-        public normalizedVelocity = Vector3.Zero();
-        public initialVelocity: Vector3;
-        public initialPosition: Vector3;
-        public nearestDistance: number;
-        public intersectionPoint: Vector3;
-        public collidedMesh: AbstractMesh;
-
-        private _collisionPoint = Vector3.Zero();
-        private _planeIntersectionPoint = Vector3.Zero();
-        private _tempVector = Vector3.Zero();
-        private _tempVector2 = Vector3.Zero();
-        private _tempVector3 = Vector3.Zero();
-        private _tempVector4 = Vector3.Zero();
-        private _edge = Vector3.Zero();
-        private _baseToVertex = Vector3.Zero();
-        private _destinationPoint = Vector3.Zero();
-        private _slidePlaneNormal = Vector3.Zero();
-        private _displacementVector = Vector3.Zero();
-
-        // Methods
-        public _initialize(source: Vector3, dir: Vector3, e: number): void {
-            this.velocity = dir;
-            Vector3.NormalizeToRef(dir, this.normalizedVelocity);
-            this.basePoint = source;
-
-            source.multiplyToRef(this.radius, this.basePointWorld);
-            dir.multiplyToRef(this.radius, this.velocityWorld);
-
-            this.velocityWorldLength = this.velocityWorld.length();
-
-            this.epsilon = e;
-            this.collisionFound = false;
-        }
-
-        public _checkPointInTriangle(point: Vector3, pa: Vector3, pb: Vector3, pc: Vector3, n: Vector3): boolean {
-            pa.subtractToRef(point, this._tempVector);
-            pb.subtractToRef(point, this._tempVector2);
-
-            Vector3.CrossToRef(this._tempVector, this._tempVector2, this._tempVector4);
-            var d = Vector3.Dot(this._tempVector4, n);
-            if (d < 0)
-                return false;
-
-            pc.subtractToRef(point, this._tempVector3);
-            Vector3.CrossToRef(this._tempVector2, this._tempVector3, this._tempVector4);
-            d = Vector3.Dot(this._tempVector4, n);
-            if (d < 0)
-                return false;
-
-            Vector3.CrossToRef(this._tempVector3, this._tempVector, this._tempVector4);
-            d = Vector3.Dot(this._tempVector4, n);
-            return d >= 0;
-        }
-
-        public _canDoCollision(sphereCenter: Vector3, sphereRadius: number, vecMin: Vector3, vecMax: Vector3): boolean {
-            var distance = Vector3.Distance(this.basePointWorld, sphereCenter);
-
-            var max = Math.max(this.radius.x, this.radius.y, this.radius.z);
-
-            if (distance > this.velocityWorldLength + max + sphereRadius) {
-                return false;
-            }
-
-            if (!intersectBoxAASphere(vecMin, vecMax, this.basePointWorld, this.velocityWorldLength + max))
-                return false;
-
-            return true;
-        }
-
-        public _testTriangle(faceIndex: number, trianglePlaneArray: Array<Plane>, p1: Vector3, p2: Vector3, p3: Vector3, hasMaterial: boolean): void {
-            var t0;
-            var embeddedInPlane = false;
-
-            //defensive programming, actually not needed.
-            if (!trianglePlaneArray) {
-                trianglePlaneArray = [];
-            }
-
-            if (!trianglePlaneArray[faceIndex]) {
-                trianglePlaneArray[faceIndex] = new Plane(0, 0, 0, 0);
-                trianglePlaneArray[faceIndex].copyFromPoints(p1, p2, p3);
-            }
-
-            var trianglePlane = trianglePlaneArray[faceIndex];
-
-            if ((!hasMaterial) && !trianglePlane.isFrontFacingTo(this.normalizedVelocity, 0))
-                return;
-
-            var signedDistToTrianglePlane = trianglePlane.signedDistanceTo(this.basePoint);
-            var normalDotVelocity = Vector3.Dot(trianglePlane.normal, this.velocity);
-
-            if (normalDotVelocity == 0) {
-                if (Math.abs(signedDistToTrianglePlane) >= 1.0)
-                    return;
-                embeddedInPlane = true;
-                t0 = 0;
-            }
-            else {
-                t0 = (-1.0 - signedDistToTrianglePlane) / normalDotVelocity;
-                var t1 = (1.0 - signedDistToTrianglePlane) / normalDotVelocity;
-
-                if (t0 > t1) {
-                    var temp = t1;
-                    t1 = t0;
-                    t0 = temp;
-                }
-
-                if (t0 > 1.0 || t1 < 0.0)
-                    return;
-
-                if (t0 < 0)
-                    t0 = 0;
-                if (t0 > 1.0)
-                    t0 = 1.0;
-            }
-
-            this._collisionPoint.copyFromFloats(0, 0, 0);
-
-            var found = false;
-            var t = 1.0;
-
-            if (!embeddedInPlane) {
-                this.basePoint.subtractToRef(trianglePlane.normal, this._planeIntersectionPoint);
-                this.velocity.scaleToRef(t0, this._tempVector);
-                this._planeIntersectionPoint.addInPlace(this._tempVector);
-
-                if (this._checkPointInTriangle(this._planeIntersectionPoint, p1, p2, p3, trianglePlane.normal)) {
-                    found = true;
-                    t = t0;
-                    this._collisionPoint.copyFrom(this._planeIntersectionPoint);
-                }
-            }
-
-            if (!found) {
-                var velocitySquaredLength = this.velocity.lengthSquared();
-
-                var a = velocitySquaredLength;
-
-                this.basePoint.subtractToRef(p1, this._tempVector);
-                var b = 2.0 * (Vector3.Dot(this.velocity, this._tempVector));
-                var c = this._tempVector.lengthSquared() - 1.0;
-
-                var lowestRoot = getLowestRoot(a, b, c, t);
-                if (lowestRoot.found) {
-                    t = lowestRoot.root;
-                    found = true;
-                    this._collisionPoint.copyFrom(p1);
-                }
-
-                this.basePoint.subtractToRef(p2, this._tempVector);
-                b = 2.0 * (Vector3.Dot(this.velocity, this._tempVector));
-                c = this._tempVector.lengthSquared() - 1.0;
-
-                lowestRoot = getLowestRoot(a, b, c, t);
-                if (lowestRoot.found) {
-                    t = lowestRoot.root;
-                    found = true;
-                    this._collisionPoint.copyFrom(p2);
-                }
-
-                this.basePoint.subtractToRef(p3, this._tempVector);
-                b = 2.0 * (Vector3.Dot(this.velocity, this._tempVector));
-                c = this._tempVector.lengthSquared() - 1.0;
-
-                lowestRoot = getLowestRoot(a, b, c, t);
-                if (lowestRoot.found) {
-                    t = lowestRoot.root;
-                    found = true;
-                    this._collisionPoint.copyFrom(p3);
-                }
-
-                p2.subtractToRef(p1, this._edge);
-                p1.subtractToRef(this.basePoint, this._baseToVertex);
-                var edgeSquaredLength = this._edge.lengthSquared();
-                var edgeDotVelocity = Vector3.Dot(this._edge, this.velocity);
-                var edgeDotBaseToVertex = Vector3.Dot(this._edge, this._baseToVertex);
-
-                a = edgeSquaredLength * (-velocitySquaredLength) + edgeDotVelocity * edgeDotVelocity;
-                b = edgeSquaredLength * (2.0 * Vector3.Dot(this.velocity, this._baseToVertex)) - 2.0 * edgeDotVelocity * edgeDotBaseToVertex;
-                c = edgeSquaredLength * (1.0 - this._baseToVertex.lengthSquared()) + edgeDotBaseToVertex * edgeDotBaseToVertex;
-
-                lowestRoot = getLowestRoot(a, b, c, t);
-                if (lowestRoot.found) {
-                    var f = (edgeDotVelocity * lowestRoot.root - edgeDotBaseToVertex) / edgeSquaredLength;
-
-                    if (f >= 0.0 && f <= 1.0) {
-                        t = lowestRoot.root;
-                        found = true;
-                        this._edge.scaleInPlace(f);
-                        p1.addToRef(this._edge, this._collisionPoint);
-                    }
-                }
-
-                p3.subtractToRef(p2, this._edge);
-                p2.subtractToRef(this.basePoint, this._baseToVertex);
-                edgeSquaredLength = this._edge.lengthSquared();
-                edgeDotVelocity = Vector3.Dot(this._edge, this.velocity);
-                edgeDotBaseToVertex = Vector3.Dot(this._edge, this._baseToVertex);
-
-                a = edgeSquaredLength * (-velocitySquaredLength) + edgeDotVelocity * edgeDotVelocity;
-                b = edgeSquaredLength * (2.0 * Vector3.Dot(this.velocity, this._baseToVertex)) - 2.0 * edgeDotVelocity * edgeDotBaseToVertex;
-                c = edgeSquaredLength * (1.0 - this._baseToVertex.lengthSquared()) + edgeDotBaseToVertex * edgeDotBaseToVertex;
-                lowestRoot = getLowestRoot(a, b, c, t);
-                if (lowestRoot.found) {
-                    f = (edgeDotVelocity * lowestRoot.root - edgeDotBaseToVertex) / edgeSquaredLength;
-
-                    if (f >= 0.0 && f <= 1.0) {
-                        t = lowestRoot.root;
-                        found = true;
-                        this._edge.scaleInPlace(f);
-                        p2.addToRef(this._edge, this._collisionPoint);
-                    }
-                }
-
-                p1.subtractToRef(p3, this._edge);
-                p3.subtractToRef(this.basePoint, this._baseToVertex);
-                edgeSquaredLength = this._edge.lengthSquared();
-                edgeDotVelocity = Vector3.Dot(this._edge, this.velocity);
-                edgeDotBaseToVertex = Vector3.Dot(this._edge, this._baseToVertex);
-
-                a = edgeSquaredLength * (-velocitySquaredLength) + edgeDotVelocity * edgeDotVelocity;
-                b = edgeSquaredLength * (2.0 * Vector3.Dot(this.velocity, this._baseToVertex)) - 2.0 * edgeDotVelocity * edgeDotBaseToVertex;
-                c = edgeSquaredLength * (1.0 - this._baseToVertex.lengthSquared()) + edgeDotBaseToVertex * edgeDotBaseToVertex;
-
-                lowestRoot = getLowestRoot(a, b, c, t);
-                if (lowestRoot.found) {
-                    f = (edgeDotVelocity * lowestRoot.root - edgeDotBaseToVertex) / edgeSquaredLength;
-
-                    if (f >= 0.0 && f <= 1.0) {
-                        t = lowestRoot.root;
-                        found = true;
-                        this._edge.scaleInPlace(f);
-                        p3.addToRef(this._edge, this._collisionPoint);
-                    }
-                }
-            }
-
-            if (found) {
-                var distToCollision = t * this.velocity.length();
-
-                if (!this.collisionFound || distToCollision < this.nearestDistance) {
-                    if (!this.intersectionPoint) {
-                        this.intersectionPoint = this._collisionPoint.clone();
-                    } else {
-                        this.intersectionPoint.copyFrom(this._collisionPoint);
-                    }
-                    this.nearestDistance = distToCollision;
-                    this.collisionFound = true;
-                }
-            }
-        }
-
-        public _collide(trianglePlaneArray: Array<Plane>, pts: Vector3[], indices: number[] | Int32Array, indexStart: number, indexEnd: number, decal: number, hasMaterial: boolean): void {
-            for (var i = indexStart; i < indexEnd; i += 3) {
-                var p1 = pts[indices[i] - decal];
-                var p2 = pts[indices[i + 1] - decal];
-                var p3 = pts[indices[i + 2] - decal];
-
-                this._testTriangle(i, trianglePlaneArray, p3, p2, p1, hasMaterial);
-            }
-        }
-
-        public _getResponse(pos: Vector3, vel: Vector3): void {
-            pos.addToRef(vel, this._destinationPoint);
-            vel.scaleInPlace((this.nearestDistance / vel.length()));
-
-            this.basePoint.addToRef(vel, pos);
-            pos.subtractToRef(this.intersectionPoint, this._slidePlaneNormal);
-            this._slidePlaneNormal.normalize();
-            this._slidePlaneNormal.scaleToRef(this.epsilon, this._displacementVector);
-
-            pos.addInPlace(this._displacementVector);
-            this.intersectionPoint.addInPlace(this._displacementVector);
-
-            this._slidePlaneNormal.scaleInPlace(Plane.SignedDistanceToPlaneFromPositionAndNormal(this.intersectionPoint, this._slidePlaneNormal, this._destinationPoint));
-            this._destinationPoint.subtractInPlace(this._slidePlaneNormal);
-
-            this._destinationPoint.subtractToRef(this.intersectionPoint, vel);
-        }
-    }
+module BABYLON {
+    var intersectBoxAASphere = (boxMin: Vector3, boxMax: Vector3, sphereCenter: Vector3, sphereRadius: number): boolean => {
+        if (boxMin.x > sphereCenter.x + sphereRadius)
+            return false;
+
+        if (sphereCenter.x - sphereRadius > boxMax.x)
+            return false;
+
+        if (boxMin.y > sphereCenter.y + sphereRadius)
+            return false;
+
+        if (sphereCenter.y - sphereRadius > boxMax.y)
+            return false;
+
+        if (boxMin.z > sphereCenter.z + sphereRadius)
+            return false;
+
+        if (sphereCenter.z - sphereRadius > boxMax.z)
+            return false;
+
+        return true;
+    };
+
+    var getLowestRoot = (a: number, b: number, c: number, maxR: number) => {
+        var determinant = b * b - 4.0 * a * c;
+        var result = { root: 0, found: false };
+
+        if (determinant < 0)
+            return result;
+
+        var sqrtD = Math.sqrt(determinant);
+        var r1 = (-b - sqrtD) / (2.0 * a);
+        var r2 = (-b + sqrtD) / (2.0 * a);
+
+        if (r1 > r2) {
+            var temp = r2;
+            r2 = r1;
+            r1 = temp;
+        }
+
+        if (r1 > 0 && r1 < maxR) {
+            result.root = r1;
+            result.found = true;
+            return result;
+        }
+
+        if (r2 > 0 && r2 < maxR) {
+            result.root = r2;
+            result.found = true;
+            return result;
+        }
+
+        return result;
+    };
+
+    export class Collider {
+        public radius = new Vector3(1, 1, 1);
+        public retry = 0;
+        public velocity: Vector3;
+        public basePoint: Vector3;
+        public epsilon: number;
+        public collisionFound: boolean;
+        public velocityWorldLength: number;
+        public basePointWorld = Vector3.Zero();
+        public velocityWorld = Vector3.Zero();
+        public normalizedVelocity = Vector3.Zero();
+        public initialVelocity: Vector3;
+        public initialPosition: Vector3;
+        public nearestDistance: number;
+        public intersectionPoint: Vector3;
+        public collidedMesh: AbstractMesh;
+
+        private _collisionPoint = Vector3.Zero();
+        private _planeIntersectionPoint = Vector3.Zero();
+        private _tempVector = Vector3.Zero();
+        private _tempVector2 = Vector3.Zero();
+        private _tempVector3 = Vector3.Zero();
+        private _tempVector4 = Vector3.Zero();
+        private _edge = Vector3.Zero();
+        private _baseToVertex = Vector3.Zero();
+        private _destinationPoint = Vector3.Zero();
+        private _slidePlaneNormal = Vector3.Zero();
+        private _displacementVector = Vector3.Zero();
+
+        // Methods
+        public _initialize(source: Vector3, dir: Vector3, e: number): void {
+            this.velocity = dir;
+            Vector3.NormalizeToRef(dir, this.normalizedVelocity);
+            this.basePoint = source;
+
+            source.multiplyToRef(this.radius, this.basePointWorld);
+            dir.multiplyToRef(this.radius, this.velocityWorld);
+
+            this.velocityWorldLength = this.velocityWorld.length();
+
+            this.epsilon = e;
+            this.collisionFound = false;
+        }
+
+        public _checkPointInTriangle(point: Vector3, pa: Vector3, pb: Vector3, pc: Vector3, n: Vector3): boolean {
+            pa.subtractToRef(point, this._tempVector);
+            pb.subtractToRef(point, this._tempVector2);
+
+            Vector3.CrossToRef(this._tempVector, this._tempVector2, this._tempVector4);
+            var d = Vector3.Dot(this._tempVector4, n);
+            if (d < 0)
+                return false;
+
+            pc.subtractToRef(point, this._tempVector3);
+            Vector3.CrossToRef(this._tempVector2, this._tempVector3, this._tempVector4);
+            d = Vector3.Dot(this._tempVector4, n);
+            if (d < 0)
+                return false;
+
+            Vector3.CrossToRef(this._tempVector3, this._tempVector, this._tempVector4);
+            d = Vector3.Dot(this._tempVector4, n);
+            return d >= 0;
+        }
+
+        public _canDoCollision(sphereCenter: Vector3, sphereRadius: number, vecMin: Vector3, vecMax: Vector3): boolean {
+            var distance = Vector3.Distance(this.basePointWorld, sphereCenter);
+
+            var max = Math.max(this.radius.x, this.radius.y, this.radius.z);
+
+            if (distance > this.velocityWorldLength + max + sphereRadius) {
+                return false;
+            }
+
+            if (!intersectBoxAASphere(vecMin, vecMax, this.basePointWorld, this.velocityWorldLength + max))
+                return false;
+
+            return true;
+        }
+
+        public _testTriangle(faceIndex: number, trianglePlaneArray: Array<Plane>, p1: Vector3, p2: Vector3, p3: Vector3, hasMaterial: boolean): void {
+            var t0;
+            var embeddedInPlane = false;
+
+            //defensive programming, actually not needed.
+            if (!trianglePlaneArray) {
+                trianglePlaneArray = [];
+            }
+
+            if (!trianglePlaneArray[faceIndex]) {
+                trianglePlaneArray[faceIndex] = new Plane(0, 0, 0, 0);
+                trianglePlaneArray[faceIndex].copyFromPoints(p1, p2, p3);
+            }
+
+            var trianglePlane = trianglePlaneArray[faceIndex];
+
+            if ((!hasMaterial) && !trianglePlane.isFrontFacingTo(this.normalizedVelocity, 0))
+                return;
+
+            var signedDistToTrianglePlane = trianglePlane.signedDistanceTo(this.basePoint);
+            var normalDotVelocity = Vector3.Dot(trianglePlane.normal, this.velocity);
+
+            if (normalDotVelocity == 0) {
+                if (Math.abs(signedDistToTrianglePlane) >= 1.0)
+                    return;
+                embeddedInPlane = true;
+                t0 = 0;
+            }
+            else {
+                t0 = (-1.0 - signedDistToTrianglePlane) / normalDotVelocity;
+                var t1 = (1.0 - signedDistToTrianglePlane) / normalDotVelocity;
+
+                if (t0 > t1) {
+                    var temp = t1;
+                    t1 = t0;
+                    t0 = temp;
+                }
+
+                if (t0 > 1.0 || t1 < 0.0)
+                    return;
+
+                if (t0 < 0)
+                    t0 = 0;
+                if (t0 > 1.0)
+                    t0 = 1.0;
+            }
+
+            this._collisionPoint.copyFromFloats(0, 0, 0);
+
+            var found = false;
+            var t = 1.0;
+
+            if (!embeddedInPlane) {
+                this.basePoint.subtractToRef(trianglePlane.normal, this._planeIntersectionPoint);
+                this.velocity.scaleToRef(t0, this._tempVector);
+                this._planeIntersectionPoint.addInPlace(this._tempVector);
+
+                if (this._checkPointInTriangle(this._planeIntersectionPoint, p1, p2, p3, trianglePlane.normal)) {
+                    found = true;
+                    t = t0;
+                    this._collisionPoint.copyFrom(this._planeIntersectionPoint);
+                }
+            }
+
+            if (!found) {
+                var velocitySquaredLength = this.velocity.lengthSquared();
+
+                var a = velocitySquaredLength;
+
+                this.basePoint.subtractToRef(p1, this._tempVector);
+                var b = 2.0 * (Vector3.Dot(this.velocity, this._tempVector));
+                var c = this._tempVector.lengthSquared() - 1.0;
+
+                var lowestRoot = getLowestRoot(a, b, c, t);
+                if (lowestRoot.found) {
+                    t = lowestRoot.root;
+                    found = true;
+                    this._collisionPoint.copyFrom(p1);
+                }
+
+                this.basePoint.subtractToRef(p2, this._tempVector);
+                b = 2.0 * (Vector3.Dot(this.velocity, this._tempVector));
+                c = this._tempVector.lengthSquared() - 1.0;
+
+                lowestRoot = getLowestRoot(a, b, c, t);
+                if (lowestRoot.found) {
+                    t = lowestRoot.root;
+                    found = true;
+                    this._collisionPoint.copyFrom(p2);
+                }
+
+                this.basePoint.subtractToRef(p3, this._tempVector);
+                b = 2.0 * (Vector3.Dot(this.velocity, this._tempVector));
+                c = this._tempVector.lengthSquared() - 1.0;
+
+                lowestRoot = getLowestRoot(a, b, c, t);
+                if (lowestRoot.found) {
+                    t = lowestRoot.root;
+                    found = true;
+                    this._collisionPoint.copyFrom(p3);
+                }
+
+                p2.subtractToRef(p1, this._edge);
+                p1.subtractToRef(this.basePoint, this._baseToVertex);
+                var edgeSquaredLength = this._edge.lengthSquared();
+                var edgeDotVelocity = Vector3.Dot(this._edge, this.velocity);
+                var edgeDotBaseToVertex = Vector3.Dot(this._edge, this._baseToVertex);
+
+                a = edgeSquaredLength * (-velocitySquaredLength) + edgeDotVelocity * edgeDotVelocity;
+                b = edgeSquaredLength * (2.0 * Vector3.Dot(this.velocity, this._baseToVertex)) - 2.0 * edgeDotVelocity * edgeDotBaseToVertex;
+                c = edgeSquaredLength * (1.0 - this._baseToVertex.lengthSquared()) + edgeDotBaseToVertex * edgeDotBaseToVertex;
+
+                lowestRoot = getLowestRoot(a, b, c, t);
+                if (lowestRoot.found) {
+                    var f = (edgeDotVelocity * lowestRoot.root - edgeDotBaseToVertex) / edgeSquaredLength;
+
+                    if (f >= 0.0 && f <= 1.0) {
+                        t = lowestRoot.root;
+                        found = true;
+                        this._edge.scaleInPlace(f);
+                        p1.addToRef(this._edge, this._collisionPoint);
+                    }
+                }
+
+                p3.subtractToRef(p2, this._edge);
+                p2.subtractToRef(this.basePoint, this._baseToVertex);
+                edgeSquaredLength = this._edge.lengthSquared();
+                edgeDotVelocity = Vector3.Dot(this._edge, this.velocity);
+                edgeDotBaseToVertex = Vector3.Dot(this._edge, this._baseToVertex);
+
+                a = edgeSquaredLength * (-velocitySquaredLength) + edgeDotVelocity * edgeDotVelocity;
+                b = edgeSquaredLength * (2.0 * Vector3.Dot(this.velocity, this._baseToVertex)) - 2.0 * edgeDotVelocity * edgeDotBaseToVertex;
+                c = edgeSquaredLength * (1.0 - this._baseToVertex.lengthSquared()) + edgeDotBaseToVertex * edgeDotBaseToVertex;
+                lowestRoot = getLowestRoot(a, b, c, t);
+                if (lowestRoot.found) {
+                    f = (edgeDotVelocity * lowestRoot.root - edgeDotBaseToVertex) / edgeSquaredLength;
+
+                    if (f >= 0.0 && f <= 1.0) {
+                        t = lowestRoot.root;
+                        found = true;
+                        this._edge.scaleInPlace(f);
+                        p2.addToRef(this._edge, this._collisionPoint);
+                    }
+                }
+
+                p1.subtractToRef(p3, this._edge);
+                p3.subtractToRef(this.basePoint, this._baseToVertex);
+                edgeSquaredLength = this._edge.lengthSquared();
+                edgeDotVelocity = Vector3.Dot(this._edge, this.velocity);
+                edgeDotBaseToVertex = Vector3.Dot(this._edge, this._baseToVertex);
+
+                a = edgeSquaredLength * (-velocitySquaredLength) + edgeDotVelocity * edgeDotVelocity;
+                b = edgeSquaredLength * (2.0 * Vector3.Dot(this.velocity, this._baseToVertex)) - 2.0 * edgeDotVelocity * edgeDotBaseToVertex;
+                c = edgeSquaredLength * (1.0 - this._baseToVertex.lengthSquared()) + edgeDotBaseToVertex * edgeDotBaseToVertex;
+
+                lowestRoot = getLowestRoot(a, b, c, t);
+                if (lowestRoot.found) {
+                    f = (edgeDotVelocity * lowestRoot.root - edgeDotBaseToVertex) / edgeSquaredLength;
+
+                    if (f >= 0.0 && f <= 1.0) {
+                        t = lowestRoot.root;
+                        found = true;
+                        this._edge.scaleInPlace(f);
+                        p3.addToRef(this._edge, this._collisionPoint);
+                    }
+                }
+            }
+
+            if (found) {
+                var distToCollision = t * this.velocity.length();
+
+                if (!this.collisionFound || distToCollision < this.nearestDistance) {
+                    if (!this.intersectionPoint) {
+                        this.intersectionPoint = this._collisionPoint.clone();
+                    } else {
+                        this.intersectionPoint.copyFrom(this._collisionPoint);
+                    }
+                    this.nearestDistance = distToCollision;
+                    this.collisionFound = true;
+                }
+            }
+        }
+
+        public _collide(trianglePlaneArray: Array<Plane>, pts: Vector3[], indices: number[] | Int32Array, indexStart: number, indexEnd: number, decal: number, hasMaterial: boolean): void {
+            for (var i = indexStart; i < indexEnd; i += 3) {
+                var p1 = pts[indices[i] - decal];
+                var p2 = pts[indices[i + 1] - decal];
+                var p3 = pts[indices[i + 2] - decal];
+
+                this._testTriangle(i, trianglePlaneArray, p3, p2, p1, hasMaterial);
+            }
+        }
+
+        public _getResponse(pos: Vector3, vel: Vector3): void {
+            pos.addToRef(vel, this._destinationPoint);
+            vel.scaleInPlace((this.nearestDistance / vel.length()));
+
+            this.basePoint.addToRef(vel, pos);
+            pos.subtractToRef(this.intersectionPoint, this._slidePlaneNormal);
+            this._slidePlaneNormal.normalize();
+            this._slidePlaneNormal.scaleToRef(this.epsilon, this._displacementVector);
+
+            pos.addInPlace(this._displacementVector);
+            this.intersectionPoint.addInPlace(this._displacementVector);
+
+            this._slidePlaneNormal.scaleInPlace(Plane.SignedDistanceToPlaneFromPositionAndNormal(this.intersectionPoint, this._slidePlaneNormal, this._destinationPoint));
+            this._destinationPoint.subtractInPlace(this._slidePlaneNormal);
+
+            this._destinationPoint.subtractToRef(this.intersectionPoint, vel);
+        }
+    }
 } 

+ 418 - 418
src/Collisions/babylon.collisionCoordinator.ts

@@ -1,418 +1,418 @@
-module BABYLON {
-
-    //WebWorker code will be inserted to this variable.
-    export var CollisionWorker = "";
-
-    export interface ICollisionCoordinator {
-        getNewPosition(position: Vector3, velocity: Vector3, collider: Collider, maximumRetry: number, excludedMesh: AbstractMesh, onNewPosition: (collisionIndex: number, newPosition: Vector3, collidedMesh?: AbstractMesh) => void, collisionIndex: number): void;
-        init(scene: Scene): void;
-        destroy(): void;
-
-        //Update meshes and geometries
-        onMeshAdded(mesh: AbstractMesh);
-        onMeshUpdated(mesh: AbstractMesh);
-        onMeshRemoved(mesh: AbstractMesh);
-        onGeometryAdded(geometry: Geometry);
-        onGeometryUpdated(geometry: Geometry);
-        onGeometryDeleted(geometry: Geometry);
-    }
-
-    export interface SerializedMesh {
-        id: string;
-        name: string;
-        uniqueId: number;
-        geometryId: string;
-        sphereCenter: Array<number>;
-        sphereRadius: number;
-        boxMinimum: Array<number>;
-        boxMaximum: Array<number>;
-        worldMatrixFromCache: any;
-        subMeshes: Array<SerializedSubMesh>;
-        checkCollisions: boolean;
-    }
-
-    export interface SerializedSubMesh {
-        position: number;
-        verticesStart: number;
-        verticesCount: number;
-        indexStart: number;
-        indexCount: number;
-        hasMaterial: boolean;
-        sphereCenter: Array<number>;
-        sphereRadius: number;
-        boxMinimum: Array<number>;
-        boxMaximum: Array<number>;
-    }
-
-    export interface SerializedGeometry {
-        id: string;
-        positions: Float32Array;
-        indices: Int32Array;
-        normals: Float32Array;
-        //uvs?: Float32Array;
-    }
-
-    export interface BabylonMessage {
-        taskType: WorkerTaskType;
-        payload: InitPayload | CollidePayload | UpdatePayload /*any for TS under 1.4*/;
-    }
-
-    export interface SerializedColliderToWorker {
-        position: Array<number>;
-        velocity: Array<number>;
-        radius: Array<number>;
-    }
-
-    export enum WorkerTaskType {
-        INIT,
-        UPDATE,
-        COLLIDE
-    }
-
-    export interface WorkerReply {
-        error: WorkerReplyType;
-        taskType: WorkerTaskType;
-        payload?: any;
-    }
-
-    export interface CollisionReplyPayload {
-        newPosition: Array<number>;
-        collisionId: number;
-        collidedMeshUniqueId: number;
-    }
-
-    export interface InitPayload {
-
-    }
-
-    export interface CollidePayload {
-        collisionId: number;
-        collider: SerializedColliderToWorker;
-        maximumRetry: number;
-        excludedMeshUniqueId?: number;
-    }
-
-    export interface UpdatePayload {
-        updatedMeshes: { [n: number]: SerializedMesh; };
-        updatedGeometries: { [s: string]: SerializedGeometry; };
-        removedMeshes: Array<number>;
-        removedGeometries: Array<string>;
-    }
-
-    export enum WorkerReplyType {
-        SUCCESS,
-        UNKNOWN_ERROR
-    }
-
-    export class CollisionCoordinatorWorker implements ICollisionCoordinator {
-
-        private _scene: Scene;
-
-        private _scaledPosition = Vector3.Zero();
-        private _scaledVelocity = Vector3.Zero();
-
-        private _collisionsCallbackArray: Array<(collisionIndex: number, newPosition: Vector3, collidedMesh?: AbstractMesh) => void>;
-
-        private _init: boolean;
-        private _runningUpdated: number;
-        private _runningCollisionTask: boolean;
-        private _worker: Worker;
-
-        private _addUpdateMeshesList: { [n: number]: SerializedMesh; }
-        private _addUpdateGeometriesList: { [s: string]: SerializedGeometry; };
-        private _toRemoveMeshesArray: Array<number>;
-        private _toRemoveGeometryArray: Array<string>;
-
-        constructor() {
-            this._collisionsCallbackArray = [];
-            this._init = false;
-            this._runningUpdated = 0;
-            this._runningCollisionTask = false;
-
-            this._addUpdateMeshesList = {};
-            this._addUpdateGeometriesList = {};
-            this._toRemoveGeometryArray = [];
-            this._toRemoveMeshesArray = [];
-        }
-
-        public static SerializeMesh = function (mesh: AbstractMesh): SerializedMesh {
-            var submeshes: Array<SerializedSubMesh> = [];
-            if (mesh.subMeshes) {
-                submeshes = mesh.subMeshes.map(function (sm, idx) {
-                    return {
-                        position: idx,
-                        verticesStart: sm.verticesStart,
-                        verticesCount: sm.verticesCount,
-                        indexStart: sm.indexStart,
-                        indexCount: sm.indexCount,
-                        hasMaterial: !!sm.getMaterial(),
-                        sphereCenter: sm.getBoundingInfo().boundingSphere.centerWorld.asArray(),
-                        sphereRadius: sm.getBoundingInfo().boundingSphere.radiusWorld,
-                        boxMinimum: sm.getBoundingInfo().boundingBox.minimumWorld.asArray(),
-                        boxMaximum: sm.getBoundingInfo().boundingBox.maximumWorld.asArray()
-                    }
-                });
-            }
-
-            var geometryId: string = null;
-            if (mesh instanceof Mesh) {
-                geometryId = (<Mesh>mesh).geometry ? (<Mesh>mesh).geometry.id : null;
-            } else if (mesh instanceof InstancedMesh) {
-                geometryId = ((<InstancedMesh>mesh).sourceMesh && (<InstancedMesh>mesh).sourceMesh.geometry) ? (<InstancedMesh>mesh).sourceMesh.geometry.id : null;
-            }
-
-            return {
-                uniqueId: mesh.uniqueId,
-                id: mesh.id,
-                name: mesh.name,
-                geometryId: geometryId,
-                sphereCenter: mesh.getBoundingInfo().boundingSphere.centerWorld.asArray(),
-                sphereRadius: mesh.getBoundingInfo().boundingSphere.radiusWorld,
-                boxMinimum: mesh.getBoundingInfo().boundingBox.minimumWorld.asArray(),
-                boxMaximum: mesh.getBoundingInfo().boundingBox.maximumWorld.asArray(),
-                worldMatrixFromCache: mesh.worldMatrixFromCache.asArray(),
-                subMeshes: submeshes,
-                checkCollisions: mesh.checkCollisions
-            }
-        }
-
-        public static SerializeGeometry = function (geometry: Geometry): SerializedGeometry {
-            return {
-                id: geometry.id,
-                positions: new Float32Array(geometry.getVerticesData(VertexBuffer.PositionKind) || []),
-                normals: new Float32Array(geometry.getVerticesData(VertexBuffer.NormalKind) || []),
-                indices: new Int32Array(geometry.getIndices() || []),
-                //uvs: new Float32Array(geometry.getVerticesData(VertexBuffer.UVKind) || [])
-            }
-        }
-
-        public getNewPosition(position: Vector3, velocity: Vector3, collider: Collider, maximumRetry: number, excludedMesh: AbstractMesh, onNewPosition: (collisionIndex: number, newPosition: Vector3, collidedMesh?: AbstractMesh) => void, collisionIndex: number): void {
-            if (!this._init) return;
-            if (this._collisionsCallbackArray[collisionIndex] || this._collisionsCallbackArray[collisionIndex + 100000]) return;
-
-            position.divideToRef(collider.radius, this._scaledPosition);
-            velocity.divideToRef(collider.radius, this._scaledVelocity);
-
-            this._collisionsCallbackArray[collisionIndex] = onNewPosition;
-
-            var payload: CollidePayload = {
-                collider: {
-                    position: this._scaledPosition.asArray(),
-                    velocity: this._scaledVelocity.asArray(),
-                    radius: collider.radius.asArray()
-                },
-                collisionId: collisionIndex,
-                excludedMeshUniqueId: excludedMesh ? excludedMesh.uniqueId : null,
-                maximumRetry: maximumRetry
-            };
-            var message: BabylonMessage = {
-                payload: payload,
-                taskType: WorkerTaskType.COLLIDE
-            }
-            this._worker.postMessage(message);
-
-        }
-
-        public init(scene: Scene): void {
-            this._scene = scene;
-            this._scene.registerAfterRender(this._afterRender);
-            var workerUrl = BABYLON.WorkerIncluded ? Engine.CodeRepository + "Collisions/babylon.collisionWorker.js" : URL.createObjectURL(new Blob([BABYLON.CollisionWorker], { type: 'application/javascript' }));
-            this._worker = new Worker(workerUrl);
-            this._worker.onmessage = this._onMessageFromWorker;
-            var message: BabylonMessage = {
-                payload: {},
-                taskType: WorkerTaskType.INIT
-            }
-            this._worker.postMessage(message);
-        }
-
-        public destroy(): void {
-            this._scene.unregisterAfterRender(this._afterRender);
-            this._worker.terminate();
-        }
-
-        public onMeshAdded(mesh: AbstractMesh) {
-            mesh.registerAfterWorldMatrixUpdate(this.onMeshUpdated);
-            this.onMeshUpdated(mesh);
-        }
-
-        public onMeshUpdated = (mesh: AbstractMesh) => {
-            this._addUpdateMeshesList[mesh.uniqueId] = CollisionCoordinatorWorker.SerializeMesh(mesh);
-        }
-
-        public onMeshRemoved(mesh: AbstractMesh) {
-            this._toRemoveMeshesArray.push(mesh.uniqueId);
-        }
-
-        public onGeometryAdded(geometry: Geometry) {
-            //TODO this will break if the user uses his own function. This should be an array of callbacks!
-            geometry.onGeometryUpdated = this.onGeometryUpdated;
-            this.onGeometryUpdated(geometry);
-        }
-
-        public onGeometryUpdated = (geometry: Geometry) => {
-            this._addUpdateGeometriesList[geometry.id] = CollisionCoordinatorWorker.SerializeGeometry(geometry);
-        }
-
-        public onGeometryDeleted(geometry: Geometry) {
-            this._toRemoveGeometryArray.push(geometry.id);
-        }
-
-        private _afterRender = () => {
-
-            if (!this._init) return;
-
-            if (this._toRemoveGeometryArray.length == 0 && this._toRemoveMeshesArray.length == 0 && Object.keys(this._addUpdateGeometriesList).length == 0 && Object.keys(this._addUpdateMeshesList).length == 0) {
-                return;
-            }
-
-            //5 concurrent updates were sent to the web worker and were not yet processed. Abort next update.
-            //TODO make sure update runs as fast as possible to be able to update 60 FPS.
-            if (this._runningUpdated > 4) {
-                return;
-            }
-
-            ++this._runningUpdated;
-
-            var payload: UpdatePayload = {
-                updatedMeshes: this._addUpdateMeshesList,
-                updatedGeometries: this._addUpdateGeometriesList,
-                removedGeometries: this._toRemoveGeometryArray,
-                removedMeshes: this._toRemoveMeshesArray
-            };
-            var message: BabylonMessage = {
-                payload: payload,
-                taskType: WorkerTaskType.UPDATE
-            }
-            var serializable = [];
-            for (var id in payload.updatedGeometries) {
-                if (payload.updatedGeometries.hasOwnProperty(id)) {
-                    //prepare transferables
-                    serializable.push((<UpdatePayload>message.payload).updatedGeometries[id].indices.buffer);
-                    serializable.push((<UpdatePayload>message.payload).updatedGeometries[id].normals.buffer);
-                    serializable.push((<UpdatePayload>message.payload).updatedGeometries[id].positions.buffer);
-                }
-            }
-
-            this._worker.postMessage(message, serializable);
-            this._addUpdateMeshesList = {};
-            this._addUpdateGeometriesList = {};
-            this._toRemoveGeometryArray = [];
-            this._toRemoveMeshesArray = [];
-        }
-
-        private _onMessageFromWorker = (e: MessageEvent) => {
-            var returnData = <WorkerReply>e.data;
-            if (returnData.error != WorkerReplyType.SUCCESS) {
-                //TODO what errors can be returned from the worker?
-                Tools.Warn("error returned from worker!");
-                return;
-            }
-
-            switch (returnData.taskType) {
-                case WorkerTaskType.INIT:
-                    this._init = true;
-                    //Update the worked with ALL of the scene's current state
-                    this._scene.meshes.forEach((mesh) => {
-                        this.onMeshAdded(mesh);
-                    });
-
-                    this._scene.getGeometries().forEach((geometry) => {
-                        this.onGeometryAdded(geometry);
-                    });
-
-                    break;
-                case WorkerTaskType.UPDATE:
-                    this._runningUpdated--;
-                    break;
-                case WorkerTaskType.COLLIDE:
-                    this._runningCollisionTask = false;
-                    var returnPayload: CollisionReplyPayload = returnData.payload;
-                    if (!this._collisionsCallbackArray[returnPayload.collisionId]) return;
-
-                    this._collisionsCallbackArray[returnPayload.collisionId](returnPayload.collisionId, Vector3.FromArray(returnPayload.newPosition), this._scene.getMeshByUniqueID(returnPayload.collidedMeshUniqueId));
-                    //cleanup
-                    this._collisionsCallbackArray[returnPayload.collisionId] = undefined;
-                    break;
-            }
-        }
-    }
-
-    export class CollisionCoordinatorLegacy implements ICollisionCoordinator {
-
-        private _scene: Scene;
-
-        private _scaledPosition = Vector3.Zero();
-        private _scaledVelocity = Vector3.Zero();
-
-        private _finalPosition = Vector3.Zero();
-
-        public getNewPosition(position: Vector3, velocity: Vector3, collider: Collider, maximumRetry: number, excludedMesh: AbstractMesh, onNewPosition: (collisionIndex: number, newPosition: Vector3, collidedMesh?: AbstractMesh) => void, collisionIndex: number): void {
-            position.divideToRef(collider.radius, this._scaledPosition);
-            velocity.divideToRef(collider.radius, this._scaledVelocity);
-            collider.collidedMesh = null;
-            collider.retry = 0;
-            collider.initialVelocity = this._scaledVelocity;
-            collider.initialPosition = this._scaledPosition;
-            this._collideWithWorld(this._scaledPosition, this._scaledVelocity, collider, maximumRetry, this._finalPosition, excludedMesh);
-
-            this._finalPosition.multiplyInPlace(collider.radius);
-            //run the callback
-            onNewPosition(collisionIndex, this._finalPosition, collider.collidedMesh);
-        }
-
-        public init(scene: Scene): void {
-            this._scene = scene;
-        }
-
-        public destroy(): void {
-            //Legacy need no destruction method.
-        }
-
-        //No update in legacy mode
-        public onMeshAdded(mesh: AbstractMesh) { }
-        public onMeshUpdated(mesh: AbstractMesh) { }
-        public onMeshRemoved(mesh: AbstractMesh) { }
-        public onGeometryAdded(geometry: Geometry) { }
-        public onGeometryUpdated(geometry: Geometry) { }
-        public onGeometryDeleted(geometry: Geometry) { }
-
-        private _collideWithWorld(position: Vector3, velocity: Vector3, collider: Collider, maximumRetry: number, finalPosition: Vector3, excludedMesh: AbstractMesh = null): void {
-            var closeDistance = Engine.CollisionsEpsilon * 10.0;
-
-            if (collider.retry >= maximumRetry) {
-                finalPosition.copyFrom(position);
-                return;
-            }
-
-            collider._initialize(position, velocity, closeDistance);
-
-            // Check all meshes
-            for (var index = 0; index < this._scene.meshes.length; index++) {
-                var mesh = this._scene.meshes[index];
-                if (mesh.isEnabled() && mesh.checkCollisions && mesh.subMeshes && mesh !== excludedMesh) {
-                    mesh._checkCollision(collider);
-                }
-            }
-
-            if (!collider.collisionFound) {
-                position.addToRef(velocity, finalPosition);
-                return;
-            }
-
-            if (velocity.x !== 0 || velocity.y !== 0 || velocity.z !== 0) {
-                collider._getResponse(position, velocity);
-            }
-
-            if (velocity.length() <= closeDistance) {
-                finalPosition.copyFrom(position);
-                return;
-            }
-
-            collider.retry++;
-            this._collideWithWorld(position, velocity, collider, maximumRetry, finalPosition, excludedMesh);
-        }
-    }
-}
-
-
+module BABYLON {
+
+    //WebWorker code will be inserted to this variable.
+    export var CollisionWorker = "";
+
+    export interface ICollisionCoordinator {
+        getNewPosition(position: Vector3, velocity: Vector3, collider: Collider, maximumRetry: number, excludedMesh: AbstractMesh, onNewPosition: (collisionIndex: number, newPosition: Vector3, collidedMesh?: AbstractMesh) => void, collisionIndex: number): void;
+        init(scene: Scene): void;
+        destroy(): void;
+
+        //Update meshes and geometries
+        onMeshAdded(mesh: AbstractMesh);
+        onMeshUpdated(mesh: AbstractMesh);
+        onMeshRemoved(mesh: AbstractMesh);
+        onGeometryAdded(geometry: Geometry);
+        onGeometryUpdated(geometry: Geometry);
+        onGeometryDeleted(geometry: Geometry);
+    }
+
+    export interface SerializedMesh {
+        id: string;
+        name: string;
+        uniqueId: number;
+        geometryId: string;
+        sphereCenter: Array<number>;
+        sphereRadius: number;
+        boxMinimum: Array<number>;
+        boxMaximum: Array<number>;
+        worldMatrixFromCache: any;
+        subMeshes: Array<SerializedSubMesh>;
+        checkCollisions: boolean;
+    }
+
+    export interface SerializedSubMesh {
+        position: number;
+        verticesStart: number;
+        verticesCount: number;
+        indexStart: number;
+        indexCount: number;
+        hasMaterial: boolean;
+        sphereCenter: Array<number>;
+        sphereRadius: number;
+        boxMinimum: Array<number>;
+        boxMaximum: Array<number>;
+    }
+
+    export interface SerializedGeometry {
+        id: string;
+        positions: Float32Array;
+        indices: Int32Array;
+        normals: Float32Array;
+        //uvs?: Float32Array;
+    }
+
+    export interface BabylonMessage {
+        taskType: WorkerTaskType;
+        payload: InitPayload | CollidePayload | UpdatePayload /*any for TS under 1.4*/;
+    }
+
+    export interface SerializedColliderToWorker {
+        position: Array<number>;
+        velocity: Array<number>;
+        radius: Array<number>;
+    }
+
+    export enum WorkerTaskType {
+        INIT,
+        UPDATE,
+        COLLIDE
+    }
+
+    export interface WorkerReply {
+        error: WorkerReplyType;
+        taskType: WorkerTaskType;
+        payload?: any;
+    }
+
+    export interface CollisionReplyPayload {
+        newPosition: Array<number>;
+        collisionId: number;
+        collidedMeshUniqueId: number;
+    }
+
+    export interface InitPayload {
+
+    }
+
+    export interface CollidePayload {
+        collisionId: number;
+        collider: SerializedColliderToWorker;
+        maximumRetry: number;
+        excludedMeshUniqueId?: number;
+    }
+
+    export interface UpdatePayload {
+        updatedMeshes: { [n: number]: SerializedMesh; };
+        updatedGeometries: { [s: string]: SerializedGeometry; };
+        removedMeshes: Array<number>;
+        removedGeometries: Array<string>;
+    }
+
+    export enum WorkerReplyType {
+        SUCCESS,
+        UNKNOWN_ERROR
+    }
+
+    export class CollisionCoordinatorWorker implements ICollisionCoordinator {
+
+        private _scene: Scene;
+
+        private _scaledPosition = Vector3.Zero();
+        private _scaledVelocity = Vector3.Zero();
+
+        private _collisionsCallbackArray: Array<(collisionIndex: number, newPosition: Vector3, collidedMesh?: AbstractMesh) => void>;
+
+        private _init: boolean;
+        private _runningUpdated: number;
+        private _runningCollisionTask: boolean;
+        private _worker: Worker;
+
+        private _addUpdateMeshesList: { [n: number]: SerializedMesh; }
+        private _addUpdateGeometriesList: { [s: string]: SerializedGeometry; };
+        private _toRemoveMeshesArray: Array<number>;
+        private _toRemoveGeometryArray: Array<string>;
+
+        constructor() {
+            this._collisionsCallbackArray = [];
+            this._init = false;
+            this._runningUpdated = 0;
+            this._runningCollisionTask = false;
+
+            this._addUpdateMeshesList = {};
+            this._addUpdateGeometriesList = {};
+            this._toRemoveGeometryArray = [];
+            this._toRemoveMeshesArray = [];
+        }
+
+        public static SerializeMesh = function (mesh: AbstractMesh): SerializedMesh {
+            var submeshes: Array<SerializedSubMesh> = [];
+            if (mesh.subMeshes) {
+                submeshes = mesh.subMeshes.map(function (sm, idx) {
+                    return {
+                        position: idx,
+                        verticesStart: sm.verticesStart,
+                        verticesCount: sm.verticesCount,
+                        indexStart: sm.indexStart,
+                        indexCount: sm.indexCount,
+                        hasMaterial: !!sm.getMaterial(),
+                        sphereCenter: sm.getBoundingInfo().boundingSphere.centerWorld.asArray(),
+                        sphereRadius: sm.getBoundingInfo().boundingSphere.radiusWorld,
+                        boxMinimum: sm.getBoundingInfo().boundingBox.minimumWorld.asArray(),
+                        boxMaximum: sm.getBoundingInfo().boundingBox.maximumWorld.asArray()
+                    }
+                });
+            }
+
+            var geometryId: string = null;
+            if (mesh instanceof Mesh) {
+                geometryId = (<Mesh>mesh).geometry ? (<Mesh>mesh).geometry.id : null;
+            } else if (mesh instanceof InstancedMesh) {
+                geometryId = ((<InstancedMesh>mesh).sourceMesh && (<InstancedMesh>mesh).sourceMesh.geometry) ? (<InstancedMesh>mesh).sourceMesh.geometry.id : null;
+            }
+
+            return {
+                uniqueId: mesh.uniqueId,
+                id: mesh.id,
+                name: mesh.name,
+                geometryId: geometryId,
+                sphereCenter: mesh.getBoundingInfo().boundingSphere.centerWorld.asArray(),
+                sphereRadius: mesh.getBoundingInfo().boundingSphere.radiusWorld,
+                boxMinimum: mesh.getBoundingInfo().boundingBox.minimumWorld.asArray(),
+                boxMaximum: mesh.getBoundingInfo().boundingBox.maximumWorld.asArray(),
+                worldMatrixFromCache: mesh.worldMatrixFromCache.asArray(),
+                subMeshes: submeshes,
+                checkCollisions: mesh.checkCollisions
+            }
+        }
+
+        public static SerializeGeometry = function (geometry: Geometry): SerializedGeometry {
+            return {
+                id: geometry.id,
+                positions: new Float32Array(geometry.getVerticesData(VertexBuffer.PositionKind) || []),
+                normals: new Float32Array(geometry.getVerticesData(VertexBuffer.NormalKind) || []),
+                indices: new Int32Array(geometry.getIndices() || []),
+                //uvs: new Float32Array(geometry.getVerticesData(VertexBuffer.UVKind) || [])
+            }
+        }
+
+        public getNewPosition(position: Vector3, velocity: Vector3, collider: Collider, maximumRetry: number, excludedMesh: AbstractMesh, onNewPosition: (collisionIndex: number, newPosition: Vector3, collidedMesh?: AbstractMesh) => void, collisionIndex: number): void {
+            if (!this._init) return;
+            if (this._collisionsCallbackArray[collisionIndex] || this._collisionsCallbackArray[collisionIndex + 100000]) return;
+
+            position.divideToRef(collider.radius, this._scaledPosition);
+            velocity.divideToRef(collider.radius, this._scaledVelocity);
+
+            this._collisionsCallbackArray[collisionIndex] = onNewPosition;
+
+            var payload: CollidePayload = {
+                collider: {
+                    position: this._scaledPosition.asArray(),
+                    velocity: this._scaledVelocity.asArray(),
+                    radius: collider.radius.asArray()
+                },
+                collisionId: collisionIndex,
+                excludedMeshUniqueId: excludedMesh ? excludedMesh.uniqueId : null,
+                maximumRetry: maximumRetry
+            };
+            var message: BabylonMessage = {
+                payload: payload,
+                taskType: WorkerTaskType.COLLIDE
+            }
+            this._worker.postMessage(message);
+
+        }
+
+        public init(scene: Scene): void {
+            this._scene = scene;
+            this._scene.registerAfterRender(this._afterRender);
+            var workerUrl = BABYLON.WorkerIncluded ? Engine.CodeRepository + "Collisions/babylon.collisionWorker.js" : URL.createObjectURL(new Blob([BABYLON.CollisionWorker], { type: 'application/javascript' }));
+            this._worker = new Worker(workerUrl);
+            this._worker.onmessage = this._onMessageFromWorker;
+            var message: BabylonMessage = {
+                payload: {},
+                taskType: WorkerTaskType.INIT
+            }
+            this._worker.postMessage(message);
+        }
+
+        public destroy(): void {
+            this._scene.unregisterAfterRender(this._afterRender);
+            this._worker.terminate();
+        }
+
+        public onMeshAdded(mesh: AbstractMesh) {
+            mesh.registerAfterWorldMatrixUpdate(this.onMeshUpdated);
+            this.onMeshUpdated(mesh);
+        }
+
+        public onMeshUpdated = (mesh: AbstractMesh) => {
+            this._addUpdateMeshesList[mesh.uniqueId] = CollisionCoordinatorWorker.SerializeMesh(mesh);
+        }
+
+        public onMeshRemoved(mesh: AbstractMesh) {
+            this._toRemoveMeshesArray.push(mesh.uniqueId);
+        }
+
+        public onGeometryAdded(geometry: Geometry) {
+            //TODO this will break if the user uses his own function. This should be an array of callbacks!
+            geometry.onGeometryUpdated = this.onGeometryUpdated;
+            this.onGeometryUpdated(geometry);
+        }
+
+        public onGeometryUpdated = (geometry: Geometry) => {
+            this._addUpdateGeometriesList[geometry.id] = CollisionCoordinatorWorker.SerializeGeometry(geometry);
+        }
+
+        public onGeometryDeleted(geometry: Geometry) {
+            this._toRemoveGeometryArray.push(geometry.id);
+        }
+
+        private _afterRender = () => {
+
+            if (!this._init) return;
+
+            if (this._toRemoveGeometryArray.length == 0 && this._toRemoveMeshesArray.length == 0 && Object.keys(this._addUpdateGeometriesList).length == 0 && Object.keys(this._addUpdateMeshesList).length == 0) {
+                return;
+            }
+
+            //5 concurrent updates were sent to the web worker and were not yet processed. Abort next update.
+            //TODO make sure update runs as fast as possible to be able to update 60 FPS.
+            if (this._runningUpdated > 4) {
+                return;
+            }
+
+            ++this._runningUpdated;
+
+            var payload: UpdatePayload = {
+                updatedMeshes: this._addUpdateMeshesList,
+                updatedGeometries: this._addUpdateGeometriesList,
+                removedGeometries: this._toRemoveGeometryArray,
+                removedMeshes: this._toRemoveMeshesArray
+            };
+            var message: BabylonMessage = {
+                payload: payload,
+                taskType: WorkerTaskType.UPDATE
+            }
+            var serializable = [];
+            for (var id in payload.updatedGeometries) {
+                if (payload.updatedGeometries.hasOwnProperty(id)) {
+                    //prepare transferables
+                    serializable.push((<UpdatePayload>message.payload).updatedGeometries[id].indices.buffer);
+                    serializable.push((<UpdatePayload>message.payload).updatedGeometries[id].normals.buffer);
+                    serializable.push((<UpdatePayload>message.payload).updatedGeometries[id].positions.buffer);
+                }
+            }
+
+            this._worker.postMessage(message, serializable);
+            this._addUpdateMeshesList = {};
+            this._addUpdateGeometriesList = {};
+            this._toRemoveGeometryArray = [];
+            this._toRemoveMeshesArray = [];
+        }
+
+        private _onMessageFromWorker = (e: MessageEvent) => {
+            var returnData = <WorkerReply>e.data;
+            if (returnData.error != WorkerReplyType.SUCCESS) {
+                //TODO what errors can be returned from the worker?
+                Tools.Warn("error returned from worker!");
+                return;
+            }
+
+            switch (returnData.taskType) {
+                case WorkerTaskType.INIT:
+                    this._init = true;
+                    //Update the worked with ALL of the scene's current state
+                    this._scene.meshes.forEach((mesh) => {
+                        this.onMeshAdded(mesh);
+                    });
+
+                    this._scene.getGeometries().forEach((geometry) => {
+                        this.onGeometryAdded(geometry);
+                    });
+
+                    break;
+                case WorkerTaskType.UPDATE:
+                    this._runningUpdated--;
+                    break;
+                case WorkerTaskType.COLLIDE:
+                    this._runningCollisionTask = false;
+                    var returnPayload: CollisionReplyPayload = returnData.payload;
+                    if (!this._collisionsCallbackArray[returnPayload.collisionId]) return;
+
+                    this._collisionsCallbackArray[returnPayload.collisionId](returnPayload.collisionId, Vector3.FromArray(returnPayload.newPosition), this._scene.getMeshByUniqueID(returnPayload.collidedMeshUniqueId));
+                    //cleanup
+                    this._collisionsCallbackArray[returnPayload.collisionId] = undefined;
+                    break;
+            }
+        }
+    }
+
+    export class CollisionCoordinatorLegacy implements ICollisionCoordinator {
+
+        private _scene: Scene;
+
+        private _scaledPosition = Vector3.Zero();
+        private _scaledVelocity = Vector3.Zero();
+
+        private _finalPosition = Vector3.Zero();
+
+        public getNewPosition(position: Vector3, velocity: Vector3, collider: Collider, maximumRetry: number, excludedMesh: AbstractMesh, onNewPosition: (collisionIndex: number, newPosition: Vector3, collidedMesh?: AbstractMesh) => void, collisionIndex: number): void {
+            position.divideToRef(collider.radius, this._scaledPosition);
+            velocity.divideToRef(collider.radius, this._scaledVelocity);
+            collider.collidedMesh = null;
+            collider.retry = 0;
+            collider.initialVelocity = this._scaledVelocity;
+            collider.initialPosition = this._scaledPosition;
+            this._collideWithWorld(this._scaledPosition, this._scaledVelocity, collider, maximumRetry, this._finalPosition, excludedMesh);
+
+            this._finalPosition.multiplyInPlace(collider.radius);
+            //run the callback
+            onNewPosition(collisionIndex, this._finalPosition, collider.collidedMesh);
+        }
+
+        public init(scene: Scene): void {
+            this._scene = scene;
+        }
+
+        public destroy(): void {
+            //Legacy need no destruction method.
+        }
+
+        //No update in legacy mode
+        public onMeshAdded(mesh: AbstractMesh) { }
+        public onMeshUpdated(mesh: AbstractMesh) { }
+        public onMeshRemoved(mesh: AbstractMesh) { }
+        public onGeometryAdded(geometry: Geometry) { }
+        public onGeometryUpdated(geometry: Geometry) { }
+        public onGeometryDeleted(geometry: Geometry) { }
+
+        private _collideWithWorld(position: Vector3, velocity: Vector3, collider: Collider, maximumRetry: number, finalPosition: Vector3, excludedMesh: AbstractMesh = null): void {
+            var closeDistance = Engine.CollisionsEpsilon * 10.0;
+
+            if (collider.retry >= maximumRetry) {
+                finalPosition.copyFrom(position);
+                return;
+            }
+
+            collider._initialize(position, velocity, closeDistance);
+
+            // Check all meshes
+            for (var index = 0; index < this._scene.meshes.length; index++) {
+                var mesh = this._scene.meshes[index];
+                if (mesh.isEnabled() && mesh.checkCollisions && mesh.subMeshes && mesh !== excludedMesh) {
+                    mesh._checkCollision(collider);
+                }
+            }
+
+            if (!collider.collisionFound) {
+                position.addToRef(velocity, finalPosition);
+                return;
+            }
+
+            if (velocity.x !== 0 || velocity.y !== 0 || velocity.z !== 0) {
+                collider._getResponse(position, velocity);
+            }
+
+            if (velocity.length() <= closeDistance) {
+                finalPosition.copyFrom(position);
+                return;
+            }
+
+            collider.retry++;
+            this._collideWithWorld(position, velocity, collider, maximumRetry, finalPosition, excludedMesh);
+        }
+    }
+}
+
+

+ 291 - 291
src/Collisions/babylon.collisionWorker.ts

@@ -1,291 +1,291 @@
-module BABYLON {
-
-    //If this file is included in the main thread, this will be initialized.
-    export var WorkerIncluded: boolean = true;
-
-    export class CollisionCache {
-        private _meshes: { [n: number]: SerializedMesh; } = {};
-        private _geometries: { [s: number]: SerializedGeometry; } = {};
-
-        public getMeshes(): { [n: number]: SerializedMesh; } {
-            return this._meshes;
-        }
-
-        public getGeometries(): { [s: number]: SerializedGeometry; } {
-            return this._geometries;
-        }
-
-        public getMesh(id: any): SerializedMesh {
-            return this._meshes[id];
-        }
-
-        public addMesh(mesh: SerializedMesh) {
-            this._meshes[mesh.uniqueId] = mesh;
-        }
-
-        public removeMesh(uniqueId: number) {
-            delete this._meshes[uniqueId];
-        }
-
-        public getGeometry(id: string): SerializedGeometry {
-            return this._geometries[id];
-        }
-
-        public addGeometry(geometry: SerializedGeometry) {
-            this._geometries[geometry.id] = geometry;
-        }
-
-        public removeGeometry(id: string) {
-            delete this._geometries[id];
-        }
-    }
-
-    export class CollideWorker {
-
-        private collisionsScalingMatrix = Matrix.Zero();
-        private collisionTranformationMatrix = Matrix.Zero();
-
-        constructor(public collider: Collider, private _collisionCache: CollisionCache, private finalPosition: Vector3) {
-
-        }
-
-        public collideWithWorld(position: Vector3, velocity: Vector3, maximumRetry: number, excludedMeshUniqueId?: number) {
-
-            //TODO CollisionsEpsilon should be defined here and not in the engine.
-            const closeDistance = 0.01; //is initializing here correct? A quick look - looks like it is fine.
-            if (this.collider.retry >= maximumRetry) {
-                this.finalPosition.copyFrom(position);
-                return;
-            }
-
-            this.collider._initialize(position, velocity, closeDistance);
-
-            // Check all meshes
-            var meshes = this._collisionCache.getMeshes();
-            var keys = Object.keys(meshes);
-            var len = keys.length;
-            var uniqueId;
-
-            for (var i = 0; i < len; ++i) {
-                uniqueId = keys[i];
-                if (parseInt(uniqueId) != excludedMeshUniqueId) {
-                    var mesh: SerializedMesh = meshes[uniqueId];
-                    if (mesh.checkCollisions)
-                        this.checkCollision(mesh);
-                }
-            }
-
-            if (!this.collider.collisionFound) {
-                position.addToRef(velocity, this.finalPosition);
-                return;
-            }
-
-            if (velocity.x !== 0 || velocity.y !== 0 || velocity.z !== 0) {
-                this.collider._getResponse(position, velocity);
-            }
-
-            if (velocity.length() <= closeDistance) {
-                this.finalPosition.copyFrom(position);
-                return;
-            }
-
-            this.collider.retry++;
-            this.collideWithWorld(position, velocity, maximumRetry, excludedMeshUniqueId);
-        }
-
-        private checkCollision(mesh: SerializedMesh) {
-
-            if (!this.collider._canDoCollision(Vector3.FromArray(mesh.sphereCenter), mesh.sphereRadius, Vector3.FromArray(mesh.boxMinimum), Vector3.FromArray(mesh.boxMaximum))) {
-                return;
-            };
-
-            // Transformation matrix
-            Matrix.ScalingToRef(1.0 / this.collider.radius.x, 1.0 / this.collider.radius.y, 1.0 / this.collider.radius.z, this.collisionsScalingMatrix);
-            var worldFromCache = Matrix.FromArray(mesh.worldMatrixFromCache);
-            worldFromCache.multiplyToRef(this.collisionsScalingMatrix, this.collisionTranformationMatrix);
-
-            this.processCollisionsForSubMeshes(this.collisionTranformationMatrix, mesh);
-            //return colTransMat;
-        }
-
-        private processCollisionsForSubMeshes(transformMatrix: Matrix, mesh: SerializedMesh): void { // No Octrees for now
-            //if (this._submeshesOctree && this.useOctreeForCollisions) {
-            //    var radius = collider.velocityWorldLength + Math.max(collider.radius.x, collider.radius.y, collider.radius.z);
-            //    var intersections = this._submeshesOctree.intersects(collider.basePointWorld, radius);
-
-            //    len = intersections.length;
-            //    subMeshes = intersections.data;
-            //} else {
-            var subMeshes = mesh.subMeshes;
-            var len = subMeshes.length;
-            //}
-
-            if (!mesh.geometryId) {
-                console.log("no mesh geometry id");
-                return;
-            }
-
-            var meshGeometry = this._collisionCache.getGeometry(mesh.geometryId);
-            if (!meshGeometry) {
-                console.log("couldn't find geometry", mesh.geometryId);
-                return;
-            }
-
-            for (var index = 0; index < len; index++) {
-                var subMesh = subMeshes[index];
-
-                // Bounding test
-                if (len > 1 && !this.checkSubmeshCollision(subMesh))
-                    continue;
-
-                this.collideForSubMesh(subMesh, transformMatrix, meshGeometry);
-                if (this.collider.collisionFound) {
-                    this.collider.collidedMesh = <any>mesh.uniqueId;
-                }
-            }
-        }
-
-        private collideForSubMesh(subMesh: SerializedSubMesh, transformMatrix: Matrix, meshGeometry: SerializedGeometry): void {
-            if (!meshGeometry['positionsArray']) {
-                meshGeometry['positionsArray'] = [];
-                for (var i = 0, len = meshGeometry.positions.length; i < len; i = i + 3) {
-                    var p = Vector3.FromArray([meshGeometry.positions[i], meshGeometry.positions[i + 1], meshGeometry.positions[i + 2]]);
-                    meshGeometry['positionsArray'].push(p);
-                }
-            }
-
-            if (!subMesh['_lastColliderWorldVertices'] || !subMesh['_lastColliderTransformMatrix'].equals(transformMatrix)) {
-                subMesh['_lastColliderTransformMatrix'] = transformMatrix.clone();
-                subMesh['_lastColliderWorldVertices'] = [];
-                subMesh['_trianglePlanes'] = [];
-                var start = subMesh.verticesStart;
-                var end = (subMesh.verticesStart + subMesh.verticesCount);
-                for (var i = start; i < end; i++) {
-                    subMesh['_lastColliderWorldVertices'].push(Vector3.TransformCoordinates(meshGeometry['positionsArray'][i], transformMatrix));
-                }
-            }        
-
-            // Collide
-            this.collider._collide(subMesh['_trianglePlanes'], subMesh['_lastColliderWorldVertices'], <any>meshGeometry.indices, subMesh.indexStart, subMesh.indexStart + subMesh.indexCount, subMesh.verticesStart, subMesh.hasMaterial);
-
-        }
-
-        private checkSubmeshCollision(subMesh: SerializedSubMesh): boolean {
-            return this.collider._canDoCollision(Vector3.FromArray(subMesh.sphereCenter), subMesh.sphereRadius, Vector3.FromArray(subMesh.boxMinimum), Vector3.FromArray(subMesh.boxMaximum));
-        }
-    }
-
-    export interface ICollisionDetector {
-        onInit(payload: InitPayload): void;
-        onUpdate(payload: UpdatePayload): void;
-        onCollision(payload: CollidePayload): void;
-    }
-
-    export class CollisionDetectorTransferable implements ICollisionDetector {
-        private _collisionCache: CollisionCache;
-
-        public onInit(payload: InitPayload) {
-            this._collisionCache = new CollisionCache();
-            var reply: WorkerReply = {
-                error: WorkerReplyType.SUCCESS,
-                taskType: WorkerTaskType.INIT
-            }
-            postMessage(reply, undefined);
-        }
-
-        public onUpdate(payload: UpdatePayload) {
-            var replay: WorkerReply = {
-                error: WorkerReplyType.SUCCESS,
-                taskType: WorkerTaskType.UPDATE
-            }
-
-            try {
-                for (var id in payload.updatedGeometries) {
-                    if (payload.updatedGeometries.hasOwnProperty(id)) {
-                        this._collisionCache.addGeometry(payload.updatedGeometries[id]);
-                    }
-                }
-                for (var uniqueId in payload.updatedMeshes) {
-                    if (payload.updatedMeshes.hasOwnProperty(uniqueId)) {
-                        this._collisionCache.addMesh(payload.updatedMeshes[uniqueId]);
-                    }
-                }
-
-                payload.removedGeometries.forEach((id) => {
-                    this._collisionCache.removeGeometry(id);
-                });
-
-                payload.removedMeshes.forEach((uniqueId) => {
-                    this._collisionCache.removeMesh(uniqueId);
-                });
-
-            } catch (x) {
-                replay.error = WorkerReplyType.UNKNOWN_ERROR;
-            }
-
-
-            postMessage(replay, undefined);
-        }
-
-        public onCollision(payload: CollidePayload) {
-            var finalPosition = Vector3.Zero();
-            //create a new collider
-            var collider = new Collider();
-            collider.radius = Vector3.FromArray(payload.collider.radius);
-
-            var colliderWorker = new CollideWorker(collider, this._collisionCache, finalPosition);
-            colliderWorker.collideWithWorld(Vector3.FromArray(payload.collider.position), Vector3.FromArray(payload.collider.velocity), payload.maximumRetry, payload.excludedMeshUniqueId);
-            var replyPayload: CollisionReplyPayload = {
-                collidedMeshUniqueId: <any>collider.collidedMesh,
-                collisionId: payload.collisionId,
-                newPosition: finalPosition.asArray()
-            }
-            var reply: WorkerReply = {
-                error: WorkerReplyType.SUCCESS,
-                taskType: WorkerTaskType.COLLIDE,
-                payload: replyPayload
-            }
-            postMessage(reply, undefined);
-        }
-    }
-
-    //TypeScript doesn't know WorkerGlobalScope
-    declare class WorkerGlobalScope { }
-
-    //check if we are in a web worker, as this code should NOT run on the main UI thread
-    try {
-        if (self && self instanceof WorkerGlobalScope) {
-
-            //Window hack to allow including babylonjs native code. the <any> is for typescript.
-            window = <any>{};
-
-            //scripts were not included, standalone worker
-            if (!BABYLON.Collider) {
-                importScripts("./babylon.collisionCoordinator.js");
-                importScripts("./babylon.collider.js");
-                importScripts("../Math/babylon.math.js");
-            }
-
-            var collisionDetector: ICollisionDetector = new CollisionDetectorTransferable();
-
-            var onNewMessage = (event: MessageEvent) => {
-                var message = <BabylonMessage>event.data;
-                switch (message.taskType) {
-                case WorkerTaskType.INIT:
-                    collisionDetector.onInit(<InitPayload>message.payload);
-                    break;
-                case WorkerTaskType.COLLIDE:
-                    collisionDetector.onCollision(<CollidePayload>message.payload);
-                    break;
-                case WorkerTaskType.UPDATE:
-                    collisionDetector.onUpdate(<UpdatePayload>message.payload);
-                    break;
-                }
-            }
-
-            self.onmessage = onNewMessage;
-        }
-    } catch (e) {
-        console.log("single worker init");
-    }
-}
+module BABYLON {
+
+    //If this file is included in the main thread, this will be initialized.
+    export var WorkerIncluded: boolean = true;
+
+    export class CollisionCache {
+        private _meshes: { [n: number]: SerializedMesh; } = {};
+        private _geometries: { [s: number]: SerializedGeometry; } = {};
+
+        public getMeshes(): { [n: number]: SerializedMesh; } {
+            return this._meshes;
+        }
+
+        public getGeometries(): { [s: number]: SerializedGeometry; } {
+            return this._geometries;
+        }
+
+        public getMesh(id: any): SerializedMesh {
+            return this._meshes[id];
+        }
+
+        public addMesh(mesh: SerializedMesh) {
+            this._meshes[mesh.uniqueId] = mesh;
+        }
+
+        public removeMesh(uniqueId: number) {
+            delete this._meshes[uniqueId];
+        }
+
+        public getGeometry(id: string): SerializedGeometry {
+            return this._geometries[id];
+        }
+
+        public addGeometry(geometry: SerializedGeometry) {
+            this._geometries[geometry.id] = geometry;
+        }
+
+        public removeGeometry(id: string) {
+            delete this._geometries[id];
+        }
+    }
+
+    export class CollideWorker {
+
+        private collisionsScalingMatrix = Matrix.Zero();
+        private collisionTranformationMatrix = Matrix.Zero();
+
+        constructor(public collider: Collider, private _collisionCache: CollisionCache, private finalPosition: Vector3) {
+
+        }
+
+        public collideWithWorld(position: Vector3, velocity: Vector3, maximumRetry: number, excludedMeshUniqueId?: number) {
+
+            //TODO CollisionsEpsilon should be defined here and not in the engine.
+            const closeDistance = 0.01; //is initializing here correct? A quick look - looks like it is fine.
+            if (this.collider.retry >= maximumRetry) {
+                this.finalPosition.copyFrom(position);
+                return;
+            }
+
+            this.collider._initialize(position, velocity, closeDistance);
+
+            // Check all meshes
+            var meshes = this._collisionCache.getMeshes();
+            var keys = Object.keys(meshes);
+            var len = keys.length;
+            var uniqueId;
+
+            for (var i = 0; i < len; ++i) {
+                uniqueId = keys[i];
+                if (parseInt(uniqueId) != excludedMeshUniqueId) {
+                    var mesh: SerializedMesh = meshes[uniqueId];
+                    if (mesh.checkCollisions)
+                        this.checkCollision(mesh);
+                }
+            }
+
+            if (!this.collider.collisionFound) {
+                position.addToRef(velocity, this.finalPosition);
+                return;
+            }
+
+            if (velocity.x !== 0 || velocity.y !== 0 || velocity.z !== 0) {
+                this.collider._getResponse(position, velocity);
+            }
+
+            if (velocity.length() <= closeDistance) {
+                this.finalPosition.copyFrom(position);
+                return;
+            }
+
+            this.collider.retry++;
+            this.collideWithWorld(position, velocity, maximumRetry, excludedMeshUniqueId);
+        }
+
+        private checkCollision(mesh: SerializedMesh) {
+
+            if (!this.collider._canDoCollision(Vector3.FromArray(mesh.sphereCenter), mesh.sphereRadius, Vector3.FromArray(mesh.boxMinimum), Vector3.FromArray(mesh.boxMaximum))) {
+                return;
+            };
+
+            // Transformation matrix
+            Matrix.ScalingToRef(1.0 / this.collider.radius.x, 1.0 / this.collider.radius.y, 1.0 / this.collider.radius.z, this.collisionsScalingMatrix);
+            var worldFromCache = Matrix.FromArray(mesh.worldMatrixFromCache);
+            worldFromCache.multiplyToRef(this.collisionsScalingMatrix, this.collisionTranformationMatrix);
+
+            this.processCollisionsForSubMeshes(this.collisionTranformationMatrix, mesh);
+            //return colTransMat;
+        }
+
+        private processCollisionsForSubMeshes(transformMatrix: Matrix, mesh: SerializedMesh): void { // No Octrees for now
+            //if (this._submeshesOctree && this.useOctreeForCollisions) {
+            //    var radius = collider.velocityWorldLength + Math.max(collider.radius.x, collider.radius.y, collider.radius.z);
+            //    var intersections = this._submeshesOctree.intersects(collider.basePointWorld, radius);
+
+            //    len = intersections.length;
+            //    subMeshes = intersections.data;
+            //} else {
+            var subMeshes = mesh.subMeshes;
+            var len = subMeshes.length;
+            //}
+
+            if (!mesh.geometryId) {
+                console.log("no mesh geometry id");
+                return;
+            }
+
+            var meshGeometry = this._collisionCache.getGeometry(mesh.geometryId);
+            if (!meshGeometry) {
+                console.log("couldn't find geometry", mesh.geometryId);
+                return;
+            }
+
+            for (var index = 0; index < len; index++) {
+                var subMesh = subMeshes[index];
+
+                // Bounding test
+                if (len > 1 && !this.checkSubmeshCollision(subMesh))
+                    continue;
+
+                this.collideForSubMesh(subMesh, transformMatrix, meshGeometry);
+                if (this.collider.collisionFound) {
+                    this.collider.collidedMesh = <any>mesh.uniqueId;
+                }
+            }
+        }
+
+        private collideForSubMesh(subMesh: SerializedSubMesh, transformMatrix: Matrix, meshGeometry: SerializedGeometry): void {
+            if (!meshGeometry['positionsArray']) {
+                meshGeometry['positionsArray'] = [];
+                for (var i = 0, len = meshGeometry.positions.length; i < len; i = i + 3) {
+                    var p = Vector3.FromArray([meshGeometry.positions[i], meshGeometry.positions[i + 1], meshGeometry.positions[i + 2]]);
+                    meshGeometry['positionsArray'].push(p);
+                }
+            }
+
+            if (!subMesh['_lastColliderWorldVertices'] || !subMesh['_lastColliderTransformMatrix'].equals(transformMatrix)) {
+                subMesh['_lastColliderTransformMatrix'] = transformMatrix.clone();
+                subMesh['_lastColliderWorldVertices'] = [];
+                subMesh['_trianglePlanes'] = [];
+                var start = subMesh.verticesStart;
+                var end = (subMesh.verticesStart + subMesh.verticesCount);
+                for (var i = start; i < end; i++) {
+                    subMesh['_lastColliderWorldVertices'].push(Vector3.TransformCoordinates(meshGeometry['positionsArray'][i], transformMatrix));
+                }
+            }        
+
+            // Collide
+            this.collider._collide(subMesh['_trianglePlanes'], subMesh['_lastColliderWorldVertices'], <any>meshGeometry.indices, subMesh.indexStart, subMesh.indexStart + subMesh.indexCount, subMesh.verticesStart, subMesh.hasMaterial);
+
+        }
+
+        private checkSubmeshCollision(subMesh: SerializedSubMesh): boolean {
+            return this.collider._canDoCollision(Vector3.FromArray(subMesh.sphereCenter), subMesh.sphereRadius, Vector3.FromArray(subMesh.boxMinimum), Vector3.FromArray(subMesh.boxMaximum));
+        }
+    }
+
+    export interface ICollisionDetector {
+        onInit(payload: InitPayload): void;
+        onUpdate(payload: UpdatePayload): void;
+        onCollision(payload: CollidePayload): void;
+    }
+
+    export class CollisionDetectorTransferable implements ICollisionDetector {
+        private _collisionCache: CollisionCache;
+
+        public onInit(payload: InitPayload) {
+            this._collisionCache = new CollisionCache();
+            var reply: WorkerReply = {
+                error: WorkerReplyType.SUCCESS,
+                taskType: WorkerTaskType.INIT
+            }
+            postMessage(reply, undefined);
+        }
+
+        public onUpdate(payload: UpdatePayload) {
+            var replay: WorkerReply = {
+                error: WorkerReplyType.SUCCESS,
+                taskType: WorkerTaskType.UPDATE
+            }
+
+            try {
+                for (var id in payload.updatedGeometries) {
+                    if (payload.updatedGeometries.hasOwnProperty(id)) {
+                        this._collisionCache.addGeometry(payload.updatedGeometries[id]);
+                    }
+                }
+                for (var uniqueId in payload.updatedMeshes) {
+                    if (payload.updatedMeshes.hasOwnProperty(uniqueId)) {
+                        this._collisionCache.addMesh(payload.updatedMeshes[uniqueId]);
+                    }
+                }
+
+                payload.removedGeometries.forEach((id) => {
+                    this._collisionCache.removeGeometry(id);
+                });
+
+                payload.removedMeshes.forEach((uniqueId) => {
+                    this._collisionCache.removeMesh(uniqueId);
+                });
+
+            } catch (x) {
+                replay.error = WorkerReplyType.UNKNOWN_ERROR;
+            }
+
+
+            postMessage(replay, undefined);
+        }
+
+        public onCollision(payload: CollidePayload) {
+            var finalPosition = Vector3.Zero();
+            //create a new collider
+            var collider = new Collider();
+            collider.radius = Vector3.FromArray(payload.collider.radius);
+
+            var colliderWorker = new CollideWorker(collider, this._collisionCache, finalPosition);
+            colliderWorker.collideWithWorld(Vector3.FromArray(payload.collider.position), Vector3.FromArray(payload.collider.velocity), payload.maximumRetry, payload.excludedMeshUniqueId);
+            var replyPayload: CollisionReplyPayload = {
+                collidedMeshUniqueId: <any>collider.collidedMesh,
+                collisionId: payload.collisionId,
+                newPosition: finalPosition.asArray()
+            }
+            var reply: WorkerReply = {
+                error: WorkerReplyType.SUCCESS,
+                taskType: WorkerTaskType.COLLIDE,
+                payload: replyPayload
+            }
+            postMessage(reply, undefined);
+        }
+    }
+
+    //TypeScript doesn't know WorkerGlobalScope
+    declare class WorkerGlobalScope { }
+
+    //check if we are in a web worker, as this code should NOT run on the main UI thread
+    try {
+        if (self && self instanceof WorkerGlobalScope) {
+
+            //Window hack to allow including babylonjs native code. the <any> is for typescript.
+            window = <any>{};
+
+            //scripts were not included, standalone worker
+            if (!BABYLON.Collider) {
+                importScripts("./babylon.collisionCoordinator.js");
+                importScripts("./babylon.collider.js");
+                importScripts("../Math/babylon.math.js");
+            }
+
+            var collisionDetector: ICollisionDetector = new CollisionDetectorTransferable();
+
+            var onNewMessage = (event: MessageEvent) => {
+                var message = <BabylonMessage>event.data;
+                switch (message.taskType) {
+                case WorkerTaskType.INIT:
+                    collisionDetector.onInit(<InitPayload>message.payload);
+                    break;
+                case WorkerTaskType.COLLIDE:
+                    collisionDetector.onCollision(<CollidePayload>message.payload);
+                    break;
+                case WorkerTaskType.UPDATE:
+                    collisionDetector.onUpdate(<UpdatePayload>message.payload);
+                    break;
+                }
+            }
+
+            self.onmessage = onNewMessage;
+        }
+    } catch (e) {
+        console.log("single worker init");
+    }
+}

+ 82 - 82
src/Collisions/babylon.pickingInfo.ts

@@ -1,82 +1,82 @@
-module BABYLON {
-    export class IntersectionInfo {
-        public faceId = 0;
-        public subMeshId = 0;
-
-        constructor(public bu: number, public bv: number, public distance: number) {
-        }
-    }
-
-    export class PickingInfo {
-        public hit = false;
-        public distance = 0;
-        public pickedPoint: Vector3 = null;
-        public pickedMesh: AbstractMesh = null;
-        public bu = 0;
-        public bv = 0;
-        public faceId = -1;
-        public subMeshId = 0;
-        public pickedSprite: Sprite = null;
-
-        // Methods
-        public getNormal(useWorldCoordinates = false, useVerticesNormals = true): Vector3 {
-            if (!this.pickedMesh || !this.pickedMesh.isVerticesDataPresent(VertexBuffer.NormalKind)) {
-                return null;
-            }
-
-            var indices = this.pickedMesh.getIndices();
-            var result: Vector3;
-
-            if (useVerticesNormals) {
-                var normals = this.pickedMesh.getVerticesData(VertexBuffer.NormalKind);
-
-                var normal0 = Vector3.FromArray(normals, indices[this.faceId * 3] * 3);
-                var normal1 = Vector3.FromArray(normals, indices[this.faceId * 3 + 1] * 3);
-                var normal2 = Vector3.FromArray(normals, indices[this.faceId * 3 + 2] * 3);
-
-                normal0 = normal0.scale(this.bu);
-                normal1 = normal1.scale(this.bv);
-                normal2 = normal2.scale(1.0 - this.bu - this.bv);
-
-                result = new Vector3(normal0.x + normal1.x + normal2.x, normal0.y + normal1.y + normal2.y, normal0.z + normal1.z + normal2.z);
-            } else {
-                var positions = this.pickedMesh.getVerticesData(VertexBuffer.PositionKind);
-
-                var vertex1 = Vector3.FromArray(positions, indices[this.faceId * 3] * 3);
-                var vertex2 = Vector3.FromArray(positions, indices[this.faceId * 3 + 1] * 3);
-                var vertex3 = Vector3.FromArray(positions, indices[this.faceId * 3 + 2] * 3);
-
-                var p1p2 = vertex1.subtract(vertex2);
-                var p3p2 = vertex3.subtract(vertex2);
-
-                result = BABYLON.Vector3.Cross(p1p2, p3p2);
-            }
-
-            if (useWorldCoordinates) {
-                result = Vector3.TransformNormal(result, this.pickedMesh.getWorldMatrix());
-            }
-
-            return BABYLON.Vector3.Normalize(result);
-        }
-
-        public getTextureCoordinates(): Vector2 {
-            if (!this.pickedMesh || !this.pickedMesh.isVerticesDataPresent(VertexBuffer.UVKind)) {
-                return null;
-            }
-
-            var indices = this.pickedMesh.getIndices();
-            var uvs = this.pickedMesh.getVerticesData(VertexBuffer.UVKind);
-
-            var uv0 = Vector2.FromArray(uvs, indices[this.faceId * 3] * 2);
-            var uv1 = Vector2.FromArray(uvs, indices[this.faceId * 3 + 1] * 2);
-            var uv2 = Vector2.FromArray(uvs, indices[this.faceId * 3 + 2] * 2);
-
-            uv0 = uv0.scale(1.0 - this.bu - this.bv);
-            uv1 = uv1.scale(this.bu);
-            uv2 = uv2.scale(this.bv);
-
-            return new Vector2(uv0.x + uv1.x + uv2.x, uv0.y + uv1.y + uv2.y);
-        }
-    }
-} 
-
+module BABYLON {
+    export class IntersectionInfo {
+        public faceId = 0;
+        public subMeshId = 0;
+
+        constructor(public bu: number, public bv: number, public distance: number) {
+        }
+    }
+
+    export class PickingInfo {
+        public hit = false;
+        public distance = 0;
+        public pickedPoint: Vector3 = null;
+        public pickedMesh: AbstractMesh = null;
+        public bu = 0;
+        public bv = 0;
+        public faceId = -1;
+        public subMeshId = 0;
+        public pickedSprite: Sprite = null;
+
+        // Methods
+        public getNormal(useWorldCoordinates = false, useVerticesNormals = true): Vector3 {
+            if (!this.pickedMesh || !this.pickedMesh.isVerticesDataPresent(VertexBuffer.NormalKind)) {
+                return null;
+            }
+
+            var indices = this.pickedMesh.getIndices();
+            var result: Vector3;
+
+            if (useVerticesNormals) {
+                var normals = this.pickedMesh.getVerticesData(VertexBuffer.NormalKind);
+
+                var normal0 = Vector3.FromArray(normals, indices[this.faceId * 3] * 3);
+                var normal1 = Vector3.FromArray(normals, indices[this.faceId * 3 + 1] * 3);
+                var normal2 = Vector3.FromArray(normals, indices[this.faceId * 3 + 2] * 3);
+
+                normal0 = normal0.scale(this.bu);
+                normal1 = normal1.scale(this.bv);
+                normal2 = normal2.scale(1.0 - this.bu - this.bv);
+
+                result = new Vector3(normal0.x + normal1.x + normal2.x, normal0.y + normal1.y + normal2.y, normal0.z + normal1.z + normal2.z);
+            } else {
+                var positions = this.pickedMesh.getVerticesData(VertexBuffer.PositionKind);
+
+                var vertex1 = Vector3.FromArray(positions, indices[this.faceId * 3] * 3);
+                var vertex2 = Vector3.FromArray(positions, indices[this.faceId * 3 + 1] * 3);
+                var vertex3 = Vector3.FromArray(positions, indices[this.faceId * 3 + 2] * 3);
+
+                var p1p2 = vertex1.subtract(vertex2);
+                var p3p2 = vertex3.subtract(vertex2);
+
+                result = BABYLON.Vector3.Cross(p1p2, p3p2);
+            }
+
+            if (useWorldCoordinates) {
+                result = Vector3.TransformNormal(result, this.pickedMesh.getWorldMatrix());
+            }
+
+            return BABYLON.Vector3.Normalize(result);
+        }
+
+        public getTextureCoordinates(): Vector2 {
+            if (!this.pickedMesh || !this.pickedMesh.isVerticesDataPresent(VertexBuffer.UVKind)) {
+                return null;
+            }
+
+            var indices = this.pickedMesh.getIndices();
+            var uvs = this.pickedMesh.getVerticesData(VertexBuffer.UVKind);
+
+            var uv0 = Vector2.FromArray(uvs, indices[this.faceId * 3] * 2);
+            var uv1 = Vector2.FromArray(uvs, indices[this.faceId * 3 + 1] * 2);
+            var uv2 = Vector2.FromArray(uvs, indices[this.faceId * 3 + 2] * 2);
+
+            uv0 = uv0.scale(1.0 - this.bu - this.bv);
+            uv1 = uv1.scale(this.bu);
+            uv2 = uv2.scale(this.bv);
+
+            return new Vector2(uv0.x + uv1.x + uv2.x, uv0.y + uv1.y + uv2.y);
+        }
+    }
+} 
+

+ 109 - 109
src/Culling/Octrees/babylon.octree.ts

@@ -1,110 +1,110 @@
-module BABYLON {
-    export interface IOctreeContainer<T> {
-        blocks: Array<OctreeBlock<T>>;
-    }
-
-    export class Octree<T> {
-        public blocks: Array<OctreeBlock<T>>;
-        public dynamicContent = new Array<T>();
-
-        private _maxBlockCapacity: number;
-        private _selectionContent: SmartArray<T>;       
-        private _creationFunc: (entry: T, block: OctreeBlock<T>) => void;
-
-        constructor(creationFunc: (entry: T, block: OctreeBlock<T>) => void, maxBlockCapacity?: number, public maxDepth = 2) {
-            this._maxBlockCapacity = maxBlockCapacity || 64;
-            this._selectionContent = new SmartArray<T>(1024);
-            this._creationFunc = creationFunc;
-        }
-
-        // Methods
-        public update(worldMin: Vector3, worldMax: Vector3, entries: T[]): void {
-            Octree._CreateBlocks(worldMin, worldMax, entries, this._maxBlockCapacity, 0, this.maxDepth, this, this._creationFunc);
-        }
-
-        public addMesh(entry: T): void {
-            for (var index = 0; index < this.blocks.length; index++) {
-                var block = this.blocks[index];
-                block.addEntry(entry);
-            }
-        }
-
-        public select(frustumPlanes: Plane[], allowDuplicate?: boolean): SmartArray<T> {
-            this._selectionContent.reset();
-
-            for (var index = 0; index < this.blocks.length; index++) {
-                var block = this.blocks[index];
-                block.select(frustumPlanes, this._selectionContent, allowDuplicate);
-            }
-
-            if (allowDuplicate) {
-                this._selectionContent.concat(this.dynamicContent);
-            } else {
-                this._selectionContent.concatWithNoDuplicate(this.dynamicContent);                
-            }
-
-            return this._selectionContent;
-        }
-
-        public intersects(sphereCenter: Vector3, sphereRadius: number, allowDuplicate?: boolean): SmartArray<T> {
-            this._selectionContent.reset();
-
-            for (var index = 0; index < this.blocks.length; index++) {
-                var block = this.blocks[index];
-                block.intersects(sphereCenter, sphereRadius, this._selectionContent, allowDuplicate);
-            }
-
-            if (allowDuplicate) {
-                this._selectionContent.concat(this.dynamicContent);
-            } else {
-                this._selectionContent.concatWithNoDuplicate(this.dynamicContent);
-            }
-
-            return this._selectionContent;
-        }
-
-        public intersectsRay(ray: Ray): SmartArray<T> {
-            this._selectionContent.reset();
-
-            for (var index = 0; index < this.blocks.length; index++) {
-                var block = this.blocks[index];
-                block.intersectsRay(ray, this._selectionContent);
-            }
-
-            this._selectionContent.concatWithNoDuplicate(this.dynamicContent);
-
-            return this._selectionContent;
-        }
-
-        public static _CreateBlocks<T>(worldMin: Vector3, worldMax: Vector3, entries: T[], maxBlockCapacity: number, currentDepth: number, maxDepth: number, target: IOctreeContainer<T>, creationFunc: (entry: T, block: OctreeBlock<T>) => void): void {
-            target.blocks = new Array<OctreeBlock<T>>();
-            var blockSize = new Vector3((worldMax.x - worldMin.x) / 2, (worldMax.y - worldMin.y) / 2, (worldMax.z - worldMin.z) / 2);
-
-            // Segmenting space
-            for (var x = 0; x < 2; x++) {
-                for (var y = 0; y < 2; y++) {
-                    for (var z = 0; z < 2; z++) {
-                        var localMin = worldMin.add(blockSize.multiplyByFloats(x, y, z));
-                        var localMax = worldMin.add(blockSize.multiplyByFloats(x + 1, y + 1, z + 1));
-
-                        var block = new OctreeBlock<T>(localMin, localMax, maxBlockCapacity, currentDepth + 1, maxDepth, creationFunc);
-                        block.addEntries(entries);
-                        target.blocks.push(block);
-                    }
-                }
-            }
-        }
-
-        public static CreationFuncForMeshes = (entry: AbstractMesh, block: OctreeBlock<AbstractMesh>): void => {
-            if (!entry.isBlocked && entry.getBoundingInfo().boundingBox.intersectsMinMax(block.minPoint, block.maxPoint)) {
-                block.entries.push(entry);
-            }
-        }
-
-        public static CreationFuncForSubMeshes = (entry: SubMesh, block: OctreeBlock<SubMesh>): void => {
-            if (entry.getBoundingInfo().boundingBox.intersectsMinMax(block.minPoint, block.maxPoint)) {
-                block.entries.push(entry);
-            }
-        }
-    }
+module BABYLON {
+    export interface IOctreeContainer<T> {
+        blocks: Array<OctreeBlock<T>>;
+    }
+
+    export class Octree<T> {
+        public blocks: Array<OctreeBlock<T>>;
+        public dynamicContent = new Array<T>();
+
+        private _maxBlockCapacity: number;
+        private _selectionContent: SmartArray<T>;       
+        private _creationFunc: (entry: T, block: OctreeBlock<T>) => void;
+
+        constructor(creationFunc: (entry: T, block: OctreeBlock<T>) => void, maxBlockCapacity?: number, public maxDepth = 2) {
+            this._maxBlockCapacity = maxBlockCapacity || 64;
+            this._selectionContent = new SmartArray<T>(1024);
+            this._creationFunc = creationFunc;
+        }
+
+        // Methods
+        public update(worldMin: Vector3, worldMax: Vector3, entries: T[]): void {
+            Octree._CreateBlocks(worldMin, worldMax, entries, this._maxBlockCapacity, 0, this.maxDepth, this, this._creationFunc);
+        }
+
+        public addMesh(entry: T): void {
+            for (var index = 0; index < this.blocks.length; index++) {
+                var block = this.blocks[index];
+                block.addEntry(entry);
+            }
+        }
+
+        public select(frustumPlanes: Plane[], allowDuplicate?: boolean): SmartArray<T> {
+            this._selectionContent.reset();
+
+            for (var index = 0; index < this.blocks.length; index++) {
+                var block = this.blocks[index];
+                block.select(frustumPlanes, this._selectionContent, allowDuplicate);
+            }
+
+            if (allowDuplicate) {
+                this._selectionContent.concat(this.dynamicContent);
+            } else {
+                this._selectionContent.concatWithNoDuplicate(this.dynamicContent);                
+            }
+
+            return this._selectionContent;
+        }
+
+        public intersects(sphereCenter: Vector3, sphereRadius: number, allowDuplicate?: boolean): SmartArray<T> {
+            this._selectionContent.reset();
+
+            for (var index = 0; index < this.blocks.length; index++) {
+                var block = this.blocks[index];
+                block.intersects(sphereCenter, sphereRadius, this._selectionContent, allowDuplicate);
+            }
+
+            if (allowDuplicate) {
+                this._selectionContent.concat(this.dynamicContent);
+            } else {
+                this._selectionContent.concatWithNoDuplicate(this.dynamicContent);
+            }
+
+            return this._selectionContent;
+        }
+
+        public intersectsRay(ray: Ray): SmartArray<T> {
+            this._selectionContent.reset();
+
+            for (var index = 0; index < this.blocks.length; index++) {
+                var block = this.blocks[index];
+                block.intersectsRay(ray, this._selectionContent);
+            }
+
+            this._selectionContent.concatWithNoDuplicate(this.dynamicContent);
+
+            return this._selectionContent;
+        }
+
+        public static _CreateBlocks<T>(worldMin: Vector3, worldMax: Vector3, entries: T[], maxBlockCapacity: number, currentDepth: number, maxDepth: number, target: IOctreeContainer<T>, creationFunc: (entry: T, block: OctreeBlock<T>) => void): void {
+            target.blocks = new Array<OctreeBlock<T>>();
+            var blockSize = new Vector3((worldMax.x - worldMin.x) / 2, (worldMax.y - worldMin.y) / 2, (worldMax.z - worldMin.z) / 2);
+
+            // Segmenting space
+            for (var x = 0; x < 2; x++) {
+                for (var y = 0; y < 2; y++) {
+                    for (var z = 0; z < 2; z++) {
+                        var localMin = worldMin.add(blockSize.multiplyByFloats(x, y, z));
+                        var localMax = worldMin.add(blockSize.multiplyByFloats(x + 1, y + 1, z + 1));
+
+                        var block = new OctreeBlock<T>(localMin, localMax, maxBlockCapacity, currentDepth + 1, maxDepth, creationFunc);
+                        block.addEntries(entries);
+                        target.blocks.push(block);
+                    }
+                }
+            }
+        }
+
+        public static CreationFuncForMeshes = (entry: AbstractMesh, block: OctreeBlock<AbstractMesh>): void => {
+            if (!entry.isBlocked && entry.getBoundingInfo().boundingBox.intersectsMinMax(block.minPoint, block.maxPoint)) {
+                block.entries.push(entry);
+            }
+        }
+
+        public static CreationFuncForSubMeshes = (entry: SubMesh, block: OctreeBlock<SubMesh>): void => {
+            if (entry.getBoundingInfo().boundingBox.intersectsMinMax(block.minPoint, block.maxPoint)) {
+                block.entries.push(entry);
+            }
+        }
+    }
 } 

+ 134 - 134
src/Culling/Octrees/babylon.octreeBlock.ts

@@ -1,135 +1,135 @@
-module BABYLON {
-    export class OctreeBlock<T> {
-        public entries = new Array<T>();
-        public blocks: Array<OctreeBlock<T>>;
-
-        private _depth: number;
-        private _maxDepth: number;
-        private _capacity: number;
-        private _minPoint: Vector3;
-        private _maxPoint: Vector3;
-        private _boundingVectors = new Array<Vector3>();
-        private _creationFunc: (entry: T, block: OctreeBlock<T>) => void;
-
-        constructor(minPoint: Vector3, maxPoint: Vector3, capacity: number, depth: number, maxDepth: number, creationFunc: (entry: T, block: OctreeBlock<T>) => void) {
-            this._capacity = capacity;
-            this._depth = depth;
-            this._maxDepth = maxDepth;
-            this._creationFunc = creationFunc;
-
-            this._minPoint = minPoint;
-            this._maxPoint = maxPoint;
-
-            this._boundingVectors.push(minPoint.clone());
-            this._boundingVectors.push(maxPoint.clone());
-
-            this._boundingVectors.push(minPoint.clone());
-            this._boundingVectors[2].x = maxPoint.x;
-
-            this._boundingVectors.push(minPoint.clone());
-            this._boundingVectors[3].y = maxPoint.y;
-
-            this._boundingVectors.push(minPoint.clone());
-            this._boundingVectors[4].z = maxPoint.z;
-
-            this._boundingVectors.push(maxPoint.clone());
-            this._boundingVectors[5].z = minPoint.z;
-
-            this._boundingVectors.push(maxPoint.clone());
-            this._boundingVectors[6].x = minPoint.x;
-
-            this._boundingVectors.push(maxPoint.clone());
-            this._boundingVectors[7].y = minPoint.y;
-        }
-
-        // Property
-        public get capacity(): number {
-            return this._capacity;
-        }
-
-        public get minPoint(): Vector3 {
-            return this._minPoint;
-        }
-
-        public get maxPoint(): Vector3 {
-            return this._maxPoint;
-        }
-
-        // Methods
-        public addEntry(entry: T): void {
-            if (this.blocks) {
-                for (var index = 0; index < this.blocks.length; index++) {
-                    var block = this.blocks[index];
-                    block.addEntry(entry);
-                }
-                return;
-            }
-
-            this._creationFunc(entry, this);
-
-            if (this.entries.length > this.capacity && this._depth < this._maxDepth) {
-                this.createInnerBlocks();
-            }
-        }
-
-        public addEntries(entries: T[]): void {
-            for (var index = 0; index < entries.length; index++) {
-                var mesh = entries[index];
-                this.addEntry(mesh);
-            }
-        }
-
-        public select(frustumPlanes: Plane[], selection: SmartArray<T>, allowDuplicate?: boolean): void {
-            if (BoundingBox.IsInFrustum(this._boundingVectors, frustumPlanes)) {
-                if (this.blocks) {
-                    for (var index = 0; index < this.blocks.length; index++) {
-                        var block = this.blocks[index];
-                        block.select(frustumPlanes, selection, allowDuplicate);
-                    }
-                    return;
-                }
-
-                if (allowDuplicate) {
-                    selection.concat(this.entries);
-                } else {
-                    selection.concatWithNoDuplicate(this.entries);
-                }
-            }
-        }
-
-        public intersects(sphereCenter: Vector3, sphereRadius: number, selection: SmartArray<T>, allowDuplicate?: boolean): void {
-            if (BoundingBox.IntersectsSphere(this._minPoint, this._maxPoint, sphereCenter, sphereRadius)) {
-                if (this.blocks) {
-                    for (var index = 0; index < this.blocks.length; index++) {
-                        var block = this.blocks[index];
-                        block.intersects(sphereCenter, sphereRadius, selection, allowDuplicate);
-                    }
-                    return;
-                }
-
-                if (allowDuplicate) {
-                    selection.concat(this.entries);
-                } else {
-                    selection.concatWithNoDuplicate(this.entries);
-                }
-            }
-        }
-
-        public intersectsRay(ray: Ray, selection: SmartArray<T>): void {
-            if (ray.intersectsBoxMinMax(this._minPoint, this._maxPoint)) {
-                if (this.blocks) {
-                    for (var index = 0; index < this.blocks.length; index++) {
-                        var block = this.blocks[index];
-                        block.intersectsRay(ray, selection);
-                    }
-                    return;
-                }
-                selection.concatWithNoDuplicate(this.entries);
-            }
-        }
-
-        public createInnerBlocks(): void {
-            Octree._CreateBlocks(this._minPoint, this._maxPoint, this.entries, this._capacity, this._depth, this._maxDepth, this, this._creationFunc);
-        }
-    }
+module BABYLON {
+    export class OctreeBlock<T> {
+        public entries = new Array<T>();
+        public blocks: Array<OctreeBlock<T>>;
+
+        private _depth: number;
+        private _maxDepth: number;
+        private _capacity: number;
+        private _minPoint: Vector3;
+        private _maxPoint: Vector3;
+        private _boundingVectors = new Array<Vector3>();
+        private _creationFunc: (entry: T, block: OctreeBlock<T>) => void;
+
+        constructor(minPoint: Vector3, maxPoint: Vector3, capacity: number, depth: number, maxDepth: number, creationFunc: (entry: T, block: OctreeBlock<T>) => void) {
+            this._capacity = capacity;
+            this._depth = depth;
+            this._maxDepth = maxDepth;
+            this._creationFunc = creationFunc;
+
+            this._minPoint = minPoint;
+            this._maxPoint = maxPoint;
+
+            this._boundingVectors.push(minPoint.clone());
+            this._boundingVectors.push(maxPoint.clone());
+
+            this._boundingVectors.push(minPoint.clone());
+            this._boundingVectors[2].x = maxPoint.x;
+
+            this._boundingVectors.push(minPoint.clone());
+            this._boundingVectors[3].y = maxPoint.y;
+
+            this._boundingVectors.push(minPoint.clone());
+            this._boundingVectors[4].z = maxPoint.z;
+
+            this._boundingVectors.push(maxPoint.clone());
+            this._boundingVectors[5].z = minPoint.z;
+
+            this._boundingVectors.push(maxPoint.clone());
+            this._boundingVectors[6].x = minPoint.x;
+
+            this._boundingVectors.push(maxPoint.clone());
+            this._boundingVectors[7].y = minPoint.y;
+        }
+
+        // Property
+        public get capacity(): number {
+            return this._capacity;
+        }
+
+        public get minPoint(): Vector3 {
+            return this._minPoint;
+        }
+
+        public get maxPoint(): Vector3 {
+            return this._maxPoint;
+        }
+
+        // Methods
+        public addEntry(entry: T): void {
+            if (this.blocks) {
+                for (var index = 0; index < this.blocks.length; index++) {
+                    var block = this.blocks[index];
+                    block.addEntry(entry);
+                }
+                return;
+            }
+
+            this._creationFunc(entry, this);
+
+            if (this.entries.length > this.capacity && this._depth < this._maxDepth) {
+                this.createInnerBlocks();
+            }
+        }
+
+        public addEntries(entries: T[]): void {
+            for (var index = 0; index < entries.length; index++) {
+                var mesh = entries[index];
+                this.addEntry(mesh);
+            }
+        }
+
+        public select(frustumPlanes: Plane[], selection: SmartArray<T>, allowDuplicate?: boolean): void {
+            if (BoundingBox.IsInFrustum(this._boundingVectors, frustumPlanes)) {
+                if (this.blocks) {
+                    for (var index = 0; index < this.blocks.length; index++) {
+                        var block = this.blocks[index];
+                        block.select(frustumPlanes, selection, allowDuplicate);
+                    }
+                    return;
+                }
+
+                if (allowDuplicate) {
+                    selection.concat(this.entries);
+                } else {
+                    selection.concatWithNoDuplicate(this.entries);
+                }
+            }
+        }
+
+        public intersects(sphereCenter: Vector3, sphereRadius: number, selection: SmartArray<T>, allowDuplicate?: boolean): void {
+            if (BoundingBox.IntersectsSphere(this._minPoint, this._maxPoint, sphereCenter, sphereRadius)) {
+                if (this.blocks) {
+                    for (var index = 0; index < this.blocks.length; index++) {
+                        var block = this.blocks[index];
+                        block.intersects(sphereCenter, sphereRadius, selection, allowDuplicate);
+                    }
+                    return;
+                }
+
+                if (allowDuplicate) {
+                    selection.concat(this.entries);
+                } else {
+                    selection.concatWithNoDuplicate(this.entries);
+                }
+            }
+        }
+
+        public intersectsRay(ray: Ray, selection: SmartArray<T>): void {
+            if (ray.intersectsBoxMinMax(this._minPoint, this._maxPoint)) {
+                if (this.blocks) {
+                    for (var index = 0; index < this.blocks.length; index++) {
+                        var block = this.blocks[index];
+                        block.intersectsRay(ray, selection);
+                    }
+                    return;
+                }
+                selection.concatWithNoDuplicate(this.entries);
+            }
+        }
+
+        public createInnerBlocks(): void {
+            Octree._CreateBlocks(this._minPoint, this._maxPoint, this.entries, this._capacity, this._depth, this._maxDepth, this, this._creationFunc);
+        }
+    }
 } 

+ 177 - 177
src/Culling/babylon.boundingBox.ts

@@ -1,178 +1,178 @@
-module BABYLON {
-    export class BoundingBox {
-        public vectors: Vector3[] = new Array<Vector3>();
-        public center: Vector3;
-        public extendSize: Vector3;
-        public directions: Vector3[];
-        public vectorsWorld: Vector3[] = new Array<Vector3>();
-        public minimumWorld: Vector3;
-        public maximumWorld: Vector3;
-
-        private _worldMatrix: Matrix;
-
-        constructor(public minimum: Vector3, public maximum: Vector3) {
-            // Bounding vectors            
-            this.vectors.push(this.minimum.clone());
-            this.vectors.push(this.maximum.clone());
-
-            this.vectors.push(this.minimum.clone());
-            this.vectors[2].x = this.maximum.x;
-
-            this.vectors.push(this.minimum.clone());
-            this.vectors[3].y = this.maximum.y;
-
-            this.vectors.push(this.minimum.clone());
-            this.vectors[4].z = this.maximum.z;
-
-            this.vectors.push(this.maximum.clone());
-            this.vectors[5].z = this.minimum.z;
-
-            this.vectors.push(this.maximum.clone());
-            this.vectors[6].x = this.minimum.x;
-
-            this.vectors.push(this.maximum.clone());
-            this.vectors[7].y = this.minimum.y;
-            
-            // OBB
-            this.center = this.maximum.add(this.minimum).scale(0.5);
-            this.extendSize = this.maximum.subtract(this.minimum).scale(0.5);
-            this.directions = [Vector3.Zero(), Vector3.Zero(), Vector3.Zero()];
-
-            // World
-            for (var index = 0; index < this.vectors.length; index++) {
-                this.vectorsWorld[index] = Vector3.Zero();
-            }
-            this.minimumWorld = Vector3.Zero();
-            this.maximumWorld = Vector3.Zero();
-
-            this._update(Matrix.Identity());
-        }
-
-        // Methods
-        public getWorldMatrix(): Matrix {
-            return this._worldMatrix;
-        }
-
-        public _update(world: Matrix): void {
-            Vector3.FromFloatsToRef(Number.MAX_VALUE, Number.MAX_VALUE, Number.MAX_VALUE, this.minimumWorld);
-            Vector3.FromFloatsToRef(-Number.MAX_VALUE, -Number.MAX_VALUE, -Number.MAX_VALUE, this.maximumWorld);
-
-            for (var index = 0; index < this.vectors.length; index++) {
-                var v = this.vectorsWorld[index];
-                Vector3.TransformCoordinatesToRef(this.vectors[index], world, v);
-
-                if (v.x < this.minimumWorld.x)
-                    this.minimumWorld.x = v.x;
-                if (v.y < this.minimumWorld.y)
-                    this.minimumWorld.y = v.y;
-                if (v.z < this.minimumWorld.z)
-                    this.minimumWorld.z = v.z;
-
-                if (v.x > this.maximumWorld.x)
-                    this.maximumWorld.x = v.x;
-                if (v.y > this.maximumWorld.y)
-                    this.maximumWorld.y = v.y;
-                if (v.z > this.maximumWorld.z)
-                    this.maximumWorld.z = v.z;
-            }
-
-            // OBB
-            this.maximumWorld.addToRef(this.minimumWorld, this.center);
-            this.center.scaleInPlace(0.5);
-
-            Vector3.FromFloatArrayToRef(world.m, 0, this.directions[0]);
-            Vector3.FromFloatArrayToRef(world.m, 4, this.directions[1]);
-            Vector3.FromFloatArrayToRef(world.m, 8, this.directions[2]);
-
-            this._worldMatrix = world;
-        }
-
-        public isInFrustum(frustumPlanes: Plane[]): boolean {
-            return BoundingBox.IsInFrustum(this.vectorsWorld, frustumPlanes);
-        }
-
-        public isCompletelyInFrustum(frustumPlanes: Plane[]): boolean {
-            return BoundingBox.IsCompletelyInFrustum(this.vectorsWorld, frustumPlanes);
-        }
-
-        public intersectsPoint(point: Vector3): boolean {
-            var delta = -Engine.Epsilon;
-
-            if (this.maximumWorld.x - point.x < delta || delta > point.x - this.minimumWorld.x)
-                return false;
-
-            if (this.maximumWorld.y - point.y < delta || delta > point.y - this.minimumWorld.y)
-                return false;
-
-            if (this.maximumWorld.z - point.z < delta || delta > point.z - this.minimumWorld.z)
-                return false;
-
-            return true;
-        }
-
-        public intersectsSphere(sphere: BoundingSphere): boolean {
-            return BoundingBox.IntersectsSphere(this.minimumWorld, this.maximumWorld, sphere.centerWorld, sphere.radiusWorld);
-        }
-
-        public intersectsMinMax(min: Vector3, max: Vector3): boolean {
-            if (this.maximumWorld.x < min.x || this.minimumWorld.x > max.x)
-                return false;
-
-            if (this.maximumWorld.y < min.y || this.minimumWorld.y > max.y)
-                return false;
-
-            if (this.maximumWorld.z < min.z || this.minimumWorld.z > max.z)
-                return false;
-
-            return true;
-        }
-
-        // Statics
-        public static Intersects(box0: BoundingBox, box1: BoundingBox): boolean {
-            if (box0.maximumWorld.x < box1.minimumWorld.x || box0.minimumWorld.x > box1.maximumWorld.x)
-                return false;
-
-            if (box0.maximumWorld.y < box1.minimumWorld.y || box0.minimumWorld.y > box1.maximumWorld.y)
-                return false;
-
-            if (box0.maximumWorld.z < box1.minimumWorld.z || box0.minimumWorld.z > box1.maximumWorld.z)
-                return false;
-
-            return true;
-        }
-
-        public static IntersectsSphere(minPoint: Vector3, maxPoint: Vector3, sphereCenter: Vector3, sphereRadius: number): boolean {
-            var vector = Vector3.Clamp(sphereCenter, minPoint, maxPoint);
-            var num = Vector3.DistanceSquared(sphereCenter, vector);
-            return (num <= (sphereRadius * sphereRadius));
-        }
-
-        public static IsCompletelyInFrustum(boundingVectors: Vector3[], frustumPlanes: Plane[]): boolean {
-            for (var p = 0; p < 6; p++) {
-                for (var i = 0; i < 8; i++) {
-                    if (frustumPlanes[p].dotCoordinate(boundingVectors[i]) < 0) {
-                        return false;
-                    }
-                }
-            }
-            return true;
-        }
-
-        public static IsInFrustum(boundingVectors: Vector3[], frustumPlanes: Plane[]): boolean {
-            for (var p = 0; p < 6; p++) {
-                var inCount = 8;
-
-                for (var i = 0; i < 8; i++) {
-                    if (frustumPlanes[p].dotCoordinate(boundingVectors[i]) < 0) {
-                        --inCount;
-                    } else {
-                        break;
-                    }
-                }
-                if (inCount === 0)
-                    return false;
-            }
-            return true;
-        }
-    }
+module BABYLON {
+    export class BoundingBox {
+        public vectors: Vector3[] = new Array<Vector3>();
+        public center: Vector3;
+        public extendSize: Vector3;
+        public directions: Vector3[];
+        public vectorsWorld: Vector3[] = new Array<Vector3>();
+        public minimumWorld: Vector3;
+        public maximumWorld: Vector3;
+
+        private _worldMatrix: Matrix;
+
+        constructor(public minimum: Vector3, public maximum: Vector3) {
+            // Bounding vectors            
+            this.vectors.push(this.minimum.clone());
+            this.vectors.push(this.maximum.clone());
+
+            this.vectors.push(this.minimum.clone());
+            this.vectors[2].x = this.maximum.x;
+
+            this.vectors.push(this.minimum.clone());
+            this.vectors[3].y = this.maximum.y;
+
+            this.vectors.push(this.minimum.clone());
+            this.vectors[4].z = this.maximum.z;
+
+            this.vectors.push(this.maximum.clone());
+            this.vectors[5].z = this.minimum.z;
+
+            this.vectors.push(this.maximum.clone());
+            this.vectors[6].x = this.minimum.x;
+
+            this.vectors.push(this.maximum.clone());
+            this.vectors[7].y = this.minimum.y;
+            
+            // OBB
+            this.center = this.maximum.add(this.minimum).scale(0.5);
+            this.extendSize = this.maximum.subtract(this.minimum).scale(0.5);
+            this.directions = [Vector3.Zero(), Vector3.Zero(), Vector3.Zero()];
+
+            // World
+            for (var index = 0; index < this.vectors.length; index++) {
+                this.vectorsWorld[index] = Vector3.Zero();
+            }
+            this.minimumWorld = Vector3.Zero();
+            this.maximumWorld = Vector3.Zero();
+
+            this._update(Matrix.Identity());
+        }
+
+        // Methods
+        public getWorldMatrix(): Matrix {
+            return this._worldMatrix;
+        }
+
+        public _update(world: Matrix): void {
+            Vector3.FromFloatsToRef(Number.MAX_VALUE, Number.MAX_VALUE, Number.MAX_VALUE, this.minimumWorld);
+            Vector3.FromFloatsToRef(-Number.MAX_VALUE, -Number.MAX_VALUE, -Number.MAX_VALUE, this.maximumWorld);
+
+            for (var index = 0; index < this.vectors.length; index++) {
+                var v = this.vectorsWorld[index];
+                Vector3.TransformCoordinatesToRef(this.vectors[index], world, v);
+
+                if (v.x < this.minimumWorld.x)
+                    this.minimumWorld.x = v.x;
+                if (v.y < this.minimumWorld.y)
+                    this.minimumWorld.y = v.y;
+                if (v.z < this.minimumWorld.z)
+                    this.minimumWorld.z = v.z;
+
+                if (v.x > this.maximumWorld.x)
+                    this.maximumWorld.x = v.x;
+                if (v.y > this.maximumWorld.y)
+                    this.maximumWorld.y = v.y;
+                if (v.z > this.maximumWorld.z)
+                    this.maximumWorld.z = v.z;
+            }
+
+            // OBB
+            this.maximumWorld.addToRef(this.minimumWorld, this.center);
+            this.center.scaleInPlace(0.5);
+
+            Vector3.FromFloatArrayToRef(world.m, 0, this.directions[0]);
+            Vector3.FromFloatArrayToRef(world.m, 4, this.directions[1]);
+            Vector3.FromFloatArrayToRef(world.m, 8, this.directions[2]);
+
+            this._worldMatrix = world;
+        }
+
+        public isInFrustum(frustumPlanes: Plane[]): boolean {
+            return BoundingBox.IsInFrustum(this.vectorsWorld, frustumPlanes);
+        }
+
+        public isCompletelyInFrustum(frustumPlanes: Plane[]): boolean {
+            return BoundingBox.IsCompletelyInFrustum(this.vectorsWorld, frustumPlanes);
+        }
+
+        public intersectsPoint(point: Vector3): boolean {
+            var delta = -Engine.Epsilon;
+
+            if (this.maximumWorld.x - point.x < delta || delta > point.x - this.minimumWorld.x)
+                return false;
+
+            if (this.maximumWorld.y - point.y < delta || delta > point.y - this.minimumWorld.y)
+                return false;
+
+            if (this.maximumWorld.z - point.z < delta || delta > point.z - this.minimumWorld.z)
+                return false;
+
+            return true;
+        }
+
+        public intersectsSphere(sphere: BoundingSphere): boolean {
+            return BoundingBox.IntersectsSphere(this.minimumWorld, this.maximumWorld, sphere.centerWorld, sphere.radiusWorld);
+        }
+
+        public intersectsMinMax(min: Vector3, max: Vector3): boolean {
+            if (this.maximumWorld.x < min.x || this.minimumWorld.x > max.x)
+                return false;
+
+            if (this.maximumWorld.y < min.y || this.minimumWorld.y > max.y)
+                return false;
+
+            if (this.maximumWorld.z < min.z || this.minimumWorld.z > max.z)
+                return false;
+
+            return true;
+        }
+
+        // Statics
+        public static Intersects(box0: BoundingBox, box1: BoundingBox): boolean {
+            if (box0.maximumWorld.x < box1.minimumWorld.x || box0.minimumWorld.x > box1.maximumWorld.x)
+                return false;
+
+            if (box0.maximumWorld.y < box1.minimumWorld.y || box0.minimumWorld.y > box1.maximumWorld.y)
+                return false;
+
+            if (box0.maximumWorld.z < box1.minimumWorld.z || box0.minimumWorld.z > box1.maximumWorld.z)
+                return false;
+
+            return true;
+        }
+
+        public static IntersectsSphere(minPoint: Vector3, maxPoint: Vector3, sphereCenter: Vector3, sphereRadius: number): boolean {
+            var vector = Vector3.Clamp(sphereCenter, minPoint, maxPoint);
+            var num = Vector3.DistanceSquared(sphereCenter, vector);
+            return (num <= (sphereRadius * sphereRadius));
+        }
+
+        public static IsCompletelyInFrustum(boundingVectors: Vector3[], frustumPlanes: Plane[]): boolean {
+            for (var p = 0; p < 6; p++) {
+                for (var i = 0; i < 8; i++) {
+                    if (frustumPlanes[p].dotCoordinate(boundingVectors[i]) < 0) {
+                        return false;
+                    }
+                }
+            }
+            return true;
+        }
+
+        public static IsInFrustum(boundingVectors: Vector3[], frustumPlanes: Plane[]): boolean {
+            for (var p = 0; p < 6; p++) {
+                var inCount = 8;
+
+                for (var i = 0; i < 8; i++) {
+                    if (frustumPlanes[p].dotCoordinate(boundingVectors[i]) < 0) {
+                        --inCount;
+                    } else {
+                        break;
+                    }
+                }
+                if (inCount === 0)
+                    return false;
+            }
+            return true;
+        }
+    }
 } 

+ 109 - 109
src/Culling/babylon.boundingInfo.ts

@@ -1,110 +1,110 @@
-module BABYLON {
-    var computeBoxExtents = (axis: Vector3, box: BoundingBox) => {
-        var p = Vector3.Dot(box.center, axis);
-
-        var r0 = Math.abs(Vector3.Dot(box.directions[0], axis)) * box.extendSize.x;
-        var r1 = Math.abs(Vector3.Dot(box.directions[1], axis)) * box.extendSize.y;
-        var r2 = Math.abs(Vector3.Dot(box.directions[2], axis)) * box.extendSize.z;
-
-        var r = r0 + r1 + r2;
-        return {
-            min: p - r,
-            max: p + r
-        };
-    }
-
-    var extentsOverlap = (min0: number, max0: number, min1: number, max1: number): boolean => !(min0 > max1 || min1 > max0);
-
-    var axisOverlap = (axis: Vector3, box0: BoundingBox, box1: BoundingBox): boolean => {
-        var result0 = computeBoxExtents(axis, box0);
-        var result1 = computeBoxExtents(axis, box1);
-
-        return extentsOverlap(result0.min, result0.max, result1.min, result1.max);
-    }
-
-    export class BoundingInfo {
-        public boundingBox: BoundingBox;
-        public boundingSphere: BoundingSphere;
-
-        constructor(public minimum: Vector3, public maximum: Vector3) {
-            this.boundingBox = new BoundingBox(minimum, maximum);
-            this.boundingSphere = new BoundingSphere(minimum, maximum);
-        }
-
-        // Methods
-        public _update(world: Matrix) {
-            this.boundingBox._update(world);
-            this.boundingSphere._update(world);
-        }
-
-        public isInFrustum(frustumPlanes: Plane[]): boolean {
-            if (!this.boundingSphere.isInFrustum(frustumPlanes))
-                return false;
-
-            return this.boundingBox.isInFrustum(frustumPlanes);
-        }
-
-        public isCompletelyInFrustum(frustumPlanes: Plane[]): boolean {
-            return this.boundingBox.isCompletelyInFrustum(frustumPlanes);
-        }
-       
-        public _checkCollision(collider: Collider): boolean {
-            return collider._canDoCollision(this.boundingSphere.centerWorld, this.boundingSphere.radiusWorld, this.boundingBox.minimumWorld, this.boundingBox.maximumWorld);
-        }
-
-        public intersectsPoint(point: Vector3): boolean {
-            if (!this.boundingSphere.centerWorld) {
-                return false;
-            }
-
-            if (!this.boundingSphere.intersectsPoint(point)) {
-                return false;
-            }
-
-            if (!this.boundingBox.intersectsPoint(point)) {
-                return false;
-            }
-
-            return true;
-        }
-
-        public intersects(boundingInfo: BoundingInfo, precise: boolean): boolean {
-            if (!this.boundingSphere.centerWorld || !boundingInfo.boundingSphere.centerWorld) {
-                return false;
-            }
-
-            if (!BoundingSphere.Intersects(this.boundingSphere, boundingInfo.boundingSphere)) {
-                return false;
-            }
-
-            if (!BoundingBox.Intersects(this.boundingBox, boundingInfo.boundingBox)) {
-                return false;
-            }
-
-            if (!precise) {
-                return true;
-            }
-
-            var box0 = this.boundingBox;
-            var box1 = boundingInfo.boundingBox;
-
-            if (!axisOverlap(box0.directions[0], box0, box1)) return false;
-            if (!axisOverlap(box0.directions[1], box0, box1)) return false;
-            if (!axisOverlap(box0.directions[2], box0, box1)) return false;
-            if (!axisOverlap(box1.directions[0], box0, box1)) return false;
-            if (!axisOverlap(box1.directions[1], box0, box1)) return false;
-            if (!axisOverlap(box1.directions[2], box0, box1)) return false;
-            if (!axisOverlap(Vector3.Cross(box0.directions[0], box1.directions[0]), box0, box1)) return false;
-            if (!axisOverlap(Vector3.Cross(box0.directions[0], box1.directions[1]), box0, box1)) return false;
-            if (!axisOverlap(Vector3.Cross(box0.directions[0], box1.directions[2]), box0, box1)) return false;
-            if (!axisOverlap(Vector3.Cross(box0.directions[1], box1.directions[0]), box0, box1)) return false;
-            if (!axisOverlap(Vector3.Cross(box0.directions[1], box1.directions[1]), box0, box1)) return false;
-            if (!axisOverlap(Vector3.Cross(box0.directions[1], box1.directions[2]), box0, box1)) return false;
-            if (!axisOverlap(Vector3.Cross(box0.directions[2], box1.directions[0]), box0, box1)) return false;
-            if (!axisOverlap(Vector3.Cross(box0.directions[2], box1.directions[1]), box0, box1)) return false;
-            if (!axisOverlap(Vector3.Cross(box0.directions[2], box1.directions[2]), box0, box1)) return false;
-
-            return true;
-        }
-    }
+module BABYLON {
+    var computeBoxExtents = (axis: Vector3, box: BoundingBox) => {
+        var p = Vector3.Dot(box.center, axis);
+
+        var r0 = Math.abs(Vector3.Dot(box.directions[0], axis)) * box.extendSize.x;
+        var r1 = Math.abs(Vector3.Dot(box.directions[1], axis)) * box.extendSize.y;
+        var r2 = Math.abs(Vector3.Dot(box.directions[2], axis)) * box.extendSize.z;
+
+        var r = r0 + r1 + r2;
+        return {
+            min: p - r,
+            max: p + r
+        };
+    }
+
+    var extentsOverlap = (min0: number, max0: number, min1: number, max1: number): boolean => !(min0 > max1 || min1 > max0);
+
+    var axisOverlap = (axis: Vector3, box0: BoundingBox, box1: BoundingBox): boolean => {
+        var result0 = computeBoxExtents(axis, box0);
+        var result1 = computeBoxExtents(axis, box1);
+
+        return extentsOverlap(result0.min, result0.max, result1.min, result1.max);
+    }
+
+    export class BoundingInfo {
+        public boundingBox: BoundingBox;
+        public boundingSphere: BoundingSphere;
+
+        constructor(public minimum: Vector3, public maximum: Vector3) {
+            this.boundingBox = new BoundingBox(minimum, maximum);
+            this.boundingSphere = new BoundingSphere(minimum, maximum);
+        }
+
+        // Methods
+        public _update(world: Matrix) {
+            this.boundingBox._update(world);
+            this.boundingSphere._update(world);
+        }
+
+        public isInFrustum(frustumPlanes: Plane[]): boolean {
+            if (!this.boundingSphere.isInFrustum(frustumPlanes))
+                return false;
+
+            return this.boundingBox.isInFrustum(frustumPlanes);
+        }
+
+        public isCompletelyInFrustum(frustumPlanes: Plane[]): boolean {
+            return this.boundingBox.isCompletelyInFrustum(frustumPlanes);
+        }
+       
+        public _checkCollision(collider: Collider): boolean {
+            return collider._canDoCollision(this.boundingSphere.centerWorld, this.boundingSphere.radiusWorld, this.boundingBox.minimumWorld, this.boundingBox.maximumWorld);
+        }
+
+        public intersectsPoint(point: Vector3): boolean {
+            if (!this.boundingSphere.centerWorld) {
+                return false;
+            }
+
+            if (!this.boundingSphere.intersectsPoint(point)) {
+                return false;
+            }
+
+            if (!this.boundingBox.intersectsPoint(point)) {
+                return false;
+            }
+
+            return true;
+        }
+
+        public intersects(boundingInfo: BoundingInfo, precise: boolean): boolean {
+            if (!this.boundingSphere.centerWorld || !boundingInfo.boundingSphere.centerWorld) {
+                return false;
+            }
+
+            if (!BoundingSphere.Intersects(this.boundingSphere, boundingInfo.boundingSphere)) {
+                return false;
+            }
+
+            if (!BoundingBox.Intersects(this.boundingBox, boundingInfo.boundingBox)) {
+                return false;
+            }
+
+            if (!precise) {
+                return true;
+            }
+
+            var box0 = this.boundingBox;
+            var box1 = boundingInfo.boundingBox;
+
+            if (!axisOverlap(box0.directions[0], box0, box1)) return false;
+            if (!axisOverlap(box0.directions[1], box0, box1)) return false;
+            if (!axisOverlap(box0.directions[2], box0, box1)) return false;
+            if (!axisOverlap(box1.directions[0], box0, box1)) return false;
+            if (!axisOverlap(box1.directions[1], box0, box1)) return false;
+            if (!axisOverlap(box1.directions[2], box0, box1)) return false;
+            if (!axisOverlap(Vector3.Cross(box0.directions[0], box1.directions[0]), box0, box1)) return false;
+            if (!axisOverlap(Vector3.Cross(box0.directions[0], box1.directions[1]), box0, box1)) return false;
+            if (!axisOverlap(Vector3.Cross(box0.directions[0], box1.directions[2]), box0, box1)) return false;
+            if (!axisOverlap(Vector3.Cross(box0.directions[1], box1.directions[0]), box0, box1)) return false;
+            if (!axisOverlap(Vector3.Cross(box0.directions[1], box1.directions[1]), box0, box1)) return false;
+            if (!axisOverlap(Vector3.Cross(box0.directions[1], box1.directions[2]), box0, box1)) return false;
+            if (!axisOverlap(Vector3.Cross(box0.directions[2], box1.directions[0]), box0, box1)) return false;
+            if (!axisOverlap(Vector3.Cross(box0.directions[2], box1.directions[1]), box0, box1)) return false;
+            if (!axisOverlap(Vector3.Cross(box0.directions[2], box1.directions[2]), box0, box1)) return false;
+
+            return true;
+        }
+    }
 } 

+ 63 - 63
src/Culling/babylon.boundingSphere.ts

@@ -1,64 +1,64 @@
-module BABYLON {
-    export class BoundingSphere {
-        public center: Vector3;
-        public radius: number;
-        public centerWorld: Vector3;
-        public radiusWorld: number;
-
-        private _tempRadiusVector = Vector3.Zero();
-
-        constructor(public minimum: Vector3, public maximum: Vector3) {
-            var distance = Vector3.Distance(minimum, maximum);
-
-            this.center = Vector3.Lerp(minimum, maximum, 0.5);
-            this.radius = distance * 0.5;
-
-            this.centerWorld = Vector3.Zero();
-            this._update(Matrix.Identity());
-        }
-
-        // Methods
-        public _update(world: Matrix): void {
-            Vector3.TransformCoordinatesToRef(this.center, world, this.centerWorld);
-            Vector3.TransformNormalFromFloatsToRef(1.0, 1.0, 1.0, world, this._tempRadiusVector);
-            this.radiusWorld = Math.max(Math.abs(this._tempRadiusVector.x), Math.abs(this._tempRadiusVector.y), Math.abs(this._tempRadiusVector.z)) * this.radius;
-        }
-
-        public isInFrustum(frustumPlanes: Plane[]): boolean {
-            for (var i = 0; i < 6; i++) {
-                if (frustumPlanes[i].dotCoordinate(this.centerWorld) <= -this.radiusWorld)
-                    return false;
-            }
-
-            return true;
-        }
-
-        public intersectsPoint(point: Vector3): boolean {
-            var x = this.centerWorld.x - point.x;
-            var y = this.centerWorld.y - point.y;
-            var z = this.centerWorld.z - point.z;
-
-            var distance = Math.sqrt((x * x) + (y * y) + (z * z));
-
-            if (Math.abs(this.radiusWorld - distance) < Engine.Epsilon)
-                return false;
-
-            return true;
-        }
-
-        // Statics
-        public static Intersects(sphere0: BoundingSphere, sphere1: BoundingSphere): boolean {
-            var x = sphere0.centerWorld.x - sphere1.centerWorld.x;
-            var y = sphere0.centerWorld.y - sphere1.centerWorld.y;
-            var z = sphere0.centerWorld.z - sphere1.centerWorld.z;
-
-            var distance = Math.sqrt((x * x) + (y * y) + (z * z));
-
-            if (sphere0.radiusWorld + sphere1.radiusWorld < distance)
-                return false;
-
-            return true;
-        }
-
-    }
+module BABYLON {
+    export class BoundingSphere {
+        public center: Vector3;
+        public radius: number;
+        public centerWorld: Vector3;
+        public radiusWorld: number;
+
+        private _tempRadiusVector = Vector3.Zero();
+
+        constructor(public minimum: Vector3, public maximum: Vector3) {
+            var distance = Vector3.Distance(minimum, maximum);
+
+            this.center = Vector3.Lerp(minimum, maximum, 0.5);
+            this.radius = distance * 0.5;
+
+            this.centerWorld = Vector3.Zero();
+            this._update(Matrix.Identity());
+        }
+
+        // Methods
+        public _update(world: Matrix): void {
+            Vector3.TransformCoordinatesToRef(this.center, world, this.centerWorld);
+            Vector3.TransformNormalFromFloatsToRef(1.0, 1.0, 1.0, world, this._tempRadiusVector);
+            this.radiusWorld = Math.max(Math.abs(this._tempRadiusVector.x), Math.abs(this._tempRadiusVector.y), Math.abs(this._tempRadiusVector.z)) * this.radius;
+        }
+
+        public isInFrustum(frustumPlanes: Plane[]): boolean {
+            for (var i = 0; i < 6; i++) {
+                if (frustumPlanes[i].dotCoordinate(this.centerWorld) <= -this.radiusWorld)
+                    return false;
+            }
+
+            return true;
+        }
+
+        public intersectsPoint(point: Vector3): boolean {
+            var x = this.centerWorld.x - point.x;
+            var y = this.centerWorld.y - point.y;
+            var z = this.centerWorld.z - point.z;
+
+            var distance = Math.sqrt((x * x) + (y * y) + (z * z));
+
+            if (Math.abs(this.radiusWorld - distance) < Engine.Epsilon)
+                return false;
+
+            return true;
+        }
+
+        // Statics
+        public static Intersects(sphere0: BoundingSphere, sphere1: BoundingSphere): boolean {
+            var x = sphere0.centerWorld.x - sphere1.centerWorld.x;
+            var y = sphere0.centerWorld.y - sphere1.centerWorld.y;
+            var z = sphere0.centerWorld.z - sphere1.centerWorld.z;
+
+            var distance = Math.sqrt((x * x) + (y * y) + (z * z));
+
+            if (sphere0.radiusWorld + sphere1.radiusWorld < distance)
+                return false;
+
+            return true;
+        }
+
+    }
 } 

Разница между файлами не показана из-за своего большого размера
+ 767 - 767
src/Debug/babylon.debugLayer.ts


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

@@ -1,105 +1,105 @@
-module BABYLON {
-    export class Layer {
-        public texture: Texture;
-        public isBackground: boolean;
-        public color: Color4;
-        public onDispose: () => void;
-        public alphaBlendingMode = Engine.ALPHA_COMBINE;
-
-        private _scene: Scene;
-        private _vertexDeclaration = [2];
-        private _vertexStrideSize = 2 * 4;
-        private _vertexBuffer: WebGLBuffer;
-        private _indexBuffer: WebGLBuffer;
-        private _effect: Effect;
-
-        constructor(public name: string, imgUrl: string, scene: Scene, isBackground?: boolean, color?: Color4) {
-            this.texture = imgUrl ? new Texture(imgUrl, scene, true) : null;
-            this.isBackground = isBackground === undefined ? true : isBackground;
-            this.color = color === undefined ? new Color4(1, 1, 1, 1) : color;
-
-            this._scene = scene;
-            this._scene.layers.push(this);
-
-            // VBO
-            var vertices = [];
-            vertices.push(1, 1);
-            vertices.push(-1, 1);
-            vertices.push(-1, -1);
-            vertices.push(1, -1);
-
-            this._vertexBuffer = scene.getEngine().createVertexBuffer(vertices);
-
-            // Indices
-            var indices = [];
-            indices.push(0);
-            indices.push(1);
-            indices.push(2);
-
-            indices.push(0);
-            indices.push(2);
-            indices.push(3);
-
-            this._indexBuffer = scene.getEngine().createIndexBuffer(indices);
-
-            // Effects
-            this._effect = this._scene.getEngine().createEffect("layer",
-                ["position"],
-                ["textureMatrix", "color"],
-                ["textureSampler"], "");
-        }
-
-        public render(): void {
-            // Check
-            if (!this._effect.isReady() || !this.texture || !this.texture.isReady())
-                return;
-
-            var engine = this._scene.getEngine();
-
-            // Render
-            engine.enableEffect(this._effect);
-            engine.setState(false);
-
-            // Texture
-            this._effect.setTexture("textureSampler", this.texture);
-            this._effect.setMatrix("textureMatrix", this.texture.getTextureMatrix());
-
-            // Color
-            this._effect.setFloat4("color", this.color.r, this.color.g, this.color.b, this.color.a);
-
-            // VBOs
-            engine.bindBuffers(this._vertexBuffer, this._indexBuffer, this._vertexDeclaration, this._vertexStrideSize, this._effect);
-
-            // Draw order
-            engine.setAlphaMode(this.alphaBlendingMode);
-            engine.draw(true, 0, 6);
-            engine.setAlphaMode(Engine.ALPHA_DISABLE);
-        }
-
-        public dispose(): void {
-            if (this._vertexBuffer) {
-                this._scene.getEngine()._releaseBuffer(this._vertexBuffer);
-                this._vertexBuffer = null;
-            }
-
-            if (this._indexBuffer) {
-                this._scene.getEngine()._releaseBuffer(this._indexBuffer);
-                this._indexBuffer = null;
-            }
-
-            if (this.texture) {
-                this.texture.dispose();
-                this.texture = null;
-            }
-
-            // Remove from scene
-            var index = this._scene.layers.indexOf(this);
-            this._scene.layers.splice(index, 1);
-
-            // Callback
-            if (this.onDispose) {
-                this.onDispose();
-            }
-        }
-    }
+module BABYLON {
+    export class Layer {
+        public texture: Texture;
+        public isBackground: boolean;
+        public color: Color4;
+        public onDispose: () => void;
+        public alphaBlendingMode = Engine.ALPHA_COMBINE;
+
+        private _scene: Scene;
+        private _vertexDeclaration = [2];
+        private _vertexStrideSize = 2 * 4;
+        private _vertexBuffer: WebGLBuffer;
+        private _indexBuffer: WebGLBuffer;
+        private _effect: Effect;
+
+        constructor(public name: string, imgUrl: string, scene: Scene, isBackground?: boolean, color?: Color4) {
+            this.texture = imgUrl ? new Texture(imgUrl, scene, true) : null;
+            this.isBackground = isBackground === undefined ? true : isBackground;
+            this.color = color === undefined ? new Color4(1, 1, 1, 1) : color;
+
+            this._scene = scene;
+            this._scene.layers.push(this);
+
+            // VBO
+            var vertices = [];
+            vertices.push(1, 1);
+            vertices.push(-1, 1);
+            vertices.push(-1, -1);
+            vertices.push(1, -1);
+
+            this._vertexBuffer = scene.getEngine().createVertexBuffer(vertices);
+
+            // Indices
+            var indices = [];
+            indices.push(0);
+            indices.push(1);
+            indices.push(2);
+
+            indices.push(0);
+            indices.push(2);
+            indices.push(3);
+
+            this._indexBuffer = scene.getEngine().createIndexBuffer(indices);
+
+            // Effects
+            this._effect = this._scene.getEngine().createEffect("layer",
+                ["position"],
+                ["textureMatrix", "color"],
+                ["textureSampler"], "");
+        }
+
+        public render(): void {
+            // Check
+            if (!this._effect.isReady() || !this.texture || !this.texture.isReady())
+                return;
+
+            var engine = this._scene.getEngine();
+
+            // Render
+            engine.enableEffect(this._effect);
+            engine.setState(false);
+
+            // Texture
+            this._effect.setTexture("textureSampler", this.texture);
+            this._effect.setMatrix("textureMatrix", this.texture.getTextureMatrix());
+
+            // Color
+            this._effect.setFloat4("color", this.color.r, this.color.g, this.color.b, this.color.a);
+
+            // VBOs
+            engine.bindBuffers(this._vertexBuffer, this._indexBuffer, this._vertexDeclaration, this._vertexStrideSize, this._effect);
+
+            // Draw order
+            engine.setAlphaMode(this.alphaBlendingMode);
+            engine.draw(true, 0, 6);
+            engine.setAlphaMode(Engine.ALPHA_DISABLE);
+        }
+
+        public dispose(): void {
+            if (this._vertexBuffer) {
+                this._scene.getEngine()._releaseBuffer(this._vertexBuffer);
+                this._vertexBuffer = null;
+            }
+
+            if (this._indexBuffer) {
+                this._scene.getEngine()._releaseBuffer(this._indexBuffer);
+                this._indexBuffer = null;
+            }
+
+            if (this.texture) {
+                this.texture.dispose();
+                this.texture = null;
+            }
+
+            // Remove from scene
+            var index = this._scene.layers.indexOf(this);
+            this._scene.layers.splice(index, 1);
+
+            // Callback
+            if (this.onDispose) {
+                this.onDispose();
+            }
+        }
+    }
 } 

+ 25 - 25
src/LensFlare/babylon.lensFlare.ts

@@ -1,26 +1,26 @@
-module BABYLON {
-    export class LensFlare {
-        public color: Color3;
-        public texture: Texture;
-
-        private _system: LensFlareSystem;
-
-        constructor(public size: number, public position: number, color, imgUrl: string, system: LensFlareSystem) {
-            this.color = color || new Color3(1, 1, 1);
-            this.texture = imgUrl ? new Texture(imgUrl, system.getScene(), true) : null;
-            this._system = system;
-
-            system.lensFlares.push(this);
-        }
-
-        public dispose = function(): void {
-            if (this.texture) {
-                this.texture.dispose();
-            }
-
-            // Remove from scene
-            var index = this._system.lensFlares.indexOf(this);
-            this._system.lensFlares.splice(index, 1);
-        };
-    }
+module BABYLON {
+    export class LensFlare {
+        public color: Color3;
+        public texture: Texture;
+
+        private _system: LensFlareSystem;
+
+        constructor(public size: number, public position: number, color, imgUrl: string, system: LensFlareSystem) {
+            this.color = color || new Color3(1, 1, 1);
+            this.texture = imgUrl ? new Texture(imgUrl, system.getScene(), true) : null;
+            this._system = system;
+
+            system.lensFlares.push(this);
+        }
+
+        public dispose = function(): void {
+            if (this.texture) {
+                this.texture.dispose();
+            }
+
+            // Remove from scene
+            var index = this._system.lensFlares.indexOf(this);
+            this._system.lensFlares.splice(index, 1);
+        };
+    }
 } 

+ 147 - 147
src/Lights/babylon.directionalLight.ts

@@ -1,148 +1,148 @@
-module BABYLON {
-    export class DirectionalLight extends Light implements IShadowLight {
-        public position: Vector3;
-
-        private _transformedDirection: Vector3;
-        public transformedPosition: Vector3;
-        private _worldMatrix: Matrix;
-
-        public shadowOrthoScale = 0.5;
-
-        public autoUpdateExtends = true;
-
-        // Cache
-        private _orthoLeft = Number.MAX_VALUE;
-        private _orthoRight = Number.MIN_VALUE;
-        private _orthoTop = Number.MIN_VALUE;
-        private _orthoBottom = Number.MAX_VALUE;
-
-        constructor(name: string, public direction: Vector3, scene: Scene) {
-            super(name, scene);
-
-            this.position = direction.scale(-1);
-        }
-
-        public getAbsolutePosition(): Vector3 {
-            return this.transformedPosition ? this.transformedPosition : this.position;
-        }
-
-        public setDirectionToTarget(target: Vector3): Vector3 {
-            this.direction = Vector3.Normalize(target.subtract(this.position));
-            return this.direction;
-        }
-
-        public setShadowProjectionMatrix(matrix: Matrix, viewMatrix: Matrix, renderList: Array<AbstractMesh>): void {
-            var activeCamera = this.getScene().activeCamera;
-
-            // Check extends
-            if (this.autoUpdateExtends || this._orthoLeft === Number.MAX_VALUE) {
-                var tempVector3 = Vector3.Zero();
-
-                this._orthoLeft = Number.MAX_VALUE;
-                this._orthoRight = Number.MIN_VALUE;
-                this._orthoTop = Number.MIN_VALUE;
-                this._orthoBottom = Number.MAX_VALUE;
-
-                for (var meshIndex = 0; meshIndex < renderList.length; meshIndex++) {
-                    var mesh = renderList[meshIndex];
-
-                    if (!mesh) {
-                        continue;
-                    }
-
-                    var boundingInfo = mesh.getBoundingInfo();
-
-                    if (!boundingInfo) {
-                        continue;
-                    }
-
-                    var boundingBox = boundingInfo.boundingBox;
-
-                    for (var index = 0; index < boundingBox.vectorsWorld.length; index++) {
-                        Vector3.TransformCoordinatesToRef(boundingBox.vectorsWorld[index], viewMatrix, tempVector3);
-
-                        if (tempVector3.x < this._orthoLeft)
-                            this._orthoLeft = tempVector3.x;
-                        if (tempVector3.y < this._orthoBottom)
-                            this._orthoBottom = tempVector3.y;
-
-                        if (tempVector3.x > this._orthoRight)
-                            this._orthoRight = tempVector3.x;
-                        if (tempVector3.y > this._orthoTop)
-                            this._orthoTop = tempVector3.y;
-                    }
-                }
-            }
-
-            var xOffset = this._orthoRight - this._orthoLeft;
-            var yOffset = this._orthoTop - this._orthoBottom;
-
-            Matrix.OrthoOffCenterLHToRef(this._orthoLeft - xOffset * this.shadowOrthoScale, this._orthoRight + xOffset * this.shadowOrthoScale,
-                this._orthoBottom - yOffset * this.shadowOrthoScale, this._orthoTop + yOffset * this.shadowOrthoScale,
-                -activeCamera.maxZ, activeCamera.maxZ, matrix);
-        }
-
-        public supportsVSM(): boolean {
-            return true;
-        }
-
-        public needRefreshPerFrame(): boolean {
-            return true;
-        }
-
-        public needCube(): boolean {
-            return false;
-        }
-
-        public getShadowDirection(faceIndex?: number): Vector3 {
-            return this.direction;
-        }
-
-        public computeTransformedPosition(): boolean {
-            if (this.parent && this.parent.getWorldMatrix) {
-                if (!this.transformedPosition) {
-                    this.transformedPosition = Vector3.Zero();
-                }
-
-                Vector3.TransformCoordinatesToRef(this.position, this.parent.getWorldMatrix(), this.transformedPosition);
-                return true;
-            }
-
-            return false;
-        }
-
-        public transferToEffect(effect: Effect, directionUniformName: string): void {
-            if (this.parent && this.parent.getWorldMatrix) {
-                if (!this._transformedDirection) {
-                    this._transformedDirection = Vector3.Zero();
-                }
-
-                Vector3.TransformNormalToRef(this.direction, this.parent.getWorldMatrix(), this._transformedDirection);
-                effect.setFloat4(directionUniformName, this._transformedDirection.x, this._transformedDirection.y, this._transformedDirection.z, 1);
-
-                return;
-            }
-
-            effect.setFloat4(directionUniformName, this.direction.x, this.direction.y, this.direction.z, 1);
-        }
-
-        public _getWorldMatrix(): Matrix {
-            if (!this._worldMatrix) {
-                this._worldMatrix = Matrix.Identity();
-            }
-
-            Matrix.TranslationToRef(this.position.x, this.position.y, this.position.z, this._worldMatrix);
-
-            return this._worldMatrix;
-        }
-
-        public serialize(): any {
-            var serializationObject = super.serialize();
-            serializationObject.type = 1;
-            serializationObject.position = this.position.asArray();
-            serializationObject.direction = this.direction.asArray();
-
-            return serializationObject;
-        }
-    }
+module BABYLON {
+    export class DirectionalLight extends Light implements IShadowLight {
+        public position: Vector3;
+
+        private _transformedDirection: Vector3;
+        public transformedPosition: Vector3;
+        private _worldMatrix: Matrix;
+
+        public shadowOrthoScale = 0.5;
+
+        public autoUpdateExtends = true;
+
+        // Cache
+        private _orthoLeft = Number.MAX_VALUE;
+        private _orthoRight = Number.MIN_VALUE;
+        private _orthoTop = Number.MIN_VALUE;
+        private _orthoBottom = Number.MAX_VALUE;
+
+        constructor(name: string, public direction: Vector3, scene: Scene) {
+            super(name, scene);
+
+            this.position = direction.scale(-1);
+        }
+
+        public getAbsolutePosition(): Vector3 {
+            return this.transformedPosition ? this.transformedPosition : this.position;
+        }
+
+        public setDirectionToTarget(target: Vector3): Vector3 {
+            this.direction = Vector3.Normalize(target.subtract(this.position));
+            return this.direction;
+        }
+
+        public setShadowProjectionMatrix(matrix: Matrix, viewMatrix: Matrix, renderList: Array<AbstractMesh>): void {
+            var activeCamera = this.getScene().activeCamera;
+
+            // Check extends
+            if (this.autoUpdateExtends || this._orthoLeft === Number.MAX_VALUE) {
+                var tempVector3 = Vector3.Zero();
+
+                this._orthoLeft = Number.MAX_VALUE;
+                this._orthoRight = Number.MIN_VALUE;
+                this._orthoTop = Number.MIN_VALUE;
+                this._orthoBottom = Number.MAX_VALUE;
+
+                for (var meshIndex = 0; meshIndex < renderList.length; meshIndex++) {
+                    var mesh = renderList[meshIndex];
+
+                    if (!mesh) {
+                        continue;
+                    }
+
+                    var boundingInfo = mesh.getBoundingInfo();
+
+                    if (!boundingInfo) {
+                        continue;
+                    }
+
+                    var boundingBox = boundingInfo.boundingBox;
+
+                    for (var index = 0; index < boundingBox.vectorsWorld.length; index++) {
+                        Vector3.TransformCoordinatesToRef(boundingBox.vectorsWorld[index], viewMatrix, tempVector3);
+
+                        if (tempVector3.x < this._orthoLeft)
+                            this._orthoLeft = tempVector3.x;
+                        if (tempVector3.y < this._orthoBottom)
+                            this._orthoBottom = tempVector3.y;
+
+                        if (tempVector3.x > this._orthoRight)
+                            this._orthoRight = tempVector3.x;
+                        if (tempVector3.y > this._orthoTop)
+                            this._orthoTop = tempVector3.y;
+                    }
+                }
+            }
+
+            var xOffset = this._orthoRight - this._orthoLeft;
+            var yOffset = this._orthoTop - this._orthoBottom;
+
+            Matrix.OrthoOffCenterLHToRef(this._orthoLeft - xOffset * this.shadowOrthoScale, this._orthoRight + xOffset * this.shadowOrthoScale,
+                this._orthoBottom - yOffset * this.shadowOrthoScale, this._orthoTop + yOffset * this.shadowOrthoScale,
+                -activeCamera.maxZ, activeCamera.maxZ, matrix);
+        }
+
+        public supportsVSM(): boolean {
+            return true;
+        }
+
+        public needRefreshPerFrame(): boolean {
+            return true;
+        }
+
+        public needCube(): boolean {
+            return false;
+        }
+
+        public getShadowDirection(faceIndex?: number): Vector3 {
+            return this.direction;
+        }
+
+        public computeTransformedPosition(): boolean {
+            if (this.parent && this.parent.getWorldMatrix) {
+                if (!this.transformedPosition) {
+                    this.transformedPosition = Vector3.Zero();
+                }
+
+                Vector3.TransformCoordinatesToRef(this.position, this.parent.getWorldMatrix(), this.transformedPosition);
+                return true;
+            }
+
+            return false;
+        }
+
+        public transferToEffect(effect: Effect, directionUniformName: string): void {
+            if (this.parent && this.parent.getWorldMatrix) {
+                if (!this._transformedDirection) {
+                    this._transformedDirection = Vector3.Zero();
+                }
+
+                Vector3.TransformNormalToRef(this.direction, this.parent.getWorldMatrix(), this._transformedDirection);
+                effect.setFloat4(directionUniformName, this._transformedDirection.x, this._transformedDirection.y, this._transformedDirection.z, 1);
+
+                return;
+            }
+
+            effect.setFloat4(directionUniformName, this.direction.x, this.direction.y, this.direction.z, 1);
+        }
+
+        public _getWorldMatrix(): Matrix {
+            if (!this._worldMatrix) {
+                this._worldMatrix = Matrix.Identity();
+            }
+
+            Matrix.TranslationToRef(this.position.x, this.position.y, this.position.z, this._worldMatrix);
+
+            return this._worldMatrix;
+        }
+
+        public serialize(): any {
+            var serializationObject = super.serialize();
+            serializationObject.type = 1;
+            serializationObject.position = this.position.asArray();
+            serializationObject.direction = this.direction.asArray();
+
+            return serializationObject;
+        }
+    }
 }  

+ 42 - 42
src/Lights/babylon.hemisphericLight.ts

@@ -1,43 +1,43 @@
-module BABYLON {
-    export class HemisphericLight extends Light {
-        public groundColor = new Color3(0.0, 0.0, 0.0);
-
-        private _worldMatrix: Matrix;
-
-        constructor(name: string, public direction: Vector3, scene: Scene) {
-            super(name, scene);
-        }
-
-        public setDirectionToTarget(target: Vector3): Vector3 {
-            this.direction = Vector3.Normalize(target.subtract(Vector3.Zero()));
-            return this.direction;
-        }
-
-        public getShadowGenerator(): ShadowGenerator {
-            return null;
-        }
-
-        public transferToEffect(effect: Effect, directionUniformName: string, groundColorUniformName: string): void {
-            var normalizeDirection = Vector3.Normalize(this.direction);
-            effect.setFloat4(directionUniformName, normalizeDirection.x, normalizeDirection.y, normalizeDirection.z, 0);
-            effect.setColor3(groundColorUniformName, this.groundColor.scale(this.intensity));
-        }
-
-        public _getWorldMatrix(): Matrix {
-            if (!this._worldMatrix) {
-                this._worldMatrix = Matrix.Identity();
-            }
-
-            return this._worldMatrix;
-        }
-
-        public serialize(): any {
-            var serializationObject = super.serialize();
-            serializationObject.type = 3;
-            serializationObject.direction = this.direction.asArray();
-            serializationObject.groundColor = this.groundColor.asArray();
-
-            return serializationObject;
-        }
-    }
+module BABYLON {
+    export class HemisphericLight extends Light {
+        public groundColor = new Color3(0.0, 0.0, 0.0);
+
+        private _worldMatrix: Matrix;
+
+        constructor(name: string, public direction: Vector3, scene: Scene) {
+            super(name, scene);
+        }
+
+        public setDirectionToTarget(target: Vector3): Vector3 {
+            this.direction = Vector3.Normalize(target.subtract(Vector3.Zero()));
+            return this.direction;
+        }
+
+        public getShadowGenerator(): ShadowGenerator {
+            return null;
+        }
+
+        public transferToEffect(effect: Effect, directionUniformName: string, groundColorUniformName: string): void {
+            var normalizeDirection = Vector3.Normalize(this.direction);
+            effect.setFloat4(directionUniformName, normalizeDirection.x, normalizeDirection.y, normalizeDirection.z, 0);
+            effect.setColor3(groundColorUniformName, this.groundColor.scale(this.intensity));
+        }
+
+        public _getWorldMatrix(): Matrix {
+            if (!this._worldMatrix) {
+                this._worldMatrix = Matrix.Identity();
+            }
+
+            return this._worldMatrix;
+        }
+
+        public serialize(): any {
+            var serializationObject = super.serialize();
+            serializationObject.type = 3;
+            serializationObject.direction = this.direction.asArray();
+            serializationObject.groundColor = this.groundColor.asArray();
+
+            return serializationObject;
+        }
+    }
 } 

+ 94 - 94
src/Lights/babylon.pointLight.ts

@@ -1,95 +1,95 @@
-module BABYLON {
-    export class PointLight extends Light implements IShadowLight {
-        private _worldMatrix: Matrix;
-        public transformedPosition: Vector3;
-
-        constructor(name: string, public position: Vector3, scene: Scene) {
-            super(name, scene);
-        }
-
-        public getAbsolutePosition(): Vector3 {
-            return this.transformedPosition ? this.transformedPosition : this.position;
-        }
-
-        public computeTransformedPosition(): boolean {
-            if (this.parent && this.parent.getWorldMatrix) {
-                if (!this.transformedPosition) {
-                    this.transformedPosition = Vector3.Zero();
-                }
-
-                Vector3.TransformCoordinatesToRef(this.position, this.parent.getWorldMatrix(), this.transformedPosition);
-
-                return true;
-            }
-
-            return false;
-        }
-
-        public transferToEffect(effect: Effect, positionUniformName: string): void {
-            if (this.parent && this.parent.getWorldMatrix) {
-                this.computeTransformedPosition();
-
-                effect.setFloat4(positionUniformName, this.transformedPosition.x, this.transformedPosition.y, this.transformedPosition.z, 0);
-
-                return;
-            }
-
-            effect.setFloat4(positionUniformName, this.position.x, this.position.y, this.position.z, 0);
-        }
-
-        public needCube(): boolean {
-            return true;
-        }
-
-        public supportsVSM(): boolean {
-            return false;
-        }
-
-        public needRefreshPerFrame(): boolean {
-            return false;
-        }
-
-        public getShadowDirection(faceIndex?: number): Vector3 {
-            switch (faceIndex) {
-                case 0:
-                    return new Vector3(1, 0, 0);
-                case 1:
-                    return new Vector3(-1, 0, 0);
-                case 2:
-                    return new Vector3(0, -1, 0);
-                case 3:
-                    return new Vector3(0, 1, 0);
-                case 4:
-                    return new Vector3(0, 0, 1);
-                case 5:
-                    return new Vector3(0, 0, -1);
-            }
-
-            return Vector3.Zero();
-        }
-
-        public setShadowProjectionMatrix(matrix: Matrix, viewMatrix: Matrix, renderList: Array<AbstractMesh>): void {
-            var activeCamera = this.getScene().activeCamera;
-            Matrix.PerspectiveFovLHToRef(Math.PI / 2, 1.0, activeCamera.minZ, activeCamera.maxZ, matrix);
-        }
-
-        public _getWorldMatrix(): Matrix {
-            if (!this._worldMatrix) {
-                this._worldMatrix = Matrix.Identity();
-            }
-
-            Matrix.TranslationToRef(this.position.x, this.position.y, this.position.z, this._worldMatrix);
-
-            return this._worldMatrix;
-        }
-
-        public serialize(): any {
-            var serializationObject = super.serialize();
-
-            serializationObject.type = 0;
-            serializationObject.position = this.position.asArray();
-
-            return serializationObject;
-        }
-    }
+module BABYLON {
+    export class PointLight extends Light implements IShadowLight {
+        private _worldMatrix: Matrix;
+        public transformedPosition: Vector3;
+
+        constructor(name: string, public position: Vector3, scene: Scene) {
+            super(name, scene);
+        }
+
+        public getAbsolutePosition(): Vector3 {
+            return this.transformedPosition ? this.transformedPosition : this.position;
+        }
+
+        public computeTransformedPosition(): boolean {
+            if (this.parent && this.parent.getWorldMatrix) {
+                if (!this.transformedPosition) {
+                    this.transformedPosition = Vector3.Zero();
+                }
+
+                Vector3.TransformCoordinatesToRef(this.position, this.parent.getWorldMatrix(), this.transformedPosition);
+
+                return true;
+            }
+
+            return false;
+        }
+
+        public transferToEffect(effect: Effect, positionUniformName: string): void {
+            if (this.parent && this.parent.getWorldMatrix) {
+                this.computeTransformedPosition();
+
+                effect.setFloat4(positionUniformName, this.transformedPosition.x, this.transformedPosition.y, this.transformedPosition.z, 0);
+
+                return;
+            }
+
+            effect.setFloat4(positionUniformName, this.position.x, this.position.y, this.position.z, 0);
+        }
+
+        public needCube(): boolean {
+            return true;
+        }
+
+        public supportsVSM(): boolean {
+            return false;
+        }
+
+        public needRefreshPerFrame(): boolean {
+            return false;
+        }
+
+        public getShadowDirection(faceIndex?: number): Vector3 {
+            switch (faceIndex) {
+                case 0:
+                    return new Vector3(1, 0, 0);
+                case 1:
+                    return new Vector3(-1, 0, 0);
+                case 2:
+                    return new Vector3(0, -1, 0);
+                case 3:
+                    return new Vector3(0, 1, 0);
+                case 4:
+                    return new Vector3(0, 0, 1);
+                case 5:
+                    return new Vector3(0, 0, -1);
+            }
+
+            return Vector3.Zero();
+        }
+
+        public setShadowProjectionMatrix(matrix: Matrix, viewMatrix: Matrix, renderList: Array<AbstractMesh>): void {
+            var activeCamera = this.getScene().activeCamera;
+            Matrix.PerspectiveFovLHToRef(Math.PI / 2, 1.0, activeCamera.minZ, activeCamera.maxZ, matrix);
+        }
+
+        public _getWorldMatrix(): Matrix {
+            if (!this._worldMatrix) {
+                this._worldMatrix = Matrix.Identity();
+            }
+
+            Matrix.TranslationToRef(this.position.x, this.position.y, this.position.z, this._worldMatrix);
+
+            return this._worldMatrix;
+        }
+
+        public serialize(): any {
+            var serializationObject = super.serialize();
+
+            serializationObject.type = 0;
+            serializationObject.position = this.position.asArray();
+
+            return serializationObject;
+        }
+    }
 } 

+ 99 - 99
src/Lights/babylon.spotLight.ts

@@ -1,100 +1,100 @@
-module BABYLON {
-    export class SpotLight extends Light implements IShadowLight {
-
-        public transformedPosition: Vector3;
-
-        private _transformedDirection: Vector3;
-        private _worldMatrix: Matrix;
-
-        constructor(name: string, public position: Vector3, public direction: Vector3, public angle: number, public exponent: number, scene: Scene) {
-            super(name, scene);
-        }
-
-        public getAbsolutePosition(): Vector3 {
-            return this.transformedPosition ? this.transformedPosition : this.position;
-        }
-
-        public setShadowProjectionMatrix(matrix: Matrix, viewMatrix: Matrix, renderList: Array<AbstractMesh>): void {
-            var activeCamera = this.getScene().activeCamera;
-            Matrix.PerspectiveFovLHToRef(this.angle, 1.0, activeCamera.minZ, activeCamera.maxZ, matrix);
-        }
-
-        public needCube(): boolean {
-            return false;
-        }
-
-        public supportsVSM(): boolean {
-            return true;
-        }
-
-        public needRefreshPerFrame(): boolean {
-            return false;
-        }
-
-        public getShadowDirection(faceIndex?: number): Vector3 {
-            return this.direction;
-        }
-
-        public setDirectionToTarget(target: Vector3): Vector3 {
-            this.direction = Vector3.Normalize(target.subtract(this.position));
-            return this.direction;
-        }
-
-        public computeTransformedPosition(): boolean {
-            if (this.parent && this.parent.getWorldMatrix) {
-                if (!this.transformedPosition) {
-                    this.transformedPosition = Vector3.Zero();
-                }
-
-                Vector3.TransformCoordinatesToRef(this.position, this.parent.getWorldMatrix(), this.transformedPosition);
-                return true;
-            }
-
-            return false;
-        }
-
-        public transferToEffect(effect: Effect, positionUniformName: string, directionUniformName: string): void {
-            var normalizeDirection;
-
-            if (this.parent && this.parent.getWorldMatrix) {
-                if (!this._transformedDirection) {
-                    this._transformedDirection = Vector3.Zero();
-                }
-
-                this.computeTransformedPosition();
-                
-                Vector3.TransformNormalToRef(this.direction, this.parent.getWorldMatrix(), this._transformedDirection);
-
-                effect.setFloat4(positionUniformName, this.transformedPosition.x, this.transformedPosition.y, this.transformedPosition.z, this.exponent);
-                normalizeDirection = Vector3.Normalize(this._transformedDirection);
-            } else {
-                effect.setFloat4(positionUniformName, this.position.x, this.position.y, this.position.z, this.exponent);
-                normalizeDirection = Vector3.Normalize(this.direction);
-            }
-
-            effect.setFloat4(directionUniformName, normalizeDirection.x, normalizeDirection.y, normalizeDirection.z, Math.cos(this.angle * 0.5));
-        }
-
-        public _getWorldMatrix(): Matrix {
-            if (!this._worldMatrix) {
-                this._worldMatrix = Matrix.Identity();
-            }
-
-            Matrix.TranslationToRef(this.position.x, this.position.y, this.position.z, this._worldMatrix);
-
-            return this._worldMatrix;
-        }
-
-        public serialize(): any {
-            var serializationObject = super.serialize();
-
-            serializationObject.type = 2;
-            serializationObject.position = this.position.asArray();
-            serializationObject.direction = this.position.asArray();
-            serializationObject.angle = this.angle;
-            serializationObject.exponent = this.exponent;
-
-            return serializationObject;
-        }
-    }
+module BABYLON {
+    export class SpotLight extends Light implements IShadowLight {
+
+        public transformedPosition: Vector3;
+
+        private _transformedDirection: Vector3;
+        private _worldMatrix: Matrix;
+
+        constructor(name: string, public position: Vector3, public direction: Vector3, public angle: number, public exponent: number, scene: Scene) {
+            super(name, scene);
+        }
+
+        public getAbsolutePosition(): Vector3 {
+            return this.transformedPosition ? this.transformedPosition : this.position;
+        }
+
+        public setShadowProjectionMatrix(matrix: Matrix, viewMatrix: Matrix, renderList: Array<AbstractMesh>): void {
+            var activeCamera = this.getScene().activeCamera;
+            Matrix.PerspectiveFovLHToRef(this.angle, 1.0, activeCamera.minZ, activeCamera.maxZ, matrix);
+        }
+
+        public needCube(): boolean {
+            return false;
+        }
+
+        public supportsVSM(): boolean {
+            return true;
+        }
+
+        public needRefreshPerFrame(): boolean {
+            return false;
+        }
+
+        public getShadowDirection(faceIndex?: number): Vector3 {
+            return this.direction;
+        }
+
+        public setDirectionToTarget(target: Vector3): Vector3 {
+            this.direction = Vector3.Normalize(target.subtract(this.position));
+            return this.direction;
+        }
+
+        public computeTransformedPosition(): boolean {
+            if (this.parent && this.parent.getWorldMatrix) {
+                if (!this.transformedPosition) {
+                    this.transformedPosition = Vector3.Zero();
+                }
+
+                Vector3.TransformCoordinatesToRef(this.position, this.parent.getWorldMatrix(), this.transformedPosition);
+                return true;
+            }
+
+            return false;
+        }
+
+        public transferToEffect(effect: Effect, positionUniformName: string, directionUniformName: string): void {
+            var normalizeDirection;
+
+            if (this.parent && this.parent.getWorldMatrix) {
+                if (!this._transformedDirection) {
+                    this._transformedDirection = Vector3.Zero();
+                }
+
+                this.computeTransformedPosition();
+                
+                Vector3.TransformNormalToRef(this.direction, this.parent.getWorldMatrix(), this._transformedDirection);
+
+                effect.setFloat4(positionUniformName, this.transformedPosition.x, this.transformedPosition.y, this.transformedPosition.z, this.exponent);
+                normalizeDirection = Vector3.Normalize(this._transformedDirection);
+            } else {
+                effect.setFloat4(positionUniformName, this.position.x, this.position.y, this.position.z, this.exponent);
+                normalizeDirection = Vector3.Normalize(this.direction);
+            }
+
+            effect.setFloat4(directionUniformName, normalizeDirection.x, normalizeDirection.y, normalizeDirection.z, Math.cos(this.angle * 0.5));
+        }
+
+        public _getWorldMatrix(): Matrix {
+            if (!this._worldMatrix) {
+                this._worldMatrix = Matrix.Identity();
+            }
+
+            Matrix.TranslationToRef(this.position.x, this.position.y, this.position.z, this._worldMatrix);
+
+            return this._worldMatrix;
+        }
+
+        public serialize(): any {
+            var serializationObject = super.serialize();
+
+            serializationObject.type = 2;
+            serializationObject.position = this.position.asArray();
+            serializationObject.direction = this.position.asArray();
+            serializationObject.angle = this.angle;
+            serializationObject.exponent = this.exponent;
+
+            return serializationObject;
+        }
+    }
 }

+ 205 - 205
src/Loading/babylon.sceneLoader.ts

@@ -1,206 +1,206 @@
-module BABYLON {
-    export interface ISceneLoaderPlugin {
-        extensions: string;
-        importMesh: (meshesNames: any, scene: Scene, data: any, rootUrl: string, meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => boolean;
-        load: (scene: Scene, data: string, rootUrl: string) => boolean;
-    }
-
-    export class SceneLoader {
-        // Flags
-        private static _ForceFullSceneLoadingForIncremental = false;
-        private static _ShowLoadingScreen = true;
-
-        public static get ForceFullSceneLoadingForIncremental() {
-            return SceneLoader._ForceFullSceneLoadingForIncremental;
-        }
-
-        public static set ForceFullSceneLoadingForIncremental(value: boolean) {
-            SceneLoader._ForceFullSceneLoadingForIncremental = value;
-        }
-
-        public static get ShowLoadingScreen() {
-            return SceneLoader._ShowLoadingScreen;
-        }
-
-        public static set ShowLoadingScreen(value: boolean) {
-            SceneLoader._ShowLoadingScreen = value;
-        }
-
-        // Members
-        private static _registeredPlugins = new Array<ISceneLoaderPlugin>();
-
-        private static _getPluginForFilename(sceneFilename): ISceneLoaderPlugin {
-            var dotPosition = sceneFilename.lastIndexOf(".");
-
-            var queryStringPosition = sceneFilename.indexOf("?");
-
-            if (queryStringPosition === -1) {
-                queryStringPosition = sceneFilename.length;
-            }
-
-            var extension = sceneFilename.substring(dotPosition, queryStringPosition).toLowerCase();
-
-            for (var index = 0; index < this._registeredPlugins.length; index++) {
-                var plugin = this._registeredPlugins[index];
-
-                if (plugin.extensions.indexOf(extension) !== -1) {
-                    return plugin;
-                }
-            }
-
-            return this._registeredPlugins[this._registeredPlugins.length - 1];
-        }
-
-        // Public functions
-        public static RegisterPlugin(plugin: ISceneLoaderPlugin): void {
-            plugin.extensions = plugin.extensions.toLowerCase();
-            SceneLoader._registeredPlugins.push(plugin);
-        }
-
-        public static ImportMesh(meshesNames: any, rootUrl: string, sceneFilename: string, scene: Scene, onsuccess?: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, progressCallBack?: () => void, onerror?: (scene: Scene, e: any) => void): void {
-            if (sceneFilename.substr && sceneFilename.substr(0, 1) === "/") {
-                Tools.Error("Wrong sceneFilename parameter");
-                return;
-            }
-
-            var loadingToken = {};
-            scene._addPendingData(loadingToken);
-
-            var manifestChecked = success => {
-                scene.database = database;
-
-                var plugin = SceneLoader._getPluginForFilename(sceneFilename);
-
-                var importMeshFromData = data => {
-                    var meshes = [];
-                    var particleSystems = [];
-                    var skeletons = [];
-
-                    try {
-                        if (!plugin.importMesh(meshesNames, scene, data, rootUrl, meshes, particleSystems, skeletons)) {
-                            if (onerror) {
-                                onerror(scene, 'Unable to import meshes from ' + rootUrl + sceneFilename);
-                            }
-                            scene._removePendingData(loadingToken);
-                            return;
-                        }
-                    } catch (e) {
-                        if (onerror) {
-                            onerror(scene, 'Unable to import meshes from ' + rootUrl + sceneFilename + ' (Exception: ' + e + ')');
-                        }
-                        scene._removePendingData(loadingToken);
-                        return;
-                    }
-
-
-                    if (onsuccess) {
-                        scene.importedMeshesFiles.push(rootUrl + sceneFilename);
-                        onsuccess(meshes, particleSystems, skeletons);
-                        scene._removePendingData(loadingToken);
-                    }
-                };
-
-                if (sceneFilename.substr && sceneFilename.substr(0, 5) === "data:") {
-                    // Direct load
-                    importMeshFromData(sceneFilename.substr(5));
-                    return;
-                }
-
-                Tools.LoadFile(rootUrl + sceneFilename, data => {
-                    importMeshFromData(data);
-                }, progressCallBack, database);
-            };
-
-            if (scene.getEngine().enableOfflineSupport) {
-                // Checking if a manifest file has been set for this scene and if offline mode has been requested
-                var database = new Database(rootUrl + sceneFilename, manifestChecked);
-            }
-            else {
-                manifestChecked(true);
-            }
-        }
-
-        /**
-        * Load a scene
-        * @param rootUrl a string that defines the root url for scene and resources
-        * @param sceneFilename a string that defines the name of the scene file. can start with "data:" following by the stringified version of the scene
-        * @param engine is the instance of BABYLON.Engine to use to create the scene
-        */
-        public static Load(rootUrl: string, sceneFilename: any, engine: Engine, onsuccess?: (scene: Scene) => void, progressCallBack?: any, onerror?: (scene: Scene) => void): void {
-            SceneLoader.Append(rootUrl, sceneFilename, new Scene(engine), onsuccess, progressCallBack, onerror);
-        }
-
-        /**
-        * Append a scene
-        * @param rootUrl a string that defines the root url for scene and resources
-        * @param sceneFilename a string that defines the name of the scene file. can start with "data:" following by the stringified version of the scene
-        * @param scene is the instance of BABYLON.Scene to append to
-        */
-        public static Append(rootUrl: string, sceneFilename: any, scene: Scene, onsuccess?: (scene: Scene) => void, progressCallBack?: any, onerror?: (scene: Scene) => void): void {
-
-            if (sceneFilename.substr && sceneFilename.substr(0, 1) === "/") {
-                Tools.Error("Wrong sceneFilename parameter");
-                return;
-            }
-
-            var plugin = this._getPluginForFilename(sceneFilename.name || sceneFilename);
-            var database;
-
-            var loadingToken = {};
-            scene._addPendingData(loadingToken);
-
-            if (SceneLoader.ShowLoadingScreen) {
-                scene.getEngine().displayLoadingUI();
-            }
-
-            var loadSceneFromData = data => {
-                scene.database = database;
-
-                if (!plugin.load(scene, data, rootUrl)) {
-                    if (onerror) {
-                        onerror(scene);
-                    }
-
-                    scene._removePendingData(loadingToken);
-                    scene.getEngine().hideLoadingUI();
-                    return;
-                }
-
-                if (onsuccess) {
-                    onsuccess(scene);
-                }
-                scene._removePendingData(loadingToken);
-
-                if (SceneLoader.ShowLoadingScreen) {
-                    scene.executeWhenReady(() => {
-                        scene.getEngine().hideLoadingUI();
-                    });
-                }                
-            };
-
-            var manifestChecked = success => {
-                Tools.LoadFile(rootUrl + sceneFilename, loadSceneFromData, progressCallBack, database);
-            };
-
-            if (sceneFilename.substr && sceneFilename.substr(0, 5) === "data:") {
-                // Direct load
-                loadSceneFromData(sceneFilename.substr(5));
-                return;
-            }
-
-            if (rootUrl.indexOf("file:") === -1) {
-                if (scene.getEngine().enableOfflineSupport) {
-                    // Checking if a manifest file has been set for this scene and if offline mode has been requested
-                    database = new Database(rootUrl + sceneFilename, manifestChecked);
-                }
-                else {
-                    manifestChecked(true);
-                }
-            }
-            // Loading file from disk via input file or drag'n'drop
-            else {
-                Tools.ReadFile(sceneFilename, loadSceneFromData, progressCallBack);
-            }
-        }
-    };
+module BABYLON {
+    export interface ISceneLoaderPlugin {
+        extensions: string;
+        importMesh: (meshesNames: any, scene: Scene, data: any, rootUrl: string, meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => boolean;
+        load: (scene: Scene, data: string, rootUrl: string) => boolean;
+    }
+
+    export class SceneLoader {
+        // Flags
+        private static _ForceFullSceneLoadingForIncremental = false;
+        private static _ShowLoadingScreen = true;
+
+        public static get ForceFullSceneLoadingForIncremental() {
+            return SceneLoader._ForceFullSceneLoadingForIncremental;
+        }
+
+        public static set ForceFullSceneLoadingForIncremental(value: boolean) {
+            SceneLoader._ForceFullSceneLoadingForIncremental = value;
+        }
+
+        public static get ShowLoadingScreen() {
+            return SceneLoader._ShowLoadingScreen;
+        }
+
+        public static set ShowLoadingScreen(value: boolean) {
+            SceneLoader._ShowLoadingScreen = value;
+        }
+
+        // Members
+        private static _registeredPlugins = new Array<ISceneLoaderPlugin>();
+
+        private static _getPluginForFilename(sceneFilename): ISceneLoaderPlugin {
+            var dotPosition = sceneFilename.lastIndexOf(".");
+
+            var queryStringPosition = sceneFilename.indexOf("?");
+
+            if (queryStringPosition === -1) {
+                queryStringPosition = sceneFilename.length;
+            }
+
+            var extension = sceneFilename.substring(dotPosition, queryStringPosition).toLowerCase();
+
+            for (var index = 0; index < this._registeredPlugins.length; index++) {
+                var plugin = this._registeredPlugins[index];
+
+                if (plugin.extensions.indexOf(extension) !== -1) {
+                    return plugin;
+                }
+            }
+
+            return this._registeredPlugins[this._registeredPlugins.length - 1];
+        }
+
+        // Public functions
+        public static RegisterPlugin(plugin: ISceneLoaderPlugin): void {
+            plugin.extensions = plugin.extensions.toLowerCase();
+            SceneLoader._registeredPlugins.push(plugin);
+        }
+
+        public static ImportMesh(meshesNames: any, rootUrl: string, sceneFilename: string, scene: Scene, onsuccess?: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, progressCallBack?: () => void, onerror?: (scene: Scene, e: any) => void): void {
+            if (sceneFilename.substr && sceneFilename.substr(0, 1) === "/") {
+                Tools.Error("Wrong sceneFilename parameter");
+                return;
+            }
+
+            var loadingToken = {};
+            scene._addPendingData(loadingToken);
+
+            var manifestChecked = success => {
+                scene.database = database;
+
+                var plugin = SceneLoader._getPluginForFilename(sceneFilename);
+
+                var importMeshFromData = data => {
+                    var meshes = [];
+                    var particleSystems = [];
+                    var skeletons = [];
+
+                    try {
+                        if (!plugin.importMesh(meshesNames, scene, data, rootUrl, meshes, particleSystems, skeletons)) {
+                            if (onerror) {
+                                onerror(scene, 'Unable to import meshes from ' + rootUrl + sceneFilename);
+                            }
+                            scene._removePendingData(loadingToken);
+                            return;
+                        }
+                    } catch (e) {
+                        if (onerror) {
+                            onerror(scene, 'Unable to import meshes from ' + rootUrl + sceneFilename + ' (Exception: ' + e + ')');
+                        }
+                        scene._removePendingData(loadingToken);
+                        return;
+                    }
+
+
+                    if (onsuccess) {
+                        scene.importedMeshesFiles.push(rootUrl + sceneFilename);
+                        onsuccess(meshes, particleSystems, skeletons);
+                        scene._removePendingData(loadingToken);
+                    }
+                };
+
+                if (sceneFilename.substr && sceneFilename.substr(0, 5) === "data:") {
+                    // Direct load
+                    importMeshFromData(sceneFilename.substr(5));
+                    return;
+                }
+
+                Tools.LoadFile(rootUrl + sceneFilename, data => {
+                    importMeshFromData(data);
+                }, progressCallBack, database);
+            };
+
+            if (scene.getEngine().enableOfflineSupport) {
+                // Checking if a manifest file has been set for this scene and if offline mode has been requested
+                var database = new Database(rootUrl + sceneFilename, manifestChecked);
+            }
+            else {
+                manifestChecked(true);
+            }
+        }
+
+        /**
+        * Load a scene
+        * @param rootUrl a string that defines the root url for scene and resources
+        * @param sceneFilename a string that defines the name of the scene file. can start with "data:" following by the stringified version of the scene
+        * @param engine is the instance of BABYLON.Engine to use to create the scene
+        */
+        public static Load(rootUrl: string, sceneFilename: any, engine: Engine, onsuccess?: (scene: Scene) => void, progressCallBack?: any, onerror?: (scene: Scene) => void): void {
+            SceneLoader.Append(rootUrl, sceneFilename, new Scene(engine), onsuccess, progressCallBack, onerror);
+        }
+
+        /**
+        * Append a scene
+        * @param rootUrl a string that defines the root url for scene and resources
+        * @param sceneFilename a string that defines the name of the scene file. can start with "data:" following by the stringified version of the scene
+        * @param scene is the instance of BABYLON.Scene to append to
+        */
+        public static Append(rootUrl: string, sceneFilename: any, scene: Scene, onsuccess?: (scene: Scene) => void, progressCallBack?: any, onerror?: (scene: Scene) => void): void {
+
+            if (sceneFilename.substr && sceneFilename.substr(0, 1) === "/") {
+                Tools.Error("Wrong sceneFilename parameter");
+                return;
+            }
+
+            var plugin = this._getPluginForFilename(sceneFilename.name || sceneFilename);
+            var database;
+
+            var loadingToken = {};
+            scene._addPendingData(loadingToken);
+
+            if (SceneLoader.ShowLoadingScreen) {
+                scene.getEngine().displayLoadingUI();
+            }
+
+            var loadSceneFromData = data => {
+                scene.database = database;
+
+                if (!plugin.load(scene, data, rootUrl)) {
+                    if (onerror) {
+                        onerror(scene);
+                    }
+
+                    scene._removePendingData(loadingToken);
+                    scene.getEngine().hideLoadingUI();
+                    return;
+                }
+
+                if (onsuccess) {
+                    onsuccess(scene);
+                }
+                scene._removePendingData(loadingToken);
+
+                if (SceneLoader.ShowLoadingScreen) {
+                    scene.executeWhenReady(() => {
+                        scene.getEngine().hideLoadingUI();
+                    });
+                }                
+            };
+
+            var manifestChecked = success => {
+                Tools.LoadFile(rootUrl + sceneFilename, loadSceneFromData, progressCallBack, database);
+            };
+
+            if (sceneFilename.substr && sceneFilename.substr(0, 5) === "data:") {
+                // Direct load
+                loadSceneFromData(sceneFilename.substr(5));
+                return;
+            }
+
+            if (rootUrl.indexOf("file:") === -1) {
+                if (scene.getEngine().enableOfflineSupport) {
+                    // Checking if a manifest file has been set for this scene and if offline mode has been requested
+                    database = new Database(rootUrl + sceneFilename, manifestChecked);
+                }
+                else {
+                    manifestChecked(true);
+                }
+            }
+            // Loading file from disk via input file or drag'n'drop
+            else {
+                Tools.ReadFile(sceneFilename, loadSceneFromData, progressCallBack);
+            }
+        }
+    };
 }

+ 133 - 133
src/Materials/Textures/Procedurals/babylon.customProceduralTexture.ts

@@ -1,134 +1,134 @@
-module BABYLON {
-    export class CustomProceduralTexture extends ProceduralTexture {
-        private _animate: boolean = true;
-        private _time: number = 0;
-        private _config: any;
-        private _texturePath: any;
-
-        constructor(name: string, texturePath: any, size: number, scene: Scene, fallbackTexture?: Texture, generateMipMaps?: boolean) {
-            super(name, size, null, scene, fallbackTexture, generateMipMaps);
-            this._texturePath = texturePath;
-
-            //Try to load json
-            this.loadJson(texturePath);
-            this.refreshRate = 1;
-        }
-
-        private loadJson(jsonUrl: string): void {
-            var that = this;
-
-            function noConfigFile() {
-                Tools.Log("No config file found in " + jsonUrl + " trying to use ShadersStore or DOM element");
-                try {
-                    that.setFragment(that._texturePath);
-                }
-                catch (ex) {
-                    Tools.Error("No json or ShaderStore or DOM element found for CustomProceduralTexture");
-                }
-            }
-
-            var configFileUrl = jsonUrl + "/config.json";
-            var xhr: XMLHttpRequest = new XMLHttpRequest();
-
-            xhr.open("GET", configFileUrl, true);
-            xhr.addEventListener("load", () => {
-                if (xhr.status === 200 || Tools.ValidateXHRData(xhr, 1)) {
-                    try {
-                        this._config = JSON.parse(xhr.response);
-
-                        this.updateShaderUniforms();
-                        this.updateTextures();
-                        this.setFragment(this._texturePath + "/custom");
-
-                        this._animate = this._config.animate;
-                        this.refreshRate = this._config.refreshrate;
-                    }
-                    catch (ex) {
-                        noConfigFile();
-                    }
-                }
-                else {
-                    noConfigFile();
-                }
-            }, false);
-
-            xhr.addEventListener("error", () => {
-                noConfigFile();
-            }, false);
-
-            try {
-                xhr.send();
-            }
-            catch (ex) {
-                Tools.Error("CustomProceduralTexture: Error on XHR send request.");
-            }
-        }
-
-        public isReady(): boolean {
-            if (!super.isReady()) {
-                return false;
-            }
-
-            for (var name in this._textures) {
-                var texture = this._textures[name];
-
-                if (!texture.isReady()) {
-                    return false;
-                }
-            }
-
-            return true;
-        }
-
-        public render(useCameraPostProcess?: boolean): void {
-            if (this._animate) {
-                this._time += this.getScene().getAnimationRatio() * 0.03;
-                this.updateShaderUniforms();
-            }
-
-            super.render(useCameraPostProcess);
-        }
-
-        public updateTextures(): void {
-            for (var i = 0; i < this._config.sampler2Ds.length; i++) {
-                this.setTexture(this._config.sampler2Ds[i].sample2Dname, new Texture(this._texturePath + "/" + this._config.sampler2Ds[i].textureRelativeUrl, this.getScene()));
-            }
-        }
-
-        public updateShaderUniforms(): void {
-            if (this._config) {
-                for (var j = 0; j < this._config.uniforms.length; j++) {
-                    var uniform = this._config.uniforms[j];
-
-                    switch (uniform.type) {
-                        case "float":
-                            this.setFloat(uniform.name, uniform.value);
-                            break;
-                        case "color3":
-                            this.setColor3(uniform.name, new Color3(uniform.r, uniform.g, uniform.b));
-                            break;
-                        case "color4":
-                            this.setColor4(uniform.name, new Color4(uniform.r, uniform.g, uniform.b, uniform.a));
-                            break;
-                        case "vector2":
-                            this.setVector2(uniform.name, new Vector2(uniform.x, uniform.y));
-                            break;
-                        case "vector3":
-                            this.setVector3(uniform.name, new Vector3(uniform.x, uniform.y, uniform.z));
-                            break;
-                    }
-                }
-            }
-
-            this.setFloat("time", this._time);
-        }
-
-        public get animate(): boolean {
-            return this._animate;
-        }
-
-        public set animate(value: boolean) {
-            this._animate = value;
-        }
-    }
+module BABYLON {
+    export class CustomProceduralTexture extends ProceduralTexture {
+        private _animate: boolean = true;
+        private _time: number = 0;
+        private _config: any;
+        private _texturePath: any;
+
+        constructor(name: string, texturePath: any, size: number, scene: Scene, fallbackTexture?: Texture, generateMipMaps?: boolean) {
+            super(name, size, null, scene, fallbackTexture, generateMipMaps);
+            this._texturePath = texturePath;
+
+            //Try to load json
+            this.loadJson(texturePath);
+            this.refreshRate = 1;
+        }
+
+        private loadJson(jsonUrl: string): void {
+            var that = this;
+
+            function noConfigFile() {
+                Tools.Log("No config file found in " + jsonUrl + " trying to use ShadersStore or DOM element");
+                try {
+                    that.setFragment(that._texturePath);
+                }
+                catch (ex) {
+                    Tools.Error("No json or ShaderStore or DOM element found for CustomProceduralTexture");
+                }
+            }
+
+            var configFileUrl = jsonUrl + "/config.json";
+            var xhr: XMLHttpRequest = new XMLHttpRequest();
+
+            xhr.open("GET", configFileUrl, true);
+            xhr.addEventListener("load", () => {
+                if (xhr.status === 200 || Tools.ValidateXHRData(xhr, 1)) {
+                    try {
+                        this._config = JSON.parse(xhr.response);
+
+                        this.updateShaderUniforms();
+                        this.updateTextures();
+                        this.setFragment(this._texturePath + "/custom");
+
+                        this._animate = this._config.animate;
+                        this.refreshRate = this._config.refreshrate;
+                    }
+                    catch (ex) {
+                        noConfigFile();
+                    }
+                }
+                else {
+                    noConfigFile();
+                }
+            }, false);
+
+            xhr.addEventListener("error", () => {
+                noConfigFile();
+            }, false);
+
+            try {
+                xhr.send();
+            }
+            catch (ex) {
+                Tools.Error("CustomProceduralTexture: Error on XHR send request.");
+            }
+        }
+
+        public isReady(): boolean {
+            if (!super.isReady()) {
+                return false;
+            }
+
+            for (var name in this._textures) {
+                var texture = this._textures[name];
+
+                if (!texture.isReady()) {
+                    return false;
+                }
+            }
+
+            return true;
+        }
+
+        public render(useCameraPostProcess?: boolean): void {
+            if (this._animate) {
+                this._time += this.getScene().getAnimationRatio() * 0.03;
+                this.updateShaderUniforms();
+            }
+
+            super.render(useCameraPostProcess);
+        }
+
+        public updateTextures(): void {
+            for (var i = 0; i < this._config.sampler2Ds.length; i++) {
+                this.setTexture(this._config.sampler2Ds[i].sample2Dname, new Texture(this._texturePath + "/" + this._config.sampler2Ds[i].textureRelativeUrl, this.getScene()));
+            }
+        }
+
+        public updateShaderUniforms(): void {
+            if (this._config) {
+                for (var j = 0; j < this._config.uniforms.length; j++) {
+                    var uniform = this._config.uniforms[j];
+
+                    switch (uniform.type) {
+                        case "float":
+                            this.setFloat(uniform.name, uniform.value);
+                            break;
+                        case "color3":
+                            this.setColor3(uniform.name, new Color3(uniform.r, uniform.g, uniform.b));
+                            break;
+                        case "color4":
+                            this.setColor4(uniform.name, new Color4(uniform.r, uniform.g, uniform.b, uniform.a));
+                            break;
+                        case "vector2":
+                            this.setVector2(uniform.name, new Vector2(uniform.x, uniform.y));
+                            break;
+                        case "vector3":
+                            this.setVector3(uniform.name, new Vector3(uniform.x, uniform.y, uniform.z));
+                            break;
+                    }
+                }
+            }
+
+            this.setFloat("time", this._time);
+        }
+
+        public get animate(): boolean {
+            return this._animate;
+        }
+
+        public set animate(value: boolean) {
+            this._animate = value;
+        }
+    }
 }

+ 322 - 322
src/Materials/Textures/Procedurals/babylon.proceduralTexture.ts

@@ -1,323 +1,323 @@
-module BABYLON {
-    export class ProceduralTexture extends Texture {
-        private _size: number;
-        public _generateMipMaps: boolean;
-        public isEnabled = true;
-        private _doNotChangeAspectRatio: boolean;
-        private _currentRefreshId = -1;
-        private _refreshRate = 1;
-
-        private _vertexBuffer: WebGLBuffer;
-        private _indexBuffer: WebGLBuffer;
-        private _effect: Effect;
-
-        private _vertexDeclaration = [2];
-        private _vertexStrideSize = 2 * 4;
-
-        private _uniforms = new Array<string>();
-        private _samplers = new Array<string>();
-        private _fragment: any;
-
-        public _textures = new Array<Texture>();
-        private _floats = new Array<number>();
-        private _floatsArrays = {};
-        private _colors3 = new Array<Color3>();
-        private _colors4 = new Array<Color4>();
-        private _vectors2 = new Array<Vector2>();
-        private _vectors3 = new Array<Vector3>();
-        private _matrices = new Array<Matrix>();
-
-        private _fallbackTexture: Texture;
-
-        private _fallbackTextureUsed = false;
-
-        constructor(name: string, size: any, fragment: any, scene: Scene, fallbackTexture?: Texture, generateMipMaps = true) {
-            super(null, scene, !generateMipMaps);
-
-            scene._proceduralTextures.push(this);
-
-            this.name = name;
-            this.isRenderTarget = true;
-            this._size = size;
-            this._generateMipMaps = generateMipMaps;
-
-            this.setFragment(fragment);
-
-            this._fallbackTexture = fallbackTexture;
-
-            this._texture = scene.getEngine().createRenderTargetTexture(size, generateMipMaps);
-
-            // VBO
-            var vertices = [];
-            vertices.push(1, 1);
-            vertices.push(-1, 1);
-            vertices.push(-1, -1);
-            vertices.push(1, -1);
-
-            this._vertexBuffer = scene.getEngine().createVertexBuffer(vertices);
-
-            // Indices
-            var indices = [];
-            indices.push(0);
-            indices.push(1);
-            indices.push(2);
-
-            indices.push(0);
-            indices.push(2);
-            indices.push(3);
-
-            this._indexBuffer = scene.getEngine().createIndexBuffer(indices);
-        }
-
-        public reset(): void {
-            if (this._effect === undefined) {
-                return;
-            }
-            var engine = this.getScene().getEngine();
-            engine._releaseEffect(this._effect);
-        }
-
-
-        public isReady(): boolean {
-            var engine = this.getScene().getEngine();
-            var shaders;
-
-            if (!this._fragment) {
-                return false;
-            }
-
-            if (this._fallbackTextureUsed) {
-                return true;
-            }
-
-            if (this._fragment.fragmentElement !== undefined) {
-                shaders = { vertex: "procedural", fragmentElement: this._fragment.fragmentElement };
-            }
-            else {
-                shaders = { vertex: "procedural", fragment: this._fragment };
-            }
-
-            this._effect = engine.createEffect(shaders,
-                ["position"],
-                this._uniforms,
-                this._samplers,
-                "", null, null, () => {
-                    this.releaseInternalTexture();
-
-                    if (this._fallbackTexture) {
-                        this._texture = this._fallbackTexture._texture;
-                        this._texture.references++;
-                    }
-
-                    this._fallbackTextureUsed = true;
-                });
-
-            return this._effect.isReady();
-        }
-
-        public resetRefreshCounter(): void {
-            this._currentRefreshId = -1;
-        }
-
-        public setFragment(fragment: any) {
-            this._fragment = fragment;
-        }
-
-        public get refreshRate(): number {
-            return this._refreshRate;
-        }
-
-        // Use 0 to render just once, 1 to render on every frame, 2 to render every two frames and so on...
-        public set refreshRate(value: number) {
-            this._refreshRate = value;
-            this.resetRefreshCounter();
-        }
-
-        public _shouldRender(): boolean {
-            if (!this.isEnabled || !this.isReady() || !this._texture) {
-                return false;
-            }
-
-            if (this._fallbackTextureUsed) {
-                return false;
-            }
-
-            if (this._currentRefreshId === -1) { // At least render once
-                this._currentRefreshId = 1;
-                return true;
-            }
-
-            if (this.refreshRate === this._currentRefreshId) {
-                this._currentRefreshId = 1;
-                return true;
-            }
-
-            this._currentRefreshId++;
-            return false;
-        }
-
-        public getRenderSize(): number {
-            return this._size;
-        }
-
-        public resize(size, generateMipMaps) {
-            if (this._fallbackTextureUsed) {
-                return;
-            }
-
-            this.releaseInternalTexture();
-            this._texture = this.getScene().getEngine().createRenderTargetTexture(size, generateMipMaps);
-        }
-
-        private _checkUniform(uniformName): void {
-            if (this._uniforms.indexOf(uniformName) === -1) {
-                this._uniforms.push(uniformName);
-            }
-        }
-
-        public setTexture(name: string, texture: Texture): ProceduralTexture {
-            if (this._samplers.indexOf(name) === -1) {
-                this._samplers.push(name);
-            }
-            this._textures[name] = texture;
-
-            return this;
-        }
-
-        public setFloat(name: string, value: number): ProceduralTexture {
-            this._checkUniform(name);
-            this._floats[name] = value;
-
-            return this;
-        }
-
-        public setFloats(name: string, value: number[]): ProceduralTexture {
-            this._checkUniform(name);
-            this._floatsArrays[name] = value;
-
-            return this;
-        }
-
-        public setColor3(name: string, value: Color3): ProceduralTexture {
-            this._checkUniform(name);
-            this._colors3[name] = value;
-
-            return this;
-        }
-
-        public setColor4(name: string, value: Color4): ProceduralTexture {
-            this._checkUniform(name);
-            this._colors4[name] = value;
-
-            return this;
-        }
-
-        public setVector2(name: string, value: Vector2): ProceduralTexture {
-            this._checkUniform(name);
-            this._vectors2[name] = value;
-
-            return this;
-        }
-
-        public setVector3(name: string, value: Vector3): ProceduralTexture {
-            this._checkUniform(name);
-            this._vectors3[name] = value;
-
-            return this;
-        }
-
-        public setMatrix(name: string, value: Matrix): ProceduralTexture {
-            this._checkUniform(name);
-            this._matrices[name] = value;
-
-            return this;
-        }
-
-        public render(useCameraPostProcess?: boolean) {
-            var scene = this.getScene();
-            var engine = scene.getEngine();
-
-            engine.bindFramebuffer(this._texture);
-
-            // Clear
-            engine.clear(scene.clearColor, true, true);
-
-            // Render
-            engine.enableEffect(this._effect);
-            engine.setState(false);
-
-            // Texture
-            for (var name in this._textures) {
-                this._effect.setTexture(name, this._textures[name]);
-            }
-
-            // Float    
-            for (name in this._floats) {
-                this._effect.setFloat(name, this._floats[name]);
-            }
-
-            // Floats   
-            for (name in this._floatsArrays) {
-                this._effect.setArray(name, this._floatsArrays[name]);
-            }
-
-            // Color3        
-            for (name in this._colors3) {
-                this._effect.setColor3(name, this._colors3[name]);
-            }
-
-            // Color4      
-            for (name in this._colors4) {
-                var color = this._colors4[name];
-                this._effect.setFloat4(name, color.r, color.g, color.b, color.a);
-            }
-
-            // Vector2        
-            for (name in this._vectors2) {
-                this._effect.setVector2(name, this._vectors2[name]);
-            }
-
-            // Vector3        
-            for (name in this._vectors3) {
-                this._effect.setVector3(name, this._vectors3[name]);
-            }
-
-            // Matrix      
-            for (name in this._matrices) {
-                this._effect.setMatrix(name, this._matrices[name]);
-            }
-
-            // VBOs
-            engine.bindBuffers(this._vertexBuffer, this._indexBuffer, this._vertexDeclaration, this._vertexStrideSize, this._effect);
-
-            // Draw order
-            engine.draw(true, 0, 6);
-
-            // Unbind
-            engine.unBindFramebuffer(this._texture);
-        }
-
-        public clone(): ProceduralTexture {
-            var textureSize = this.getSize();
-            var newTexture = new ProceduralTexture(this.name, textureSize.width, this._fragment, this.getScene(), this._fallbackTexture, this._generateMipMaps);
-
-            // Base texture
-            newTexture.hasAlpha = this.hasAlpha;
-            newTexture.level = this.level;
-
-            // RenderTarget Texture
-            newTexture.coordinatesMode = this.coordinatesMode;
-
-            return newTexture;
-        }
-
-        public dispose(): void {
-            var index = this.getScene()._proceduralTextures.indexOf(this);
-
-            if (index >= 0) {
-                this.getScene()._proceduralTextures.splice(index, 1);
-            }
-            super.dispose();
-        }
-    }
+module BABYLON {
+    export class ProceduralTexture extends Texture {
+        private _size: number;
+        public _generateMipMaps: boolean;
+        public isEnabled = true;
+        private _doNotChangeAspectRatio: boolean;
+        private _currentRefreshId = -1;
+        private _refreshRate = 1;
+
+        private _vertexBuffer: WebGLBuffer;
+        private _indexBuffer: WebGLBuffer;
+        private _effect: Effect;
+
+        private _vertexDeclaration = [2];
+        private _vertexStrideSize = 2 * 4;
+
+        private _uniforms = new Array<string>();
+        private _samplers = new Array<string>();
+        private _fragment: any;
+
+        public _textures = new Array<Texture>();
+        private _floats = new Array<number>();
+        private _floatsArrays = {};
+        private _colors3 = new Array<Color3>();
+        private _colors4 = new Array<Color4>();
+        private _vectors2 = new Array<Vector2>();
+        private _vectors3 = new Array<Vector3>();
+        private _matrices = new Array<Matrix>();
+
+        private _fallbackTexture: Texture;
+
+        private _fallbackTextureUsed = false;
+
+        constructor(name: string, size: any, fragment: any, scene: Scene, fallbackTexture?: Texture, generateMipMaps = true) {
+            super(null, scene, !generateMipMaps);
+
+            scene._proceduralTextures.push(this);
+
+            this.name = name;
+            this.isRenderTarget = true;
+            this._size = size;
+            this._generateMipMaps = generateMipMaps;
+
+            this.setFragment(fragment);
+
+            this._fallbackTexture = fallbackTexture;
+
+            this._texture = scene.getEngine().createRenderTargetTexture(size, generateMipMaps);
+
+            // VBO
+            var vertices = [];
+            vertices.push(1, 1);
+            vertices.push(-1, 1);
+            vertices.push(-1, -1);
+            vertices.push(1, -1);
+
+            this._vertexBuffer = scene.getEngine().createVertexBuffer(vertices);
+
+            // Indices
+            var indices = [];
+            indices.push(0);
+            indices.push(1);
+            indices.push(2);
+
+            indices.push(0);
+            indices.push(2);
+            indices.push(3);
+
+            this._indexBuffer = scene.getEngine().createIndexBuffer(indices);
+        }
+
+        public reset(): void {
+            if (this._effect === undefined) {
+                return;
+            }
+            var engine = this.getScene().getEngine();
+            engine._releaseEffect(this._effect);
+        }
+
+
+        public isReady(): boolean {
+            var engine = this.getScene().getEngine();
+            var shaders;
+
+            if (!this._fragment) {
+                return false;
+            }
+
+            if (this._fallbackTextureUsed) {
+                return true;
+            }
+
+            if (this._fragment.fragmentElement !== undefined) {
+                shaders = { vertex: "procedural", fragmentElement: this._fragment.fragmentElement };
+            }
+            else {
+                shaders = { vertex: "procedural", fragment: this._fragment };
+            }
+
+            this._effect = engine.createEffect(shaders,
+                ["position"],
+                this._uniforms,
+                this._samplers,
+                "", null, null, () => {
+                    this.releaseInternalTexture();
+
+                    if (this._fallbackTexture) {
+                        this._texture = this._fallbackTexture._texture;
+                        this._texture.references++;
+                    }
+
+                    this._fallbackTextureUsed = true;
+                });
+
+            return this._effect.isReady();
+        }
+
+        public resetRefreshCounter(): void {
+            this._currentRefreshId = -1;
+        }
+
+        public setFragment(fragment: any) {
+            this._fragment = fragment;
+        }
+
+        public get refreshRate(): number {
+            return this._refreshRate;
+        }
+
+        // Use 0 to render just once, 1 to render on every frame, 2 to render every two frames and so on...
+        public set refreshRate(value: number) {
+            this._refreshRate = value;
+            this.resetRefreshCounter();
+        }
+
+        public _shouldRender(): boolean {
+            if (!this.isEnabled || !this.isReady() || !this._texture) {
+                return false;
+            }
+
+            if (this._fallbackTextureUsed) {
+                return false;
+            }
+
+            if (this._currentRefreshId === -1) { // At least render once
+                this._currentRefreshId = 1;
+                return true;
+            }
+
+            if (this.refreshRate === this._currentRefreshId) {
+                this._currentRefreshId = 1;
+                return true;
+            }
+
+            this._currentRefreshId++;
+            return false;
+        }
+
+        public getRenderSize(): number {
+            return this._size;
+        }
+
+        public resize(size, generateMipMaps) {
+            if (this._fallbackTextureUsed) {
+                return;
+            }
+
+            this.releaseInternalTexture();
+            this._texture = this.getScene().getEngine().createRenderTargetTexture(size, generateMipMaps);
+        }
+
+        private _checkUniform(uniformName): void {
+            if (this._uniforms.indexOf(uniformName) === -1) {
+                this._uniforms.push(uniformName);
+            }
+        }
+
+        public setTexture(name: string, texture: Texture): ProceduralTexture {
+            if (this._samplers.indexOf(name) === -1) {
+                this._samplers.push(name);
+            }
+            this._textures[name] = texture;
+
+            return this;
+        }
+
+        public setFloat(name: string, value: number): ProceduralTexture {
+            this._checkUniform(name);
+            this._floats[name] = value;
+
+            return this;
+        }
+
+        public setFloats(name: string, value: number[]): ProceduralTexture {
+            this._checkUniform(name);
+            this._floatsArrays[name] = value;
+
+            return this;
+        }
+
+        public setColor3(name: string, value: Color3): ProceduralTexture {
+            this._checkUniform(name);
+            this._colors3[name] = value;
+
+            return this;
+        }
+
+        public setColor4(name: string, value: Color4): ProceduralTexture {
+            this._checkUniform(name);
+            this._colors4[name] = value;
+
+            return this;
+        }
+
+        public setVector2(name: string, value: Vector2): ProceduralTexture {
+            this._checkUniform(name);
+            this._vectors2[name] = value;
+
+            return this;
+        }
+
+        public setVector3(name: string, value: Vector3): ProceduralTexture {
+            this._checkUniform(name);
+            this._vectors3[name] = value;
+
+            return this;
+        }
+
+        public setMatrix(name: string, value: Matrix): ProceduralTexture {
+            this._checkUniform(name);
+            this._matrices[name] = value;
+
+            return this;
+        }
+
+        public render(useCameraPostProcess?: boolean) {
+            var scene = this.getScene();
+            var engine = scene.getEngine();
+
+            engine.bindFramebuffer(this._texture);
+
+            // Clear
+            engine.clear(scene.clearColor, true, true);
+
+            // Render
+            engine.enableEffect(this._effect);
+            engine.setState(false);
+
+            // Texture
+            for (var name in this._textures) {
+                this._effect.setTexture(name, this._textures[name]);
+            }
+
+            // Float    
+            for (name in this._floats) {
+                this._effect.setFloat(name, this._floats[name]);
+            }
+
+            // Floats   
+            for (name in this._floatsArrays) {
+                this._effect.setArray(name, this._floatsArrays[name]);
+            }
+
+            // Color3        
+            for (name in this._colors3) {
+                this._effect.setColor3(name, this._colors3[name]);
+            }
+
+            // Color4      
+            for (name in this._colors4) {
+                var color = this._colors4[name];
+                this._effect.setFloat4(name, color.r, color.g, color.b, color.a);
+            }
+
+            // Vector2        
+            for (name in this._vectors2) {
+                this._effect.setVector2(name, this._vectors2[name]);
+            }
+
+            // Vector3        
+            for (name in this._vectors3) {
+                this._effect.setVector3(name, this._vectors3[name]);
+            }
+
+            // Matrix      
+            for (name in this._matrices) {
+                this._effect.setMatrix(name, this._matrices[name]);
+            }
+
+            // VBOs
+            engine.bindBuffers(this._vertexBuffer, this._indexBuffer, this._vertexDeclaration, this._vertexStrideSize, this._effect);
+
+            // Draw order
+            engine.draw(true, 0, 6);
+
+            // Unbind
+            engine.unBindFramebuffer(this._texture);
+        }
+
+        public clone(): ProceduralTexture {
+            var textureSize = this.getSize();
+            var newTexture = new ProceduralTexture(this.name, textureSize.width, this._fragment, this.getScene(), this._fallbackTexture, this._generateMipMaps);
+
+            // Base texture
+            newTexture.hasAlpha = this.hasAlpha;
+            newTexture.level = this.level;
+
+            // RenderTarget Texture
+            newTexture.coordinatesMode = this.coordinatesMode;
+
+            return newTexture;
+        }
+
+        public dispose(): void {
+            var index = this.getScene()._proceduralTextures.indexOf(this);
+
+            if (index >= 0) {
+                this.getScene()._proceduralTextures.splice(index, 1);
+            }
+            super.dispose();
+        }
+    }
 } 

+ 103 - 103
src/Materials/Textures/babylon.dynamicTexture.ts

@@ -1,104 +1,104 @@
-module BABYLON {
-    export class DynamicTexture extends Texture {
-        private _generateMipMaps: boolean;
-        private _canvas: HTMLCanvasElement;
-        private _context: CanvasRenderingContext2D;
-
-        constructor(name: string, options: any, scene: Scene, generateMipMaps: boolean, samplingMode: number = Texture.TRILINEAR_SAMPLINGMODE) {
-            super(null, scene, !generateMipMaps);
-
-            this.name = name;
-
-            this.wrapU = Texture.CLAMP_ADDRESSMODE;
-            this.wrapV = Texture.CLAMP_ADDRESSMODE;
-
-            this._generateMipMaps = generateMipMaps;
-
-            if (options.getContext) {
-                this._canvas = options;
-                this._texture = scene.getEngine().createDynamicTexture(options.width, options.height, generateMipMaps, samplingMode);
-            } else {
-                this._canvas = document.createElement("canvas");
-
-                if (options.width) {
-                    this._texture = scene.getEngine().createDynamicTexture(options.width, options.height, generateMipMaps, samplingMode);
-                } else {
-                    this._texture = scene.getEngine().createDynamicTexture(options, options, generateMipMaps, samplingMode);
-                }
-            }
-
-            var textureSize = this.getSize();
-
-            this._canvas.width = textureSize.width;
-            this._canvas.height = textureSize.height;
-            this._context = this._canvas.getContext("2d");
-        }
-
-        public get canRescale(): boolean {
-            return true;
-        }
-
-        public scale(ratio: number): void {
-            var textureSize = this.getSize();
-
-            textureSize.width *= ratio;
-            textureSize.height *= ratio;
-
-            this._canvas.width = textureSize.width;
-            this._canvas.height = textureSize.height;
-
-            this.releaseInternalTexture();
-
-            this._texture = this.getScene().getEngine().createDynamicTexture(textureSize.width, textureSize.height, this._generateMipMaps, this._samplingMode);
-        }
-
-        public getContext(): CanvasRenderingContext2D {
-            return this._context;
-        }
-
-        public clear(): void {
-            var size = this.getSize();
-            this._context.fillRect(0, 0, size.width, size.height);
-        }
-
-        public update(invertY?: boolean): void {
-            this.getScene().getEngine().updateDynamicTexture(this._texture, this._canvas, invertY === undefined ? true : invertY);
-        }
-
-        public drawText(text: string, x: number, y: number, font: string, color: string, clearColor: string, invertY?: boolean, update = true) {
-            var size = this.getSize();
-            if (clearColor) {
-                this._context.fillStyle = clearColor;
-                this._context.fillRect(0, 0, size.width, size.height);
-            }
-
-            this._context.font = font;
-            if (x === null) {
-                var textSize = this._context.measureText(text);
-                x = (size.width - textSize.width) / 2;
-            }
-
-            this._context.fillStyle = color;
-            this._context.fillText(text, x, y);
-
-            if (update) {
-                this.update(invertY);
-            }
-        }
-
-        public clone(): DynamicTexture {
-            var textureSize = this.getSize();
-            var newTexture = new DynamicTexture(this.name, textureSize.width, this.getScene(), this._generateMipMaps);
-
-            // Base texture
-            newTexture.hasAlpha = this.hasAlpha;
-            newTexture.level = this.level;
-
-            // Dynamic Texture
-            newTexture.wrapU = this.wrapU;
-            newTexture.wrapV = this.wrapV;
-
-            return newTexture;
-        }
-    }
+module BABYLON {
+    export class DynamicTexture extends Texture {
+        private _generateMipMaps: boolean;
+        private _canvas: HTMLCanvasElement;
+        private _context: CanvasRenderingContext2D;
+
+        constructor(name: string, options: any, scene: Scene, generateMipMaps: boolean, samplingMode: number = Texture.TRILINEAR_SAMPLINGMODE) {
+            super(null, scene, !generateMipMaps);
+
+            this.name = name;
+
+            this.wrapU = Texture.CLAMP_ADDRESSMODE;
+            this.wrapV = Texture.CLAMP_ADDRESSMODE;
+
+            this._generateMipMaps = generateMipMaps;
+
+            if (options.getContext) {
+                this._canvas = options;
+                this._texture = scene.getEngine().createDynamicTexture(options.width, options.height, generateMipMaps, samplingMode);
+            } else {
+                this._canvas = document.createElement("canvas");
+
+                if (options.width) {
+                    this._texture = scene.getEngine().createDynamicTexture(options.width, options.height, generateMipMaps, samplingMode);
+                } else {
+                    this._texture = scene.getEngine().createDynamicTexture(options, options, generateMipMaps, samplingMode);
+                }
+            }
+
+            var textureSize = this.getSize();
+
+            this._canvas.width = textureSize.width;
+            this._canvas.height = textureSize.height;
+            this._context = this._canvas.getContext("2d");
+        }
+
+        public get canRescale(): boolean {
+            return true;
+        }
+
+        public scale(ratio: number): void {
+            var textureSize = this.getSize();
+
+            textureSize.width *= ratio;
+            textureSize.height *= ratio;
+
+            this._canvas.width = textureSize.width;
+            this._canvas.height = textureSize.height;
+
+            this.releaseInternalTexture();
+
+            this._texture = this.getScene().getEngine().createDynamicTexture(textureSize.width, textureSize.height, this._generateMipMaps, this._samplingMode);
+        }
+
+        public getContext(): CanvasRenderingContext2D {
+            return this._context;
+        }
+
+        public clear(): void {
+            var size = this.getSize();
+            this._context.fillRect(0, 0, size.width, size.height);
+        }
+
+        public update(invertY?: boolean): void {
+            this.getScene().getEngine().updateDynamicTexture(this._texture, this._canvas, invertY === undefined ? true : invertY);
+        }
+
+        public drawText(text: string, x: number, y: number, font: string, color: string, clearColor: string, invertY?: boolean, update = true) {
+            var size = this.getSize();
+            if (clearColor) {
+                this._context.fillStyle = clearColor;
+                this._context.fillRect(0, 0, size.width, size.height);
+            }
+
+            this._context.font = font;
+            if (x === null) {
+                var textSize = this._context.measureText(text);
+                x = (size.width - textSize.width) / 2;
+            }
+
+            this._context.fillStyle = color;
+            this._context.fillText(text, x, y);
+
+            if (update) {
+                this.update(invertY);
+            }
+        }
+
+        public clone(): DynamicTexture {
+            var textureSize = this.getSize();
+            var newTexture = new DynamicTexture(this.name, textureSize.width, this.getScene(), this._generateMipMaps);
+
+            // Base texture
+            newTexture.hasAlpha = this.hasAlpha;
+            newTexture.level = this.level;
+
+            // Dynamic Texture
+            newTexture.wrapU = this.wrapU;
+            newTexture.wrapV = this.wrapV;
+
+            return newTexture;
+        }
+    }
 } 

+ 62 - 62
src/Materials/Textures/babylon.mirrorTexture.ts

@@ -1,63 +1,63 @@
-module BABYLON {
-    export class MirrorTexture extends RenderTargetTexture {
-        public mirrorPlane = new Plane(0, 1, 0, 1);
-
-        private _transformMatrix = Matrix.Zero();
-        private _mirrorMatrix = Matrix.Zero();
-        private _savedViewMatrix: Matrix;
-
-        constructor(name: string, size: number, scene: Scene, generateMipMaps?: boolean) {
-            super(name, size, scene, generateMipMaps, true);
-
-            this.onBeforeRender = () => {
-                Matrix.ReflectionToRef(this.mirrorPlane, this._mirrorMatrix);
-                this._savedViewMatrix = scene.getViewMatrix();
-
-                this._mirrorMatrix.multiplyToRef(this._savedViewMatrix, this._transformMatrix);
-
-                scene.setTransformMatrix(this._transformMatrix, scene.getProjectionMatrix());
-
-                scene.clipPlane = this.mirrorPlane;
-
-                scene.getEngine().cullBackFaces = false;
-
-                scene._mirroredCameraPosition = Vector3.TransformCoordinates(scene.activeCamera.position, this._mirrorMatrix);
-            }
-
-            this.onAfterRender = () => {
-                scene.setTransformMatrix(this._savedViewMatrix, scene.getProjectionMatrix());
-                scene.getEngine().cullBackFaces = true;
-                scene._mirroredCameraPosition = null;
-
-                delete scene.clipPlane;
-            }
-        }
-
-        public clone(): MirrorTexture {
-            var textureSize = this.getSize();
-            var newTexture = new MirrorTexture(this.name, textureSize.width, this.getScene(), this._generateMipMaps);
-
-            // Base texture
-            newTexture.hasAlpha = this.hasAlpha;
-            newTexture.level = this.level;
-
-            // Mirror Texture
-            newTexture.mirrorPlane = this.mirrorPlane.clone();
-            newTexture.renderList = this.renderList.slice(0);
-
-            return newTexture;
-        }
-
-        public serialize(): any {
-            if (!this.name) {
-                return null;
-            }
-
-            var serializationObject = super.serialize();
-
-            serializationObject.mirrorPlane = this.mirrorPlane.asArray();
-
-            return serializationObject;
-        }
-    }
+module BABYLON {
+    export class MirrorTexture extends RenderTargetTexture {
+        public mirrorPlane = new Plane(0, 1, 0, 1);
+
+        private _transformMatrix = Matrix.Zero();
+        private _mirrorMatrix = Matrix.Zero();
+        private _savedViewMatrix: Matrix;
+
+        constructor(name: string, size: number, scene: Scene, generateMipMaps?: boolean) {
+            super(name, size, scene, generateMipMaps, true);
+
+            this.onBeforeRender = () => {
+                Matrix.ReflectionToRef(this.mirrorPlane, this._mirrorMatrix);
+                this._savedViewMatrix = scene.getViewMatrix();
+
+                this._mirrorMatrix.multiplyToRef(this._savedViewMatrix, this._transformMatrix);
+
+                scene.setTransformMatrix(this._transformMatrix, scene.getProjectionMatrix());
+
+                scene.clipPlane = this.mirrorPlane;
+
+                scene.getEngine().cullBackFaces = false;
+
+                scene._mirroredCameraPosition = Vector3.TransformCoordinates(scene.activeCamera.position, this._mirrorMatrix);
+            }
+
+            this.onAfterRender = () => {
+                scene.setTransformMatrix(this._savedViewMatrix, scene.getProjectionMatrix());
+                scene.getEngine().cullBackFaces = true;
+                scene._mirroredCameraPosition = null;
+
+                delete scene.clipPlane;
+            }
+        }
+
+        public clone(): MirrorTexture {
+            var textureSize = this.getSize();
+            var newTexture = new MirrorTexture(this.name, textureSize.width, this.getScene(), this._generateMipMaps);
+
+            // Base texture
+            newTexture.hasAlpha = this.hasAlpha;
+            newTexture.level = this.level;
+
+            // Mirror Texture
+            newTexture.mirrorPlane = this.mirrorPlane.clone();
+            newTexture.renderList = this.renderList.slice(0);
+
+            return newTexture;
+        }
+
+        public serialize(): any {
+            if (!this.name) {
+                return null;
+            }
+
+            var serializationObject = super.serialize();
+
+            serializationObject.mirrorPlane = this.mirrorPlane.asArray();
+
+            return serializationObject;
+        }
+    }
 } 

+ 36 - 36
src/Materials/Textures/babylon.rawTexture.ts

@@ -1,37 +1,37 @@
-module BABYLON {
-    export class RawTexture extends Texture {
-        constructor(data: ArrayBufferView, width: number, height: number, public format: number, scene: Scene, generateMipMaps: boolean = true, invertY: boolean = false, samplingMode: number = Texture.TRILINEAR_SAMPLINGMODE) {
-            super(null, scene, !generateMipMaps, invertY);
-
-            this._texture = scene.getEngine().createRawTexture(data, width, height, format, generateMipMaps, invertY, samplingMode);
-
-            this.wrapU = Texture.CLAMP_ADDRESSMODE;
-            this.wrapV = Texture.CLAMP_ADDRESSMODE;
-        }
-
-        public update(data: ArrayBufferView): void {
-            this.getScene().getEngine().updateRawTexture(this._texture, data, this.format, this._invertY);
-        }
-
-        // Statics
-        public static CreateLuminanceTexture(data: ArrayBufferView, width: number, height: number, scene: Scene, generateMipMaps: boolean = true, invertY: boolean = false, samplingMode: number = Texture.TRILINEAR_SAMPLINGMODE): RawTexture {
-            return new RawTexture(data, width, height, Engine.TEXTUREFORMAT_LUMINANCE, scene, generateMipMaps, invertY, samplingMode);
-        }
-
-        public static CreateLuminanceAlphaTexture(data: ArrayBufferView, width: number, height: number, scene: Scene, generateMipMaps: boolean = true, invertY: boolean = false, samplingMode: number = Texture.TRILINEAR_SAMPLINGMODE): RawTexture {
-            return new RawTexture(data, width, height, Engine.TEXTUREFORMAT_LUMINANCE_ALPHA, scene, generateMipMaps, invertY, samplingMode);
-        }
-
-        public static CreateAlphaTexture(data: ArrayBufferView, width: number, height: number, scene: Scene, generateMipMaps: boolean = true, invertY: boolean = false, samplingMode: number = Texture.TRILINEAR_SAMPLINGMODE): RawTexture {
-            return new RawTexture(data, width, height, Engine.TEXTUREFORMAT_ALPHA, scene, generateMipMaps, invertY, samplingMode);
-        }
-
-        public static CreateRGBTexture(data: ArrayBufferView, width: number, height: number, scene: Scene, generateMipMaps: boolean = true, invertY: boolean = false, samplingMode: number = Texture.TRILINEAR_SAMPLINGMODE): RawTexture {
-            return new RawTexture(data, width, height, Engine.TEXTUREFORMAT_RGB, scene, generateMipMaps, invertY, samplingMode);
-        }
-
-        public static CreateRGBATexture(data: ArrayBufferView, width: number, height: number, scene: Scene, generateMipMaps: boolean = true, invertY: boolean = false, samplingMode: number = Texture.TRILINEAR_SAMPLINGMODE): RawTexture {
-            return new RawTexture(data, width, height, Engine.TEXTUREFORMAT_RGBA, scene, generateMipMaps, invertY, samplingMode);
-        }
-    }
+module BABYLON {
+    export class RawTexture extends Texture {
+        constructor(data: ArrayBufferView, width: number, height: number, public format: number, scene: Scene, generateMipMaps: boolean = true, invertY: boolean = false, samplingMode: number = Texture.TRILINEAR_SAMPLINGMODE) {
+            super(null, scene, !generateMipMaps, invertY);
+
+            this._texture = scene.getEngine().createRawTexture(data, width, height, format, generateMipMaps, invertY, samplingMode);
+
+            this.wrapU = Texture.CLAMP_ADDRESSMODE;
+            this.wrapV = Texture.CLAMP_ADDRESSMODE;
+        }
+
+        public update(data: ArrayBufferView): void {
+            this.getScene().getEngine().updateRawTexture(this._texture, data, this.format, this._invertY);
+        }
+
+        // Statics
+        public static CreateLuminanceTexture(data: ArrayBufferView, width: number, height: number, scene: Scene, generateMipMaps: boolean = true, invertY: boolean = false, samplingMode: number = Texture.TRILINEAR_SAMPLINGMODE): RawTexture {
+            return new RawTexture(data, width, height, Engine.TEXTUREFORMAT_LUMINANCE, scene, generateMipMaps, invertY, samplingMode);
+        }
+
+        public static CreateLuminanceAlphaTexture(data: ArrayBufferView, width: number, height: number, scene: Scene, generateMipMaps: boolean = true, invertY: boolean = false, samplingMode: number = Texture.TRILINEAR_SAMPLINGMODE): RawTexture {
+            return new RawTexture(data, width, height, Engine.TEXTUREFORMAT_LUMINANCE_ALPHA, scene, generateMipMaps, invertY, samplingMode);
+        }
+
+        public static CreateAlphaTexture(data: ArrayBufferView, width: number, height: number, scene: Scene, generateMipMaps: boolean = true, invertY: boolean = false, samplingMode: number = Texture.TRILINEAR_SAMPLINGMODE): RawTexture {
+            return new RawTexture(data, width, height, Engine.TEXTUREFORMAT_ALPHA, scene, generateMipMaps, invertY, samplingMode);
+        }
+
+        public static CreateRGBTexture(data: ArrayBufferView, width: number, height: number, scene: Scene, generateMipMaps: boolean = true, invertY: boolean = false, samplingMode: number = Texture.TRILINEAR_SAMPLINGMODE): RawTexture {
+            return new RawTexture(data, width, height, Engine.TEXTUREFORMAT_RGB, scene, generateMipMaps, invertY, samplingMode);
+        }
+
+        public static CreateRGBATexture(data: ArrayBufferView, width: number, height: number, scene: Scene, generateMipMaps: boolean = true, invertY: boolean = false, samplingMode: number = Texture.TRILINEAR_SAMPLINGMODE): RawTexture {
+            return new RawTexture(data, width, height, Engine.TEXTUREFORMAT_RGBA, scene, generateMipMaps, invertY, samplingMode);
+        }
+    }
 }

+ 278 - 278
src/Materials/Textures/babylon.renderTargetTexture.ts

@@ -1,279 +1,279 @@
-module BABYLON {
-    export class RenderTargetTexture extends Texture {
-        public static _REFRESHRATE_RENDER_ONCE: number = 0;
-        public static _REFRESHRATE_RENDER_ONEVERYFRAME: number = 1;
-        public static _REFRESHRATE_RENDER_ONEVERYTWOFRAMES: number = 2;
-
-        public static get REFRESHRATE_RENDER_ONCE(): number {
-            return RenderTargetTexture._REFRESHRATE_RENDER_ONCE;
-        }
-
-        public static get REFRESHRATE_RENDER_ONEVERYFRAME(): number {
-            return RenderTargetTexture._REFRESHRATE_RENDER_ONEVERYFRAME;
-        }
-
-        public static get REFRESHRATE_RENDER_ONEVERYTWOFRAMES(): number {
-            return RenderTargetTexture._REFRESHRATE_RENDER_ONEVERYTWOFRAMES;
-        }
-
-        public renderList = new Array<AbstractMesh>();
-        public renderParticles = true;
-        public renderSprites = false;
-        public coordinatesMode = Texture.PROJECTION_MODE;
-        public onBeforeRender: (faceIndex: number) => void;
-        public onAfterRender: (faceIndex: number) => void;
-        public onAfterUnbind: () => void;
-        public onClear: (engine: Engine) => void;
-        public activeCamera: Camera;
-        public customRenderFunction: (opaqueSubMeshes: SmartArray<SubMesh>, transparentSubMeshes: SmartArray<SubMesh>, alphaTestSubMeshes: SmartArray<SubMesh>, beforeTransparents?: () => void) => void;
-
-        private _size: number;
-        public _generateMipMaps: boolean;
-        private _renderingManager: RenderingManager;
-        public _waitingRenderList: string[];
-        private _doNotChangeAspectRatio: boolean;
-        private _currentRefreshId = -1;
-        private _refreshRate = 1;
-        private _textureMatrix: Matrix;
-
-        constructor(name: string, size: any, scene: Scene, generateMipMaps?: boolean, doNotChangeAspectRatio: boolean = true, type: number = Engine.TEXTURETYPE_UNSIGNED_INT, public isCube = false) {
-            super(null, scene, !generateMipMaps);
-
-            this.name = name;
-            this.isRenderTarget = true;
-            this._size = size;
-            this._generateMipMaps = generateMipMaps;
-            this._doNotChangeAspectRatio = doNotChangeAspectRatio;
-
-            if (isCube) {
-                this._texture = scene.getEngine().createRenderTargetCubeTexture(size, { generateMipMaps: generateMipMaps });
-                this.coordinatesMode = Texture.INVCUBIC_MODE;
-                this._textureMatrix = Matrix.Identity();
-            } else {
-                this._texture = scene.getEngine().createRenderTargetTexture(size, { generateMipMaps: generateMipMaps, type: type });
-            }
-
-            // Rendering groups
-            this._renderingManager = new RenderingManager(scene);
-        }
-
-        public resetRefreshCounter(): void {
-            this._currentRefreshId = -1;
-        }
-
-        public get refreshRate(): number {
-            return this._refreshRate;
-        }
-
-        // Use 0 to render just once, 1 to render on every frame, 2 to render every two frames and so on...
-        public set refreshRate(value: number) {
-            this._refreshRate = value;
-            this.resetRefreshCounter();
-        }
-
-        public _shouldRender(): boolean {
-            if (this._currentRefreshId === -1) { // At least render once
-                this._currentRefreshId = 1;
-                return true;
-            }
-
-            if (this.refreshRate === this._currentRefreshId) {
-                this._currentRefreshId = 1;
-                return true;
-            }
-
-            this._currentRefreshId++;
-            return false;
-        }
-
-        public isReady(): boolean {
-            if (!this.getScene().renderTargetsEnabled) {
-                return false;
-            }
-            return super.isReady();
-        }
-
-        public getRenderSize(): number {
-            return this._size;
-        }
-
-        public get canRescale(): boolean {
-            return true;
-        }
-
-        public scale(ratio: number): void {
-            var newSize = this._size * ratio;
-
-            this.resize(newSize, this._generateMipMaps);
-        }
-
-        public getReflectionTextureMatrix(): Matrix {
-            if (this.isCube) {
-                return this._textureMatrix;
-            }
-
-            return super.getReflectionTextureMatrix();
-        }
-
-        public resize(size: any, generateMipMaps?: boolean) {
-            this.releaseInternalTexture();
-            if (this.isCube) {
-                this._texture = this.getScene().getEngine().createRenderTargetCubeTexture(size);
-            } else {
-                this._texture = this.getScene().getEngine().createRenderTargetTexture(size, generateMipMaps);
-            }
-        }
-
-        public render(useCameraPostProcess?: boolean, dumpForDebug?: boolean) {
-            var scene = this.getScene();
-
-            if (this._waitingRenderList) {
-                this.renderList = [];
-                for (var index = 0; index < this._waitingRenderList.length; index++) {
-                    var id = this._waitingRenderList[index];
-                    this.renderList.push(scene.getMeshByID(id));
-                }
-
-                delete this._waitingRenderList;
-            }
-
-            if (this.renderList && this.renderList.length === 0) {
-                return;
-            }
-
-            // Prepare renderingManager
-            this._renderingManager.reset();
-
-            var currentRenderList = this.renderList ? this.renderList : scene.getActiveMeshes().data;
-
-            for (var meshIndex = 0; meshIndex < currentRenderList.length; meshIndex++) {
-                var mesh = currentRenderList[meshIndex];
-
-                if (mesh) {
-                    if (!mesh.isReady()) {
-                        // Reset _currentRefreshId
-                        this.resetRefreshCounter();
-                        continue;
-                    }
-
-                    if (mesh.isEnabled() && mesh.isVisible && mesh.subMeshes && ((mesh.layerMask & scene.activeCamera.layerMask) !== 0)) {
-                        mesh._activate(scene.getRenderId());
-
-                        for (var subIndex = 0; subIndex < mesh.subMeshes.length; subIndex++) {
-                            var subMesh = mesh.subMeshes[subIndex];
-                            scene._activeIndices += subMesh.indexCount;
-                            this._renderingManager.dispatch(subMesh);
-                        }
-                    }
-                }
-            }
-            
-            if (this.isCube) {
-                for (var face = 0; face < 6; face++) {
-                    this.renderToTarget(face, currentRenderList, useCameraPostProcess, dumpForDebug);
-                }
-            } else {
-                this.renderToTarget(0, currentRenderList, useCameraPostProcess, dumpForDebug);
-            }
-
-            if (this.onAfterUnbind) {
-                this.onAfterUnbind();
-            }
-
-            scene.resetCachedMaterial();
-        }
-
-        renderToTarget(faceIndex: number, currentRenderList: AbstractMesh[], useCameraPostProcess: boolean, dumpForDebug: boolean): void {
-            var scene = this.getScene();
-            var engine = scene.getEngine();
-
-            // Bind
-            if (!useCameraPostProcess || !scene.postProcessManager._prepareFrame(this._texture)) {
-                if (this.isCube) {
-                    engine.bindFramebuffer(this._texture, faceIndex);
-                } else {
-                    engine.bindFramebuffer(this._texture);
-                }
-            }
-
-            if (this.onBeforeRender) {
-                this.onBeforeRender(faceIndex);
-            }
-
-            // Clear
-            if (this.onClear) {
-                this.onClear(engine);
-            } else {
-                engine.clear(scene.clearColor, true, true);
-            }
-
-            if (!this._doNotChangeAspectRatio) {
-                scene.updateTransformMatrix(true);
-            }
-
-            // Render
-            this._renderingManager.render(this.customRenderFunction, currentRenderList, this.renderParticles, this.renderSprites);
-
-            if (useCameraPostProcess) {
-                scene.postProcessManager._finalizeFrame(false, this._texture, faceIndex);
-            }
-
-            if (!this._doNotChangeAspectRatio) {
-                scene.updateTransformMatrix(true);
-            }
-
-            if (this.onAfterRender) {
-                this.onAfterRender(faceIndex);
-            }
-
-            // Dump ?
-            if (dumpForDebug) {
-                Tools.DumpFramebuffer(this._size, this._size, engine);
-            }
-
-            // Unbind
-            if (!this.isCube || faceIndex === 5) {
-                if (this.isCube) {
-
-                    if (faceIndex === 5) {
-                        engine.generateMipMapsForCubemap(this._texture);
-                    }
-                }
-
-                engine.unBindFramebuffer(this._texture, this.isCube);
-            }
-        }
-
-        public clone(): RenderTargetTexture {
-            var textureSize = this.getSize();
-            var newTexture = new RenderTargetTexture(this.name, textureSize.width, this.getScene(), this._generateMipMaps);
-
-            // Base texture
-            newTexture.hasAlpha = this.hasAlpha;
-            newTexture.level = this.level;
-
-            // RenderTarget Texture
-            newTexture.coordinatesMode = this.coordinatesMode;
-            newTexture.renderList = this.renderList.slice(0);
-
-            return newTexture;
-        }
-
-        public serialize(): any {
-            if (!this.name) {
-                return null;
-            }
-
-            var serializationObject = super.serialize();
-
-            serializationObject.renderTargetSize = this.getRenderSize();
-            serializationObject.renderList = [];
-
-            for (var index = 0; index < this.renderList.length; index++) {
-                serializationObject.renderList.push(this.renderList[index].id);
-            }
-
-            return serializationObject;
-        }
-    }
+module BABYLON {
+    export class RenderTargetTexture extends Texture {
+        public static _REFRESHRATE_RENDER_ONCE: number = 0;
+        public static _REFRESHRATE_RENDER_ONEVERYFRAME: number = 1;
+        public static _REFRESHRATE_RENDER_ONEVERYTWOFRAMES: number = 2;
+
+        public static get REFRESHRATE_RENDER_ONCE(): number {
+            return RenderTargetTexture._REFRESHRATE_RENDER_ONCE;
+        }
+
+        public static get REFRESHRATE_RENDER_ONEVERYFRAME(): number {
+            return RenderTargetTexture._REFRESHRATE_RENDER_ONEVERYFRAME;
+        }
+
+        public static get REFRESHRATE_RENDER_ONEVERYTWOFRAMES(): number {
+            return RenderTargetTexture._REFRESHRATE_RENDER_ONEVERYTWOFRAMES;
+        }
+
+        public renderList = new Array<AbstractMesh>();
+        public renderParticles = true;
+        public renderSprites = false;
+        public coordinatesMode = Texture.PROJECTION_MODE;
+        public onBeforeRender: (faceIndex: number) => void;
+        public onAfterRender: (faceIndex: number) => void;
+        public onAfterUnbind: () => void;
+        public onClear: (engine: Engine) => void;
+        public activeCamera: Camera;
+        public customRenderFunction: (opaqueSubMeshes: SmartArray<SubMesh>, transparentSubMeshes: SmartArray<SubMesh>, alphaTestSubMeshes: SmartArray<SubMesh>, beforeTransparents?: () => void) => void;
+
+        private _size: number;
+        public _generateMipMaps: boolean;
+        private _renderingManager: RenderingManager;
+        public _waitingRenderList: string[];
+        private _doNotChangeAspectRatio: boolean;
+        private _currentRefreshId = -1;
+        private _refreshRate = 1;
+        private _textureMatrix: Matrix;
+
+        constructor(name: string, size: any, scene: Scene, generateMipMaps?: boolean, doNotChangeAspectRatio: boolean = true, type: number = Engine.TEXTURETYPE_UNSIGNED_INT, public isCube = false) {
+            super(null, scene, !generateMipMaps);
+
+            this.name = name;
+            this.isRenderTarget = true;
+            this._size = size;
+            this._generateMipMaps = generateMipMaps;
+            this._doNotChangeAspectRatio = doNotChangeAspectRatio;
+
+            if (isCube) {
+                this._texture = scene.getEngine().createRenderTargetCubeTexture(size, { generateMipMaps: generateMipMaps });
+                this.coordinatesMode = Texture.INVCUBIC_MODE;
+                this._textureMatrix = Matrix.Identity();
+            } else {
+                this._texture = scene.getEngine().createRenderTargetTexture(size, { generateMipMaps: generateMipMaps, type: type });
+            }
+
+            // Rendering groups
+            this._renderingManager = new RenderingManager(scene);
+        }
+
+        public resetRefreshCounter(): void {
+            this._currentRefreshId = -1;
+        }
+
+        public get refreshRate(): number {
+            return this._refreshRate;
+        }
+
+        // Use 0 to render just once, 1 to render on every frame, 2 to render every two frames and so on...
+        public set refreshRate(value: number) {
+            this._refreshRate = value;
+            this.resetRefreshCounter();
+        }
+
+        public _shouldRender(): boolean {
+            if (this._currentRefreshId === -1) { // At least render once
+                this._currentRefreshId = 1;
+                return true;
+            }
+
+            if (this.refreshRate === this._currentRefreshId) {
+                this._currentRefreshId = 1;
+                return true;
+            }
+
+            this._currentRefreshId++;
+            return false;
+        }
+
+        public isReady(): boolean {
+            if (!this.getScene().renderTargetsEnabled) {
+                return false;
+            }
+            return super.isReady();
+        }
+
+        public getRenderSize(): number {
+            return this._size;
+        }
+
+        public get canRescale(): boolean {
+            return true;
+        }
+
+        public scale(ratio: number): void {
+            var newSize = this._size * ratio;
+
+            this.resize(newSize, this._generateMipMaps);
+        }
+
+        public getReflectionTextureMatrix(): Matrix {
+            if (this.isCube) {
+                return this._textureMatrix;
+            }
+
+            return super.getReflectionTextureMatrix();
+        }
+
+        public resize(size: any, generateMipMaps?: boolean) {
+            this.releaseInternalTexture();
+            if (this.isCube) {
+                this._texture = this.getScene().getEngine().createRenderTargetCubeTexture(size);
+            } else {
+                this._texture = this.getScene().getEngine().createRenderTargetTexture(size, generateMipMaps);
+            }
+        }
+
+        public render(useCameraPostProcess?: boolean, dumpForDebug?: boolean) {
+            var scene = this.getScene();
+
+            if (this._waitingRenderList) {
+                this.renderList = [];
+                for (var index = 0; index < this._waitingRenderList.length; index++) {
+                    var id = this._waitingRenderList[index];
+                    this.renderList.push(scene.getMeshByID(id));
+                }
+
+                delete this._waitingRenderList;
+            }
+
+            if (this.renderList && this.renderList.length === 0) {
+                return;
+            }
+
+            // Prepare renderingManager
+            this._renderingManager.reset();
+
+            var currentRenderList = this.renderList ? this.renderList : scene.getActiveMeshes().data;
+
+            for (var meshIndex = 0; meshIndex < currentRenderList.length; meshIndex++) {
+                var mesh = currentRenderList[meshIndex];
+
+                if (mesh) {
+                    if (!mesh.isReady()) {
+                        // Reset _currentRefreshId
+                        this.resetRefreshCounter();
+                        continue;
+                    }
+
+                    if (mesh.isEnabled() && mesh.isVisible && mesh.subMeshes && ((mesh.layerMask & scene.activeCamera.layerMask) !== 0)) {
+                        mesh._activate(scene.getRenderId());
+
+                        for (var subIndex = 0; subIndex < mesh.subMeshes.length; subIndex++) {
+                            var subMesh = mesh.subMeshes[subIndex];
+                            scene._activeIndices += subMesh.indexCount;
+                            this._renderingManager.dispatch(subMesh);
+                        }
+                    }
+                }
+            }
+            
+            if (this.isCube) {
+                for (var face = 0; face < 6; face++) {
+                    this.renderToTarget(face, currentRenderList, useCameraPostProcess, dumpForDebug);
+                }
+            } else {
+                this.renderToTarget(0, currentRenderList, useCameraPostProcess, dumpForDebug);
+            }
+
+            if (this.onAfterUnbind) {
+                this.onAfterUnbind();
+            }
+
+            scene.resetCachedMaterial();
+        }
+
+        renderToTarget(faceIndex: number, currentRenderList: AbstractMesh[], useCameraPostProcess: boolean, dumpForDebug: boolean): void {
+            var scene = this.getScene();
+            var engine = scene.getEngine();
+
+            // Bind
+            if (!useCameraPostProcess || !scene.postProcessManager._prepareFrame(this._texture)) {
+                if (this.isCube) {
+                    engine.bindFramebuffer(this._texture, faceIndex);
+                } else {
+                    engine.bindFramebuffer(this._texture);
+                }
+            }
+
+            if (this.onBeforeRender) {
+                this.onBeforeRender(faceIndex);
+            }
+
+            // Clear
+            if (this.onClear) {
+                this.onClear(engine);
+            } else {
+                engine.clear(scene.clearColor, true, true);
+            }
+
+            if (!this._doNotChangeAspectRatio) {
+                scene.updateTransformMatrix(true);
+            }
+
+            // Render
+            this._renderingManager.render(this.customRenderFunction, currentRenderList, this.renderParticles, this.renderSprites);
+
+            if (useCameraPostProcess) {
+                scene.postProcessManager._finalizeFrame(false, this._texture, faceIndex);
+            }
+
+            if (!this._doNotChangeAspectRatio) {
+                scene.updateTransformMatrix(true);
+            }
+
+            if (this.onAfterRender) {
+                this.onAfterRender(faceIndex);
+            }
+
+            // Dump ?
+            if (dumpForDebug) {
+                Tools.DumpFramebuffer(this._size, this._size, engine);
+            }
+
+            // Unbind
+            if (!this.isCube || faceIndex === 5) {
+                if (this.isCube) {
+
+                    if (faceIndex === 5) {
+                        engine.generateMipMapsForCubemap(this._texture);
+                    }
+                }
+
+                engine.unBindFramebuffer(this._texture, this.isCube);
+            }
+        }
+
+        public clone(): RenderTargetTexture {
+            var textureSize = this.getSize();
+            var newTexture = new RenderTargetTexture(this.name, textureSize.width, this.getScene(), this._generateMipMaps);
+
+            // Base texture
+            newTexture.hasAlpha = this.hasAlpha;
+            newTexture.level = this.level;
+
+            // RenderTarget Texture
+            newTexture.coordinatesMode = this.coordinatesMode;
+            newTexture.renderList = this.renderList.slice(0);
+
+            return newTexture;
+        }
+
+        public serialize(): any {
+            if (!this.name) {
+                return null;
+            }
+
+            var serializationObject = super.serialize();
+
+            serializationObject.renderTargetSize = this.getRenderSize();
+            serializationObject.renderList = [];
+
+            for (var index = 0; index < this.renderList.length; index++) {
+                serializationObject.renderList.push(this.renderList[index].id);
+            }
+
+            return serializationObject;
+        }
+    }
 } 

+ 57 - 57
src/Materials/Textures/babylon.videoTexture.ts

@@ -1,58 +1,58 @@
-module BABYLON {
-    export class VideoTexture extends Texture {
-        public video: HTMLVideoElement;
-
-        private _autoLaunch = true;
-        private _lastUpdate: number;
-
-        constructor(name: string, urls: string[], scene: Scene, generateMipMaps = false, invertY = false, samplingMode: number = Texture.TRILINEAR_SAMPLINGMODE) {
-            super(null, scene, !generateMipMaps, invertY);
-
-            this.name = name;
-
-            this.video = document.createElement("video");
-            this.video.autoplay = false;
-            this.video.loop = true;
-
-            this.video.addEventListener("canplaythrough", () => {
-                if (Tools.IsExponentOfTwo(this.video.videoWidth) && Tools.IsExponentOfTwo(this.video.videoHeight)) {
-                    this.wrapU = Texture.WRAP_ADDRESSMODE;
-                    this.wrapV = Texture.WRAP_ADDRESSMODE;
-                } else {
-                    this.wrapU = Texture.CLAMP_ADDRESSMODE;
-                    this.wrapV = Texture.CLAMP_ADDRESSMODE;
-                    generateMipMaps = false;
-                }
-
-                this._texture = scene.getEngine().createDynamicTexture(this.video.videoWidth, this.video.videoHeight, generateMipMaps, samplingMode, false);
-                this._texture.isReady = true;
-            });
-
-            urls.forEach(url => {
-                //Backwards-compatibility for typescript 1. from 1.3 it should say "SOURCE". see here - https://github.com/Microsoft/TypeScript/issues/1850
-                var source = <HTMLSourceElement> document.createElement("source");
-                source.src = url;
-                this.video.appendChild(source);
-            });
-
-            this._lastUpdate = Tools.Now;
-        }
-
-        public update(): boolean {
-            if (this._autoLaunch) {
-                this._autoLaunch = false;
-                this.video.play();
-            }
-
-            var now = Tools.Now;
-
-            if (now - this._lastUpdate < 15 || this.video.readyState !== this.video.HAVE_ENOUGH_DATA) {
-               return false;
-            }
-
-            this._lastUpdate = now;
-            this.getScene().getEngine().updateVideoTexture(this._texture, this.video, this._invertY);
-            return true;
-        }
-    }
+module BABYLON {
+    export class VideoTexture extends Texture {
+        public video: HTMLVideoElement;
+
+        private _autoLaunch = true;
+        private _lastUpdate: number;
+
+        constructor(name: string, urls: string[], scene: Scene, generateMipMaps = false, invertY = false, samplingMode: number = Texture.TRILINEAR_SAMPLINGMODE) {
+            super(null, scene, !generateMipMaps, invertY);
+
+            this.name = name;
+
+            this.video = document.createElement("video");
+            this.video.autoplay = false;
+            this.video.loop = true;
+
+            this.video.addEventListener("canplaythrough", () => {
+                if (Tools.IsExponentOfTwo(this.video.videoWidth) && Tools.IsExponentOfTwo(this.video.videoHeight)) {
+                    this.wrapU = Texture.WRAP_ADDRESSMODE;
+                    this.wrapV = Texture.WRAP_ADDRESSMODE;
+                } else {
+                    this.wrapU = Texture.CLAMP_ADDRESSMODE;
+                    this.wrapV = Texture.CLAMP_ADDRESSMODE;
+                    generateMipMaps = false;
+                }
+
+                this._texture = scene.getEngine().createDynamicTexture(this.video.videoWidth, this.video.videoHeight, generateMipMaps, samplingMode, false);
+                this._texture.isReady = true;
+            });
+
+            urls.forEach(url => {
+                //Backwards-compatibility for typescript 1. from 1.3 it should say "SOURCE". see here - https://github.com/Microsoft/TypeScript/issues/1850
+                var source = <HTMLSourceElement> document.createElement("source");
+                source.src = url;
+                this.video.appendChild(source);
+            });
+
+            this._lastUpdate = Tools.Now;
+        }
+
+        public update(): boolean {
+            if (this._autoLaunch) {
+                this._autoLaunch = false;
+                this.video.play();
+            }
+
+            var now = Tools.Now;
+
+            if (now - this._lastUpdate < 15 || this.video.readyState !== this.video.HAVE_ENOUGH_DATA) {
+               return false;
+            }
+
+            this._lastUpdate = now;
+            this.getScene().getEngine().updateVideoTexture(this._texture, this.video, this._invertY);
+            return true;
+        }
+    }
 } 

Разница между файлами не показана из-за своего большого размера
+ 510 - 510
src/Materials/babylon.effect.ts


+ 295 - 295
src/Materials/babylon.shaderMaterial.ts

@@ -1,296 +1,296 @@
-module BABYLON {
-    export class ShaderMaterial extends Material {
-        private _shaderPath: any;
-        private _options: any;
-        private _textures = new Array<Texture>();
-        private _floats = new Array<number>();
-        private _floatsArrays = {};
-        private _colors3 = new Array<Color3>();
-        private _colors4 = new Array<Color4>();
-        private _vectors2 = new Array<Vector2>();
-        private _vectors3 = new Array<Vector3>();
-        private _vectors4 = new Array<Vector4>();
-        private _matrices = new Array<Matrix>();
-        private _matrices3x3 = new Array<Float32Array>();
-        private _matrices2x2 = new Array<Float32Array>();
-        private _cachedWorldViewMatrix = new Matrix();
-        private _renderId: number;
-
-        constructor(name: string, scene: Scene, shaderPath: any, options: any) {
-            super(name, scene);
-            this._shaderPath = shaderPath;
-
-            options.needAlphaBlending = options.needAlphaBlending || false;
-            options.needAlphaTesting = options.needAlphaTesting || false;
-            options.attributes = options.attributes || ["position", "normal", "uv"];
-            options.uniforms = options.uniforms || ["worldViewProjection"];
-            options.samplers = options.samplers || [];
-            options.defines = options.defines || [];
-
-            this._options = options;
-        }
-
-        public needAlphaBlending(): boolean {
-            return this._options.needAlphaBlending;
-        }
-
-        public needAlphaTesting(): boolean {
-            return this._options.needAlphaTesting;
-        }
-
-        private _checkUniform(uniformName): void {
-            if (this._options.uniforms.indexOf(uniformName) === -1) {
-                this._options.uniforms.push(uniformName);
-            }
-        }
-
-        public setTexture(name: string, texture: Texture): ShaderMaterial {
-            if (this._options.samplers.indexOf(name) === -1) {
-                this._options.samplers.push(name);
-            }
-            this._textures[name] = texture;
-
-            return this;
-        }
-
-        public setFloat(name: string, value: number): ShaderMaterial {
-            this._checkUniform(name);
-            this._floats[name] = value;
-
-            return this;
-        }
-
-        public setFloats(name: string, value: number[]): ShaderMaterial {
-            this._checkUniform(name);
-            this._floatsArrays[name] = value;
-
-            return this;
-        }
-
-        public setColor3(name: string, value: Color3): ShaderMaterial {
-            this._checkUniform(name);
-            this._colors3[name] = value;
-
-            return this;
-        }
-
-        public setColor4(name: string, value: Color4): ShaderMaterial {
-            this._checkUniform(name);
-            this._colors4[name] = value;
-
-            return this;
-        }
-
-        public setVector2(name: string, value: Vector2): ShaderMaterial {
-            this._checkUniform(name);
-            this._vectors2[name] = value;
-
-            return this;
-        }
-
-        public setVector3(name: string, value: Vector3): ShaderMaterial {
-            this._checkUniform(name);
-            this._vectors3[name] = value;
-
-            return this;
-        }
-
-        public setVector4(name: string, value: Vector4): ShaderMaterial {
-            this._checkUniform(name);
-            this._vectors4[name] = value;
-
-            return this;
-        }
-
-        public setMatrix(name: string, value: Matrix): ShaderMaterial {
-            this._checkUniform(name);
-            this._matrices[name] = value;
-
-            return this;
-        }
-
-        public setMatrix3x3(name: string, value: Float32Array): ShaderMaterial {
-            this._checkUniform(name);
-            this._matrices3x3[name] = value;
-
-            return this;
-        }
-
-        public setMatrix2x2(name: string, value: Float32Array): ShaderMaterial {
-            this._checkUniform(name);
-            this._matrices2x2[name] = value;
-
-            return this;
-        }
-
-        public isReady(mesh?: AbstractMesh, useInstances?: boolean): boolean {
-            var scene = this.getScene();
-            var engine = scene.getEngine();
-
-            if (!this.checkReadyOnEveryCall) {
-                if (this._renderId === scene.getRenderId()) {
-                    return true;
-                }
-            }
-
-            // Instances
-            var defines = [];
-            var fallbacks = new EffectFallbacks();
-            if (useInstances) {
-                defines.push("#define INSTANCES");
-            }
-
-            for (var index = 0; index < this._options.defines.length; index++) {
-                defines.push(this._options.defines[index]);
-            }
-
-            // Bones
-            if (mesh && mesh.useBones && mesh.computeBonesUsingShaders) {
-                defines.push("#define NUM_BONE_INFLUENCERS " + mesh.numBoneInfluencers);
-                defines.push("#define BonesPerMesh " + (mesh.skeleton.bones.length + 1));
-                fallbacks.addCPUSkinningFallback(0, mesh);
-            }
-
-            // Alpha test
-            if (engine.getAlphaTesting()) {
-                defines.push("#define ALPHATEST");
-            }
-
-            var previousEffect = this._effect;
-            var join = defines.join("\n");
-
-            this._effect = engine.createEffect(this._shaderPath,
-                this._options.attributes,
-                this._options.uniforms,
-                this._options.samplers,
-                join, fallbacks, this.onCompiled, this.onError);
-
-            if (!this._effect.isReady()) {
-                return false;
-            }
-
-            if (previousEffect !== this._effect) {
-                scene.resetCachedMaterial();
-            }
-
-            this._renderId = scene.getRenderId();
-
-            return true;
-        }
-
-        public bindOnlyWorldMatrix(world: Matrix): void {
-            var scene = this.getScene();
-
-            if (this._options.uniforms.indexOf("world") !== -1) {
-                this._effect.setMatrix("world", world);
-            }
-
-            if (this._options.uniforms.indexOf("worldView") !== -1) {
-                world.multiplyToRef(scene.getViewMatrix(), this._cachedWorldViewMatrix);
-                this._effect.setMatrix("worldView", this._cachedWorldViewMatrix);
-            }
-
-            if (this._options.uniforms.indexOf("worldViewProjection") !== -1) {
-                this._effect.setMatrix("worldViewProjection", world.multiply(scene.getTransformMatrix()));
-            }
-        }
-
-        public bind(world: Matrix, mesh?: Mesh): void {
-            // Std values
-            this.bindOnlyWorldMatrix(world);
-
-            if (this.getScene().getCachedMaterial() !== this) {
-                if (this._options.uniforms.indexOf("view") !== -1) {
-                    this._effect.setMatrix("view", this.getScene().getViewMatrix());
-                }
-
-                if (this._options.uniforms.indexOf("projection") !== -1) {
-                    this._effect.setMatrix("projection", this.getScene().getProjectionMatrix());
-                }
-
-                if (this._options.uniforms.indexOf("viewProjection") !== -1) {
-                    this._effect.setMatrix("viewProjection", this.getScene().getTransformMatrix());
-                }
-
-                // Bones
-                if (mesh && mesh.useBones && mesh.computeBonesUsingShaders) {
-                    this._effect.setMatrices("mBones", mesh.skeleton.getTransformMatrices());
-                }
-
-                // Texture
-                for (var name in this._textures) {
-                    this._effect.setTexture(name, this._textures[name]);
-                }
-
-                // Float    
-                for (name in this._floats) {
-                    this._effect.setFloat(name, this._floats[name]);
-                }
-
-                // Float s   
-                for (name in this._floatsArrays) {
-                    this._effect.setArray(name, this._floatsArrays[name]);
-                }
-
-                // Color3        
-                for (name in this._colors3) {
-                    this._effect.setColor3(name, this._colors3[name]);
-                }
-
-                // Color4      
-                for (name in this._colors4) {
-                    var color = this._colors4[name];
-                    this._effect.setFloat4(name, color.r, color.g, color.b, color.a);
-                }
-
-                // Vector2        
-                for (name in this._vectors2) {
-                    this._effect.setVector2(name, this._vectors2[name]);
-                }
-
-                // Vector3        
-                for (name in this._vectors3) {
-                    this._effect.setVector3(name, this._vectors3[name]);
-                }
-
-                // Vector4        
-                for (name in this._vectors4) {
-                    this._effect.setVector4(name, this._vectors4[name]);
-                }
-
-                // Matrix      
-                for (name in this._matrices) {
-                    this._effect.setMatrix(name, this._matrices[name]);
-                }
-
-                // Matrix 3x3
-                for (name in this._matrices3x3) {
-                    this._effect.setMatrix3x3(name, this._matrices3x3[name]);
-                }
-
-                // Matrix 2x2
-                for (name in this._matrices2x2) {
-                    this._effect.setMatrix2x2(name, this._matrices2x2[name]);
-                }
-            }
-
-            super.bind(world, mesh);
-        }
-
-        public clone(name: string): ShaderMaterial {
-            var newShaderMaterial = new ShaderMaterial(name, this.getScene(), this._shaderPath, this._options);
-
-            return newShaderMaterial;
-        }        
-
-        public dispose(forceDisposeEffect?: boolean): void {
-            for (var name in this._textures) {
-                this._textures[name].dispose();
-            }
-
-            this._textures = [];
-
-            super.dispose(forceDisposeEffect);
-        }
-    }
+module BABYLON {
+    export class ShaderMaterial extends Material {
+        private _shaderPath: any;
+        private _options: any;
+        private _textures = new Array<Texture>();
+        private _floats = new Array<number>();
+        private _floatsArrays = {};
+        private _colors3 = new Array<Color3>();
+        private _colors4 = new Array<Color4>();
+        private _vectors2 = new Array<Vector2>();
+        private _vectors3 = new Array<Vector3>();
+        private _vectors4 = new Array<Vector4>();
+        private _matrices = new Array<Matrix>();
+        private _matrices3x3 = new Array<Float32Array>();
+        private _matrices2x2 = new Array<Float32Array>();
+        private _cachedWorldViewMatrix = new Matrix();
+        private _renderId: number;
+
+        constructor(name: string, scene: Scene, shaderPath: any, options: any) {
+            super(name, scene);
+            this._shaderPath = shaderPath;
+
+            options.needAlphaBlending = options.needAlphaBlending || false;
+            options.needAlphaTesting = options.needAlphaTesting || false;
+            options.attributes = options.attributes || ["position", "normal", "uv"];
+            options.uniforms = options.uniforms || ["worldViewProjection"];
+            options.samplers = options.samplers || [];
+            options.defines = options.defines || [];
+
+            this._options = options;
+        }
+
+        public needAlphaBlending(): boolean {
+            return this._options.needAlphaBlending;
+        }
+
+        public needAlphaTesting(): boolean {
+            return this._options.needAlphaTesting;
+        }
+
+        private _checkUniform(uniformName): void {
+            if (this._options.uniforms.indexOf(uniformName) === -1) {
+                this._options.uniforms.push(uniformName);
+            }
+        }
+
+        public setTexture(name: string, texture: Texture): ShaderMaterial {
+            if (this._options.samplers.indexOf(name) === -1) {
+                this._options.samplers.push(name);
+            }
+            this._textures[name] = texture;
+
+            return this;
+        }
+
+        public setFloat(name: string, value: number): ShaderMaterial {
+            this._checkUniform(name);
+            this._floats[name] = value;
+
+            return this;
+        }
+
+        public setFloats(name: string, value: number[]): ShaderMaterial {
+            this._checkUniform(name);
+            this._floatsArrays[name] = value;
+
+            return this;
+        }
+
+        public setColor3(name: string, value: Color3): ShaderMaterial {
+            this._checkUniform(name);
+            this._colors3[name] = value;
+
+            return this;
+        }
+
+        public setColor4(name: string, value: Color4): ShaderMaterial {
+            this._checkUniform(name);
+            this._colors4[name] = value;
+
+            return this;
+        }
+
+        public setVector2(name: string, value: Vector2): ShaderMaterial {
+            this._checkUniform(name);
+            this._vectors2[name] = value;
+
+            return this;
+        }
+
+        public setVector3(name: string, value: Vector3): ShaderMaterial {
+            this._checkUniform(name);
+            this._vectors3[name] = value;
+
+            return this;
+        }
+
+        public setVector4(name: string, value: Vector4): ShaderMaterial {
+            this._checkUniform(name);
+            this._vectors4[name] = value;
+
+            return this;
+        }
+
+        public setMatrix(name: string, value: Matrix): ShaderMaterial {
+            this._checkUniform(name);
+            this._matrices[name] = value;
+
+            return this;
+        }
+
+        public setMatrix3x3(name: string, value: Float32Array): ShaderMaterial {
+            this._checkUniform(name);
+            this._matrices3x3[name] = value;
+
+            return this;
+        }
+
+        public setMatrix2x2(name: string, value: Float32Array): ShaderMaterial {
+            this._checkUniform(name);
+            this._matrices2x2[name] = value;
+
+            return this;
+        }
+
+        public isReady(mesh?: AbstractMesh, useInstances?: boolean): boolean {
+            var scene = this.getScene();
+            var engine = scene.getEngine();
+
+            if (!this.checkReadyOnEveryCall) {
+                if (this._renderId === scene.getRenderId()) {
+                    return true;
+                }
+            }
+
+            // Instances
+            var defines = [];
+            var fallbacks = new EffectFallbacks();
+            if (useInstances) {
+                defines.push("#define INSTANCES");
+            }
+
+            for (var index = 0; index < this._options.defines.length; index++) {
+                defines.push(this._options.defines[index]);
+            }
+
+            // Bones
+            if (mesh && mesh.useBones && mesh.computeBonesUsingShaders) {
+                defines.push("#define NUM_BONE_INFLUENCERS " + mesh.numBoneInfluencers);
+                defines.push("#define BonesPerMesh " + (mesh.skeleton.bones.length + 1));
+                fallbacks.addCPUSkinningFallback(0, mesh);
+            }
+
+            // Alpha test
+            if (engine.getAlphaTesting()) {
+                defines.push("#define ALPHATEST");
+            }
+
+            var previousEffect = this._effect;
+            var join = defines.join("\n");
+
+            this._effect = engine.createEffect(this._shaderPath,
+                this._options.attributes,
+                this._options.uniforms,
+                this._options.samplers,
+                join, fallbacks, this.onCompiled, this.onError);
+
+            if (!this._effect.isReady()) {
+                return false;
+            }
+
+            if (previousEffect !== this._effect) {
+                scene.resetCachedMaterial();
+            }
+
+            this._renderId = scene.getRenderId();
+
+            return true;
+        }
+
+        public bindOnlyWorldMatrix(world: Matrix): void {
+            var scene = this.getScene();
+
+            if (this._options.uniforms.indexOf("world") !== -1) {
+                this._effect.setMatrix("world", world);
+            }
+
+            if (this._options.uniforms.indexOf("worldView") !== -1) {
+                world.multiplyToRef(scene.getViewMatrix(), this._cachedWorldViewMatrix);
+                this._effect.setMatrix("worldView", this._cachedWorldViewMatrix);
+            }
+
+            if (this._options.uniforms.indexOf("worldViewProjection") !== -1) {
+                this._effect.setMatrix("worldViewProjection", world.multiply(scene.getTransformMatrix()));
+            }
+        }
+
+        public bind(world: Matrix, mesh?: Mesh): void {
+            // Std values
+            this.bindOnlyWorldMatrix(world);
+
+            if (this.getScene().getCachedMaterial() !== this) {
+                if (this._options.uniforms.indexOf("view") !== -1) {
+                    this._effect.setMatrix("view", this.getScene().getViewMatrix());
+                }
+
+                if (this._options.uniforms.indexOf("projection") !== -1) {
+                    this._effect.setMatrix("projection", this.getScene().getProjectionMatrix());
+                }
+
+                if (this._options.uniforms.indexOf("viewProjection") !== -1) {
+                    this._effect.setMatrix("viewProjection", this.getScene().getTransformMatrix());
+                }
+
+                // Bones
+                if (mesh && mesh.useBones && mesh.computeBonesUsingShaders) {
+                    this._effect.setMatrices("mBones", mesh.skeleton.getTransformMatrices());
+                }
+
+                // Texture
+                for (var name in this._textures) {
+                    this._effect.setTexture(name, this._textures[name]);
+                }
+
+                // Float    
+                for (name in this._floats) {
+                    this._effect.setFloat(name, this._floats[name]);
+                }
+
+                // Float s   
+                for (name in this._floatsArrays) {
+                    this._effect.setArray(name, this._floatsArrays[name]);
+                }
+
+                // Color3        
+                for (name in this._colors3) {
+                    this._effect.setColor3(name, this._colors3[name]);
+                }
+
+                // Color4      
+                for (name in this._colors4) {
+                    var color = this._colors4[name];
+                    this._effect.setFloat4(name, color.r, color.g, color.b, color.a);
+                }
+
+                // Vector2        
+                for (name in this._vectors2) {
+                    this._effect.setVector2(name, this._vectors2[name]);
+                }
+
+                // Vector3        
+                for (name in this._vectors3) {
+                    this._effect.setVector3(name, this._vectors3[name]);
+                }
+
+                // Vector4        
+                for (name in this._vectors4) {
+                    this._effect.setVector4(name, this._vectors4[name]);
+                }
+
+                // Matrix      
+                for (name in this._matrices) {
+                    this._effect.setMatrix(name, this._matrices[name]);
+                }
+
+                // Matrix 3x3
+                for (name in this._matrices3x3) {
+                    this._effect.setMatrix3x3(name, this._matrices3x3[name]);
+                }
+
+                // Matrix 2x2
+                for (name in this._matrices2x2) {
+                    this._effect.setMatrix2x2(name, this._matrices2x2[name]);
+                }
+            }
+
+            super.bind(world, mesh);
+        }
+
+        public clone(name: string): ShaderMaterial {
+            var newShaderMaterial = new ShaderMaterial(name, this.getScene(), this._shaderPath, this._options);
+
+            return newShaderMaterial;
+        }        
+
+        public dispose(forceDisposeEffect?: boolean): void {
+            for (var name in this._textures) {
+                this._textures[name].dispose();
+            }
+
+            this._textures = [];
+
+            super.dispose(forceDisposeEffect);
+        }
+    }
 } 

+ 321 - 321
src/Math/babylon.math.SIMD.ts

@@ -1,321 +1,321 @@
-module BABYLON {
-
-    declare var SIMD;
-
-    export class SIMDVector3 {
-        public static TransformCoordinatesToRefSIMD(vector: Vector3, transformation: Matrix, result: Vector3): void {
-            var v = SIMD.float32x4.loadXYZ((<any>vector)._data, 0);
-            var m0 = SIMD.float32x4.load(transformation.m, 0);
-            var m1 = SIMD.float32x4.load(transformation.m, 4);
-            var m2 = SIMD.float32x4.load(transformation.m, 8);
-            var m3 = SIMD.float32x4.load(transformation.m, 12);
-            var r = SIMD.float32x4.add(SIMD.float32x4.add(SIMD.float32x4.mul(SIMD.float32x4.swizzle(v, 0, 0, 0, 0), m0), SIMD.float32x4.mul(SIMD.float32x4.swizzle(v, 1, 1, 1, 1), m1)), SIMD.float32x4.add(SIMD.float32x4.mul(SIMD.float32x4.swizzle(v, 2, 2, 2, 2), m2), m3));
-            r = SIMD.float32x4.div(r, SIMD.float32x4.swizzle(r, 3, 3, 3, 3));
-            SIMD.float32x4.storeXYZ((<any>result)._data, 0, r);
-        }
-
-        public static TransformCoordinatesFromFloatsToRefSIMD(x: number, y: number, z: number, transformation: Matrix, result: Vector3): void {
-            var v0 = SIMD.float32x4.splat(x);
-            var v1 = SIMD.float32x4.splat(y);
-            var v2 = SIMD.float32x4.splat(z);
-            var m0 = SIMD.float32x4.load(transformation.m, 0);
-            var m1 = SIMD.float32x4.load(transformation.m, 4);
-            var m2 = SIMD.float32x4.load(transformation.m, 8);
-            var m3 = SIMD.float32x4.load(transformation.m, 12);
-            var r = SIMD.float32x4.add(SIMD.float32x4.add(SIMD.float32x4.mul(v0, m0), SIMD.float32x4.mul(v1, m1)), SIMD.float32x4.add(SIMD.float32x4.mul(v2, m2), m3));
-            r = SIMD.float32x4.div(r, SIMD.float32x4.swizzle(r, 3, 3, 3, 3));
-            SIMD.float32x4.storeXYZ((<any>result)._data, 0, r);
-        }
-    }
-
-    export class SIMDMatrix {
-        public multiplyToArraySIMD(other: Matrix, result: Matrix, offset = 0): void {
-            var tm = (<any>this).m;
-            var om = other.m;
-            var om0 = SIMD.float32x4.load(om, 0);
-            var om1 = SIMD.float32x4.load(om, 4);
-            var om2 = SIMD.float32x4.load(om, 8);
-            var om3 = SIMD.float32x4.load(om, 12);
-
-            var tm0 = SIMD.float32x4.load(tm, 0);
-            SIMD.float32x4.store(result, offset + 0, SIMD.float32x4.add(
-                SIMD.float32x4.mul(SIMD.float32x4.swizzle(tm0, 0, 0, 0, 0), om0),
-                SIMD.float32x4.add(
-                    SIMD.float32x4.mul(SIMD.float32x4.swizzle(tm0, 1, 1, 1, 1), om1),
-                    SIMD.float32x4.add(
-                        SIMD.float32x4.mul(SIMD.float32x4.swizzle(tm0, 2, 2, 2, 2), om2),
-                        SIMD.float32x4.mul(SIMD.float32x4.swizzle(tm0, 3, 3, 3, 3), om3)))));
-
-            var tm1 = SIMD.float32x4.load(tm, 4);
-            SIMD.float32x4.store(result, offset + 4, SIMD.float32x4.add(
-                SIMD.float32x4.mul(SIMD.float32x4.swizzle(tm1, 0, 0, 0, 0), om0),
-                SIMD.float32x4.add(
-                    SIMD.float32x4.mul(SIMD.float32x4.swizzle(tm1, 1, 1, 1, 1), om1),
-                    SIMD.float32x4.add(
-                        SIMD.float32x4.mul(SIMD.float32x4.swizzle(tm1, 2, 2, 2, 2), om2),
-                        SIMD.float32x4.mul(SIMD.float32x4.swizzle(tm1, 3, 3, 3, 3), om3)))));
-
-            var tm2 = SIMD.float32x4.load(tm, 8);
-            SIMD.float32x4.store(result, offset + 8, SIMD.float32x4.add(
-                SIMD.float32x4.mul(SIMD.float32x4.swizzle(tm2, 0, 0, 0, 0), om0),
-                SIMD.float32x4.add(
-                    SIMD.float32x4.mul(SIMD.float32x4.swizzle(tm2, 1, 1, 1, 1), om1),
-                    SIMD.float32x4.add(
-                        SIMD.float32x4.mul(SIMD.float32x4.swizzle(tm2, 2, 2, 2, 2), om2),
-                        SIMD.float32x4.mul(SIMD.float32x4.swizzle(tm2, 3, 3, 3, 3), om3)))));
-
-            var tm3 = SIMD.float32x4.load(tm, 12);
-            SIMD.float32x4.store(result, offset + 12, SIMD.float32x4.add(
-                SIMD.float32x4.mul(SIMD.float32x4.swizzle(tm3, 0, 0, 0, 0), om0),
-                SIMD.float32x4.add(
-                    SIMD.float32x4.mul(SIMD.float32x4.swizzle(tm3, 1, 1, 1, 1), om1),
-                    SIMD.float32x4.add(
-                        SIMD.float32x4.mul(SIMD.float32x4.swizzle(tm3, 2, 2, 2, 2), om2),
-                        SIMD.float32x4.mul(SIMD.float32x4.swizzle(tm3, 3, 3, 3, 3), om3)))));
-        }
-
-        public invertToRefSIMD(other: Matrix): Matrix {
-            var src = (<any>this).m;
-            var dest = other.m;
-            var row0, row1, row2, row3;
-            var tmp1;
-            var minor0, minor1, minor2, minor3;
-            var det;
-
-            // Load the 4 rows
-            var src0 = SIMD.float32x4.load(src, 0);
-            var src1 = SIMD.float32x4.load(src, 4);
-            var src2 = SIMD.float32x4.load(src, 8);
-            var src3 = SIMD.float32x4.load(src, 12);
-
-            // Transpose the source matrix.  Sort of.  Not a true transpose operation
-
-            tmp1 = SIMD.float32x4.shuffle(src0, src1, 0, 1, 4, 5);
-            row1 = SIMD.float32x4.shuffle(src2, src3, 0, 1, 4, 5);
-            row0 = SIMD.float32x4.shuffle(tmp1, row1, 0, 2, 4, 6);
-            row1 = SIMD.float32x4.shuffle(row1, tmp1, 1, 3, 5, 7);
-
-            tmp1 = SIMD.float32x4.shuffle(src0, src1, 2, 3, 6, 7);
-            row3 = SIMD.float32x4.shuffle(src2, src3, 2, 3, 6, 7);
-            row2 = SIMD.float32x4.shuffle(tmp1, row3, 0, 2, 4, 6);
-            row3 = SIMD.float32x4.shuffle(row3, tmp1, 1, 3, 5, 7);
-
-            // This is a true transposition, but it will lead to an incorrect result
-
-            //tmp1 = SIMD.float32x4.shuffle(src0, src1, 0, 1, 4, 5);
-            //tmp2 = SIMD.float32x4.shuffle(src2, src3, 0, 1, 4, 5);
-            //row0  = SIMD.float32x4.shuffle(tmp1, tmp2, 0, 2, 4, 6);
-            //row1  = SIMD.float32x4.shuffle(tmp1, tmp2, 1, 3, 5, 7);
-
-            //tmp1 = SIMD.float32x4.shuffle(src0, src1, 2, 3, 6, 7);
-            //tmp2 = SIMD.float32x4.shuffle(src2, src3, 2, 3, 6, 7);
-            //row2  = SIMD.float32x4.shuffle(tmp1, tmp2, 0, 2, 4, 6);
-            //row3  = SIMD.float32x4.shuffle(tmp1, tmp2, 1, 3, 5, 7);
-
-            // ----
-            tmp1 = SIMD.float32x4.mul(row2, row3);
-            tmp1 = SIMD.float32x4.swizzle(tmp1, 1, 0, 3, 2); // 0xB1 = 10110001
-            minor0 = SIMD.float32x4.mul(row1, tmp1);
-            minor1 = SIMD.float32x4.mul(row0, tmp1);
-            tmp1 = SIMD.float32x4.swizzle(tmp1, 2, 3, 0, 1); // 0x4E = 01001110
-            minor0 = SIMD.float32x4.sub(SIMD.float32x4.mul(row1, tmp1), minor0);
-            minor1 = SIMD.float32x4.sub(SIMD.float32x4.mul(row0, tmp1), minor1);
-            minor1 = SIMD.float32x4.swizzle(minor1, 2, 3, 0, 1); // 0x4E = 01001110
-
-            // ----
-            tmp1 = SIMD.float32x4.mul(row1, row2);
-            tmp1 = SIMD.float32x4.swizzle(tmp1, 1, 0, 3, 2); // 0xB1 = 10110001
-            minor0 = SIMD.float32x4.add(SIMD.float32x4.mul(row3, tmp1), minor0);
-            minor3 = SIMD.float32x4.mul(row0, tmp1);
-            tmp1 = SIMD.float32x4.swizzle(tmp1, 2, 3, 0, 1); // 0x4E = 01001110
-            minor0 = SIMD.float32x4.sub(minor0, SIMD.float32x4.mul(row3, tmp1));
-            minor3 = SIMD.float32x4.sub(SIMD.float32x4.mul(row0, tmp1), minor3);
-            minor3 = SIMD.float32x4.swizzle(minor3, 2, 3, 0, 1); // 0x4E = 01001110
-
-            // ----
-            tmp1 = SIMD.float32x4.mul(SIMD.float32x4.swizzle(row1, 2, 3, 0, 1), row3); // 0x4E = 01001110
-            tmp1 = SIMD.float32x4.swizzle(tmp1, 1, 0, 3, 2); // 0xB1 = 10110001
-            row2 = SIMD.float32x4.swizzle(row2, 2, 3, 0, 1);  // 0x4E = 01001110
-            minor0 = SIMD.float32x4.add(SIMD.float32x4.mul(row2, tmp1), minor0);
-            minor2 = SIMD.float32x4.mul(row0, tmp1);
-            tmp1 = SIMD.float32x4.swizzle(tmp1, 2, 3, 0, 1); // 0x4E = 01001110
-            minor0 = SIMD.float32x4.sub(minor0, SIMD.float32x4.mul(row2, tmp1));
-            minor2 = SIMD.float32x4.sub(SIMD.float32x4.mul(row0, tmp1), minor2);
-            minor2 = SIMD.float32x4.swizzle(minor2, 2, 3, 0, 1); // 0x4E = 01001110
-
-            // ----
-            tmp1 = SIMD.float32x4.mul(row0, row1);
-            tmp1 = SIMD.float32x4.swizzle(tmp1, 1, 0, 3, 2); // 0xB1 = 10110001
-            minor2 = SIMD.float32x4.add(SIMD.float32x4.mul(row3, tmp1), minor2);
-            minor3 = SIMD.float32x4.sub(SIMD.float32x4.mul(row2, tmp1), minor3);
-            tmp1 = SIMD.float32x4.swizzle(tmp1, 2, 3, 0, 1); // 0x4E = 01001110
-            minor2 = SIMD.float32x4.sub(SIMD.float32x4.mul(row3, tmp1), minor2);
-            minor3 = SIMD.float32x4.sub(minor3, SIMD.float32x4.mul(row2, tmp1));
-
-            // ----
-            tmp1 = SIMD.float32x4.mul(row0, row3);
-            tmp1 = SIMD.float32x4.swizzle(tmp1, 1, 0, 3, 2); // 0xB1 = 10110001
-            minor1 = SIMD.float32x4.sub(minor1, SIMD.float32x4.mul(row2, tmp1));
-            minor2 = SIMD.float32x4.add(SIMD.float32x4.mul(row1, tmp1), minor2);
-            tmp1 = SIMD.float32x4.swizzle(tmp1, 2, 3, 0, 1); // 0x4E = 01001110
-            minor1 = SIMD.float32x4.add(SIMD.float32x4.mul(row2, tmp1), minor1);
-            minor2 = SIMD.float32x4.sub(minor2, SIMD.float32x4.mul(row1, tmp1));
-
-            // ----
-            tmp1 = SIMD.float32x4.mul(row0, row2);
-            tmp1 = SIMD.float32x4.swizzle(tmp1, 1, 0, 3, 2); // 0xB1 = 10110001
-            minor1 = SIMD.float32x4.add(SIMD.float32x4.mul(row3, tmp1), minor1);
-            minor3 = SIMD.float32x4.sub(minor3, SIMD.float32x4.mul(row1, tmp1));
-            tmp1 = SIMD.float32x4.swizzle(tmp1, 2, 3, 0, 1); // 0x4E = 01001110
-            minor1 = SIMD.float32x4.sub(minor1, SIMD.float32x4.mul(row3, tmp1));
-            minor3 = SIMD.float32x4.add(SIMD.float32x4.mul(row1, tmp1), minor3);
-
-            // Compute determinant
-            det = SIMD.float32x4.mul(row0, minor0);
-            det = SIMD.float32x4.add(SIMD.float32x4.swizzle(det, 2, 3, 0, 1), det); // 0x4E = 01001110
-            det = SIMD.float32x4.add(SIMD.float32x4.swizzle(det, 1, 0, 3, 2), det); // 0xB1 = 10110001
-            tmp1 = SIMD.float32x4.reciprocalApproximation(det);
-            det = SIMD.float32x4.sub(SIMD.float32x4.add(tmp1, tmp1), SIMD.float32x4.mul(det, SIMD.float32x4.mul(tmp1, tmp1)));
-            det = SIMD.float32x4.swizzle(det, 0, 0, 0, 0);
-
-            // These shuffles aren't necessary if the faulty transposition is done
-            // up at the top of this function.
-            //minor0 = SIMD.float32x4.swizzle(minor0, 2, 1, 0, 3);
-            //minor1 = SIMD.float32x4.swizzle(minor1, 2, 1, 0, 3);
-            //minor2 = SIMD.float32x4.swizzle(minor2, 2, 1, 0, 3);
-            //minor3 = SIMD.float32x4.swizzle(minor3, 2, 1, 0, 3);
-
-            // Compute final values by multiplying with 1/det
-            minor0 = SIMD.float32x4.mul(det, minor0);
-            minor1 = SIMD.float32x4.mul(det, minor1);
-            minor2 = SIMD.float32x4.mul(det, minor2);
-            minor3 = SIMD.float32x4.mul(det, minor3);
-
-            SIMD.float32x4.store(dest, 0, minor0);
-            SIMD.float32x4.store(dest, 4, minor1);
-            SIMD.float32x4.store(dest, 8, minor2);
-            SIMD.float32x4.store(dest, 12, minor3);
-
-            return (<any>this);
-        }
-
-        public static LookAtLHToRefSIMD(eyeRef: Vector3, targetRef: Vector3, upRef: Vector3, result: Matrix): void {
-            var out = result.m;
-            var center = SIMD.float32x4(targetRef.x, targetRef.y, targetRef.z, 0);
-            var eye = SIMD.float32x4(eyeRef.x, eyeRef.y, eyeRef.z, 0);
-            var up = SIMD.float32x4(upRef.x, upRef.y, upRef.z, 0);
-
-            // cc.kmVec3Subtract(f, pCenter, pEye);
-            var f = SIMD.float32x4.sub(center, eye);
-            // cc.kmVec3Normalize(f, f);    
-            var tmp = SIMD.float32x4.mul(f, f);
-            tmp = SIMD.float32x4.add(tmp, SIMD.float32x4.add(SIMD.float32x4.swizzle(tmp, 1, 2, 0, 3), SIMD.float32x4.swizzle(tmp, 2, 0, 1, 3)));
-            f = SIMD.float32x4.mul(f, SIMD.float32x4.reciprocalSqrtApproximation(tmp));
-
-            // cc.kmVec3Assign(up, pUp);
-            // cc.kmVec3Normalize(up, up);
-            tmp = SIMD.float32x4.mul(up, up);
-            tmp = SIMD.float32x4.add(tmp, SIMD.float32x4.add(SIMD.float32x4.swizzle(tmp, 1, 2, 0, 3), SIMD.float32x4.swizzle(tmp, 2, 0, 1, 3)));
-            up = SIMD.float32x4.mul(up, SIMD.float32x4.reciprocalSqrtApproximation(tmp));
-            // cc.kmVec3Cross(s, f, up);
-            var s = SIMD.float32x4.sub(SIMD.float32x4.mul(SIMD.float32x4.swizzle(f, 1, 2, 0, 3), SIMD.float32x4.swizzle(up, 2, 0, 1, 3)), SIMD.float32x4.mul(SIMD.float32x4.swizzle(f, 2, 0, 1, 3), SIMD.float32x4.swizzle(up, 1, 2, 0, 3)));
-            // cc.kmVec3Normalize(s, s);
-            tmp = SIMD.float32x4.mul(s, s);
-            tmp = SIMD.float32x4.add(tmp, SIMD.float32x4.add(SIMD.float32x4.swizzle(tmp, 1, 2, 0, 3), SIMD.float32x4.swizzle(tmp, 2, 0, 1, 3)));
-            s = SIMD.float32x4.mul(s, SIMD.float32x4.reciprocalSqrtApproximation(tmp));
-            // cc.kmVec3Cross(u, s, f);
-            var u = SIMD.float32x4.sub(SIMD.float32x4.mul(SIMD.float32x4.swizzle(s, 1, 2, 0, 3), SIMD.float32x4.swizzle(f, 2, 0, 1, 3)), SIMD.float32x4.mul(SIMD.float32x4.swizzle(s, 2, 0, 1, 3), SIMD.float32x4.swizzle(f, 1, 2, 0, 3)));
-            // cc.kmVec3Normalize(s, s);
-            tmp = SIMD.float32x4.mul(s, s);
-            tmp = SIMD.float32x4.add(tmp, SIMD.float32x4.add(SIMD.float32x4.swizzle(tmp, 1, 2, 0, 3), SIMD.float32x4.swizzle(tmp, 2, 0, 1, 3)));
-            s = SIMD.float32x4.mul(s, SIMD.float32x4.reciprocalSqrtApproximation(tmp));
-
-            var zero = SIMD.float32x4.splat(0.0);
-            s = SIMD.float32x4.neg(s);
-            var tmp01 = SIMD.float32x4.shuffle(s, u, 0, 1, 4, 5);
-            var tmp23 = SIMD.float32x4.shuffle(f, zero, 0, 1, 4, 5);
-            var a0 = SIMD.float32x4.shuffle(tmp01, tmp23, 0, 2, 4, 6);
-            var a1 = SIMD.float32x4.shuffle(tmp01, tmp23, 1, 3, 5, 7);
-            tmp01 = SIMD.float32x4.shuffle(s, u, 2, 3, 6, 7);
-            tmp23 = SIMD.float32x4.shuffle(f, zero, 2, 3, 6, 7);
-            var a2 = SIMD.float32x4.shuffle(tmp01, tmp23, 0, 2, 4, 6);
-            var a3 = SIMD.float32x4(0.0, 0.0, 0.0, 1.0);
-            var b0 = SIMD.float32x4(1.0, 0.0, 0.0, 0.0);
-            var b1 = SIMD.float32x4(0.0, 1.0, 0.0, 0.0);
-            var b2 = SIMD.float32x4(0.0, 0.0, 1.0, 0.0);
-            var b3 = SIMD.float32x4.neg(eye);
-            b3 = SIMD.float32x4.withW(b3, 1.0);
-
-            SIMD.float32x4.store(out, 0, SIMD.float32x4.add(SIMD.float32x4.mul(SIMD.float32x4.swizzle(b0, 0, 0, 0, 0), a0), SIMD.float32x4.add(SIMD.float32x4.mul(SIMD.float32x4.swizzle(b0, 1, 1, 1, 1), a1), SIMD.float32x4.add(SIMD.float32x4.mul(SIMD.float32x4.swizzle(b0, 2, 2, 2, 2), a2), SIMD.float32x4.mul(SIMD.float32x4.swizzle(b0, 3, 3, 3, 3), a3)))));
-            SIMD.float32x4.store(out, 4, SIMD.float32x4.add(SIMD.float32x4.mul(SIMD.float32x4.swizzle(b1, 0, 0, 0, 0), a0), SIMD.float32x4.add(SIMD.float32x4.mul(SIMD.float32x4.swizzle(b1, 1, 1, 1, 1), a1), SIMD.float32x4.add(SIMD.float32x4.mul(SIMD.float32x4.swizzle(b1, 2, 2, 2, 2), a2), SIMD.float32x4.mul(SIMD.float32x4.swizzle(b1, 3, 3, 3, 3), a3)))));
-            SIMD.float32x4.store(out, 8, SIMD.float32x4.add(SIMD.float32x4.mul(SIMD.float32x4.swizzle(b2, 0, 0, 0, 0), a0), SIMD.float32x4.add(SIMD.float32x4.mul(SIMD.float32x4.swizzle(b2, 1, 1, 1, 1), a1), SIMD.float32x4.add(SIMD.float32x4.mul(SIMD.float32x4.swizzle(b2, 2, 2, 2, 2), a2), SIMD.float32x4.mul(SIMD.float32x4.swizzle(b2, 3, 3, 3, 3), a3)))));
-            SIMD.float32x4.store(out, 12, SIMD.float32x4.add(SIMD.float32x4.mul(SIMD.float32x4.swizzle(b3, 0, 0, 0, 0), a0), SIMD.float32x4.add(SIMD.float32x4.mul(SIMD.float32x4.swizzle(b3, 1, 1, 1, 1), a1), SIMD.float32x4.add(SIMD.float32x4.mul(SIMD.float32x4.swizzle(b3, 2, 2, 2, 2), a2), SIMD.float32x4.mul(SIMD.float32x4.swizzle(b3, 3, 3, 3, 3), a3)))));
-        }
-    }
-
-    var previousMultiplyToArray = Matrix.prototype.multiplyToArray;
-    var previousInvertToRef = Matrix.prototype.invertToRef;
-    var previousLookAtLHToRef = Matrix.LookAtLHToRef;
-    var previousTransformCoordinatesToRef = Vector3.TransformCoordinatesToRef;
-    var previousTransformCoordinatesFromFloatsToRef = Vector3.TransformCoordinatesFromFloatsToRef;
-
-    export class SIMDHelper {
-        private static _isEnabled = false;
-
-        public static get IsEnabled(): boolean {
-            return SIMDHelper._isEnabled;
-        }
-
-        public static DisableSIMD(): void {
-            // Replace functions
-            Matrix.prototype.multiplyToArray = <any>previousMultiplyToArray;
-            Matrix.prototype.invertToRef = <any>previousInvertToRef;
-            Matrix.LookAtLHToRef = <any>previousLookAtLHToRef;
-            Vector3.TransformCoordinatesToRef = <any>previousTransformCoordinatesToRef;
-            Vector3.TransformCoordinatesFromFloatsToRef = <any>previousTransformCoordinatesFromFloatsToRef;
-
-            SIMDHelper._isEnabled = false;
-        }
-
-        public static EnableSIMD(): void {
-            if (window.SIMD === undefined) {
-                return;
-            }
-
-            // Replace functions
-            Matrix.prototype.multiplyToArray = <any>SIMDMatrix.prototype.multiplyToArraySIMD;
-            Matrix.prototype.invertToRef = <any>SIMDMatrix.prototype.invertToRefSIMD;
-            Matrix.LookAtLHToRef = <any>SIMDMatrix.LookAtLHToRefSIMD;
-            Vector3.TransformCoordinatesToRef = <any>SIMDVector3.TransformCoordinatesToRefSIMD;
-            Vector3.TransformCoordinatesFromFloatsToRef = <any>SIMDVector3.TransformCoordinatesFromFloatsToRefSIMD;
-
-            Object.defineProperty(Vector3.prototype, "x", {
-                get() { return this._data[0]; },
-                set(value: number) {
-                    if (!this._data) {
-                        this._data = new Float32Array(3);
-                    }
-                    this._data[0] = value;
-                }
-            });
-
-            Object.defineProperty(Vector3.prototype, "y", {
-                get() { return this._data[1]; },
-                set(value: number) {
-                    this._data[1] = value;
-                }
-            });
-
-            Object.defineProperty(Vector3.prototype, "z", {
-                get() { return this._data[2]; },
-                set(value: number) {
-                    this._data[2] = value;
-                }
-            });
-
-            SIMDHelper._isEnabled = true;
-        }
-    }
-}
-
-
+module BABYLON {
+
+    declare var SIMD;
+
+    export class SIMDVector3 {
+        public static TransformCoordinatesToRefSIMD(vector: Vector3, transformation: Matrix, result: Vector3): void {
+            var v = SIMD.float32x4.loadXYZ((<any>vector)._data, 0);
+            var m0 = SIMD.float32x4.load(transformation.m, 0);
+            var m1 = SIMD.float32x4.load(transformation.m, 4);
+            var m2 = SIMD.float32x4.load(transformation.m, 8);
+            var m3 = SIMD.float32x4.load(transformation.m, 12);
+            var r = SIMD.float32x4.add(SIMD.float32x4.add(SIMD.float32x4.mul(SIMD.float32x4.swizzle(v, 0, 0, 0, 0), m0), SIMD.float32x4.mul(SIMD.float32x4.swizzle(v, 1, 1, 1, 1), m1)), SIMD.float32x4.add(SIMD.float32x4.mul(SIMD.float32x4.swizzle(v, 2, 2, 2, 2), m2), m3));
+            r = SIMD.float32x4.div(r, SIMD.float32x4.swizzle(r, 3, 3, 3, 3));
+            SIMD.float32x4.storeXYZ((<any>result)._data, 0, r);
+        }
+
+        public static TransformCoordinatesFromFloatsToRefSIMD(x: number, y: number, z: number, transformation: Matrix, result: Vector3): void {
+            var v0 = SIMD.float32x4.splat(x);
+            var v1 = SIMD.float32x4.splat(y);
+            var v2 = SIMD.float32x4.splat(z);
+            var m0 = SIMD.float32x4.load(transformation.m, 0);
+            var m1 = SIMD.float32x4.load(transformation.m, 4);
+            var m2 = SIMD.float32x4.load(transformation.m, 8);
+            var m3 = SIMD.float32x4.load(transformation.m, 12);
+            var r = SIMD.float32x4.add(SIMD.float32x4.add(SIMD.float32x4.mul(v0, m0), SIMD.float32x4.mul(v1, m1)), SIMD.float32x4.add(SIMD.float32x4.mul(v2, m2), m3));
+            r = SIMD.float32x4.div(r, SIMD.float32x4.swizzle(r, 3, 3, 3, 3));
+            SIMD.float32x4.storeXYZ((<any>result)._data, 0, r);
+        }
+    }
+
+    export class SIMDMatrix {
+        public multiplyToArraySIMD(other: Matrix, result: Matrix, offset = 0): void {
+            var tm = (<any>this).m;
+            var om = other.m;
+            var om0 = SIMD.float32x4.load(om, 0);
+            var om1 = SIMD.float32x4.load(om, 4);
+            var om2 = SIMD.float32x4.load(om, 8);
+            var om3 = SIMD.float32x4.load(om, 12);
+
+            var tm0 = SIMD.float32x4.load(tm, 0);
+            SIMD.float32x4.store(result, offset + 0, SIMD.float32x4.add(
+                SIMD.float32x4.mul(SIMD.float32x4.swizzle(tm0, 0, 0, 0, 0), om0),
+                SIMD.float32x4.add(
+                    SIMD.float32x4.mul(SIMD.float32x4.swizzle(tm0, 1, 1, 1, 1), om1),
+                    SIMD.float32x4.add(
+                        SIMD.float32x4.mul(SIMD.float32x4.swizzle(tm0, 2, 2, 2, 2), om2),
+                        SIMD.float32x4.mul(SIMD.float32x4.swizzle(tm0, 3, 3, 3, 3), om3)))));
+
+            var tm1 = SIMD.float32x4.load(tm, 4);
+            SIMD.float32x4.store(result, offset + 4, SIMD.float32x4.add(
+                SIMD.float32x4.mul(SIMD.float32x4.swizzle(tm1, 0, 0, 0, 0), om0),
+                SIMD.float32x4.add(
+                    SIMD.float32x4.mul(SIMD.float32x4.swizzle(tm1, 1, 1, 1, 1), om1),
+                    SIMD.float32x4.add(
+                        SIMD.float32x4.mul(SIMD.float32x4.swizzle(tm1, 2, 2, 2, 2), om2),
+                        SIMD.float32x4.mul(SIMD.float32x4.swizzle(tm1, 3, 3, 3, 3), om3)))));
+
+            var tm2 = SIMD.float32x4.load(tm, 8);
+            SIMD.float32x4.store(result, offset + 8, SIMD.float32x4.add(
+                SIMD.float32x4.mul(SIMD.float32x4.swizzle(tm2, 0, 0, 0, 0), om0),
+                SIMD.float32x4.add(
+                    SIMD.float32x4.mul(SIMD.float32x4.swizzle(tm2, 1, 1, 1, 1), om1),
+                    SIMD.float32x4.add(
+                        SIMD.float32x4.mul(SIMD.float32x4.swizzle(tm2, 2, 2, 2, 2), om2),
+                        SIMD.float32x4.mul(SIMD.float32x4.swizzle(tm2, 3, 3, 3, 3), om3)))));
+
+            var tm3 = SIMD.float32x4.load(tm, 12);
+            SIMD.float32x4.store(result, offset + 12, SIMD.float32x4.add(
+                SIMD.float32x4.mul(SIMD.float32x4.swizzle(tm3, 0, 0, 0, 0), om0),
+                SIMD.float32x4.add(
+                    SIMD.float32x4.mul(SIMD.float32x4.swizzle(tm3, 1, 1, 1, 1), om1),
+                    SIMD.float32x4.add(
+                        SIMD.float32x4.mul(SIMD.float32x4.swizzle(tm3, 2, 2, 2, 2), om2),
+                        SIMD.float32x4.mul(SIMD.float32x4.swizzle(tm3, 3, 3, 3, 3), om3)))));
+        }
+
+        public invertToRefSIMD(other: Matrix): Matrix {
+            var src = (<any>this).m;
+            var dest = other.m;
+            var row0, row1, row2, row3;
+            var tmp1;
+            var minor0, minor1, minor2, minor3;
+            var det;
+
+            // Load the 4 rows
+            var src0 = SIMD.float32x4.load(src, 0);
+            var src1 = SIMD.float32x4.load(src, 4);
+            var src2 = SIMD.float32x4.load(src, 8);
+            var src3 = SIMD.float32x4.load(src, 12);
+
+            // Transpose the source matrix.  Sort of.  Not a true transpose operation
+
+            tmp1 = SIMD.float32x4.shuffle(src0, src1, 0, 1, 4, 5);
+            row1 = SIMD.float32x4.shuffle(src2, src3, 0, 1, 4, 5);
+            row0 = SIMD.float32x4.shuffle(tmp1, row1, 0, 2, 4, 6);
+            row1 = SIMD.float32x4.shuffle(row1, tmp1, 1, 3, 5, 7);
+
+            tmp1 = SIMD.float32x4.shuffle(src0, src1, 2, 3, 6, 7);
+            row3 = SIMD.float32x4.shuffle(src2, src3, 2, 3, 6, 7);
+            row2 = SIMD.float32x4.shuffle(tmp1, row3, 0, 2, 4, 6);
+            row3 = SIMD.float32x4.shuffle(row3, tmp1, 1, 3, 5, 7);
+
+            // This is a true transposition, but it will lead to an incorrect result
+
+            //tmp1 = SIMD.float32x4.shuffle(src0, src1, 0, 1, 4, 5);
+            //tmp2 = SIMD.float32x4.shuffle(src2, src3, 0, 1, 4, 5);
+            //row0  = SIMD.float32x4.shuffle(tmp1, tmp2, 0, 2, 4, 6);
+            //row1  = SIMD.float32x4.shuffle(tmp1, tmp2, 1, 3, 5, 7);
+
+            //tmp1 = SIMD.float32x4.shuffle(src0, src1, 2, 3, 6, 7);
+            //tmp2 = SIMD.float32x4.shuffle(src2, src3, 2, 3, 6, 7);
+            //row2  = SIMD.float32x4.shuffle(tmp1, tmp2, 0, 2, 4, 6);
+            //row3  = SIMD.float32x4.shuffle(tmp1, tmp2, 1, 3, 5, 7);
+
+            // ----
+            tmp1 = SIMD.float32x4.mul(row2, row3);
+            tmp1 = SIMD.float32x4.swizzle(tmp1, 1, 0, 3, 2); // 0xB1 = 10110001
+            minor0 = SIMD.float32x4.mul(row1, tmp1);
+            minor1 = SIMD.float32x4.mul(row0, tmp1);
+            tmp1 = SIMD.float32x4.swizzle(tmp1, 2, 3, 0, 1); // 0x4E = 01001110
+            minor0 = SIMD.float32x4.sub(SIMD.float32x4.mul(row1, tmp1), minor0);
+            minor1 = SIMD.float32x4.sub(SIMD.float32x4.mul(row0, tmp1), minor1);
+            minor1 = SIMD.float32x4.swizzle(minor1, 2, 3, 0, 1); // 0x4E = 01001110
+
+            // ----
+            tmp1 = SIMD.float32x4.mul(row1, row2);
+            tmp1 = SIMD.float32x4.swizzle(tmp1, 1, 0, 3, 2); // 0xB1 = 10110001
+            minor0 = SIMD.float32x4.add(SIMD.float32x4.mul(row3, tmp1), minor0);
+            minor3 = SIMD.float32x4.mul(row0, tmp1);
+            tmp1 = SIMD.float32x4.swizzle(tmp1, 2, 3, 0, 1); // 0x4E = 01001110
+            minor0 = SIMD.float32x4.sub(minor0, SIMD.float32x4.mul(row3, tmp1));
+            minor3 = SIMD.float32x4.sub(SIMD.float32x4.mul(row0, tmp1), minor3);
+            minor3 = SIMD.float32x4.swizzle(minor3, 2, 3, 0, 1); // 0x4E = 01001110
+
+            // ----
+            tmp1 = SIMD.float32x4.mul(SIMD.float32x4.swizzle(row1, 2, 3, 0, 1), row3); // 0x4E = 01001110
+            tmp1 = SIMD.float32x4.swizzle(tmp1, 1, 0, 3, 2); // 0xB1 = 10110001
+            row2 = SIMD.float32x4.swizzle(row2, 2, 3, 0, 1);  // 0x4E = 01001110
+            minor0 = SIMD.float32x4.add(SIMD.float32x4.mul(row2, tmp1), minor0);
+            minor2 = SIMD.float32x4.mul(row0, tmp1);
+            tmp1 = SIMD.float32x4.swizzle(tmp1, 2, 3, 0, 1); // 0x4E = 01001110
+            minor0 = SIMD.float32x4.sub(minor0, SIMD.float32x4.mul(row2, tmp1));
+            minor2 = SIMD.float32x4.sub(SIMD.float32x4.mul(row0, tmp1), minor2);
+            minor2 = SIMD.float32x4.swizzle(minor2, 2, 3, 0, 1); // 0x4E = 01001110
+
+            // ----
+            tmp1 = SIMD.float32x4.mul(row0, row1);
+            tmp1 = SIMD.float32x4.swizzle(tmp1, 1, 0, 3, 2); // 0xB1 = 10110001
+            minor2 = SIMD.float32x4.add(SIMD.float32x4.mul(row3, tmp1), minor2);
+            minor3 = SIMD.float32x4.sub(SIMD.float32x4.mul(row2, tmp1), minor3);
+            tmp1 = SIMD.float32x4.swizzle(tmp1, 2, 3, 0, 1); // 0x4E = 01001110
+            minor2 = SIMD.float32x4.sub(SIMD.float32x4.mul(row3, tmp1), minor2);
+            minor3 = SIMD.float32x4.sub(minor3, SIMD.float32x4.mul(row2, tmp1));
+
+            // ----
+            tmp1 = SIMD.float32x4.mul(row0, row3);
+            tmp1 = SIMD.float32x4.swizzle(tmp1, 1, 0, 3, 2); // 0xB1 = 10110001
+            minor1 = SIMD.float32x4.sub(minor1, SIMD.float32x4.mul(row2, tmp1));
+            minor2 = SIMD.float32x4.add(SIMD.float32x4.mul(row1, tmp1), minor2);
+            tmp1 = SIMD.float32x4.swizzle(tmp1, 2, 3, 0, 1); // 0x4E = 01001110
+            minor1 = SIMD.float32x4.add(SIMD.float32x4.mul(row2, tmp1), minor1);
+            minor2 = SIMD.float32x4.sub(minor2, SIMD.float32x4.mul(row1, tmp1));
+
+            // ----
+            tmp1 = SIMD.float32x4.mul(row0, row2);
+            tmp1 = SIMD.float32x4.swizzle(tmp1, 1, 0, 3, 2); // 0xB1 = 10110001
+            minor1 = SIMD.float32x4.add(SIMD.float32x4.mul(row3, tmp1), minor1);
+            minor3 = SIMD.float32x4.sub(minor3, SIMD.float32x4.mul(row1, tmp1));
+            tmp1 = SIMD.float32x4.swizzle(tmp1, 2, 3, 0, 1); // 0x4E = 01001110
+            minor1 = SIMD.float32x4.sub(minor1, SIMD.float32x4.mul(row3, tmp1));
+            minor3 = SIMD.float32x4.add(SIMD.float32x4.mul(row1, tmp1), minor3);
+
+            // Compute determinant
+            det = SIMD.float32x4.mul(row0, minor0);
+            det = SIMD.float32x4.add(SIMD.float32x4.swizzle(det, 2, 3, 0, 1), det); // 0x4E = 01001110
+            det = SIMD.float32x4.add(SIMD.float32x4.swizzle(det, 1, 0, 3, 2), det); // 0xB1 = 10110001
+            tmp1 = SIMD.float32x4.reciprocalApproximation(det);
+            det = SIMD.float32x4.sub(SIMD.float32x4.add(tmp1, tmp1), SIMD.float32x4.mul(det, SIMD.float32x4.mul(tmp1, tmp1)));
+            det = SIMD.float32x4.swizzle(det, 0, 0, 0, 0);
+
+            // These shuffles aren't necessary if the faulty transposition is done
+            // up at the top of this function.
+            //minor0 = SIMD.float32x4.swizzle(minor0, 2, 1, 0, 3);
+            //minor1 = SIMD.float32x4.swizzle(minor1, 2, 1, 0, 3);
+            //minor2 = SIMD.float32x4.swizzle(minor2, 2, 1, 0, 3);
+            //minor3 = SIMD.float32x4.swizzle(minor3, 2, 1, 0, 3);
+
+            // Compute final values by multiplying with 1/det
+            minor0 = SIMD.float32x4.mul(det, minor0);
+            minor1 = SIMD.float32x4.mul(det, minor1);
+            minor2 = SIMD.float32x4.mul(det, minor2);
+            minor3 = SIMD.float32x4.mul(det, minor3);
+
+            SIMD.float32x4.store(dest, 0, minor0);
+            SIMD.float32x4.store(dest, 4, minor1);
+            SIMD.float32x4.store(dest, 8, minor2);
+            SIMD.float32x4.store(dest, 12, minor3);
+
+            return (<any>this);
+        }
+
+        public static LookAtLHToRefSIMD(eyeRef: Vector3, targetRef: Vector3, upRef: Vector3, result: Matrix): void {
+            var out = result.m;
+            var center = SIMD.float32x4(targetRef.x, targetRef.y, targetRef.z, 0);
+            var eye = SIMD.float32x4(eyeRef.x, eyeRef.y, eyeRef.z, 0);
+            var up = SIMD.float32x4(upRef.x, upRef.y, upRef.z, 0);
+
+            // cc.kmVec3Subtract(f, pCenter, pEye);
+            var f = SIMD.float32x4.sub(center, eye);
+            // cc.kmVec3Normalize(f, f);    
+            var tmp = SIMD.float32x4.mul(f, f);
+            tmp = SIMD.float32x4.add(tmp, SIMD.float32x4.add(SIMD.float32x4.swizzle(tmp, 1, 2, 0, 3), SIMD.float32x4.swizzle(tmp, 2, 0, 1, 3)));
+            f = SIMD.float32x4.mul(f, SIMD.float32x4.reciprocalSqrtApproximation(tmp));
+
+            // cc.kmVec3Assign(up, pUp);
+            // cc.kmVec3Normalize(up, up);
+            tmp = SIMD.float32x4.mul(up, up);
+            tmp = SIMD.float32x4.add(tmp, SIMD.float32x4.add(SIMD.float32x4.swizzle(tmp, 1, 2, 0, 3), SIMD.float32x4.swizzle(tmp, 2, 0, 1, 3)));
+            up = SIMD.float32x4.mul(up, SIMD.float32x4.reciprocalSqrtApproximation(tmp));
+            // cc.kmVec3Cross(s, f, up);
+            var s = SIMD.float32x4.sub(SIMD.float32x4.mul(SIMD.float32x4.swizzle(f, 1, 2, 0, 3), SIMD.float32x4.swizzle(up, 2, 0, 1, 3)), SIMD.float32x4.mul(SIMD.float32x4.swizzle(f, 2, 0, 1, 3), SIMD.float32x4.swizzle(up, 1, 2, 0, 3)));
+            // cc.kmVec3Normalize(s, s);
+            tmp = SIMD.float32x4.mul(s, s);
+            tmp = SIMD.float32x4.add(tmp, SIMD.float32x4.add(SIMD.float32x4.swizzle(tmp, 1, 2, 0, 3), SIMD.float32x4.swizzle(tmp, 2, 0, 1, 3)));
+            s = SIMD.float32x4.mul(s, SIMD.float32x4.reciprocalSqrtApproximation(tmp));
+            // cc.kmVec3Cross(u, s, f);
+            var u = SIMD.float32x4.sub(SIMD.float32x4.mul(SIMD.float32x4.swizzle(s, 1, 2, 0, 3), SIMD.float32x4.swizzle(f, 2, 0, 1, 3)), SIMD.float32x4.mul(SIMD.float32x4.swizzle(s, 2, 0, 1, 3), SIMD.float32x4.swizzle(f, 1, 2, 0, 3)));
+            // cc.kmVec3Normalize(s, s);
+            tmp = SIMD.float32x4.mul(s, s);
+            tmp = SIMD.float32x4.add(tmp, SIMD.float32x4.add(SIMD.float32x4.swizzle(tmp, 1, 2, 0, 3), SIMD.float32x4.swizzle(tmp, 2, 0, 1, 3)));
+            s = SIMD.float32x4.mul(s, SIMD.float32x4.reciprocalSqrtApproximation(tmp));
+
+            var zero = SIMD.float32x4.splat(0.0);
+            s = SIMD.float32x4.neg(s);
+            var tmp01 = SIMD.float32x4.shuffle(s, u, 0, 1, 4, 5);
+            var tmp23 = SIMD.float32x4.shuffle(f, zero, 0, 1, 4, 5);
+            var a0 = SIMD.float32x4.shuffle(tmp01, tmp23, 0, 2, 4, 6);
+            var a1 = SIMD.float32x4.shuffle(tmp01, tmp23, 1, 3, 5, 7);
+            tmp01 = SIMD.float32x4.shuffle(s, u, 2, 3, 6, 7);
+            tmp23 = SIMD.float32x4.shuffle(f, zero, 2, 3, 6, 7);
+            var a2 = SIMD.float32x4.shuffle(tmp01, tmp23, 0, 2, 4, 6);
+            var a3 = SIMD.float32x4(0.0, 0.0, 0.0, 1.0);
+            var b0 = SIMD.float32x4(1.0, 0.0, 0.0, 0.0);
+            var b1 = SIMD.float32x4(0.0, 1.0, 0.0, 0.0);
+            var b2 = SIMD.float32x4(0.0, 0.0, 1.0, 0.0);
+            var b3 = SIMD.float32x4.neg(eye);
+            b3 = SIMD.float32x4.withW(b3, 1.0);
+
+            SIMD.float32x4.store(out, 0, SIMD.float32x4.add(SIMD.float32x4.mul(SIMD.float32x4.swizzle(b0, 0, 0, 0, 0), a0), SIMD.float32x4.add(SIMD.float32x4.mul(SIMD.float32x4.swizzle(b0, 1, 1, 1, 1), a1), SIMD.float32x4.add(SIMD.float32x4.mul(SIMD.float32x4.swizzle(b0, 2, 2, 2, 2), a2), SIMD.float32x4.mul(SIMD.float32x4.swizzle(b0, 3, 3, 3, 3), a3)))));
+            SIMD.float32x4.store(out, 4, SIMD.float32x4.add(SIMD.float32x4.mul(SIMD.float32x4.swizzle(b1, 0, 0, 0, 0), a0), SIMD.float32x4.add(SIMD.float32x4.mul(SIMD.float32x4.swizzle(b1, 1, 1, 1, 1), a1), SIMD.float32x4.add(SIMD.float32x4.mul(SIMD.float32x4.swizzle(b1, 2, 2, 2, 2), a2), SIMD.float32x4.mul(SIMD.float32x4.swizzle(b1, 3, 3, 3, 3), a3)))));
+            SIMD.float32x4.store(out, 8, SIMD.float32x4.add(SIMD.float32x4.mul(SIMD.float32x4.swizzle(b2, 0, 0, 0, 0), a0), SIMD.float32x4.add(SIMD.float32x4.mul(SIMD.float32x4.swizzle(b2, 1, 1, 1, 1), a1), SIMD.float32x4.add(SIMD.float32x4.mul(SIMD.float32x4.swizzle(b2, 2, 2, 2, 2), a2), SIMD.float32x4.mul(SIMD.float32x4.swizzle(b2, 3, 3, 3, 3), a3)))));
+            SIMD.float32x4.store(out, 12, SIMD.float32x4.add(SIMD.float32x4.mul(SIMD.float32x4.swizzle(b3, 0, 0, 0, 0), a0), SIMD.float32x4.add(SIMD.float32x4.mul(SIMD.float32x4.swizzle(b3, 1, 1, 1, 1), a1), SIMD.float32x4.add(SIMD.float32x4.mul(SIMD.float32x4.swizzle(b3, 2, 2, 2, 2), a2), SIMD.float32x4.mul(SIMD.float32x4.swizzle(b3, 3, 3, 3, 3), a3)))));
+        }
+    }
+
+    var previousMultiplyToArray = Matrix.prototype.multiplyToArray;
+    var previousInvertToRef = Matrix.prototype.invertToRef;
+    var previousLookAtLHToRef = Matrix.LookAtLHToRef;
+    var previousTransformCoordinatesToRef = Vector3.TransformCoordinatesToRef;
+    var previousTransformCoordinatesFromFloatsToRef = Vector3.TransformCoordinatesFromFloatsToRef;
+
+    export class SIMDHelper {
+        private static _isEnabled = false;
+
+        public static get IsEnabled(): boolean {
+            return SIMDHelper._isEnabled;
+        }
+
+        public static DisableSIMD(): void {
+            // Replace functions
+            Matrix.prototype.multiplyToArray = <any>previousMultiplyToArray;
+            Matrix.prototype.invertToRef = <any>previousInvertToRef;
+            Matrix.LookAtLHToRef = <any>previousLookAtLHToRef;
+            Vector3.TransformCoordinatesToRef = <any>previousTransformCoordinatesToRef;
+            Vector3.TransformCoordinatesFromFloatsToRef = <any>previousTransformCoordinatesFromFloatsToRef;
+
+            SIMDHelper._isEnabled = false;
+        }
+
+        public static EnableSIMD(): void {
+            if (window.SIMD === undefined) {
+                return;
+            }
+
+            // Replace functions
+            Matrix.prototype.multiplyToArray = <any>SIMDMatrix.prototype.multiplyToArraySIMD;
+            Matrix.prototype.invertToRef = <any>SIMDMatrix.prototype.invertToRefSIMD;
+            Matrix.LookAtLHToRef = <any>SIMDMatrix.LookAtLHToRefSIMD;
+            Vector3.TransformCoordinatesToRef = <any>SIMDVector3.TransformCoordinatesToRefSIMD;
+            Vector3.TransformCoordinatesFromFloatsToRef = <any>SIMDVector3.TransformCoordinatesFromFloatsToRefSIMD;
+
+            Object.defineProperty(Vector3.prototype, "x", {
+                get() { return this._data[0]; },
+                set(value: number) {
+                    if (!this._data) {
+                        this._data = new Float32Array(3);
+                    }
+                    this._data[0] = value;
+                }
+            });
+
+            Object.defineProperty(Vector3.prototype, "y", {
+                get() { return this._data[1]; },
+                set(value: number) {
+                    this._data[1] = value;
+                }
+            });
+
+            Object.defineProperty(Vector3.prototype, "z", {
+                get() { return this._data[2]; },
+                set(value: number) {
+                    this._data[2] = value;
+                }
+            });
+
+            SIMDHelper._isEnabled = true;
+        }
+    }
+}
+
+

Разница между файлами не показана из-за своего большого размера
+ 3618 - 3618
src/Math/babylon.math.ts


Разница между файлами не показана из-за своего большого размера
+ 1062 - 1062
src/Mesh/babylon.abstractMesh.ts


Разница между файлами не показана из-за своего большого размера
+ 609 - 609
src/Mesh/babylon.csg.ts


+ 37 - 37
src/Mesh/babylon.groundMesh.ts

@@ -1,38 +1,38 @@
-module BABYLON {
-    export class GroundMesh extends Mesh {
-        public generateOctree = false;
-
-        private _worldInverse = new Matrix();
-        public _subdivisions: number;
-
-        constructor(name: string, scene: Scene) {
-            super(name, scene);
-        }
-
-        public get subdivisions(): number {
-            return this._subdivisions;
-        }
-
-        public optimize(chunksCount: number, octreeBlocksSize = 32): void {
-            this._subdivisions = chunksCount;
-            this.subdivide(this._subdivisions);
-            this.createOrUpdateSubmeshesOctree(octreeBlocksSize);
-        }
-
-        public getHeightAtCoordinates(x: number, z: number): number {
-            var ray = new Ray(new Vector3(x, this.getBoundingInfo().boundingBox.maximumWorld.y + 1, z), new Vector3(0, -1, 0));
-
-            this.getWorldMatrix().invertToRef(this._worldInverse);
-
-            ray = Ray.Transform(ray, this._worldInverse);
-
-            var pickInfo = this.intersects(ray);
-
-            if (pickInfo.hit) {
-                return pickInfo.pickedPoint.y;
-            }
-
-            return 0;
-        }
-    }
+module BABYLON {
+    export class GroundMesh extends Mesh {
+        public generateOctree = false;
+
+        private _worldInverse = new Matrix();
+        public _subdivisions: number;
+
+        constructor(name: string, scene: Scene) {
+            super(name, scene);
+        }
+
+        public get subdivisions(): number {
+            return this._subdivisions;
+        }
+
+        public optimize(chunksCount: number, octreeBlocksSize = 32): void {
+            this._subdivisions = chunksCount;
+            this.subdivide(this._subdivisions);
+            this.createOrUpdateSubmeshesOctree(octreeBlocksSize);
+        }
+
+        public getHeightAtCoordinates(x: number, z: number): number {
+            var ray = new Ray(new Vector3(x, this.getBoundingInfo().boundingBox.maximumWorld.y + 1, z), new Vector3(0, -1, 0));
+
+            this.getWorldMatrix().invertToRef(this._worldInverse);
+
+            ray = Ray.Transform(ray, this._worldInverse);
+
+            var pickInfo = this.intersects(ray);
+
+            if (pickInfo.hit) {
+                return pickInfo.pickedPoint.y;
+            }
+
+            return 0;
+        }
+    }
 } 

+ 67 - 67
src/Mesh/babylon.linesMesh.ts

@@ -1,68 +1,68 @@
-module BABYLON {
-    export class LinesMesh extends Mesh {
-        public color = new Color3(1, 1, 1);
-        public alpha = 1;
-
-        private _colorShader: ShaderMaterial;
-
-        constructor(name: string, scene: Scene, parent: Node = null, source?: Mesh, doNotCloneChildren?: boolean) {
-            super(name, scene, parent, source, doNotCloneChildren);
-
-            this._colorShader = new ShaderMaterial("colorShader", scene, "color",
-                {
-                    attributes: ["position"],
-                    uniforms: ["worldViewProjection", "color"],
-                    needAlphaBlending: true
-                });
-        }
-
-        public get material(): Material {
-            return this._colorShader;
-        }
-
-        public get isPickable(): boolean {
-            return false;
-        }
-
-        public get checkCollisions(): boolean {
-            return false;
-        }
-
-        public _bind(subMesh: SubMesh, effect: Effect, fillMode: number): void {
-            var engine = this.getScene().getEngine();
-
-            var indexToBind = this._geometry.getIndexBuffer();
-
-            // VBOs
-            engine.bindBuffers(this._geometry.getVertexBuffer(VertexBuffer.PositionKind).getBuffer(), indexToBind, [3], 3 * 4, this._colorShader.getEffect());
-
-            // Color
-            this._colorShader.setColor4("color", this.color.toColor4(this.alpha));
-        }
-
-        public _draw(subMesh: SubMesh, fillMode: number, instancesCount?: number): void {
-            if (!this._geometry || !this._geometry.getVertexBuffers() || !this._geometry.getIndexBuffer()) {
-                return;
-            }
-
-            var engine = this.getScene().getEngine();
-
-            // Draw order
-            engine.draw(false, subMesh.indexStart, subMesh.indexCount);
-        }
-
-        public intersects(ray: Ray, fastCheck?: boolean) {
-            return null;
-        }
-
-        public dispose(doNotRecurse?: boolean): void {
-            this._colorShader.dispose();
-
-            super.dispose(doNotRecurse);
-        }
-
-        public clone(name: string, newParent?: Node, doNotCloneChildren?: boolean): LinesMesh {
-            return new LinesMesh(name, this.getScene(), newParent, this, doNotCloneChildren);
-        }
-    }
+module BABYLON {
+    export class LinesMesh extends Mesh {
+        public color = new Color3(1, 1, 1);
+        public alpha = 1;
+
+        private _colorShader: ShaderMaterial;
+
+        constructor(name: string, scene: Scene, parent: Node = null, source?: Mesh, doNotCloneChildren?: boolean) {
+            super(name, scene, parent, source, doNotCloneChildren);
+
+            this._colorShader = new ShaderMaterial("colorShader", scene, "color",
+                {
+                    attributes: ["position"],
+                    uniforms: ["worldViewProjection", "color"],
+                    needAlphaBlending: true
+                });
+        }
+
+        public get material(): Material {
+            return this._colorShader;
+        }
+
+        public get isPickable(): boolean {
+            return false;
+        }
+
+        public get checkCollisions(): boolean {
+            return false;
+        }
+
+        public _bind(subMesh: SubMesh, effect: Effect, fillMode: number): void {
+            var engine = this.getScene().getEngine();
+
+            var indexToBind = this._geometry.getIndexBuffer();
+
+            // VBOs
+            engine.bindBuffers(this._geometry.getVertexBuffer(VertexBuffer.PositionKind).getBuffer(), indexToBind, [3], 3 * 4, this._colorShader.getEffect());
+
+            // Color
+            this._colorShader.setColor4("color", this.color.toColor4(this.alpha));
+        }
+
+        public _draw(subMesh: SubMesh, fillMode: number, instancesCount?: number): void {
+            if (!this._geometry || !this._geometry.getVertexBuffers() || !this._geometry.getIndexBuffer()) {
+                return;
+            }
+
+            var engine = this.getScene().getEngine();
+
+            // Draw order
+            engine.draw(false, subMesh.indexStart, subMesh.indexCount);
+        }
+
+        public intersects(ray: Ray, fastCheck?: boolean) {
+            return null;
+        }
+
+        public dispose(doNotRecurse?: boolean): void {
+            this._colorShader.dispose();
+
+            super.dispose(doNotRecurse);
+        }
+
+        public clone(name: string, newParent?: Node, doNotCloneChildren?: boolean): LinesMesh {
+            return new LinesMesh(name, this.getScene(), newParent, this, doNotCloneChildren);
+        }
+    }
 } 

Разница между файлами не показана из-за своего большого размера
+ 802 - 802
src/Mesh/babylon.meshBuilder.ts


+ 5 - 5
src/Mesh/babylon.meshLODLevel.ts

@@ -1,6 +1,6 @@
-module BABYLON.Internals {
-    export class MeshLODLevel {
-        constructor(public distance: number, public mesh: Mesh) {
-        }
-    }
+module BABYLON.Internals {
+    export class MeshLODLevel {
+        constructor(public distance: number, public mesh: Mesh) {
+        }
+    }
 } 

Разница между файлами не показана из-за своего большого размера
+ 764 - 764
src/Mesh/babylon.meshSimplification.ts


+ 273 - 273
src/Mesh/babylon.polygonMesh.ts

@@ -1,273 +1,273 @@
-module BABYLON {
-    class IndexedVector2 extends Vector2 {
-        constructor(original: Vector2, public index: number) {
-            super(original.x, original.y);
-        }
-    }
-
-    class PolygonPoints {
-        elements = new Array<IndexedVector2>();
-
-        add(originalPoints: Array<Vector2>): Array<IndexedVector2> {
-
-            var result = new Array<IndexedVector2>();
-            originalPoints.forEach(point => {
-                if (result.length === 0 || !point.equalsWithEpsilon(result[0])) {
-                    var newPoint = new IndexedVector2(point, this.elements.length);
-                    result.push(newPoint);
-                    this.elements.push(newPoint);
-                }
-            });
-
-            return result;
-        }
-
-        computeBounds(): { min: Vector2; max: Vector2; width: number; height: number } {
-            var lmin = new Vector2(this.elements[0].x, this.elements[0].y);
-            var lmax = new Vector2(this.elements[0].x, this.elements[0].y);
-
-            this.elements.forEach(point => {
-
-                // x
-                if (point.x < lmin.x) {
-                    lmin.x = point.x;
-                }
-                else if (point.x > lmax.x) {
-                    lmax.x = point.x;
-                }
-
-                // y
-                if (point.y < lmin.y) {
-                    lmin.y = point.y;
-                }
-                else if (point.y > lmax.y) {
-                    lmax.y = point.y;
-                }
-
-            });
-
-            return {
-                min: lmin,
-                max: lmax,
-                width: lmax.x - lmin.x,
-                height: lmax.y - lmin.y
-            };
-        }
-    }
-
-    export class Polygon {
-        static Rectangle(xmin: number, ymin: number, xmax: number, ymax: number): Vector2[] {
-            return [
-                new Vector2(xmin, ymin),
-                new Vector2(xmax, ymin),
-                new Vector2(xmax, ymax),
-                new Vector2(xmin, ymax)
-            ];
-        }
-
-        static Circle(radius: number, cx: number = 0, cy: number = 0, numberOfSides: number = 32): Vector2[] {
-            var result = new Array<Vector2>();
-
-            var angle = 0;
-            var increment = (Math.PI * 2) / numberOfSides;
-
-            for (var i = 0; i < numberOfSides; i++) {
-                result.push(new Vector2(
-                    cx + Math.cos(angle) * radius,
-                    cy + Math.sin(angle) * radius
-                    ));
-                angle -= increment;
-            }
-
-            return result;
-        }
-
-        static Parse(input: string): Vector2[] {
-            var floats = input.split(/[^-+eE\.\d]+/).map(parseFloat).filter(val => (!isNaN(val)));
-            var i: number, result = [];
-            for (i = 0; i < (floats.length & 0x7FFFFFFE); i += 2) {
-                result.push(new Vector2(floats[i], floats[i + 1]));
-            }
-            return result;
-        }
-
-        static StartingAt(x: number, y: number): Path2 {
-            return Path2.StartingAt(x, y);
-        }
-    }
-
-    export class PolygonMeshBuilder {
-
-        private _swctx: poly2tri.SweepContext;
-        private _points = new PolygonPoints();
-        private _outlinepoints = new PolygonPoints();
-        private _holes = [];
-
-        private _name: string;
-        private _scene: Scene;
-
-        constructor(name: string, contours: Path2, scene: Scene)
-        constructor(name: string, contours: Vector2[], scene: Scene)
-        constructor(name: string, contours: any, scene: Scene) {
-            if (!("poly2tri" in window)) {
-                throw "PolygonMeshBuilder cannot be used because poly2tri is not referenced";
-            }
-
-            this._name = name;
-            this._scene = scene;
-
-            var points: Vector2[];
-            if (contours instanceof Path2) {
-                points = (<Path2>contours).getPoints();
-            } else {
-                points = (<Vector2[]>contours);
-            }
-
-            this._swctx = new poly2tri.SweepContext(this._points.add(points));
-            this._outlinepoints.add(points)
-        }
-
-        addHole(hole: Vector2[]): PolygonMeshBuilder {
-            this._swctx.addHole(this._points.add(hole));
-            var holepoints = new PolygonPoints();
-            holepoints.add(hole); 
-            this._holes.push(holepoints) ;
-            return this;
-        }
-
-        build(updatable: boolean = false, depth?:number): Mesh {
-            var result = new Mesh(this._name, this._scene);
-
-            var normals = [];
-            var positions = [];
-            var uvs = [];
-
-            var bounds = this._points.computeBounds();
-            this._points.elements.forEach((p) => {
-                normals.push(0, 1.0, 0);
-                positions.push(p.x, 0, p.y);
-                uvs.push((p.x - bounds.min.x) / bounds.width, (p.y - bounds.min.y) / bounds.height);
-            });
-
-            var indices = [];
-
-            this._swctx.triangulate();
-            this._swctx.getTriangles().forEach((triangle) => {
-                triangle.getPoints().forEach((point) => {
-                    indices.push((<IndexedVector2>point).index);
-                });
-            });
-
-            if (depth > 0) { 
-                var positionscount = (positions.length / 3); //get the current pointcount
-               
-                this._points.elements.forEach((p) => { //add the elements at the depth
-                    normals.push(0, -1.0, 0);                   
-                    positions.push(p.x, -depth, p.y);                
-                    uvs.push(1-(p.x - bounds.min.x) / bounds.width,1-(p.y - bounds.min.y) / bounds.height);
-                });
-
-                var p1: IndexedVector2;           //we need to change order of point so the triangles are made in the rigth way.
-                var p2: IndexedVector2;
-                var poscounter: number = 0;
-                this._swctx.getTriangles().forEach((triangle) => {
-                    triangle.getPoints().forEach((point) => {
-
-                        switch (poscounter) {
-                            case 0:
-                                p1 = <IndexedVector2>point;
-                                break;
-                            case 1:
-                                p2 = <IndexedVector2>point;
-                                break;
-                            case 2:
-                                indices.push((<IndexedVector2>point).index + positionscount); 
-                                indices.push(p2.index + positionscount);
-                                indices.push(p1.index + positionscount);
-                                poscounter = -1;
-                                break;
-                        }
-                        poscounter++;
-                        //indices.push((<IndexedVector2>point).index + positionscount);
-                    });
-                });
-                //Add the sides
-                this.addSide(positions, normals, uvs, indices, bounds, this._outlinepoints, depth, false)
-
-                this._holes.forEach((hole) => {
-                    this.addSide(positions, normals, uvs, indices, bounds, hole, depth, true)
-                });                               
-            }
-
-            result.setVerticesData(VertexBuffer.PositionKind, positions, updatable);
-            result.setVerticesData(VertexBuffer.NormalKind, normals, updatable);
-            result.setVerticesData(VertexBuffer.UVKind, uvs, updatable);
-            result.setIndices(indices);
-
-            return result;
-        } 
-
-       private addSide(positions: any[], normals: any[], uvs: any[], indices:any[],bounds: any, points: PolygonPoints, depth:number, flip:boolean ){
-            var StartIndex: number = positions.length / 3;
-            var ulength: number = 0;
-            for (var i: number = 0; i < points.elements.length; i++) {
-                var p: IndexedVector2 = points.elements[i];
-                var p1: IndexedVector2
-                if ((i + 1) > points.elements.length - 1) {
-                    p1 = points.elements[0];
-                }
-                else {
-                    p1 = points.elements[i + 1];
-                }
-
-                positions.push(p.x, 0, p.y);
-                positions.push(p.x, -depth, p.y);
-                positions.push(p1.x, 0, p1.y);
-                positions.push(p1.x, -depth, p1.y);
-
-                var v1 = new Vector3(p.x, 0, p.y);
-                var v2 = new Vector3(p1.x, 0, p1.y);
-                var v3 = v2.subtract(v1);
-                var v4 = new Vector3(0, 1, 0);
-                var vn = Vector3.Cross(v3, v4);
-                vn = vn.normalize();
-                
-                uvs.push(ulength / bounds.width, 0);
-                uvs.push(ulength / bounds.width, 1);
-                ulength += v3.length();
-                uvs.push((ulength / bounds.width), 0);
-                uvs.push((ulength / bounds.width), 1);
-
-                if (!flip) {
-                    normals.push(-vn.x,- vn.y, -vn.z);
-                    normals.push(-vn.x, -vn.y, -vn.z);
-                    normals.push(-vn.x, -vn.y, -vn.z);
-                    normals.push(-vn.x, -vn.y, -vn.z);
-
-                    indices.push(StartIndex);
-                    indices.push(StartIndex + 1);
-                    indices.push(StartIndex + 2);
-
-                    indices.push(StartIndex + 1);
-                    indices.push(StartIndex + 3);
-                    indices.push(StartIndex + 2);
-                }
-                else {
-                    normals.push(vn.x, vn.y, vn.z);
-                    normals.push(vn.x, vn.y, vn.z);
-                    normals.push(vn.x, vn.y, vn.z);
-                    normals.push(vn.x, vn.y, vn.z);
-
-                    indices.push(StartIndex);
-                    indices.push(StartIndex + 2);
-                    indices.push(StartIndex + 1);
-
-                    indices.push(StartIndex + 1);
-                    indices.push(StartIndex + 2);
-                    indices.push(StartIndex + 3);
-                }                
-                StartIndex += 4;
-            };
-        }
-    }
-}
+module BABYLON {
+    class IndexedVector2 extends Vector2 {
+        constructor(original: Vector2, public index: number) {
+            super(original.x, original.y);
+        }
+    }
+
+    class PolygonPoints {
+        elements = new Array<IndexedVector2>();
+
+        add(originalPoints: Array<Vector2>): Array<IndexedVector2> {
+
+            var result = new Array<IndexedVector2>();
+            originalPoints.forEach(point => {
+                if (result.length === 0 || !point.equalsWithEpsilon(result[0])) {
+                    var newPoint = new IndexedVector2(point, this.elements.length);
+                    result.push(newPoint);
+                    this.elements.push(newPoint);
+                }
+            });
+
+            return result;
+        }
+
+        computeBounds(): { min: Vector2; max: Vector2; width: number; height: number } {
+            var lmin = new Vector2(this.elements[0].x, this.elements[0].y);
+            var lmax = new Vector2(this.elements[0].x, this.elements[0].y);
+
+            this.elements.forEach(point => {
+
+                // x
+                if (point.x < lmin.x) {
+                    lmin.x = point.x;
+                }
+                else if (point.x > lmax.x) {
+                    lmax.x = point.x;
+                }
+
+                // y
+                if (point.y < lmin.y) {
+                    lmin.y = point.y;
+                }
+                else if (point.y > lmax.y) {
+                    lmax.y = point.y;
+                }
+
+            });
+
+            return {
+                min: lmin,
+                max: lmax,
+                width: lmax.x - lmin.x,
+                height: lmax.y - lmin.y
+            };
+        }
+    }
+
+    export class Polygon {
+        static Rectangle(xmin: number, ymin: number, xmax: number, ymax: number): Vector2[] {
+            return [
+                new Vector2(xmin, ymin),
+                new Vector2(xmax, ymin),
+                new Vector2(xmax, ymax),
+                new Vector2(xmin, ymax)
+            ];
+        }
+
+        static Circle(radius: number, cx: number = 0, cy: number = 0, numberOfSides: number = 32): Vector2[] {
+            var result = new Array<Vector2>();
+
+            var angle = 0;
+            var increment = (Math.PI * 2) / numberOfSides;
+
+            for (var i = 0; i < numberOfSides; i++) {
+                result.push(new Vector2(
+                    cx + Math.cos(angle) * radius,
+                    cy + Math.sin(angle) * radius
+                    ));
+                angle -= increment;
+            }
+
+            return result;
+        }
+
+        static Parse(input: string): Vector2[] {
+            var floats = input.split(/[^-+eE\.\d]+/).map(parseFloat).filter(val => (!isNaN(val)));
+            var i: number, result = [];
+            for (i = 0; i < (floats.length & 0x7FFFFFFE); i += 2) {
+                result.push(new Vector2(floats[i], floats[i + 1]));
+            }
+            return result;
+        }
+
+        static StartingAt(x: number, y: number): Path2 {
+            return Path2.StartingAt(x, y);
+        }
+    }
+
+    export class PolygonMeshBuilder {
+
+        private _swctx: poly2tri.SweepContext;
+        private _points = new PolygonPoints();
+        private _outlinepoints = new PolygonPoints();
+        private _holes = [];
+
+        private _name: string;
+        private _scene: Scene;
+
+        constructor(name: string, contours: Path2, scene: Scene)
+        constructor(name: string, contours: Vector2[], scene: Scene)
+        constructor(name: string, contours: any, scene: Scene) {
+            if (!("poly2tri" in window)) {
+                throw "PolygonMeshBuilder cannot be used because poly2tri is not referenced";
+            }
+
+            this._name = name;
+            this._scene = scene;
+
+            var points: Vector2[];
+            if (contours instanceof Path2) {
+                points = (<Path2>contours).getPoints();
+            } else {
+                points = (<Vector2[]>contours);
+            }
+
+            this._swctx = new poly2tri.SweepContext(this._points.add(points));
+            this._outlinepoints.add(points)
+        }
+
+        addHole(hole: Vector2[]): PolygonMeshBuilder {
+            this._swctx.addHole(this._points.add(hole));
+            var holepoints = new PolygonPoints();
+            holepoints.add(hole); 
+            this._holes.push(holepoints) ;
+            return this;
+        }
+
+        build(updatable: boolean = false, depth?:number): Mesh {
+            var result = new Mesh(this._name, this._scene);
+
+            var normals = [];
+            var positions = [];
+            var uvs = [];
+
+            var bounds = this._points.computeBounds();
+            this._points.elements.forEach((p) => {
+                normals.push(0, 1.0, 0);
+                positions.push(p.x, 0, p.y);
+                uvs.push((p.x - bounds.min.x) / bounds.width, (p.y - bounds.min.y) / bounds.height);
+            });
+
+            var indices = [];
+
+            this._swctx.triangulate();
+            this._swctx.getTriangles().forEach((triangle) => {
+                triangle.getPoints().forEach((point) => {
+                    indices.push((<IndexedVector2>point).index);
+                });
+            });
+
+            if (depth > 0) { 
+                var positionscount = (positions.length / 3); //get the current pointcount
+               
+                this._points.elements.forEach((p) => { //add the elements at the depth
+                    normals.push(0, -1.0, 0);                   
+                    positions.push(p.x, -depth, p.y);                
+                    uvs.push(1-(p.x - bounds.min.x) / bounds.width,1-(p.y - bounds.min.y) / bounds.height);
+                });
+
+                var p1: IndexedVector2;           //we need to change order of point so the triangles are made in the rigth way.
+                var p2: IndexedVector2;
+                var poscounter: number = 0;
+                this._swctx.getTriangles().forEach((triangle) => {
+                    triangle.getPoints().forEach((point) => {
+
+                        switch (poscounter) {
+                            case 0:
+                                p1 = <IndexedVector2>point;
+                                break;
+                            case 1:
+                                p2 = <IndexedVector2>point;
+                                break;
+                            case 2:
+                                indices.push((<IndexedVector2>point).index + positionscount); 
+                                indices.push(p2.index + positionscount);
+                                indices.push(p1.index + positionscount);
+                                poscounter = -1;
+                                break;
+                        }
+                        poscounter++;
+                        //indices.push((<IndexedVector2>point).index + positionscount);
+                    });
+                });
+                //Add the sides
+                this.addSide(positions, normals, uvs, indices, bounds, this._outlinepoints, depth, false)
+
+                this._holes.forEach((hole) => {
+                    this.addSide(positions, normals, uvs, indices, bounds, hole, depth, true)
+                });                               
+            }
+
+            result.setVerticesData(VertexBuffer.PositionKind, positions, updatable);
+            result.setVerticesData(VertexBuffer.NormalKind, normals, updatable);
+            result.setVerticesData(VertexBuffer.UVKind, uvs, updatable);
+            result.setIndices(indices);
+
+            return result;
+        } 
+
+       private addSide(positions: any[], normals: any[], uvs: any[], indices:any[],bounds: any, points: PolygonPoints, depth:number, flip:boolean ){
+            var StartIndex: number = positions.length / 3;
+            var ulength: number = 0;
+            for (var i: number = 0; i < points.elements.length; i++) {
+                var p: IndexedVector2 = points.elements[i];
+                var p1: IndexedVector2
+                if ((i + 1) > points.elements.length - 1) {
+                    p1 = points.elements[0];
+                }
+                else {
+                    p1 = points.elements[i + 1];
+                }
+
+                positions.push(p.x, 0, p.y);
+                positions.push(p.x, -depth, p.y);
+                positions.push(p1.x, 0, p1.y);
+                positions.push(p1.x, -depth, p1.y);
+
+                var v1 = new Vector3(p.x, 0, p.y);
+                var v2 = new Vector3(p1.x, 0, p1.y);
+                var v3 = v2.subtract(v1);
+                var v4 = new Vector3(0, 1, 0);
+                var vn = Vector3.Cross(v3, v4);
+                vn = vn.normalize();
+                
+                uvs.push(ulength / bounds.width, 0);
+                uvs.push(ulength / bounds.width, 1);
+                ulength += v3.length();
+                uvs.push((ulength / bounds.width), 0);
+                uvs.push((ulength / bounds.width), 1);
+
+                if (!flip) {
+                    normals.push(-vn.x,- vn.y, -vn.z);
+                    normals.push(-vn.x, -vn.y, -vn.z);
+                    normals.push(-vn.x, -vn.y, -vn.z);
+                    normals.push(-vn.x, -vn.y, -vn.z);
+
+                    indices.push(StartIndex);
+                    indices.push(StartIndex + 1);
+                    indices.push(StartIndex + 2);
+
+                    indices.push(StartIndex + 1);
+                    indices.push(StartIndex + 3);
+                    indices.push(StartIndex + 2);
+                }
+                else {
+                    normals.push(vn.x, vn.y, vn.z);
+                    normals.push(vn.x, vn.y, vn.z);
+                    normals.push(vn.x, vn.y, vn.z);
+                    normals.push(vn.x, vn.y, vn.z);
+
+                    indices.push(StartIndex);
+                    indices.push(StartIndex + 2);
+                    indices.push(StartIndex + 1);
+
+                    indices.push(StartIndex + 1);
+                    indices.push(StartIndex + 2);
+                    indices.push(StartIndex + 3);
+                }                
+                StartIndex += 4;
+            };
+        }
+    }
+}

+ 192 - 192
src/Mesh/babylon.subMesh.ts

@@ -1,192 +1,192 @@
-module BABYLON {
-    export class SubMesh {
-        public linesIndexCount: number;
-
-        private _mesh: AbstractMesh;
-        private _renderingMesh: Mesh;
-        private _boundingInfo: BoundingInfo;
-        private _linesIndexBuffer: WebGLBuffer;
-        public _lastColliderWorldVertices: Vector3[];
-        public _trianglePlanes: Plane[];
-        public _lastColliderTransformMatrix: Matrix;
-
-        public _renderId = 0;
-        public _alphaIndex: number;
-        public _distanceToCamera: number;
-        public _id: number;
-
-        constructor(public materialIndex: number, public verticesStart: number, public verticesCount: number, public indexStart, public indexCount: number, mesh: AbstractMesh, renderingMesh?: Mesh, createBoundingBox: boolean = true) {
-            this._mesh = mesh;
-            this._renderingMesh = renderingMesh || <Mesh>mesh;
-            mesh.subMeshes.push(this);
-
-            this._trianglePlanes = [];
-
-            this._id = mesh.subMeshes.length - 1;
-
-            if (createBoundingBox) {
-                this.refreshBoundingInfo();
-                mesh.computeWorldMatrix(true);
-            }
-        }
-
-        public getBoundingInfo(): BoundingInfo {
-            return this._boundingInfo;
-        }
-
-        public getMesh(): AbstractMesh {
-            return this._mesh;
-        }
-
-        public getRenderingMesh(): Mesh {
-            return this._renderingMesh;
-        }
-
-        public getMaterial(): Material {
-            var rootMaterial = this._renderingMesh.material;
-
-            if (rootMaterial && rootMaterial instanceof MultiMaterial) {
-                var multiMaterial = <MultiMaterial>rootMaterial;
-                return multiMaterial.getSubMaterial(this.materialIndex);
-            }
-
-            if (!rootMaterial) {
-                return this._mesh.getScene().defaultMaterial;
-            }
-
-            return rootMaterial;
-        }
-
-        // Methods
-        public refreshBoundingInfo(): void {
-            var data = this._renderingMesh.getVerticesData(VertexBuffer.PositionKind);
-
-            if (!data) {
-                this._boundingInfo = this._mesh._boundingInfo;
-                return;
-            }
-
-            var indices = this._renderingMesh.getIndices();
-            var extend: { minimum: Vector3, maximum: Vector3 };
-
-            //is this the only submesh?
-            if (this.indexStart === 0 && this.indexCount === indices.length) {
-                //the rendering mesh's bounding info can be used, it is the standard submesh for all indices.
-                extend = { minimum: this._renderingMesh.getBoundingInfo().minimum.clone(), maximum: this._renderingMesh.getBoundingInfo().maximum.clone() };
-            } else {
-                extend = Tools.ExtractMinAndMaxIndexed(data, indices, this.indexStart, this.indexCount);
-            }
-            this._boundingInfo = new BoundingInfo(extend.minimum, extend.maximum);
-        }
-
-        public _checkCollision(collider: Collider): boolean {
-            return this._boundingInfo._checkCollision(collider);
-        }
-
-        public updateBoundingInfo(world: Matrix): void {
-            if (!this._boundingInfo) {
-                this.refreshBoundingInfo();
-            }
-            this._boundingInfo._update(world);
-        }
-
-        public isInFrustum(frustumPlanes: Plane[]): boolean {
-            return this._boundingInfo.isInFrustum(frustumPlanes);
-        }
-
-        public render(enableAlphaMode: boolean): void {
-            this._renderingMesh.render(this, enableAlphaMode);
-        }
-
-        public getLinesIndexBuffer(indices: number[] | Int32Array, engine): WebGLBuffer {
-            if (!this._linesIndexBuffer) {
-                var linesIndices = [];
-
-                for (var index = this.indexStart; index < this.indexStart + this.indexCount; index += 3) {
-                    linesIndices.push(indices[index], indices[index + 1],
-                        indices[index + 1], indices[index + 2],
-                        indices[index + 2], indices[index]);
-                }
-
-                this._linesIndexBuffer = engine.createIndexBuffer(linesIndices);
-                this.linesIndexCount = linesIndices.length;
-            }
-            return this._linesIndexBuffer;
-        }
-
-        public canIntersects(ray: Ray): boolean {
-            return ray.intersectsBox(this._boundingInfo.boundingBox);
-        }
-
-        public intersects(ray: Ray, positions: Vector3[], indices: number[] | Int32Array, fastCheck?: boolean): IntersectionInfo {
-            var intersectInfo: IntersectionInfo = null;
-
-            // Triangles test
-            for (var index = this.indexStart; index < this.indexStart + this.indexCount; index += 3) {
-                var p0 = positions[indices[index]];
-                var p1 = positions[indices[index + 1]];
-                var p2 = positions[indices[index + 2]];
-
-                var currentIntersectInfo = ray.intersectsTriangle(p0, p1, p2);
-
-                if (currentIntersectInfo) {
-                    if (currentIntersectInfo.distance < 0) {
-                        continue;
-                    }
-
-                    if (fastCheck || !intersectInfo || currentIntersectInfo.distance < intersectInfo.distance) {
-                        intersectInfo = currentIntersectInfo;
-                        intersectInfo.faceId = index / 3;
-
-                        if (fastCheck) {
-                            break;
-                        }
-                    }
-                }
-            }
-
-            return intersectInfo;
-        }
-
-        // Clone    
-        public clone(newMesh: AbstractMesh, newRenderingMesh?: Mesh): SubMesh {
-            var result = new SubMesh(this.materialIndex, this.verticesStart, this.verticesCount, this.indexStart, this.indexCount, newMesh, newRenderingMesh, false);
-
-            result._boundingInfo = new BoundingInfo(this._boundingInfo.minimum, this._boundingInfo.maximum);
-
-            return result;
-        }
-
-        // Dispose
-        public dispose() {
-            if (this._linesIndexBuffer) {
-                this._mesh.getScene().getEngine()._releaseBuffer(this._linesIndexBuffer);
-                this._linesIndexBuffer = null;
-            }
-
-            // Remove from mesh
-            var index = this._mesh.subMeshes.indexOf(this);
-            this._mesh.subMeshes.splice(index, 1);
-        }
-
-        // Statics
-        public static CreateFromIndices(materialIndex: number, startIndex: number, indexCount: number, mesh: AbstractMesh, renderingMesh?: Mesh): SubMesh {
-            var minVertexIndex = Number.MAX_VALUE;
-            var maxVertexIndex = -Number.MAX_VALUE;
-
-            renderingMesh = renderingMesh || <Mesh>mesh;
-            var indices = renderingMesh.getIndices();
-
-            for (var index = startIndex; index < startIndex + indexCount; index++) {
-                var vertexIndex = indices[index];
-
-                if (vertexIndex < minVertexIndex)
-                    minVertexIndex = vertexIndex;
-                if (vertexIndex > maxVertexIndex)
-                    maxVertexIndex = vertexIndex;
-            }
-
-            return new SubMesh(materialIndex, minVertexIndex, maxVertexIndex - minVertexIndex + 1, startIndex, indexCount, mesh, renderingMesh);
-        }
-    }
-}
+module BABYLON {
+    export class SubMesh {
+        public linesIndexCount: number;
+
+        private _mesh: AbstractMesh;
+        private _renderingMesh: Mesh;
+        private _boundingInfo: BoundingInfo;
+        private _linesIndexBuffer: WebGLBuffer;
+        public _lastColliderWorldVertices: Vector3[];
+        public _trianglePlanes: Plane[];
+        public _lastColliderTransformMatrix: Matrix;
+
+        public _renderId = 0;
+        public _alphaIndex: number;
+        public _distanceToCamera: number;
+        public _id: number;
+
+        constructor(public materialIndex: number, public verticesStart: number, public verticesCount: number, public indexStart, public indexCount: number, mesh: AbstractMesh, renderingMesh?: Mesh, createBoundingBox: boolean = true) {
+            this._mesh = mesh;
+            this._renderingMesh = renderingMesh || <Mesh>mesh;
+            mesh.subMeshes.push(this);
+
+            this._trianglePlanes = [];
+
+            this._id = mesh.subMeshes.length - 1;
+
+            if (createBoundingBox) {
+                this.refreshBoundingInfo();
+                mesh.computeWorldMatrix(true);
+            }
+        }
+
+        public getBoundingInfo(): BoundingInfo {
+            return this._boundingInfo;
+        }
+
+        public getMesh(): AbstractMesh {
+            return this._mesh;
+        }
+
+        public getRenderingMesh(): Mesh {
+            return this._renderingMesh;
+        }
+
+        public getMaterial(): Material {
+            var rootMaterial = this._renderingMesh.material;
+
+            if (rootMaterial && rootMaterial instanceof MultiMaterial) {
+                var multiMaterial = <MultiMaterial>rootMaterial;
+                return multiMaterial.getSubMaterial(this.materialIndex);
+            }
+
+            if (!rootMaterial) {
+                return this._mesh.getScene().defaultMaterial;
+            }
+
+            return rootMaterial;
+        }
+
+        // Methods
+        public refreshBoundingInfo(): void {
+            var data = this._renderingMesh.getVerticesData(VertexBuffer.PositionKind);
+
+            if (!data) {
+                this._boundingInfo = this._mesh._boundingInfo;
+                return;
+            }
+
+            var indices = this._renderingMesh.getIndices();
+            var extend: { minimum: Vector3, maximum: Vector3 };
+
+            //is this the only submesh?
+            if (this.indexStart === 0 && this.indexCount === indices.length) {
+                //the rendering mesh's bounding info can be used, it is the standard submesh for all indices.
+                extend = { minimum: this._renderingMesh.getBoundingInfo().minimum.clone(), maximum: this._renderingMesh.getBoundingInfo().maximum.clone() };
+            } else {
+                extend = Tools.ExtractMinAndMaxIndexed(data, indices, this.indexStart, this.indexCount);
+            }
+            this._boundingInfo = new BoundingInfo(extend.minimum, extend.maximum);
+        }
+
+        public _checkCollision(collider: Collider): boolean {
+            return this._boundingInfo._checkCollision(collider);
+        }
+
+        public updateBoundingInfo(world: Matrix): void {
+            if (!this._boundingInfo) {
+                this.refreshBoundingInfo();
+            }
+            this._boundingInfo._update(world);
+        }
+
+        public isInFrustum(frustumPlanes: Plane[]): boolean {
+            return this._boundingInfo.isInFrustum(frustumPlanes);
+        }
+
+        public render(enableAlphaMode: boolean): void {
+            this._renderingMesh.render(this, enableAlphaMode);
+        }
+
+        public getLinesIndexBuffer(indices: number[] | Int32Array, engine): WebGLBuffer {
+            if (!this._linesIndexBuffer) {
+                var linesIndices = [];
+
+                for (var index = this.indexStart; index < this.indexStart + this.indexCount; index += 3) {
+                    linesIndices.push(indices[index], indices[index + 1],
+                        indices[index + 1], indices[index + 2],
+                        indices[index + 2], indices[index]);
+                }
+
+                this._linesIndexBuffer = engine.createIndexBuffer(linesIndices);
+                this.linesIndexCount = linesIndices.length;
+            }
+            return this._linesIndexBuffer;
+        }
+
+        public canIntersects(ray: Ray): boolean {
+            return ray.intersectsBox(this._boundingInfo.boundingBox);
+        }
+
+        public intersects(ray: Ray, positions: Vector3[], indices: number[] | Int32Array, fastCheck?: boolean): IntersectionInfo {
+            var intersectInfo: IntersectionInfo = null;
+
+            // Triangles test
+            for (var index = this.indexStart; index < this.indexStart + this.indexCount; index += 3) {
+                var p0 = positions[indices[index]];
+                var p1 = positions[indices[index + 1]];
+                var p2 = positions[indices[index + 2]];
+
+                var currentIntersectInfo = ray.intersectsTriangle(p0, p1, p2);
+
+                if (currentIntersectInfo) {
+                    if (currentIntersectInfo.distance < 0) {
+                        continue;
+                    }
+
+                    if (fastCheck || !intersectInfo || currentIntersectInfo.distance < intersectInfo.distance) {
+                        intersectInfo = currentIntersectInfo;
+                        intersectInfo.faceId = index / 3;
+
+                        if (fastCheck) {
+                            break;
+                        }
+                    }
+                }
+            }
+
+            return intersectInfo;
+        }
+
+        // Clone    
+        public clone(newMesh: AbstractMesh, newRenderingMesh?: Mesh): SubMesh {
+            var result = new SubMesh(this.materialIndex, this.verticesStart, this.verticesCount, this.indexStart, this.indexCount, newMesh, newRenderingMesh, false);
+
+            result._boundingInfo = new BoundingInfo(this._boundingInfo.minimum, this._boundingInfo.maximum);
+
+            return result;
+        }
+
+        // Dispose
+        public dispose() {
+            if (this._linesIndexBuffer) {
+                this._mesh.getScene().getEngine()._releaseBuffer(this._linesIndexBuffer);
+                this._linesIndexBuffer = null;
+            }
+
+            // Remove from mesh
+            var index = this._mesh.subMeshes.indexOf(this);
+            this._mesh.subMeshes.splice(index, 1);
+        }
+
+        // Statics
+        public static CreateFromIndices(materialIndex: number, startIndex: number, indexCount: number, mesh: AbstractMesh, renderingMesh?: Mesh): SubMesh {
+            var minVertexIndex = Number.MAX_VALUE;
+            var maxVertexIndex = -Number.MAX_VALUE;
+
+            renderingMesh = renderingMesh || <Mesh>mesh;
+            var indices = renderingMesh.getIndices();
+
+            for (var index = startIndex; index < startIndex + indexCount; index++) {
+                var vertexIndex = indices[index];
+
+                if (vertexIndex < minVertexIndex)
+                    minVertexIndex = vertexIndex;
+                if (vertexIndex > maxVertexIndex)
+                    maxVertexIndex = vertexIndex;
+            }
+
+            return new SubMesh(materialIndex, minVertexIndex, maxVertexIndex - minVertexIndex + 1, startIndex, indexCount, mesh, renderingMesh);
+        }
+    }
+}

+ 193 - 193
src/Mesh/babylon.vertexBuffer.ts

@@ -1,194 +1,194 @@
-module BABYLON {
-    export class VertexBuffer {
-        private _mesh: Mesh;
-        private _engine: Engine;
-        private _buffer: WebGLBuffer;
-        private _data: number[] | Float32Array;
-        private _updatable: boolean;
-        private _kind: string;
-        private _strideSize: number;
-
-        constructor(engine: any, data: number[] | Float32Array, kind: string, updatable: boolean, postponeInternalCreation?: boolean, stride?: number) {
-            if (engine instanceof Mesh) { // old versions of BABYLON.VertexBuffer accepted 'mesh' instead of 'engine'
-                this._engine = engine.getScene().getEngine();
-            }
-            else {
-                this._engine = engine;
-            }
-
-            this._updatable = updatable;
-
-            this._data = data;
-
-            if (!postponeInternalCreation) { // by default
-                this.create();
-            }
-
-            this._kind = kind;
-
-            if (stride) {
-                this._strideSize = stride;
-                return;
-            }
-
-            // Deduce stride from kind
-            switch (kind) {
-                case VertexBuffer.PositionKind:
-                    this._strideSize = 3;
-                    break;
-                case VertexBuffer.NormalKind:
-                    this._strideSize = 3;
-                    break;
-                case VertexBuffer.UVKind:
-                case VertexBuffer.UV2Kind:
-                case VertexBuffer.UV3Kind:
-                case VertexBuffer.UV4Kind:
-                case VertexBuffer.UV5Kind:
-                case VertexBuffer.UV6Kind:
-                    this._strideSize = 2;
-                    break;
-                case VertexBuffer.ColorKind:
-                    this._strideSize = 4;
-                    break;
-                case VertexBuffer.MatricesIndicesKind:
-                case VertexBuffer.MatricesIndicesExtraKind:
-                    this._strideSize = 4;
-                    break;
-                case VertexBuffer.MatricesWeightsKind:
-                case VertexBuffer.MatricesWeightsExtraKind:
-                    this._strideSize = 4;
-                    break;
-            }
-        }
-
-        // Properties
-        public isUpdatable(): boolean {
-            return this._updatable;
-        }
-
-        public getData(): number[] | Float32Array {
-            return this._data;
-        }
-
-        public getBuffer(): WebGLBuffer {
-            return this._buffer;
-        }
-
-        public getStrideSize(): number {
-            return this._strideSize;
-        }
-
-        // Methods
-        public create(data?: number[] | Float32Array): void {
-            if (!data && this._buffer) {
-                return; // nothing to do
-            }
-
-            data = data || this._data;
-
-            if (!this._buffer) { // create buffer
-                if (this._updatable) {
-                    this._buffer = this._engine.createDynamicVertexBuffer(data.length * 4);
-                } else {
-                    this._buffer = this._engine.createVertexBuffer(data);
-                }
-            }
-
-            if (this._updatable) { // update buffer
-                this._engine.updateDynamicVertexBuffer(this._buffer, data);
-                this._data = data;
-            }
-        }
-
-        public update(data: number[] | Float32Array): void {
-            this.create(data);
-        }
-
-        public updateDirectly(data: Float32Array, offset: number): void {
-            if (!this._buffer) {
-                return;
-            }
-
-            if (this._updatable) { // update buffer
-                this._engine.updateDynamicVertexBuffer(this._buffer, data, offset);
-                this._data = null;
-            }
-        }
-
-        public dispose(): void {
-            if (!this._buffer) {
-                return;
-            }
-            if (this._engine._releaseBuffer(this._buffer)) {
-                this._buffer = null;
-            }
-        }
-
-        // Enums
-        private static _PositionKind = "position";
-        private static _NormalKind = "normal";
-        private static _UVKind = "uv";
-        private static _UV2Kind = "uv2";
-        private static _UV3Kind = "uv3";
-        private static _UV4Kind = "uv4";
-        private static _UV5Kind = "uv5";
-        private static _UV6Kind = "uv6";
-        private static _ColorKind = "color";
-        private static _MatricesIndicesKind = "matricesIndices";
-        private static _MatricesWeightsKind = "matricesWeights";
-        private static _MatricesIndicesExtraKind = "matricesIndicesExtra";
-        private static _MatricesWeightsExtraKind = "matricesWeightsExtra";
-
-        public static get PositionKind(): string {
-            return VertexBuffer._PositionKind;
-        }
-
-        public static get NormalKind(): string {
-            return VertexBuffer._NormalKind;
-        }
-
-        public static get UVKind(): string {
-            return VertexBuffer._UVKind;
-        }
-
-        public static get UV2Kind(): string {
-            return VertexBuffer._UV2Kind;
-        }
-
-        public static get UV3Kind(): string {
-            return VertexBuffer._UV3Kind;
-        }
-
-        public static get UV4Kind(): string {
-            return VertexBuffer._UV4Kind;
-        }
-
-        public static get UV5Kind(): string {
-            return VertexBuffer._UV5Kind;
-        }
-
-        public static get UV6Kind(): string {
-            return VertexBuffer._UV6Kind;
-        }
-
-        public static get ColorKind(): string {
-            return VertexBuffer._ColorKind;
-        }
-
-        public static get MatricesIndicesKind(): string {
-            return VertexBuffer._MatricesIndicesKind;
-        }
-
-        public static get MatricesWeightsKind(): string {
-            return VertexBuffer._MatricesWeightsKind;
-        }
-
-        public static get MatricesIndicesExtraKind(): string {
-            return VertexBuffer._MatricesIndicesExtraKind;
-        }
-
-        public static get MatricesWeightsExtraKind(): string {
-            return VertexBuffer._MatricesWeightsExtraKind;
-        }
-    }
+module BABYLON {
+    export class VertexBuffer {
+        private _mesh: Mesh;
+        private _engine: Engine;
+        private _buffer: WebGLBuffer;
+        private _data: number[] | Float32Array;
+        private _updatable: boolean;
+        private _kind: string;
+        private _strideSize: number;
+
+        constructor(engine: any, data: number[] | Float32Array, kind: string, updatable: boolean, postponeInternalCreation?: boolean, stride?: number) {
+            if (engine instanceof Mesh) { // old versions of BABYLON.VertexBuffer accepted 'mesh' instead of 'engine'
+                this._engine = engine.getScene().getEngine();
+            }
+            else {
+                this._engine = engine;
+            }
+
+            this._updatable = updatable;
+
+            this._data = data;
+
+            if (!postponeInternalCreation) { // by default
+                this.create();
+            }
+
+            this._kind = kind;
+
+            if (stride) {
+                this._strideSize = stride;
+                return;
+            }
+
+            // Deduce stride from kind
+            switch (kind) {
+                case VertexBuffer.PositionKind:
+                    this._strideSize = 3;
+                    break;
+                case VertexBuffer.NormalKind:
+                    this._strideSize = 3;
+                    break;
+                case VertexBuffer.UVKind:
+                case VertexBuffer.UV2Kind:
+                case VertexBuffer.UV3Kind:
+                case VertexBuffer.UV4Kind:
+                case VertexBuffer.UV5Kind:
+                case VertexBuffer.UV6Kind:
+                    this._strideSize = 2;
+                    break;
+                case VertexBuffer.ColorKind:
+                    this._strideSize = 4;
+                    break;
+                case VertexBuffer.MatricesIndicesKind:
+                case VertexBuffer.MatricesIndicesExtraKind:
+                    this._strideSize = 4;
+                    break;
+                case VertexBuffer.MatricesWeightsKind:
+                case VertexBuffer.MatricesWeightsExtraKind:
+                    this._strideSize = 4;
+                    break;
+            }
+        }
+
+        // Properties
+        public isUpdatable(): boolean {
+            return this._updatable;
+        }
+
+        public getData(): number[] | Float32Array {
+            return this._data;
+        }
+
+        public getBuffer(): WebGLBuffer {
+            return this._buffer;
+        }
+
+        public getStrideSize(): number {
+            return this._strideSize;
+        }
+
+        // Methods
+        public create(data?: number[] | Float32Array): void {
+            if (!data && this._buffer) {
+                return; // nothing to do
+            }
+
+            data = data || this._data;
+
+            if (!this._buffer) { // create buffer
+                if (this._updatable) {
+                    this._buffer = this._engine.createDynamicVertexBuffer(data.length * 4);
+                } else {
+                    this._buffer = this._engine.createVertexBuffer(data);
+                }
+            }
+
+            if (this._updatable) { // update buffer
+                this._engine.updateDynamicVertexBuffer(this._buffer, data);
+                this._data = data;
+            }
+        }
+
+        public update(data: number[] | Float32Array): void {
+            this.create(data);
+        }
+
+        public updateDirectly(data: Float32Array, offset: number): void {
+            if (!this._buffer) {
+                return;
+            }
+
+            if (this._updatable) { // update buffer
+                this._engine.updateDynamicVertexBuffer(this._buffer, data, offset);
+                this._data = null;
+            }
+        }
+
+        public dispose(): void {
+            if (!this._buffer) {
+                return;
+            }
+            if (this._engine._releaseBuffer(this._buffer)) {
+                this._buffer = null;
+            }
+        }
+
+        // Enums
+        private static _PositionKind = "position";
+        private static _NormalKind = "normal";
+        private static _UVKind = "uv";
+        private static _UV2Kind = "uv2";
+        private static _UV3Kind = "uv3";
+        private static _UV4Kind = "uv4";
+        private static _UV5Kind = "uv5";
+        private static _UV6Kind = "uv6";
+        private static _ColorKind = "color";
+        private static _MatricesIndicesKind = "matricesIndices";
+        private static _MatricesWeightsKind = "matricesWeights";
+        private static _MatricesIndicesExtraKind = "matricesIndicesExtra";
+        private static _MatricesWeightsExtraKind = "matricesWeightsExtra";
+
+        public static get PositionKind(): string {
+            return VertexBuffer._PositionKind;
+        }
+
+        public static get NormalKind(): string {
+            return VertexBuffer._NormalKind;
+        }
+
+        public static get UVKind(): string {
+            return VertexBuffer._UVKind;
+        }
+
+        public static get UV2Kind(): string {
+            return VertexBuffer._UV2Kind;
+        }
+
+        public static get UV3Kind(): string {
+            return VertexBuffer._UV3Kind;
+        }
+
+        public static get UV4Kind(): string {
+            return VertexBuffer._UV4Kind;
+        }
+
+        public static get UV5Kind(): string {
+            return VertexBuffer._UV5Kind;
+        }
+
+        public static get UV6Kind(): string {
+            return VertexBuffer._UV6Kind;
+        }
+
+        public static get ColorKind(): string {
+            return VertexBuffer._ColorKind;
+        }
+
+        public static get MatricesIndicesKind(): string {
+            return VertexBuffer._MatricesIndicesKind;
+        }
+
+        public static get MatricesWeightsKind(): string {
+            return VertexBuffer._MatricesWeightsKind;
+        }
+
+        public static get MatricesIndicesExtraKind(): string {
+            return VertexBuffer._MatricesIndicesExtraKind;
+        }
+
+        public static get MatricesWeightsExtraKind(): string {
+            return VertexBuffer._MatricesWeightsExtraKind;
+        }
+    }
 } 

+ 24 - 24
src/Particles/babylon.particle.ts

@@ -1,25 +1,25 @@
-module BABYLON {
-    export class Particle {
-        public position = Vector3.Zero();
-        public direction = Vector3.Zero();
-        public color = new Color4(0, 0, 0, 0);
-        public colorStep = new Color4(0, 0, 0, 0);
-        public lifeTime = 1.0;
-        public age = 0;
-        public size = 0;
-        public angle = 0;
-        public angularSpeed = 0;
-
-        public copyTo(other: Particle) {
-            other.position.copyFrom(this.position);
-            other.direction.copyFrom(this.direction);
-            other.color.copyFrom(this.color);
-            other.colorStep.copyFrom(this.colorStep);
-            other.lifeTime = this.lifeTime;
-            other.age = this.age;
-            other.size = this.size;
-            other.angle = this.angle;
-            other.angularSpeed = this.angularSpeed;
-        }
-    }
+module BABYLON {
+    export class Particle {
+        public position = Vector3.Zero();
+        public direction = Vector3.Zero();
+        public color = new Color4(0, 0, 0, 0);
+        public colorStep = new Color4(0, 0, 0, 0);
+        public lifeTime = 1.0;
+        public age = 0;
+        public size = 0;
+        public angle = 0;
+        public angularSpeed = 0;
+
+        public copyTo(other: Particle) {
+            other.position.copyFrom(this.position);
+            other.direction.copyFrom(this.direction);
+            other.color.copyFrom(this.color);
+            other.colorStep.copyFrom(this.colorStep);
+            other.lifeTime = this.lifeTime;
+            other.age = this.age;
+            other.size = this.size;
+            other.angle = this.angle;
+            other.angularSpeed = this.angularSpeed;
+        }
+    }
 } 

+ 44 - 44
src/Particles/babylon.solidParticle.ts

@@ -1,44 +1,44 @@
-module BABYLON {
-
-    export class SolidParticle {
-        public idx: number;                     // particle global index
-        public color = new Color4(1, 1, 1, 1);  // color
-        public position = Vector3.Zero();       // position
-        public rotation = Vector3.Zero();       // rotation
-        public quaternion: Vector4;             // quaternion, will overwrite rotation
-        public scale = new Vector3(1, 1, 1);    // scale
-        public uvs = new Vector4(0, 0, 1, 1);   // uvs
-        public velocity = Vector3.Zero();       // velocity
-        public alive = true;                    // alive
-        public _pos: number;                    // index of this particle in the global "positions" array
-        public _model: ModelShape;              // model shape reference
-        public shapeId: number;                 // model shape id
-        public idxInShape: number;              // index of the particle in its shape id
-
-        constructor(particleIndex: number, positionIndex: number, model: ModelShape, shapeId: number, idxInShape: number) {
-            this.idx = particleIndex;
-            this._pos = positionIndex;
-            this._model = model;
-            this.shapeId = shapeId;
-            this.idxInShape = idxInShape;
-        }
-    }
-
-    export class ModelShape {
-        public shapeID: number;
-        public _shape: Vector3[];
-        public _shapeUV: number[];
-        public _positionFunction: (particle: SolidParticle, i: number, s: number) => void;
-        public _vertexFunction: (particle: SolidParticle, vertex: Vector3, i: number) => void;
-
-        constructor(id: number, shape: Vector3[], shapeUV: number[], posFunction: (particle: SolidParticle, i: number, s: number) => void, vtxFunction: (particle: SolidParticle, vertex: Vector3, i: number) => void) {
-            this.shapeID = id;
-            this._shape = shape;
-            this._shapeUV = shapeUV;
-            this._positionFunction = posFunction;
-            this._vertexFunction = vtxFunction;
-        }
-    }
-}
-
-
+module BABYLON {
+
+    export class SolidParticle {
+        public idx: number;                     // particle global index
+        public color = new Color4(1, 1, 1, 1);  // color
+        public position = Vector3.Zero();       // position
+        public rotation = Vector3.Zero();       // rotation
+        public quaternion: Vector4;             // quaternion, will overwrite rotation
+        public scale = new Vector3(1, 1, 1);    // scale
+        public uvs = new Vector4(0, 0, 1, 1);   // uvs
+        public velocity = Vector3.Zero();       // velocity
+        public alive = true;                    // alive
+        public _pos: number;                    // index of this particle in the global "positions" array
+        public _model: ModelShape;              // model shape reference
+        public shapeId: number;                 // model shape id
+        public idxInShape: number;              // index of the particle in its shape id
+
+        constructor(particleIndex: number, positionIndex: number, model: ModelShape, shapeId: number, idxInShape: number) {
+            this.idx = particleIndex;
+            this._pos = positionIndex;
+            this._model = model;
+            this.shapeId = shapeId;
+            this.idxInShape = idxInShape;
+        }
+    }
+
+    export class ModelShape {
+        public shapeID: number;
+        public _shape: Vector3[];
+        public _shapeUV: number[];
+        public _positionFunction: (particle: SolidParticle, i: number, s: number) => void;
+        public _vertexFunction: (particle: SolidParticle, vertex: Vector3, i: number) => void;
+
+        constructor(id: number, shape: Vector3[], shapeUV: number[], posFunction: (particle: SolidParticle, i: number, s: number) => void, vtxFunction: (particle: SolidParticle, vertex: Vector3, i: number) => void) {
+            this.shapeID = id;
+            this._shape = shape;
+            this._shapeUV = shapeUV;
+            this._positionFunction = posFunction;
+            this._vertexFunction = vtxFunction;
+        }
+    }
+}
+
+

Разница между файлами не показана из-за своего большого размера
+ 636 - 636
src/Particles/babylon.solidParticleSystem.ts


+ 489 - 489
src/Physics/Plugins/babylon.cannonJSPlugin.ts

@@ -1,490 +1,490 @@
-module BABYLON {
-    declare var CANNON;
-
-    interface IRegisteredMesh {
-        mesh: AbstractMesh;
-        body: any; //Cannon body
-        material: any;
-        delta: Vector3;
-        deltaRotation: Quaternion;
-        heightmap: boolean;
-        collisionFunction?: (event: any) => void;
-
-    }
-
-    export class CannonJSPlugin implements IPhysicsEnginePlugin {
-
-        private _world: any;
-        private _registeredMeshes: Array<IRegisteredMesh> = [];
-        private _physicsMaterials = [];
-        private _gravity: Vector3;
-
-        public name = "cannon";
-
-        public initialize(iterations: number = 10): void {
-            this._world = new CANNON.World();
-            this._world.broadphase = new CANNON.NaiveBroadphase();
-            this._world.solver.iterations = iterations;
-        }
-
-        private _checkWithEpsilon(value: number): number {
-            return value < PhysicsEngine.Epsilon ? PhysicsEngine.Epsilon : value;
-        }
-
-        public runOneStep(delta: number): void {
-            this._world.step(delta);
-
-            this._registeredMeshes.forEach((registeredMesh) => {
-
-                // Body position
-                var bodyX = registeredMesh.body.position.x,
-                    bodyY = registeredMesh.body.position.y,
-                    bodyZ = registeredMesh.body.position.z;
-
-                registeredMesh.mesh.position.x = bodyX + registeredMesh.delta.x;
-                registeredMesh.mesh.position.y = bodyY + registeredMesh.delta.y;
-                registeredMesh.mesh.position.z = bodyZ + registeredMesh.delta.z;
-
-                registeredMesh.mesh.rotationQuaternion.copyFrom(registeredMesh.body.quaternion);
-                if (registeredMesh.deltaRotation) {
-                    registeredMesh.mesh.rotationQuaternion.multiplyInPlace(registeredMesh.deltaRotation);
-                }
-
-                //is the physics collision callback is set?
-                if (registeredMesh.mesh.onPhysicsCollide) {
-                    if (!registeredMesh.collisionFunction) {
-                        registeredMesh.collisionFunction = (e) => {
-                            //find the mesh that collided with the registered mesh
-                            for (var idx = 0; idx < this._registeredMeshes.length; idx++) {
-                                if (this._registeredMeshes[idx].body == e.body) {
-                                    registeredMesh.mesh.onPhysicsCollide(this._registeredMeshes[idx].mesh);
-                                }
-                            }
-                        }
-                        registeredMesh.body.addEventListener("collide", registeredMesh.collisionFunction);
-                    }
-                } else {
-                    //unregister, in case the function was removed for some reason
-                    if (registeredMesh.collisionFunction) {
-                        registeredMesh.body.removeEventListener("collide", registeredMesh.collisionFunction);
-                    }
-                }
-            });
-        }
-
-        public setGravity(gravity: Vector3): void {
-            this._gravity = gravity;
-            this._world.gravity.set(gravity.x, gravity.y, gravity.z);
-        }
-
-        public getGravity(): Vector3 {
-            return this._gravity;
-        }
-
-        public registerMesh(mesh: AbstractMesh, impostor: number, options?: PhysicsBodyCreationOptions): any {
-            this.unregisterMesh(mesh);
-
-            if (!mesh.rotationQuaternion) {
-                mesh.rotationQuaternion = Quaternion.RotationYawPitchRoll(mesh.rotation.y, mesh.rotation.x, mesh.rotation.z);
-            }
-
-            mesh.computeWorldMatrix(true);
-
-            var shape = this._createShape(mesh, impostor);
-
-            return this._createRigidBodyFromShape(shape, mesh, options);
-        }
-
-        private _createShape(mesh: AbstractMesh, impostor: number) {
-		
-            //get the correct bounding box
-            var oldQuaternion = mesh.rotationQuaternion;
-            mesh.rotationQuaternion = new Quaternion(0, 0, 0, 1);
-            mesh.computeWorldMatrix(true);
-
-            var returnValue;
-
-            switch (impostor) {
-                case PhysicsEngine.SphereImpostor:
-                    var bbox = mesh.getBoundingInfo().boundingBox;
-                    var radiusX = bbox.maximumWorld.x - bbox.minimumWorld.x;
-                    var radiusY = bbox.maximumWorld.y - bbox.minimumWorld.y;
-                    var radiusZ = bbox.maximumWorld.z - bbox.minimumWorld.z;
-
-                    returnValue = new CANNON.Sphere(Math.max(this._checkWithEpsilon(radiusX), this._checkWithEpsilon(radiusY), this._checkWithEpsilon(radiusZ)) / 2);
-
-                    break;
-                //TMP also for cylinder - TODO Cannon supports cylinder natively.
-                case PhysicsEngine.CylinderImpostor:
-                    Tools.Warn("CylinderImposter not yet implemented, using BoxImposter instead");
-                case PhysicsEngine.BoxImpostor:
-                    bbox = mesh.getBoundingInfo().boundingBox;
-                    var min = bbox.minimumWorld;
-                    var max = bbox.maximumWorld;
-                    var box = max.subtract(min).scale(0.5);
-                    returnValue = new CANNON.Box(new CANNON.Vec3(this._checkWithEpsilon(box.x), this._checkWithEpsilon(box.y), this._checkWithEpsilon(box.z)));
-                    break;
-                case PhysicsEngine.PlaneImpostor:
-                    Tools.Warn("Attention, Cannon.js PlaneImposter might not behave as you wish. Consider using BoxImposter instead");
-                    returnValue = new CANNON.Plane();
-                    break;
-                case PhysicsEngine.MeshImpostor:
-                    var rawVerts = mesh.getVerticesData(VertexBuffer.PositionKind);
-                    var rawFaces = mesh.getIndices();
-
-                    returnValue = this._createConvexPolyhedron(rawVerts, rawFaces, mesh);
-                    break;
-                case PhysicsEngine.HeightmapImpostor:
-                    returnValue = this._createHeightmap(mesh);
-                    break;
-
-            }
-
-            mesh.rotationQuaternion = oldQuaternion;
-
-            return returnValue;
-        }
-
-        private _createConvexPolyhedron(rawVerts: number[] | Float32Array, rawFaces: number[] | Int32Array, mesh: AbstractMesh): any {
-            var verts = [], faces = [];
-
-            mesh.computeWorldMatrix(true);
-
-            //reuse this variable
-            var transformed = Vector3.Zero();
-            // Get vertices
-            for (var i = 0; i < rawVerts.length; i += 3) {
-                Vector3.TransformNormalFromFloatsToRef(rawVerts[i], rawVerts[i + 1], rawVerts[i + 2], mesh.getWorldMatrix(), transformed);
-                verts.push(new CANNON.Vec3(transformed.x, transformed.y, transformed.z));
-            }
-
-            // Get faces
-            for (var j = 0; j < rawFaces.length; j += 3) {
-                faces.push([rawFaces[j], rawFaces[j + 2], rawFaces[j + 1]]);
-            }
-
-            var shape = new CANNON.ConvexPolyhedron(verts, faces);
-
-            return shape;
-        }
-
-        private _createHeightmap(mesh: AbstractMesh, pointDepth?: number) {
-            var pos = mesh.getVerticesData(VertexBuffer.PositionKind);
-            var matrix = [];
-    
-            //For now pointDepth will not be used and will be automatically calculated.
-            //Future reference - try and find the best place to add a reference to the pointDepth variable.
-            var arraySize = pointDepth || ~~(Math.sqrt(pos.length / 3) - 1);
-
-            var dim = Math.min(mesh.getBoundingInfo().boundingBox.extendSize.x, mesh.getBoundingInfo().boundingBox.extendSize.z);
-
-            var elementSize = dim * 2 / arraySize;
-
-            var minY = mesh.getBoundingInfo().boundingBox.extendSize.y;
-
-            for (var i = 0; i < pos.length; i = i + 3) {
-                var x = Math.round((pos[i + 0]) / elementSize + arraySize / 2);
-                var z = Math.round(((pos[i + 2]) / elementSize - arraySize / 2) * -1);
-                var y = pos[i + 1] + minY;
-                if (!matrix[x]) {
-                    matrix[x] = [];
-                }
-                if (!matrix[x][z]) {
-                    matrix[x][z] = y;
-                }
-                matrix[x][z] = Math.max(y, matrix[x][z]);
-            }
-
-
-            for (var x = 0; x <= arraySize; ++x) {
-                if (!matrix[x]) {
-                    var loc = 1;
-                    while (!matrix[(x + loc) % arraySize]) {
-                        loc++;
-                    }
-                    matrix[x] = matrix[(x + loc) % arraySize].slice();
-                    //console.log("missing x", x);
-                }
-                for (var z = 0; z <= arraySize; ++z) {
-                    if (!matrix[x][z]) {
-                        var loc = 1;
-                        var newValue;
-                        while (newValue === undefined) {
-                            newValue = matrix[x][(z + loc++) % arraySize];
-                        }
-                        matrix[x][z] = newValue;
-
-                    }
-                }
-            }
-
-            var shape = new CANNON.Heightfield(matrix, {
-                elementSize: elementSize
-            });
-            
-            //For future reference, needed for body transformation
-            shape.minY = minY;
-
-            return shape;
-        }
-
-        private _addMaterial(friction: number, restitution: number) {
-            var index;
-            var mat;
-
-            for (index = 0; index < this._physicsMaterials.length; index++) {
-                mat = this._physicsMaterials[index];
-
-                if (mat.friction === friction && mat.restitution === restitution) {
-                    return mat;
-                }
-            }
-
-            var currentMat = new CANNON.Material("mat");
-            this._physicsMaterials.push(currentMat);
-
-            for (index = 0; index < this._physicsMaterials.length; index++) {
-                mat = this._physicsMaterials[index];
-
-                var contactMaterial = new CANNON.ContactMaterial(mat, currentMat, { friction: friction, restitution: restitution });
-
-                this._world.addContactMaterial(contactMaterial);
-            }
-
-            return currentMat;
-        }
-
-        private _createRigidBodyFromShape(shape: any, mesh: AbstractMesh, options: PhysicsBodyCreationOptions): any {
-            if (!mesh.rotationQuaternion) {
-                mesh.rotationQuaternion = Quaternion.RotationYawPitchRoll(mesh.rotation.y, mesh.rotation.x, mesh.rotation.z);
-            }
-            
-            // The delta between the mesh position and the mesh bounding box center
-            var bbox = mesh.getBoundingInfo().boundingBox;
-            var deltaPosition = mesh.position.subtract(bbox.center);
-            var deltaRotation;
-
-            var material = this._addMaterial(options.friction, options.restitution);
-            var body = new CANNON.Body({
-                mass: options.mass,
-                material: material,
-                position: new CANNON.Vec3(bbox.center.x, bbox.center.y, bbox.center.z)
-            });
-
-            body.quaternion = new CANNON.Quaternion(mesh.rotationQuaternion.x, mesh.rotationQuaternion.y, mesh.rotationQuaternion.z, mesh.rotationQuaternion.w);
-            //is shape is a plane or a heightmap, it must be rotated 90 degs in the X axis.
-            if (shape.type === CANNON.Shape.types.PLANE || shape.type === CANNON.Shape.types.HEIGHTFIELD) {
-                //-90 DEG in X, precalculated
-                var tmpQ = new CANNON.Quaternion(-0.7071067811865475, 0, 0, 0.7071067811865475);
-                body.quaternion = body.quaternion.mult(tmpQ);
-                //Invert! (Precalculated, 90 deg in X)
-                deltaRotation = new Quaternion(0.7071067811865475, 0, 0, 0.7071067811865475);
-            }
-            
-            //If it is a heightfield, if should be centered.
-            if (shape.type === CANNON.Shape.types.HEIGHTFIELD) {
-                
-                //calculate the correct body position:
-                var rotationQuaternion = mesh.rotationQuaternion;
-                mesh.rotationQuaternion = new BABYLON.Quaternion();
-                mesh.computeWorldMatrix(true);
-                
-                //get original center with no rotation
-                var center = mesh.getBoundingInfo().boundingBox.center.clone();
-
-                var oldPivot = mesh.getPivotMatrix() || Matrix.Translation(0, 0, 0);
-                
-                //rotation is back
-                mesh.rotationQuaternion = rotationQuaternion;
-        
-                //calculate the new center using a pivot (since Cannon.js doesn't center height maps)
-                var p = Matrix.Translation(mesh.getBoundingInfo().boundingBox.extendSize.x, 0, -mesh.getBoundingInfo().boundingBox.extendSize.z);
-                mesh.setPivotMatrix(p);
-                mesh.computeWorldMatrix(true);
-        
-                //calculate the translation
-                var translation = mesh.getBoundingInfo().boundingBox.center.subtract(center).subtract(mesh.position).negate();
-
-                body.position = new CANNON.Vec3(translation.x, translation.y - mesh.getBoundingInfo().boundingBox.extendSize.y, translation.z);
-                //add it inverted to the delta 
-                deltaPosition = mesh.getBoundingInfo().boundingBox.center.subtract(center);
-                deltaPosition.y += mesh.getBoundingInfo().boundingBox.extendSize.y;
-
-                mesh.setPivotMatrix(oldPivot);
-                mesh.computeWorldMatrix(true);
-            }
-            
-            //add the shape
-            body.addShape(shape);
-
-            this._world.add(body);
-
-            this._registeredMeshes.push({ mesh: mesh, body: body, material: material, delta: deltaPosition, deltaRotation: deltaRotation, heightmap: shape.type === CANNON.Shape.types.HEIGHTFIELD });
-
-            return body;
-        }
-
-        public registerMeshesAsCompound(parts: PhysicsCompoundBodyPart[], options: PhysicsBodyCreationOptions): any {
-
-            var initialMesh = parts[0].mesh;
-
-            this.unregisterMesh(initialMesh);
-
-            initialMesh.computeWorldMatrix(true);
-
-            var initialShape = this._createShape(initialMesh, parts[0].impostor);
-            var body = this._createRigidBodyFromShape(initialShape, initialMesh, options);
-
-            for (var index = 1; index < parts.length; index++) {
-                var mesh = parts[index].mesh;
-                mesh.computeWorldMatrix(true);
-                var shape = this._createShape(mesh, parts[index].impostor);
-                var localPosition = mesh.position;
-
-                body.addShape(shape, new CANNON.Vec3(localPosition.x, localPosition.y, localPosition.z));
-            }
-
-            return body;
-        }
-
-        private _unbindBody(body): void {
-            for (var index = 0; index < this._registeredMeshes.length; index++) {
-                var registeredMesh = this._registeredMeshes[index];
-
-                if (registeredMesh.body === body) {
-                    this._world.remove(registeredMesh.body);
-                    registeredMesh.body = null;
-                    registeredMesh.delta = null;
-                    registeredMesh.deltaRotation = null;
-                }
-            }
-        }
-
-        public unregisterMesh(mesh: AbstractMesh): void {
-            for (var index = 0; index < this._registeredMeshes.length; index++) {
-                var registeredMesh = this._registeredMeshes[index];
-
-                if (registeredMesh.mesh === mesh) {
-                    // Remove body
-                    if (registeredMesh.body) {
-                        this._unbindBody(registeredMesh.body);
-                    }
-
-                    this._registeredMeshes.splice(index, 1);
-                    return;
-                }
-            }
-        }
-
-        public applyImpulse(mesh: AbstractMesh, force: Vector3, contactPoint: Vector3): void {
-            var worldPoint = new CANNON.Vec3(contactPoint.x, contactPoint.y, contactPoint.z);
-            var impulse = new CANNON.Vec3(force.x, force.y, force.z);
-
-            for (var index = 0; index < this._registeredMeshes.length; index++) {
-                var registeredMesh = this._registeredMeshes[index];
-
-                if (registeredMesh.mesh === mesh) {
-                    registeredMesh.body.applyImpulse(impulse, worldPoint);
-                    return;
-                }
-            }
-        }
-
-        public updateBodyPosition = function (mesh: AbstractMesh): void {
-            for (var index = 0; index < this._registeredMeshes.length; index++) {
-                var registeredMesh = this._registeredMeshes[index];
-                if (registeredMesh.mesh === mesh || registeredMesh.mesh === mesh.parent) {
-                    var body = registeredMesh.body;
-
-                    var center = mesh.getBoundingInfo().boundingBox.center;
-                    body.position.set(center.x, center.y, center.z);
-
-                    body.quaternion.copy(mesh.rotationQuaternion);
-
-                    if (registeredMesh.deltaRotation) {
-                        var tmpQ = new CANNON.Quaternion(-0.7071067811865475, 0, 0, 0.7071067811865475);
-                        body.quaternion = body.quaternion.mult(tmpQ);
-                    }
-
-                    if (registeredMesh.heightmap) {
-                        //calculate the correct body position:
-                        var rotationQuaternion = mesh.rotationQuaternion;
-                        mesh.rotationQuaternion = new BABYLON.Quaternion();
-                        mesh.computeWorldMatrix(true);
-                        
-                        //get original center with no rotation
-                        var center = mesh.getBoundingInfo().boundingBox.center.clone();
-
-                        var oldPivot = mesh.getPivotMatrix() || Matrix.Translation(0, 0, 0);
-                        
-                        //rotation is back
-                        mesh.rotationQuaternion = rotationQuaternion;
-                
-                        //calculate the new center using a pivot (since Cannon.js doesn't center height maps)
-                        var p = Matrix.Translation(mesh.getBoundingInfo().boundingBox.extendSize.x, 0, -mesh.getBoundingInfo().boundingBox.extendSize.z);
-                        mesh.setPivotMatrix(p);
-                        mesh.computeWorldMatrix(true);
-                
-                        //calculate the translation
-                        var translation = mesh.getBoundingInfo().boundingBox.center.subtract(center).subtract(mesh.position).negate();
-
-                        body.position = new CANNON.Vec3(translation.x, translation.y - mesh.getBoundingInfo().boundingBox.extendSize.y, translation.z);
-                        //add it inverted to the delta 
-                        registeredMesh.delta = mesh.getBoundingInfo().boundingBox.center.subtract(center);
-                        registeredMesh.delta.y += mesh.getBoundingInfo().boundingBox.extendSize.y;
-
-                        mesh.setPivotMatrix(oldPivot);
-                        mesh.computeWorldMatrix(true);
-                    }
-                    return;
-                }
-            }
-        }
-
-        public createLink(mesh1: AbstractMesh, mesh2: AbstractMesh, pivot1: Vector3, pivot2: Vector3): boolean {
-            var body1 = null, body2 = null;
-            for (var index = 0; index < this._registeredMeshes.length; index++) {
-                var registeredMesh = this._registeredMeshes[index];
-
-                if (registeredMesh.mesh === mesh1) {
-                    body1 = registeredMesh.body;
-                } else if (registeredMesh.mesh === mesh2) {
-                    body2 = registeredMesh.body;
-                }
-            }
-
-            if (!body1 || !body2) {
-                return false;
-            }
-
-            var constraint = new CANNON.PointToPointConstraint(body1, new CANNON.Vec3(pivot1.x, pivot1.y, pivot1.z), body2, new CANNON.Vec3(pivot2.x, pivot2.y, pivot2.z));
-            this._world.addConstraint(constraint);
-
-            return true;
-        }
-
-        public dispose(): void {
-            while (this._registeredMeshes.length) {
-                this.unregisterMesh(this._registeredMeshes[0].mesh);
-            }
-        }
-
-        public isSupported(): boolean {
-            return window.CANNON !== undefined;
-        }
-
-        public getWorldObject(): any {
-            return this._world;
-        }
-
-        public getPhysicsBodyOfMesh(mesh: AbstractMesh) {
-            for (var index = 0; index < this._registeredMeshes.length; index++) {
-                var registeredMesh = this._registeredMeshes[index];
-                if (registeredMesh.mesh === mesh) {
-                    return registeredMesh.body;
-                }
-            }
-            return null;
-        }
-    }
+module BABYLON {
+    declare var CANNON;
+
+    interface IRegisteredMesh {
+        mesh: AbstractMesh;
+        body: any; //Cannon body
+        material: any;
+        delta: Vector3;
+        deltaRotation: Quaternion;
+        heightmap: boolean;
+        collisionFunction?: (event: any) => void;
+
+    }
+
+    export class CannonJSPlugin implements IPhysicsEnginePlugin {
+
+        private _world: any;
+        private _registeredMeshes: Array<IRegisteredMesh> = [];
+        private _physicsMaterials = [];
+        private _gravity: Vector3;
+
+        public name = "cannon";
+
+        public initialize(iterations: number = 10): void {
+            this._world = new CANNON.World();
+            this._world.broadphase = new CANNON.NaiveBroadphase();
+            this._world.solver.iterations = iterations;
+        }
+
+        private _checkWithEpsilon(value: number): number {
+            return value < PhysicsEngine.Epsilon ? PhysicsEngine.Epsilon : value;
+        }
+
+        public runOneStep(delta: number): void {
+            this._world.step(delta);
+
+            this._registeredMeshes.forEach((registeredMesh) => {
+
+                // Body position
+                var bodyX = registeredMesh.body.position.x,
+                    bodyY = registeredMesh.body.position.y,
+                    bodyZ = registeredMesh.body.position.z;
+
+                registeredMesh.mesh.position.x = bodyX + registeredMesh.delta.x;
+                registeredMesh.mesh.position.y = bodyY + registeredMesh.delta.y;
+                registeredMesh.mesh.position.z = bodyZ + registeredMesh.delta.z;
+
+                registeredMesh.mesh.rotationQuaternion.copyFrom(registeredMesh.body.quaternion);
+                if (registeredMesh.deltaRotation) {
+                    registeredMesh.mesh.rotationQuaternion.multiplyInPlace(registeredMesh.deltaRotation);
+                }
+
+                //is the physics collision callback is set?
+                if (registeredMesh.mesh.onPhysicsCollide) {
+                    if (!registeredMesh.collisionFunction) {
+                        registeredMesh.collisionFunction = (e) => {
+                            //find the mesh that collided with the registered mesh
+                            for (var idx = 0; idx < this._registeredMeshes.length; idx++) {
+                                if (this._registeredMeshes[idx].body == e.body) {
+                                    registeredMesh.mesh.onPhysicsCollide(this._registeredMeshes[idx].mesh);
+                                }
+                            }
+                        }
+                        registeredMesh.body.addEventListener("collide", registeredMesh.collisionFunction);
+                    }
+                } else {
+                    //unregister, in case the function was removed for some reason
+                    if (registeredMesh.collisionFunction) {
+                        registeredMesh.body.removeEventListener("collide", registeredMesh.collisionFunction);
+                    }
+                }
+            });
+        }
+
+        public setGravity(gravity: Vector3): void {
+            this._gravity = gravity;
+            this._world.gravity.set(gravity.x, gravity.y, gravity.z);
+        }
+
+        public getGravity(): Vector3 {
+            return this._gravity;
+        }
+
+        public registerMesh(mesh: AbstractMesh, impostor: number, options?: PhysicsBodyCreationOptions): any {
+            this.unregisterMesh(mesh);
+
+            if (!mesh.rotationQuaternion) {
+                mesh.rotationQuaternion = Quaternion.RotationYawPitchRoll(mesh.rotation.y, mesh.rotation.x, mesh.rotation.z);
+            }
+
+            mesh.computeWorldMatrix(true);
+
+            var shape = this._createShape(mesh, impostor);
+
+            return this._createRigidBodyFromShape(shape, mesh, options);
+        }
+
+        private _createShape(mesh: AbstractMesh, impostor: number) {
+		
+            //get the correct bounding box
+            var oldQuaternion = mesh.rotationQuaternion;
+            mesh.rotationQuaternion = new Quaternion(0, 0, 0, 1);
+            mesh.computeWorldMatrix(true);
+
+            var returnValue;
+
+            switch (impostor) {
+                case PhysicsEngine.SphereImpostor:
+                    var bbox = mesh.getBoundingInfo().boundingBox;
+                    var radiusX = bbox.maximumWorld.x - bbox.minimumWorld.x;
+                    var radiusY = bbox.maximumWorld.y - bbox.minimumWorld.y;
+                    var radiusZ = bbox.maximumWorld.z - bbox.minimumWorld.z;
+
+                    returnValue = new CANNON.Sphere(Math.max(this._checkWithEpsilon(radiusX), this._checkWithEpsilon(radiusY), this._checkWithEpsilon(radiusZ)) / 2);
+
+                    break;
+                //TMP also for cylinder - TODO Cannon supports cylinder natively.
+                case PhysicsEngine.CylinderImpostor:
+                    Tools.Warn("CylinderImposter not yet implemented, using BoxImposter instead");
+                case PhysicsEngine.BoxImpostor:
+                    bbox = mesh.getBoundingInfo().boundingBox;
+                    var min = bbox.minimumWorld;
+                    var max = bbox.maximumWorld;
+                    var box = max.subtract(min).scale(0.5);
+                    returnValue = new CANNON.Box(new CANNON.Vec3(this._checkWithEpsilon(box.x), this._checkWithEpsilon(box.y), this._checkWithEpsilon(box.z)));
+                    break;
+                case PhysicsEngine.PlaneImpostor:
+                    Tools.Warn("Attention, Cannon.js PlaneImposter might not behave as you wish. Consider using BoxImposter instead");
+                    returnValue = new CANNON.Plane();
+                    break;
+                case PhysicsEngine.MeshImpostor:
+                    var rawVerts = mesh.getVerticesData(VertexBuffer.PositionKind);
+                    var rawFaces = mesh.getIndices();
+
+                    returnValue = this._createConvexPolyhedron(rawVerts, rawFaces, mesh);
+                    break;
+                case PhysicsEngine.HeightmapImpostor:
+                    returnValue = this._createHeightmap(mesh);
+                    break;
+
+            }
+
+            mesh.rotationQuaternion = oldQuaternion;
+
+            return returnValue;
+        }
+
+        private _createConvexPolyhedron(rawVerts: number[] | Float32Array, rawFaces: number[] | Int32Array, mesh: AbstractMesh): any {
+            var verts = [], faces = [];
+
+            mesh.computeWorldMatrix(true);
+
+            //reuse this variable
+            var transformed = Vector3.Zero();
+            // Get vertices
+            for (var i = 0; i < rawVerts.length; i += 3) {
+                Vector3.TransformNormalFromFloatsToRef(rawVerts[i], rawVerts[i + 1], rawVerts[i + 2], mesh.getWorldMatrix(), transformed);
+                verts.push(new CANNON.Vec3(transformed.x, transformed.y, transformed.z));
+            }
+
+            // Get faces
+            for (var j = 0; j < rawFaces.length; j += 3) {
+                faces.push([rawFaces[j], rawFaces[j + 2], rawFaces[j + 1]]);
+            }
+
+            var shape = new CANNON.ConvexPolyhedron(verts, faces);
+
+            return shape;
+        }
+
+        private _createHeightmap(mesh: AbstractMesh, pointDepth?: number) {
+            var pos = mesh.getVerticesData(VertexBuffer.PositionKind);
+            var matrix = [];
+    
+            //For now pointDepth will not be used and will be automatically calculated.
+            //Future reference - try and find the best place to add a reference to the pointDepth variable.
+            var arraySize = pointDepth || ~~(Math.sqrt(pos.length / 3) - 1);
+
+            var dim = Math.min(mesh.getBoundingInfo().boundingBox.extendSize.x, mesh.getBoundingInfo().boundingBox.extendSize.z);
+
+            var elementSize = dim * 2 / arraySize;
+
+            var minY = mesh.getBoundingInfo().boundingBox.extendSize.y;
+
+            for (var i = 0; i < pos.length; i = i + 3) {
+                var x = Math.round((pos[i + 0]) / elementSize + arraySize / 2);
+                var z = Math.round(((pos[i + 2]) / elementSize - arraySize / 2) * -1);
+                var y = pos[i + 1] + minY;
+                if (!matrix[x]) {
+                    matrix[x] = [];
+                }
+                if (!matrix[x][z]) {
+                    matrix[x][z] = y;
+                }
+                matrix[x][z] = Math.max(y, matrix[x][z]);
+            }
+
+
+            for (var x = 0; x <= arraySize; ++x) {
+                if (!matrix[x]) {
+                    var loc = 1;
+                    while (!matrix[(x + loc) % arraySize]) {
+                        loc++;
+                    }
+                    matrix[x] = matrix[(x + loc) % arraySize].slice();
+                    //console.log("missing x", x);
+                }
+                for (var z = 0; z <= arraySize; ++z) {
+                    if (!matrix[x][z]) {
+                        var loc = 1;
+                        var newValue;
+                        while (newValue === undefined) {
+                            newValue = matrix[x][(z + loc++) % arraySize];
+                        }
+                        matrix[x][z] = newValue;
+
+                    }
+                }
+            }
+
+            var shape = new CANNON.Heightfield(matrix, {
+                elementSize: elementSize
+            });
+            
+            //For future reference, needed for body transformation
+            shape.minY = minY;
+
+            return shape;
+        }
+
+        private _addMaterial(friction: number, restitution: number) {
+            var index;
+            var mat;
+
+            for (index = 0; index < this._physicsMaterials.length; index++) {
+                mat = this._physicsMaterials[index];
+
+                if (mat.friction === friction && mat.restitution === restitution) {
+                    return mat;
+                }
+            }
+
+            var currentMat = new CANNON.Material("mat");
+            this._physicsMaterials.push(currentMat);
+
+            for (index = 0; index < this._physicsMaterials.length; index++) {
+                mat = this._physicsMaterials[index];
+
+                var contactMaterial = new CANNON.ContactMaterial(mat, currentMat, { friction: friction, restitution: restitution });
+
+                this._world.addContactMaterial(contactMaterial);
+            }
+
+            return currentMat;
+        }
+
+        private _createRigidBodyFromShape(shape: any, mesh: AbstractMesh, options: PhysicsBodyCreationOptions): any {
+            if (!mesh.rotationQuaternion) {
+                mesh.rotationQuaternion = Quaternion.RotationYawPitchRoll(mesh.rotation.y, mesh.rotation.x, mesh.rotation.z);
+            }
+            
+            // The delta between the mesh position and the mesh bounding box center
+            var bbox = mesh.getBoundingInfo().boundingBox;
+            var deltaPosition = mesh.position.subtract(bbox.center);
+            var deltaRotation;
+
+            var material = this._addMaterial(options.friction, options.restitution);
+            var body = new CANNON.Body({
+                mass: options.mass,
+                material: material,
+                position: new CANNON.Vec3(bbox.center.x, bbox.center.y, bbox.center.z)
+            });
+
+            body.quaternion = new CANNON.Quaternion(mesh.rotationQuaternion.x, mesh.rotationQuaternion.y, mesh.rotationQuaternion.z, mesh.rotationQuaternion.w);
+            //is shape is a plane or a heightmap, it must be rotated 90 degs in the X axis.
+            if (shape.type === CANNON.Shape.types.PLANE || shape.type === CANNON.Shape.types.HEIGHTFIELD) {
+                //-90 DEG in X, precalculated
+                var tmpQ = new CANNON.Quaternion(-0.7071067811865475, 0, 0, 0.7071067811865475);
+                body.quaternion = body.quaternion.mult(tmpQ);
+                //Invert! (Precalculated, 90 deg in X)
+                deltaRotation = new Quaternion(0.7071067811865475, 0, 0, 0.7071067811865475);
+            }
+            
+            //If it is a heightfield, if should be centered.
+            if (shape.type === CANNON.Shape.types.HEIGHTFIELD) {
+                
+                //calculate the correct body position:
+                var rotationQuaternion = mesh.rotationQuaternion;
+                mesh.rotationQuaternion = new BABYLON.Quaternion();
+                mesh.computeWorldMatrix(true);
+                
+                //get original center with no rotation
+                var center = mesh.getBoundingInfo().boundingBox.center.clone();
+
+                var oldPivot = mesh.getPivotMatrix() || Matrix.Translation(0, 0, 0);
+                
+                //rotation is back
+                mesh.rotationQuaternion = rotationQuaternion;
+        
+                //calculate the new center using a pivot (since Cannon.js doesn't center height maps)
+                var p = Matrix.Translation(mesh.getBoundingInfo().boundingBox.extendSize.x, 0, -mesh.getBoundingInfo().boundingBox.extendSize.z);
+                mesh.setPivotMatrix(p);
+                mesh.computeWorldMatrix(true);
+        
+                //calculate the translation
+                var translation = mesh.getBoundingInfo().boundingBox.center.subtract(center).subtract(mesh.position).negate();
+
+                body.position = new CANNON.Vec3(translation.x, translation.y - mesh.getBoundingInfo().boundingBox.extendSize.y, translation.z);
+                //add it inverted to the delta 
+                deltaPosition = mesh.getBoundingInfo().boundingBox.center.subtract(center);
+                deltaPosition.y += mesh.getBoundingInfo().boundingBox.extendSize.y;
+
+                mesh.setPivotMatrix(oldPivot);
+                mesh.computeWorldMatrix(true);
+            }
+            
+            //add the shape
+            body.addShape(shape);
+
+            this._world.add(body);
+
+            this._registeredMeshes.push({ mesh: mesh, body: body, material: material, delta: deltaPosition, deltaRotation: deltaRotation, heightmap: shape.type === CANNON.Shape.types.HEIGHTFIELD });
+
+            return body;
+        }
+
+        public registerMeshesAsCompound(parts: PhysicsCompoundBodyPart[], options: PhysicsBodyCreationOptions): any {
+
+            var initialMesh = parts[0].mesh;
+
+            this.unregisterMesh(initialMesh);
+
+            initialMesh.computeWorldMatrix(true);
+
+            var initialShape = this._createShape(initialMesh, parts[0].impostor);
+            var body = this._createRigidBodyFromShape(initialShape, initialMesh, options);
+
+            for (var index = 1; index < parts.length; index++) {
+                var mesh = parts[index].mesh;
+                mesh.computeWorldMatrix(true);
+                var shape = this._createShape(mesh, parts[index].impostor);
+                var localPosition = mesh.position;
+
+                body.addShape(shape, new CANNON.Vec3(localPosition.x, localPosition.y, localPosition.z));
+            }
+
+            return body;
+        }
+
+        private _unbindBody(body): void {
+            for (var index = 0; index < this._registeredMeshes.length; index++) {
+                var registeredMesh = this._registeredMeshes[index];
+
+                if (registeredMesh.body === body) {
+                    this._world.remove(registeredMesh.body);
+                    registeredMesh.body = null;
+                    registeredMesh.delta = null;
+                    registeredMesh.deltaRotation = null;
+                }
+            }
+        }
+
+        public unregisterMesh(mesh: AbstractMesh): void {
+            for (var index = 0; index < this._registeredMeshes.length; index++) {
+                var registeredMesh = this._registeredMeshes[index];
+
+                if (registeredMesh.mesh === mesh) {
+                    // Remove body
+                    if (registeredMesh.body) {
+                        this._unbindBody(registeredMesh.body);
+                    }
+
+                    this._registeredMeshes.splice(index, 1);
+                    return;
+                }
+            }
+        }
+
+        public applyImpulse(mesh: AbstractMesh, force: Vector3, contactPoint: Vector3): void {
+            var worldPoint = new CANNON.Vec3(contactPoint.x, contactPoint.y, contactPoint.z);
+            var impulse = new CANNON.Vec3(force.x, force.y, force.z);
+
+            for (var index = 0; index < this._registeredMeshes.length; index++) {
+                var registeredMesh = this._registeredMeshes[index];
+
+                if (registeredMesh.mesh === mesh) {
+                    registeredMesh.body.applyImpulse(impulse, worldPoint);
+                    return;
+                }
+            }
+        }
+
+        public updateBodyPosition = function (mesh: AbstractMesh): void {
+            for (var index = 0; index < this._registeredMeshes.length; index++) {
+                var registeredMesh = this._registeredMeshes[index];
+                if (registeredMesh.mesh === mesh || registeredMesh.mesh === mesh.parent) {
+                    var body = registeredMesh.body;
+
+                    var center = mesh.getBoundingInfo().boundingBox.center;
+                    body.position.set(center.x, center.y, center.z);
+
+                    body.quaternion.copy(mesh.rotationQuaternion);
+
+                    if (registeredMesh.deltaRotation) {
+                        var tmpQ = new CANNON.Quaternion(-0.7071067811865475, 0, 0, 0.7071067811865475);
+                        body.quaternion = body.quaternion.mult(tmpQ);
+                    }
+
+                    if (registeredMesh.heightmap) {
+                        //calculate the correct body position:
+                        var rotationQuaternion = mesh.rotationQuaternion;
+                        mesh.rotationQuaternion = new BABYLON.Quaternion();
+                        mesh.computeWorldMatrix(true);
+                        
+                        //get original center with no rotation
+                        var center = mesh.getBoundingInfo().boundingBox.center.clone();
+
+                        var oldPivot = mesh.getPivotMatrix() || Matrix.Translation(0, 0, 0);
+                        
+                        //rotation is back
+                        mesh.rotationQuaternion = rotationQuaternion;
+                
+                        //calculate the new center using a pivot (since Cannon.js doesn't center height maps)
+                        var p = Matrix.Translation(mesh.getBoundingInfo().boundingBox.extendSize.x, 0, -mesh.getBoundingInfo().boundingBox.extendSize.z);
+                        mesh.setPivotMatrix(p);
+                        mesh.computeWorldMatrix(true);
+                
+                        //calculate the translation
+                        var translation = mesh.getBoundingInfo().boundingBox.center.subtract(center).subtract(mesh.position).negate();
+
+                        body.position = new CANNON.Vec3(translation.x, translation.y - mesh.getBoundingInfo().boundingBox.extendSize.y, translation.z);
+                        //add it inverted to the delta 
+                        registeredMesh.delta = mesh.getBoundingInfo().boundingBox.center.subtract(center);
+                        registeredMesh.delta.y += mesh.getBoundingInfo().boundingBox.extendSize.y;
+
+                        mesh.setPivotMatrix(oldPivot);
+                        mesh.computeWorldMatrix(true);
+                    }
+                    return;
+                }
+            }
+        }
+
+        public createLink(mesh1: AbstractMesh, mesh2: AbstractMesh, pivot1: Vector3, pivot2: Vector3): boolean {
+            var body1 = null, body2 = null;
+            for (var index = 0; index < this._registeredMeshes.length; index++) {
+                var registeredMesh = this._registeredMeshes[index];
+
+                if (registeredMesh.mesh === mesh1) {
+                    body1 = registeredMesh.body;
+                } else if (registeredMesh.mesh === mesh2) {
+                    body2 = registeredMesh.body;
+                }
+            }
+
+            if (!body1 || !body2) {
+                return false;
+            }
+
+            var constraint = new CANNON.PointToPointConstraint(body1, new CANNON.Vec3(pivot1.x, pivot1.y, pivot1.z), body2, new CANNON.Vec3(pivot2.x, pivot2.y, pivot2.z));
+            this._world.addConstraint(constraint);
+
+            return true;
+        }
+
+        public dispose(): void {
+            while (this._registeredMeshes.length) {
+                this.unregisterMesh(this._registeredMeshes[0].mesh);
+            }
+        }
+
+        public isSupported(): boolean {
+            return window.CANNON !== undefined;
+        }
+
+        public getWorldObject(): any {
+            return this._world;
+        }
+
+        public getPhysicsBodyOfMesh(mesh: AbstractMesh) {
+            for (var index = 0; index < this._registeredMeshes.length; index++) {
+                var registeredMesh = this._registeredMeshes[index];
+                if (registeredMesh.mesh === mesh) {
+                    return registeredMesh.body;
+                }
+            }
+            return null;
+        }
+    }
 }

+ 412 - 412
src/Physics/Plugins/babylon.oimoJSPlugin.ts

@@ -1,413 +1,413 @@
-module BABYLON {
-    declare var OIMO;
-
-    export class OimoJSPlugin implements IPhysicsEnginePlugin {
-        private _world;
-        private _registeredMeshes = [];
-
-        public name = "oimo";
-
-        private _gravity: Vector3;
-
-        private _checkWithEpsilon(value: number): number {
-            return value < PhysicsEngine.Epsilon ? PhysicsEngine.Epsilon : value;
-        }
-
-        public initialize(iterations?: number): void {
-            this._world = new OIMO.World(null, null, iterations);
-            this._world.clear();
-        }
-
-        public setGravity(gravity: Vector3): void {
-            this._gravity = this._world.gravity = gravity;
-        }
-
-        public getGravity(): Vector3 {
-            return this._gravity;
-        }
-
-        public registerMesh(mesh: AbstractMesh, impostor: number, options: PhysicsBodyCreationOptions): any {
-            this.unregisterMesh(mesh);
-
-            if (!mesh.rotationQuaternion) {
-                mesh.rotationQuaternion = Quaternion.RotationYawPitchRoll(mesh.rotation.y, mesh.rotation.x, mesh.rotation.z);
-            }
-
-            mesh.computeWorldMatrix(true);
-
-            var bbox = mesh.getBoundingInfo().boundingBox;
-
-            // The delta between the mesh position and the mesh bounding box center
-            var deltaPosition = mesh.position.subtract(bbox.center);
-            
-            //calculate rotation to fit Oimo's needs (Euler...)
-            var rot = new OIMO.Euler().setFromQuaternion({ x: mesh.rotationQuaternion.x, y: mesh.rotationQuaternion.y, z: mesh.rotationQuaternion.z, s: mesh.rotationQuaternion.w });
-
-            //get the correct bounding box
-            var oldQuaternion = mesh.rotationQuaternion;
-            mesh.rotationQuaternion = new Quaternion(0, 0, 0, 1);
-            mesh.computeWorldMatrix(true);
-
-            var bodyConfig: any = {
-                name: mesh.uniqueId,
-                pos: [bbox.center.x, bbox.center.y, bbox.center.z],
-                rot: [rot.x / OIMO.TO_RAD, rot.y / OIMO.TO_RAD, rot.z / OIMO.TO_RAD],
-                move: options.mass != 0,
-                config: [options.mass, options.friction, options.restitution],
-                world: this._world
-            };
-
-            // register mesh
-            switch (impostor) {
-                case PhysicsEngine.SphereImpostor:
-                    var radiusX = bbox.maximumWorld.x - bbox.minimumWorld.x;
-                    var radiusY = bbox.maximumWorld.y - bbox.minimumWorld.y;
-                    var radiusZ = bbox.maximumWorld.z - bbox.minimumWorld.z;
-
-                    var size = Math.max(
-                        this._checkWithEpsilon(radiusX),
-                        this._checkWithEpsilon(radiusY),
-                        this._checkWithEpsilon(radiusZ)) / 2;
-
-                    bodyConfig.type = 'sphere';
-                    bodyConfig.size = [size];
-                    break;
-
-                case PhysicsEngine.PlaneImpostor:
-                //Oimo "fakes" a cylinder as a box, so why don't we!
-                case PhysicsEngine.CylinderImpostor:
-                case PhysicsEngine.BoxImpostor:
-
-                    var min = bbox.minimumWorld;
-                    var max = bbox.maximumWorld;
-                    var box = max.subtract(min);
-                    var sizeX = this._checkWithEpsilon(box.x);
-                    var sizeY = this._checkWithEpsilon(box.y);
-                    var sizeZ = this._checkWithEpsilon(box.z);
-
-                    bodyConfig.type = 'box';
-                    bodyConfig.size = [sizeX, sizeY, sizeZ];
-                    break;
-            }
-
-            var body = new OIMO.Body(bodyConfig);
-
-            //We have to access the rigid body's properties to set the quaternion. 
-            //The setQuaternion function of Oimo only sets the newOrientation that is only set after an impulse is given or a collision.
-            //body.body.orientation = new OIMO.Quat(mesh.rotationQuaternion.w, mesh.rotationQuaternion.x, mesh.rotationQuaternion.y, mesh.rotationQuaternion.z);
-            //TEST
-            //body.body.resetQuaternion(new OIMO.Quat(mesh.rotationQuaternion.w, mesh.rotationQuaternion.x, mesh.rotationQuaternion.y, mesh.rotationQuaternion.z));
-            //update the internal rotation matrix
-            //body.body.syncShapes();
-            
-            this._registeredMeshes.push({
-                mesh: mesh,
-                body: body,
-                delta: deltaPosition
-            });
-			
-            //for the sake of consistency.
-            mesh.rotationQuaternion = oldQuaternion;
-
-            return body;
-        }
-
-        public registerMeshesAsCompound(parts: PhysicsCompoundBodyPart[], options: PhysicsBodyCreationOptions): any {
-            var types = [],
-                sizes = [],
-                positions = [],
-                rotations = [];
-
-            var initialMesh = parts[0].mesh;
-
-            for (var index = 0; index < parts.length; index++) {
-                var part = parts[index];
-                var bodyParameters = this._createBodyAsCompound(part, options, initialMesh);
-                types.push(bodyParameters.type);
-                sizes.push.apply(sizes, bodyParameters.size);
-                positions.push.apply(positions, bodyParameters.pos);
-                rotations.push.apply(rotations, bodyParameters.rot);
-            }
-
-            var body = new OIMO.Body({
-                name: initialMesh.uniqueId,
-                type: types,
-                size: sizes,
-                pos: positions,
-                rot: rotations,
-                move: options.mass != 0,
-                config: [options.mass, options.friction, options.restitution],
-                world: this._world
-            });
-            
-            //Reset the body's rotation to be of the initial mesh's.
-            var rot = new OIMO.Euler().setFromQuaternion({ x: initialMesh.rotationQuaternion.x, y: initialMesh.rotationQuaternion.y, z: initialMesh.rotationQuaternion.z, s: initialMesh.rotationQuaternion.w });
-
-            body.resetRotation(rot.x / OIMO.TO_RAD, rot.y / OIMO.TO_RAD, rot.z / OIMO.TO_RAD);
-
-            this._registeredMeshes.push({
-                mesh: initialMesh,
-                body: body
-            });
-
-            return body;
-        }
-
-        private _createBodyAsCompound(part: PhysicsCompoundBodyPart, options: PhysicsBodyCreationOptions, initialMesh: AbstractMesh): any {
-            var mesh = part.mesh;
-
-            if (!mesh.rotationQuaternion) {
-                mesh.rotationQuaternion = Quaternion.RotationYawPitchRoll(mesh.rotation.y, mesh.rotation.x, mesh.rotation.z);
-            }
-			
-            // We need the bounding box/sphere info to compute the physics body
-            mesh.computeWorldMatrix(true);
-
-            var rot = new OIMO.Euler().setFromQuaternion({ x: mesh.rotationQuaternion.x, y: mesh.rotationQuaternion.y, z: mesh.rotationQuaternion.z, s: mesh.rotationQuaternion.w });
-
-            var bodyParameters: any = {
-                name: mesh.uniqueId,
-                pos: [mesh.position.x, mesh.position.y, mesh.position.z],
-                //A bug in Oimo (Body class) prevents us from using rot directly.
-                rot: [0, 0, 0],
-                //For future reference, if the bug will ever be fixed.
-                realRot: [rot.x / OIMO.TO_RAD, rot.y / OIMO.TO_RAD, rot.z / OIMO.TO_RAD]
-            };
-
-            var oldQuaternion = mesh.rotationQuaternion;
-            mesh.rotationQuaternion = new Quaternion(0, 0, 0, 1);
-            mesh.computeWorldMatrix(true);
-
-            switch (part.impostor) {
-                case PhysicsEngine.SphereImpostor:
-                    var bbox = mesh.getBoundingInfo().boundingBox;
-                    var radiusX = bbox.maximumWorld.x - bbox.minimumWorld.x;
-                    var radiusY = bbox.maximumWorld.y - bbox.minimumWorld.y;
-                    var radiusZ = bbox.maximumWorld.z - bbox.minimumWorld.z;
-
-                    var size = Math.max(
-                        this._checkWithEpsilon(radiusX),
-                        this._checkWithEpsilon(radiusY),
-                        this._checkWithEpsilon(radiusZ)) / 2;
-
-                    bodyParameters.type = 'sphere';
-                    bodyParameters.size = [size, size, size];
-
-                    break;
-
-                case PhysicsEngine.PlaneImpostor:
-                case PhysicsEngine.CylinderImpostor:
-                case PhysicsEngine.BoxImpostor:
-                    bbox = mesh.getBoundingInfo().boundingBox;
-                    var min = bbox.minimumWorld;
-                    var max = bbox.maximumWorld;
-                    var box = max.subtract(min);
-                    var sizeX = this._checkWithEpsilon(box.x);
-                    var sizeY = this._checkWithEpsilon(box.y);
-                    var sizeZ = this._checkWithEpsilon(box.z);
-
-                    bodyParameters.type = 'box';
-                    bodyParameters.size = [sizeX, sizeY, sizeZ];
-
-                    break;
-            }
-
-            mesh.rotationQuaternion = oldQuaternion;
-
-            return bodyParameters;
-        }
-
-        public unregisterMesh(mesh: AbstractMesh): void {
-            for (var index = 0; index < this._registeredMeshes.length; index++) {
-                var registeredMesh = this._registeredMeshes[index];
-                if (registeredMesh.mesh === mesh || registeredMesh.mesh === mesh.parent) {
-                    if (registeredMesh.body) {
-                        this._world.removeRigidBody(registeredMesh.body.body);
-                        this._unbindBody(registeredMesh.body);
-                    }
-                    this._registeredMeshes.splice(index, 1);
-                    return;
-                }
-            }
-        }
-
-        private _unbindBody(body: any): void {
-            for (var index = 0; index < this._registeredMeshes.length; index++) {
-                var registeredMesh = this._registeredMeshes[index];
-                if (registeredMesh.body === body) {
-                    registeredMesh.body = null;
-                }
-            }
-        }
-
-        /**
-         * Update the body position according to the mesh position
-         * @param mesh
-         */
-        public updateBodyPosition = function (mesh: AbstractMesh): void {
-
-            for (var index = 0; index < this._registeredMeshes.length; index++) {
-                var registeredMesh = this._registeredMeshes[index];
-                var body = registeredMesh.body.body;
-                var updated: boolean = false;
-                var newPosition: Vector3;
-                if (registeredMesh.mesh === mesh || registeredMesh.mesh === mesh.parent) {
-                    mesh.computeWorldMatrix(true);
-
-                    newPosition = mesh.getBoundingInfo().boundingBox.center;
-
-                    updated = true;
-                }
-                // Case where the parent has been updated
-                else if (registeredMesh.mesh.parent === mesh) {
-                    mesh.computeWorldMatrix(true);
-                    registeredMesh.mesh.computeWorldMatrix(true);
-
-                    newPosition = registeredMesh.mesh.getAbsolutePosition();
-
-                    updated = true;
-                }
-
-                if (updated) {
-                    body.setPosition(new OIMO.Vec3(newPosition.x, newPosition.y, newPosition.z));
-                    body.setQuaternion(mesh.rotationQuaternion);
-                    body.sleeping = false;
-                    //force Oimo to update the body's position
-                    body.updatePosition(1);
-                }
-            }
-        }
-
-        public applyImpulse(mesh: AbstractMesh, force: Vector3, contactPoint: Vector3): void {
-            for (var index = 0; index < this._registeredMeshes.length; index++) {
-                var registeredMesh = this._registeredMeshes[index];
-                if (registeredMesh.mesh === mesh || registeredMesh.mesh === mesh.parent) {
-                    // Get object mass to have a behaviour similar to cannon.js
-                    var mass = registeredMesh.body.body.massInfo.mass;
-                    // The force is scaled with the mass of object
-                    registeredMesh.body.body.applyImpulse(contactPoint.scale(OIMO.INV_SCALE), force.scale(OIMO.INV_SCALE * mass));
-                    return;
-                }
-            }
-        }
-
-        public createLink(mesh1: AbstractMesh, mesh2: AbstractMesh, pivot1: Vector3, pivot2: Vector3, options?: any): boolean {
-            var body1 = null,
-                body2 = null;
-            for (var index = 0; index < this._registeredMeshes.length; index++) {
-                var registeredMesh = this._registeredMeshes[index];
-                if (registeredMesh.mesh === mesh1) {
-                    body1 = registeredMesh.body.body;
-                } else if (registeredMesh.mesh === mesh2) {
-                    body2 = registeredMesh.body.body;
-                }
-            }
-            if (!body1 || !body2) {
-                return false;
-            }
-            if (!options) {
-                options = {};
-            }
-
-            new OIMO.Link({
-                type: options.type,
-                body1: body1,
-                body2: body2,
-                min: options.min,
-                max: options.max,
-                axe1: options.axe1,
-                axe2: options.axe2,
-                pos1: [pivot1.x, pivot1.y, pivot1.z],
-                pos2: [pivot2.x, pivot2.y, pivot2.z],
-                collision: options.collision,
-                spring: options.spring,
-                world: this._world
-            });
-
-            return true;
-
-        }
-
-        public dispose(): void {
-            this._world.clear();
-            while (this._registeredMeshes.length) {
-                this.unregisterMesh(this._registeredMeshes[0].mesh);
-            }
-        }
-
-        public isSupported(): boolean {
-            return OIMO !== undefined;
-        }
-
-        public getWorldObject(): any {
-            return this._world;
-        }
-
-        public getPhysicsBodyOfMesh(mesh: AbstractMesh) {
-            for (var index = 0; index < this._registeredMeshes.length; index++) {
-                var registeredMesh = this._registeredMeshes[index];
-                if (registeredMesh.mesh === mesh) {
-                    return registeredMesh.body;
-                }
-            }
-            return null;
-        }
-
-        private _getLastShape(body: any): any {
-            var lastShape = body.shapes;
-            while (lastShape.next) {
-                lastShape = lastShape.next;
-            }
-            return lastShape;
-        }
-
-        public runOneStep(time: number): void {
-            this._world.step();
-
-            // Update the position of all registered meshes
-            var i = this._registeredMeshes.length;
-            var m;
-            while (i--) {
-
-                var body = this._registeredMeshes[i].body.body;
-                var mesh = this._registeredMeshes[i].mesh;
-
-                if (!this._registeredMeshes[i].delta) {
-                    this._registeredMeshes[i].delta = Vector3.Zero();
-                }
-
-                if (!body.sleeping) {
-                    //TODO check that
-                    if (body.shapes.next) {
-                        var parentShape = this._getLastShape(body);
-                        mesh.position.x = parentShape.position.x * OIMO.WORLD_SCALE;
-                        mesh.position.y = parentShape.position.y * OIMO.WORLD_SCALE;
-                        mesh.position.z = parentShape.position.z * OIMO.WORLD_SCALE;
-                    } else {
-                        mesh.position.copyFrom(body.getPosition()).addInPlace(this._registeredMeshes[i].delta);
-
-                    }
-                    mesh.rotationQuaternion.copyFrom(body.getQuaternion());
-                    mesh.computeWorldMatrix();
-                }
-                
-                //check if the collide callback is set. 
-                if (mesh.onPhysicsCollide) {
-                    var meshUniqueName = mesh.uniqueId;
-                    var contact = this._world.contacts;
-                    while (contact !== null) {
-                        //is this body colliding with any other?
-                        if ((contact.body1.name == mesh.uniqueId || contact.body2.name == mesh.uniqueId) && contact.touching && /* !contact.sleeping*/ !contact.body1.sleeping && !contact.body2.sleeping) {
-                            var otherUniqueId = contact.body1.name == mesh.uniqueId ? contact.body2.name : contact.body1.name;
-                            //get the mesh and execute the callback
-                            var otherMesh = mesh.getScene().getMeshByUniqueID(otherUniqueId);
-                            if (otherMesh)
-                                mesh.onPhysicsCollide(otherMesh);
-                        }
-                        contact = contact.next;
-                    }
-                }
-            }
-        }
-    }
+module BABYLON {
+    declare var OIMO;
+
+    export class OimoJSPlugin implements IPhysicsEnginePlugin {
+        private _world;
+        private _registeredMeshes = [];
+
+        public name = "oimo";
+
+        private _gravity: Vector3;
+
+        private _checkWithEpsilon(value: number): number {
+            return value < PhysicsEngine.Epsilon ? PhysicsEngine.Epsilon : value;
+        }
+
+        public initialize(iterations?: number): void {
+            this._world = new OIMO.World(null, null, iterations);
+            this._world.clear();
+        }
+
+        public setGravity(gravity: Vector3): void {
+            this._gravity = this._world.gravity = gravity;
+        }
+
+        public getGravity(): Vector3 {
+            return this._gravity;
+        }
+
+        public registerMesh(mesh: AbstractMesh, impostor: number, options: PhysicsBodyCreationOptions): any {
+            this.unregisterMesh(mesh);
+
+            if (!mesh.rotationQuaternion) {
+                mesh.rotationQuaternion = Quaternion.RotationYawPitchRoll(mesh.rotation.y, mesh.rotation.x, mesh.rotation.z);
+            }
+
+            mesh.computeWorldMatrix(true);
+
+            var bbox = mesh.getBoundingInfo().boundingBox;
+
+            // The delta between the mesh position and the mesh bounding box center
+            var deltaPosition = mesh.position.subtract(bbox.center);
+            
+            //calculate rotation to fit Oimo's needs (Euler...)
+            var rot = new OIMO.Euler().setFromQuaternion({ x: mesh.rotationQuaternion.x, y: mesh.rotationQuaternion.y, z: mesh.rotationQuaternion.z, s: mesh.rotationQuaternion.w });
+
+            //get the correct bounding box
+            var oldQuaternion = mesh.rotationQuaternion;
+            mesh.rotationQuaternion = new Quaternion(0, 0, 0, 1);
+            mesh.computeWorldMatrix(true);
+
+            var bodyConfig: any = {
+                name: mesh.uniqueId,
+                pos: [bbox.center.x, bbox.center.y, bbox.center.z],
+                rot: [rot.x / OIMO.TO_RAD, rot.y / OIMO.TO_RAD, rot.z / OIMO.TO_RAD],
+                move: options.mass != 0,
+                config: [options.mass, options.friction, options.restitution],
+                world: this._world
+            };
+
+            // register mesh
+            switch (impostor) {
+                case PhysicsEngine.SphereImpostor:
+                    var radiusX = bbox.maximumWorld.x - bbox.minimumWorld.x;
+                    var radiusY = bbox.maximumWorld.y - bbox.minimumWorld.y;
+                    var radiusZ = bbox.maximumWorld.z - bbox.minimumWorld.z;
+
+                    var size = Math.max(
+                        this._checkWithEpsilon(radiusX),
+                        this._checkWithEpsilon(radiusY),
+                        this._checkWithEpsilon(radiusZ)) / 2;
+
+                    bodyConfig.type = 'sphere';
+                    bodyConfig.size = [size];
+                    break;
+
+                case PhysicsEngine.PlaneImpostor:
+                //Oimo "fakes" a cylinder as a box, so why don't we!
+                case PhysicsEngine.CylinderImpostor:
+                case PhysicsEngine.BoxImpostor:
+
+                    var min = bbox.minimumWorld;
+                    var max = bbox.maximumWorld;
+                    var box = max.subtract(min);
+                    var sizeX = this._checkWithEpsilon(box.x);
+                    var sizeY = this._checkWithEpsilon(box.y);
+                    var sizeZ = this._checkWithEpsilon(box.z);
+
+                    bodyConfig.type = 'box';
+                    bodyConfig.size = [sizeX, sizeY, sizeZ];
+                    break;
+            }
+
+            var body = new OIMO.Body(bodyConfig);
+
+            //We have to access the rigid body's properties to set the quaternion. 
+            //The setQuaternion function of Oimo only sets the newOrientation that is only set after an impulse is given or a collision.
+            //body.body.orientation = new OIMO.Quat(mesh.rotationQuaternion.w, mesh.rotationQuaternion.x, mesh.rotationQuaternion.y, mesh.rotationQuaternion.z);
+            //TEST
+            //body.body.resetQuaternion(new OIMO.Quat(mesh.rotationQuaternion.w, mesh.rotationQuaternion.x, mesh.rotationQuaternion.y, mesh.rotationQuaternion.z));
+            //update the internal rotation matrix
+            //body.body.syncShapes();
+            
+            this._registeredMeshes.push({
+                mesh: mesh,
+                body: body,
+                delta: deltaPosition
+            });
+			
+            //for the sake of consistency.
+            mesh.rotationQuaternion = oldQuaternion;
+
+            return body;
+        }
+
+        public registerMeshesAsCompound(parts: PhysicsCompoundBodyPart[], options: PhysicsBodyCreationOptions): any {
+            var types = [],
+                sizes = [],
+                positions = [],
+                rotations = [];
+
+            var initialMesh = parts[0].mesh;
+
+            for (var index = 0; index < parts.length; index++) {
+                var part = parts[index];
+                var bodyParameters = this._createBodyAsCompound(part, options, initialMesh);
+                types.push(bodyParameters.type);
+                sizes.push.apply(sizes, bodyParameters.size);
+                positions.push.apply(positions, bodyParameters.pos);
+                rotations.push.apply(rotations, bodyParameters.rot);
+            }
+
+            var body = new OIMO.Body({
+                name: initialMesh.uniqueId,
+                type: types,
+                size: sizes,
+                pos: positions,
+                rot: rotations,
+                move: options.mass != 0,
+                config: [options.mass, options.friction, options.restitution],
+                world: this._world
+            });
+            
+            //Reset the body's rotation to be of the initial mesh's.
+            var rot = new OIMO.Euler().setFromQuaternion({ x: initialMesh.rotationQuaternion.x, y: initialMesh.rotationQuaternion.y, z: initialMesh.rotationQuaternion.z, s: initialMesh.rotationQuaternion.w });
+
+            body.resetRotation(rot.x / OIMO.TO_RAD, rot.y / OIMO.TO_RAD, rot.z / OIMO.TO_RAD);
+
+            this._registeredMeshes.push({
+                mesh: initialMesh,
+                body: body
+            });
+
+            return body;
+        }
+
+        private _createBodyAsCompound(part: PhysicsCompoundBodyPart, options: PhysicsBodyCreationOptions, initialMesh: AbstractMesh): any {
+            var mesh = part.mesh;
+
+            if (!mesh.rotationQuaternion) {
+                mesh.rotationQuaternion = Quaternion.RotationYawPitchRoll(mesh.rotation.y, mesh.rotation.x, mesh.rotation.z);
+            }
+			
+            // We need the bounding box/sphere info to compute the physics body
+            mesh.computeWorldMatrix(true);
+
+            var rot = new OIMO.Euler().setFromQuaternion({ x: mesh.rotationQuaternion.x, y: mesh.rotationQuaternion.y, z: mesh.rotationQuaternion.z, s: mesh.rotationQuaternion.w });
+
+            var bodyParameters: any = {
+                name: mesh.uniqueId,
+                pos: [mesh.position.x, mesh.position.y, mesh.position.z],
+                //A bug in Oimo (Body class) prevents us from using rot directly.
+                rot: [0, 0, 0],
+                //For future reference, if the bug will ever be fixed.
+                realRot: [rot.x / OIMO.TO_RAD, rot.y / OIMO.TO_RAD, rot.z / OIMO.TO_RAD]
+            };
+
+            var oldQuaternion = mesh.rotationQuaternion;
+            mesh.rotationQuaternion = new Quaternion(0, 0, 0, 1);
+            mesh.computeWorldMatrix(true);
+
+            switch (part.impostor) {
+                case PhysicsEngine.SphereImpostor:
+                    var bbox = mesh.getBoundingInfo().boundingBox;
+                    var radiusX = bbox.maximumWorld.x - bbox.minimumWorld.x;
+                    var radiusY = bbox.maximumWorld.y - bbox.minimumWorld.y;
+                    var radiusZ = bbox.maximumWorld.z - bbox.minimumWorld.z;
+
+                    var size = Math.max(
+                        this._checkWithEpsilon(radiusX),
+                        this._checkWithEpsilon(radiusY),
+                        this._checkWithEpsilon(radiusZ)) / 2;
+
+                    bodyParameters.type = 'sphere';
+                    bodyParameters.size = [size, size, size];
+
+                    break;
+
+                case PhysicsEngine.PlaneImpostor:
+                case PhysicsEngine.CylinderImpostor:
+                case PhysicsEngine.BoxImpostor:
+                    bbox = mesh.getBoundingInfo().boundingBox;
+                    var min = bbox.minimumWorld;
+                    var max = bbox.maximumWorld;
+                    var box = max.subtract(min);
+                    var sizeX = this._checkWithEpsilon(box.x);
+                    var sizeY = this._checkWithEpsilon(box.y);
+                    var sizeZ = this._checkWithEpsilon(box.z);
+
+                    bodyParameters.type = 'box';
+                    bodyParameters.size = [sizeX, sizeY, sizeZ];
+
+                    break;
+            }
+
+            mesh.rotationQuaternion = oldQuaternion;
+
+            return bodyParameters;
+        }
+
+        public unregisterMesh(mesh: AbstractMesh): void {
+            for (var index = 0; index < this._registeredMeshes.length; index++) {
+                var registeredMesh = this._registeredMeshes[index];
+                if (registeredMesh.mesh === mesh || registeredMesh.mesh === mesh.parent) {
+                    if (registeredMesh.body) {
+                        this._world.removeRigidBody(registeredMesh.body.body);
+                        this._unbindBody(registeredMesh.body);
+                    }
+                    this._registeredMeshes.splice(index, 1);
+                    return;
+                }
+            }
+        }
+
+        private _unbindBody(body: any): void {
+            for (var index = 0; index < this._registeredMeshes.length; index++) {
+                var registeredMesh = this._registeredMeshes[index];
+                if (registeredMesh.body === body) {
+                    registeredMesh.body = null;
+                }
+            }
+        }
+
+        /**
+         * Update the body position according to the mesh position
+         * @param mesh
+         */
+        public updateBodyPosition = function (mesh: AbstractMesh): void {
+
+            for (var index = 0; index < this._registeredMeshes.length; index++) {
+                var registeredMesh = this._registeredMeshes[index];
+                var body = registeredMesh.body.body;
+                var updated: boolean = false;
+                var newPosition: Vector3;
+                if (registeredMesh.mesh === mesh || registeredMesh.mesh === mesh.parent) {
+                    mesh.computeWorldMatrix(true);
+
+                    newPosition = mesh.getBoundingInfo().boundingBox.center;
+
+                    updated = true;
+                }
+                // Case where the parent has been updated
+                else if (registeredMesh.mesh.parent === mesh) {
+                    mesh.computeWorldMatrix(true);
+                    registeredMesh.mesh.computeWorldMatrix(true);
+
+                    newPosition = registeredMesh.mesh.getAbsolutePosition();
+
+                    updated = true;
+                }
+
+                if (updated) {
+                    body.setPosition(new OIMO.Vec3(newPosition.x, newPosition.y, newPosition.z));
+                    body.setQuaternion(mesh.rotationQuaternion);
+                    body.sleeping = false;
+                    //force Oimo to update the body's position
+                    body.updatePosition(1);
+                }
+            }
+        }
+
+        public applyImpulse(mesh: AbstractMesh, force: Vector3, contactPoint: Vector3): void {
+            for (var index = 0; index < this._registeredMeshes.length; index++) {
+                var registeredMesh = this._registeredMeshes[index];
+                if (registeredMesh.mesh === mesh || registeredMesh.mesh === mesh.parent) {
+                    // Get object mass to have a behaviour similar to cannon.js
+                    var mass = registeredMesh.body.body.massInfo.mass;
+                    // The force is scaled with the mass of object
+                    registeredMesh.body.body.applyImpulse(contactPoint.scale(OIMO.INV_SCALE), force.scale(OIMO.INV_SCALE * mass));
+                    return;
+                }
+            }
+        }
+
+        public createLink(mesh1: AbstractMesh, mesh2: AbstractMesh, pivot1: Vector3, pivot2: Vector3, options?: any): boolean {
+            var body1 = null,
+                body2 = null;
+            for (var index = 0; index < this._registeredMeshes.length; index++) {
+                var registeredMesh = this._registeredMeshes[index];
+                if (registeredMesh.mesh === mesh1) {
+                    body1 = registeredMesh.body.body;
+                } else if (registeredMesh.mesh === mesh2) {
+                    body2 = registeredMesh.body.body;
+                }
+            }
+            if (!body1 || !body2) {
+                return false;
+            }
+            if (!options) {
+                options = {};
+            }
+
+            new OIMO.Link({
+                type: options.type,
+                body1: body1,
+                body2: body2,
+                min: options.min,
+                max: options.max,
+                axe1: options.axe1,
+                axe2: options.axe2,
+                pos1: [pivot1.x, pivot1.y, pivot1.z],
+                pos2: [pivot2.x, pivot2.y, pivot2.z],
+                collision: options.collision,
+                spring: options.spring,
+                world: this._world
+            });
+
+            return true;
+
+        }
+
+        public dispose(): void {
+            this._world.clear();
+            while (this._registeredMeshes.length) {
+                this.unregisterMesh(this._registeredMeshes[0].mesh);
+            }
+        }
+
+        public isSupported(): boolean {
+            return OIMO !== undefined;
+        }
+
+        public getWorldObject(): any {
+            return this._world;
+        }
+
+        public getPhysicsBodyOfMesh(mesh: AbstractMesh) {
+            for (var index = 0; index < this._registeredMeshes.length; index++) {
+                var registeredMesh = this._registeredMeshes[index];
+                if (registeredMesh.mesh === mesh) {
+                    return registeredMesh.body;
+                }
+            }
+            return null;
+        }
+
+        private _getLastShape(body: any): any {
+            var lastShape = body.shapes;
+            while (lastShape.next) {
+                lastShape = lastShape.next;
+            }
+            return lastShape;
+        }
+
+        public runOneStep(time: number): void {
+            this._world.step();
+
+            // Update the position of all registered meshes
+            var i = this._registeredMeshes.length;
+            var m;
+            while (i--) {
+
+                var body = this._registeredMeshes[i].body.body;
+                var mesh = this._registeredMeshes[i].mesh;
+
+                if (!this._registeredMeshes[i].delta) {
+                    this._registeredMeshes[i].delta = Vector3.Zero();
+                }
+
+                if (!body.sleeping) {
+                    //TODO check that
+                    if (body.shapes.next) {
+                        var parentShape = this._getLastShape(body);
+                        mesh.position.x = parentShape.position.x * OIMO.WORLD_SCALE;
+                        mesh.position.y = parentShape.position.y * OIMO.WORLD_SCALE;
+                        mesh.position.z = parentShape.position.z * OIMO.WORLD_SCALE;
+                    } else {
+                        mesh.position.copyFrom(body.getPosition()).addInPlace(this._registeredMeshes[i].delta);
+
+                    }
+                    mesh.rotationQuaternion.copyFrom(body.getQuaternion());
+                    mesh.computeWorldMatrix();
+                }
+                
+                //check if the collide callback is set. 
+                if (mesh.onPhysicsCollide) {
+                    var meshUniqueName = mesh.uniqueId;
+                    var contact = this._world.contacts;
+                    while (contact !== null) {
+                        //is this body colliding with any other?
+                        if ((contact.body1.name == mesh.uniqueId || contact.body2.name == mesh.uniqueId) && contact.touching && /* !contact.sleeping*/ !contact.body1.sleeping && !contact.body2.sleeping) {
+                            var otherUniqueId = contact.body1.name == mesh.uniqueId ? contact.body2.name : contact.body1.name;
+                            //get the mesh and execute the callback
+                            var otherMesh = mesh.getScene().getMeshByUniqueID(otherUniqueId);
+                            if (otherMesh)
+                                mesh.onPhysicsCollide(otherMesh);
+                        }
+                        contact = contact.next;
+                    }
+                }
+            }
+        }
+    }
 }

+ 116 - 116
src/Physics/babylon.physicsEngine.ts

@@ -1,117 +1,117 @@
-module BABYLON {
-    export interface IPhysicsEnginePlugin {
-        name: string;
-        initialize(iterations?: number);
-        setGravity(gravity: Vector3): void;
-        getGravity(): Vector3;
-        runOneStep(delta: number): void;
-        registerMesh(mesh: AbstractMesh, impostor: number, options: PhysicsBodyCreationOptions): any;
-        registerMeshesAsCompound(parts: PhysicsCompoundBodyPart[], options: PhysicsBodyCreationOptions): any;
-        unregisterMesh(mesh: AbstractMesh);
-        applyImpulse(mesh: AbstractMesh, force: Vector3, contactPoint: Vector3): void;
-        createLink(mesh1: AbstractMesh, mesh2: AbstractMesh, pivot1: Vector3, pivot2: Vector3, options?: any): boolean;
-        dispose(): void;
-        isSupported(): boolean;
-        updateBodyPosition(mesh: AbstractMesh): void;
-        getWorldObject(): any; //Will return the physics world object of the engine used.
-        getPhysicsBodyOfMesh(mesh: AbstractMesh): any;
-    }
-
-    export interface PhysicsBodyCreationOptions {
-        mass: number;
-        friction: number;
-        restitution: number;
-    }
-
-    export interface PhysicsCompoundBodyPart {
-        mesh: Mesh;
-        impostor: number;
-    }
-
-    export class PhysicsEngine {
-        public gravity: Vector3;
-
-        private _currentPlugin: IPhysicsEnginePlugin;
-
-        constructor(plugin?: IPhysicsEnginePlugin) {
-            this._currentPlugin = plugin || new OimoJSPlugin();
-        }
-
-        public _initialize(gravity?: Vector3) {
-            this._currentPlugin.initialize();
-            this._setGravity(gravity);
-        }
-
-        public _runOneStep(delta: number): void {
-            if (delta > 0.1) {
-                delta = 0.1;
-            } else if (delta <= 0) {
-                delta = 1.0 / 60.0;
-            }
-
-            this._currentPlugin.runOneStep(delta);
-        }
-
-        public _setGravity(gravity: Vector3): void {
-            this.gravity = gravity || new Vector3(0, -9.807, 0);
-            this._currentPlugin.setGravity(this.gravity);
-        }
-
-        public _getGravity(): Vector3 {
-            return this._currentPlugin.getGravity();
-        }
-
-        public _registerMesh(mesh: AbstractMesh, impostor: number, options: PhysicsBodyCreationOptions): any {
-            return this._currentPlugin.registerMesh(mesh, impostor, options);
-        }
-
-        public _registerMeshesAsCompound(parts: PhysicsCompoundBodyPart[], options: PhysicsBodyCreationOptions): any {
-            return this._currentPlugin.registerMeshesAsCompound(parts, options);
-        }
-
-        public _unregisterMesh(mesh: AbstractMesh): void {
-            this._currentPlugin.unregisterMesh(mesh);
-        }
-
-        public _applyImpulse(mesh: AbstractMesh, force: Vector3, contactPoint: Vector3): void {
-            this._currentPlugin.applyImpulse(mesh, force, contactPoint);
-        }
-
-        public _createLink(mesh1: AbstractMesh, mesh2: AbstractMesh, pivot1: Vector3, pivot2: Vector3, options?: any): boolean {
-            return this._currentPlugin.createLink(mesh1, mesh2, pivot1, pivot2, options);
-        }
-
-        public _updateBodyPosition(mesh: AbstractMesh): void {
-            this._currentPlugin.updateBodyPosition(mesh);
-        }
-
-        public dispose(): void {
-            this._currentPlugin.dispose();
-        }
-
-        public isSupported(): boolean {
-            return this._currentPlugin.isSupported();
-        }
-
-        public getPhysicsBodyOfMesh(mesh: AbstractMesh) {
-            return this._currentPlugin.getPhysicsBodyOfMesh(mesh);
-        }
-
-        public getPhysicsPluginName(): string {
-            return this._currentPlugin.name;
-        }
-
-        // Statics
-        public static NoImpostor = 0;
-        public static SphereImpostor = 1;
-        public static BoxImpostor = 2;
-        public static PlaneImpostor = 3;
-        public static MeshImpostor = 4;
-        public static CapsuleImpostor = 5;
-        public static ConeImpostor = 6;
-        public static CylinderImpostor = 7;
-        public static ConvexHullImpostor = 8;
-        public static HeightmapImpostor = 9;
-        public static Epsilon = 0.001;
-    }
+module BABYLON {
+    export interface IPhysicsEnginePlugin {
+        name: string;
+        initialize(iterations?: number);
+        setGravity(gravity: Vector3): void;
+        getGravity(): Vector3;
+        runOneStep(delta: number): void;
+        registerMesh(mesh: AbstractMesh, impostor: number, options: PhysicsBodyCreationOptions): any;
+        registerMeshesAsCompound(parts: PhysicsCompoundBodyPart[], options: PhysicsBodyCreationOptions): any;
+        unregisterMesh(mesh: AbstractMesh);
+        applyImpulse(mesh: AbstractMesh, force: Vector3, contactPoint: Vector3): void;
+        createLink(mesh1: AbstractMesh, mesh2: AbstractMesh, pivot1: Vector3, pivot2: Vector3, options?: any): boolean;
+        dispose(): void;
+        isSupported(): boolean;
+        updateBodyPosition(mesh: AbstractMesh): void;
+        getWorldObject(): any; //Will return the physics world object of the engine used.
+        getPhysicsBodyOfMesh(mesh: AbstractMesh): any;
+    }
+
+    export interface PhysicsBodyCreationOptions {
+        mass: number;
+        friction: number;
+        restitution: number;
+    }
+
+    export interface PhysicsCompoundBodyPart {
+        mesh: Mesh;
+        impostor: number;
+    }
+
+    export class PhysicsEngine {
+        public gravity: Vector3;
+
+        private _currentPlugin: IPhysicsEnginePlugin;
+
+        constructor(plugin?: IPhysicsEnginePlugin) {
+            this._currentPlugin = plugin || new OimoJSPlugin();
+        }
+
+        public _initialize(gravity?: Vector3) {
+            this._currentPlugin.initialize();
+            this._setGravity(gravity);
+        }
+
+        public _runOneStep(delta: number): void {
+            if (delta > 0.1) {
+                delta = 0.1;
+            } else if (delta <= 0) {
+                delta = 1.0 / 60.0;
+            }
+
+            this._currentPlugin.runOneStep(delta);
+        }
+
+        public _setGravity(gravity: Vector3): void {
+            this.gravity = gravity || new Vector3(0, -9.807, 0);
+            this._currentPlugin.setGravity(this.gravity);
+        }
+
+        public _getGravity(): Vector3 {
+            return this._currentPlugin.getGravity();
+        }
+
+        public _registerMesh(mesh: AbstractMesh, impostor: number, options: PhysicsBodyCreationOptions): any {
+            return this._currentPlugin.registerMesh(mesh, impostor, options);
+        }
+
+        public _registerMeshesAsCompound(parts: PhysicsCompoundBodyPart[], options: PhysicsBodyCreationOptions): any {
+            return this._currentPlugin.registerMeshesAsCompound(parts, options);
+        }
+
+        public _unregisterMesh(mesh: AbstractMesh): void {
+            this._currentPlugin.unregisterMesh(mesh);
+        }
+
+        public _applyImpulse(mesh: AbstractMesh, force: Vector3, contactPoint: Vector3): void {
+            this._currentPlugin.applyImpulse(mesh, force, contactPoint);
+        }
+
+        public _createLink(mesh1: AbstractMesh, mesh2: AbstractMesh, pivot1: Vector3, pivot2: Vector3, options?: any): boolean {
+            return this._currentPlugin.createLink(mesh1, mesh2, pivot1, pivot2, options);
+        }
+
+        public _updateBodyPosition(mesh: AbstractMesh): void {
+            this._currentPlugin.updateBodyPosition(mesh);
+        }
+
+        public dispose(): void {
+            this._currentPlugin.dispose();
+        }
+
+        public isSupported(): boolean {
+            return this._currentPlugin.isSupported();
+        }
+
+        public getPhysicsBodyOfMesh(mesh: AbstractMesh) {
+            return this._currentPlugin.getPhysicsBodyOfMesh(mesh);
+        }
+
+        public getPhysicsPluginName(): string {
+            return this._currentPlugin.name;
+        }
+
+        // Statics
+        public static NoImpostor = 0;
+        public static SphereImpostor = 1;
+        public static BoxImpostor = 2;
+        public static PlaneImpostor = 3;
+        public static MeshImpostor = 4;
+        public static CapsuleImpostor = 5;
+        public static ConeImpostor = 6;
+        public static CylinderImpostor = 7;
+        public static ConvexHullImpostor = 8;
+        public static HeightmapImpostor = 9;
+        public static Epsilon = 0.001;
+    }
 }

+ 218 - 218
src/PostProcess/RenderPipeline/babylon.postProcessRenderEffect.ts

@@ -1,219 +1,219 @@
-module BABYLON {
-    export class PostProcessRenderEffect {
-        private _engine: Engine;
-
-        private _postProcesses: any;
-        private _getPostProcess: () => PostProcess;
-
-        private _singleInstance: boolean;
-
-        private _cameras: Camera[];
-        private _indicesForCamera: number[][];
-
-        private _renderPasses: any;
-        private _renderEffectAsPasses: any;
-
-        // private
-        public _name: string;
-
-        public applyParameters: (postProcess: PostProcess) => void;
-
-        constructor(engine: Engine, name: string, getPostProcess: () => PostProcess, singleInstance?: boolean) {
-            this._engine = engine;
-            this._name = name;
-            this._singleInstance = singleInstance || true;
-
-            this._getPostProcess = getPostProcess;
-
-            this._cameras = [];
-            this._indicesForCamera = [];
-
-            this._postProcesses = {};
-
-            this._renderPasses = {};
-            this._renderEffectAsPasses = {};
-        }
-
-        public get isSupported(): boolean {
-            for (var index in this._postProcesses) {
-                if (!this._postProcesses[index].isSupported) {
-                    return false;
-                }
-            }
-            return true;
-        }
-
-        public _update(): void {
-            for (var renderPassName in this._renderPasses) {
-                this._renderPasses[renderPassName]._update();
-            }
-        }
-
-        public addPass(renderPass: PostProcessRenderPass): void {
-            this._renderPasses[renderPass._name] = renderPass;
-
-            this._linkParameters();
-        }
-
-        public removePass(renderPass: PostProcessRenderPass): void {
-            delete this._renderPasses[renderPass._name];
-
-            this._linkParameters();
-        }
-
-        public addRenderEffectAsPass(renderEffect: PostProcessRenderEffect): void {
-            this._renderEffectAsPasses[renderEffect._name] = renderEffect;
-
-            this._linkParameters();
-        }
-
-        public getPass(passName: string): void {
-            for (var renderPassName in this._renderPasses) {
-                if (renderPassName === passName) {
-                    return this._renderPasses[passName];
-                }
-            }
-        }
-
-        public emptyPasses(): void {
-            this._renderPasses = {};
-
-            this._linkParameters();
-        }
-
-        // private
-        public _attachCameras(cameras: Camera);
-        public _attachCameras(cameras: Camera[]);
-        public _attachCameras(cameras: any): void {
-            var cameraKey;
-
-            var _cam = Tools.MakeArray(cameras || this._cameras);
-
-            for (var i = 0; i < _cam.length; i++) {
-                var camera = _cam[i];
-                var cameraName = camera.name;
-
-                if (this._singleInstance) {
-                    cameraKey = 0;
-                }
-                else {
-                    cameraKey = cameraName;
-                }
-
-                this._postProcesses[cameraKey] = this._postProcesses[cameraKey] || this._getPostProcess();
-
-                var index = camera.attachPostProcess(this._postProcesses[cameraKey]);
-
-                if (!this._indicesForCamera[cameraName]) {
-                    this._indicesForCamera[cameraName] = [];
-                }
-
-                this._indicesForCamera[cameraName].push(index);
-
-                if (this._cameras.indexOf(camera) === -1) {
-                    this._cameras[cameraName] = camera;
-                }
-
-                for (var passName in this._renderPasses) {
-                    this._renderPasses[passName]._incRefCount();
-                }
-            }
-
-            this._linkParameters();
-        }
-
-        // private
-        public _detachCameras(cameras: Camera);
-        public _detachCameras(cameras: Camera[]);
-        public _detachCameras(cameras: any): void {
-            var _cam = Tools.MakeArray(cameras || this._cameras);
-
-            for (var i = 0; i < _cam.length; i++) {
-                var camera = _cam[i];
-                var cameraName = camera.name;
-
-                camera.detachPostProcess(this._postProcesses[this._singleInstance ? 0 : cameraName], this._indicesForCamera[cameraName]);
-
-                var index = this._cameras.indexOf(cameraName);
-
-                this._indicesForCamera.splice(index, 1);
-                this._cameras.splice(index, 1);
-
-                for (var passName in this._renderPasses) {
-                    this._renderPasses[passName]._decRefCount();
-                }
-            }
-        }
-
-        // private
-        public _enable(cameras: Camera);
-        public _enable(cameras: Camera[]);
-        public _enable(cameras: any): void {
-            var _cam = Tools.MakeArray(cameras || this._cameras);
-
-            for (var i = 0; i < _cam.length; i++) {
-                var camera = _cam[i];
-                var cameraName = camera.name;
-
-                for (var j = 0; j < this._indicesForCamera[cameraName].length; j++) {
-                    if (camera._postProcesses[this._indicesForCamera[cameraName][j]] === undefined) {
-                        cameras[i].attachPostProcess(this._postProcesses[this._singleInstance ? 0 : cameraName], this._indicesForCamera[cameraName][j]);
-                    }
-                }
-
-                for (var passName in this._renderPasses) {
-                    this._renderPasses[passName]._incRefCount();
-                }
-            }
-        }
-
-        // private
-        public _disable(cameras: Camera);
-        public _disable(cameras: Camera[]);
-        public _disable(cameras: any): void {
-            var _cam = Tools.MakeArray(cameras || this._cameras);
-
-            for (var i = 0; i < _cam.length; i++) {
-                var camera = _cam[i];
-                var cameraName = camera.Name;
-
-                camera.detachPostProcess(this._postProcesses[this._singleInstance ? 0 : cameraName], this._indicesForCamera[cameraName]);
-
-                for (var passName in this._renderPasses) {
-                    this._renderPasses[passName]._decRefCount();
-                }
-            }
-        }
-
-        public getPostProcess(camera?: Camera): PostProcess {
-            if (this._singleInstance) {
-                return this._postProcesses[0];
-            }
-            else {
-                return this._postProcesses[camera.name];
-            }
-        }
-
-        private _linkParameters(): void {
-            for (var index in this._postProcesses) {
-                if (this.applyParameters) {
-                    this.applyParameters(this._postProcesses[index]);
-                }
-
-                this._postProcesses[index].onBeforeRender = (effect: Effect) => {
-                    this._linkTextures(effect);
-                };
-            }
-        }
-
-        private _linkTextures(effect): void {
-            for (var renderPassName in this._renderPasses) {
-                effect.setTexture(renderPassName, this._renderPasses[renderPassName].getRenderTexture());
-            }
-
-            for (var renderEffectName in this._renderEffectAsPasses) {
-                effect.setTextureFromPostProcess(renderEffectName + "Sampler", this._renderEffectAsPasses[renderEffectName].getPostProcess());
-            }
-        }
-    }
+module BABYLON {
+    export class PostProcessRenderEffect {
+        private _engine: Engine;
+
+        private _postProcesses: any;
+        private _getPostProcess: () => PostProcess;
+
+        private _singleInstance: boolean;
+
+        private _cameras: Camera[];
+        private _indicesForCamera: number[][];
+
+        private _renderPasses: any;
+        private _renderEffectAsPasses: any;
+
+        // private
+        public _name: string;
+
+        public applyParameters: (postProcess: PostProcess) => void;
+
+        constructor(engine: Engine, name: string, getPostProcess: () => PostProcess, singleInstance?: boolean) {
+            this._engine = engine;
+            this._name = name;
+            this._singleInstance = singleInstance || true;
+
+            this._getPostProcess = getPostProcess;
+
+            this._cameras = [];
+            this._indicesForCamera = [];
+
+            this._postProcesses = {};
+
+            this._renderPasses = {};
+            this._renderEffectAsPasses = {};
+        }
+
+        public get isSupported(): boolean {
+            for (var index in this._postProcesses) {
+                if (!this._postProcesses[index].isSupported) {
+                    return false;
+                }
+            }
+            return true;
+        }
+
+        public _update(): void {
+            for (var renderPassName in this._renderPasses) {
+                this._renderPasses[renderPassName]._update();
+            }
+        }
+
+        public addPass(renderPass: PostProcessRenderPass): void {
+            this._renderPasses[renderPass._name] = renderPass;
+
+            this._linkParameters();
+        }
+
+        public removePass(renderPass: PostProcessRenderPass): void {
+            delete this._renderPasses[renderPass._name];
+
+            this._linkParameters();
+        }
+
+        public addRenderEffectAsPass(renderEffect: PostProcessRenderEffect): void {
+            this._renderEffectAsPasses[renderEffect._name] = renderEffect;
+
+            this._linkParameters();
+        }
+
+        public getPass(passName: string): void {
+            for (var renderPassName in this._renderPasses) {
+                if (renderPassName === passName) {
+                    return this._renderPasses[passName];
+                }
+            }
+        }
+
+        public emptyPasses(): void {
+            this._renderPasses = {};
+
+            this._linkParameters();
+        }
+
+        // private
+        public _attachCameras(cameras: Camera);
+        public _attachCameras(cameras: Camera[]);
+        public _attachCameras(cameras: any): void {
+            var cameraKey;
+
+            var _cam = Tools.MakeArray(cameras || this._cameras);
+
+            for (var i = 0; i < _cam.length; i++) {
+                var camera = _cam[i];
+                var cameraName = camera.name;
+
+                if (this._singleInstance) {
+                    cameraKey = 0;
+                }
+                else {
+                    cameraKey = cameraName;
+                }
+
+                this._postProcesses[cameraKey] = this._postProcesses[cameraKey] || this._getPostProcess();
+
+                var index = camera.attachPostProcess(this._postProcesses[cameraKey]);
+
+                if (!this._indicesForCamera[cameraName]) {
+                    this._indicesForCamera[cameraName] = [];
+                }
+
+                this._indicesForCamera[cameraName].push(index);
+
+                if (this._cameras.indexOf(camera) === -1) {
+                    this._cameras[cameraName] = camera;
+                }
+
+                for (var passName in this._renderPasses) {
+                    this._renderPasses[passName]._incRefCount();
+                }
+            }
+
+            this._linkParameters();
+        }
+
+        // private
+        public _detachCameras(cameras: Camera);
+        public _detachCameras(cameras: Camera[]);
+        public _detachCameras(cameras: any): void {
+            var _cam = Tools.MakeArray(cameras || this._cameras);
+
+            for (var i = 0; i < _cam.length; i++) {
+                var camera = _cam[i];
+                var cameraName = camera.name;
+
+                camera.detachPostProcess(this._postProcesses[this._singleInstance ? 0 : cameraName], this._indicesForCamera[cameraName]);
+
+                var index = this._cameras.indexOf(cameraName);
+
+                this._indicesForCamera.splice(index, 1);
+                this._cameras.splice(index, 1);
+
+                for (var passName in this._renderPasses) {
+                    this._renderPasses[passName]._decRefCount();
+                }
+            }
+        }
+
+        // private
+        public _enable(cameras: Camera);
+        public _enable(cameras: Camera[]);
+        public _enable(cameras: any): void {
+            var _cam = Tools.MakeArray(cameras || this._cameras);
+
+            for (var i = 0; i < _cam.length; i++) {
+                var camera = _cam[i];
+                var cameraName = camera.name;
+
+                for (var j = 0; j < this._indicesForCamera[cameraName].length; j++) {
+                    if (camera._postProcesses[this._indicesForCamera[cameraName][j]] === undefined) {
+                        cameras[i].attachPostProcess(this._postProcesses[this._singleInstance ? 0 : cameraName], this._indicesForCamera[cameraName][j]);
+                    }
+                }
+
+                for (var passName in this._renderPasses) {
+                    this._renderPasses[passName]._incRefCount();
+                }
+            }
+        }
+
+        // private
+        public _disable(cameras: Camera);
+        public _disable(cameras: Camera[]);
+        public _disable(cameras: any): void {
+            var _cam = Tools.MakeArray(cameras || this._cameras);
+
+            for (var i = 0; i < _cam.length; i++) {
+                var camera = _cam[i];
+                var cameraName = camera.Name;
+
+                camera.detachPostProcess(this._postProcesses[this._singleInstance ? 0 : cameraName], this._indicesForCamera[cameraName]);
+
+                for (var passName in this._renderPasses) {
+                    this._renderPasses[passName]._decRefCount();
+                }
+            }
+        }
+
+        public getPostProcess(camera?: Camera): PostProcess {
+            if (this._singleInstance) {
+                return this._postProcesses[0];
+            }
+            else {
+                return this._postProcesses[camera.name];
+            }
+        }
+
+        private _linkParameters(): void {
+            for (var index in this._postProcesses) {
+                if (this.applyParameters) {
+                    this.applyParameters(this._postProcesses[index]);
+                }
+
+                this._postProcesses[index].onBeforeRender = (effect: Effect) => {
+                    this._linkTextures(effect);
+                };
+            }
+        }
+
+        private _linkTextures(effect): void {
+            for (var renderPassName in this._renderPasses) {
+                effect.setTexture(renderPassName, this._renderPasses[renderPassName].getRenderTexture());
+            }
+
+            for (var renderEffectName in this._renderEffectAsPasses) {
+                effect.setTextureFromPostProcess(renderEffectName + "Sampler", this._renderEffectAsPasses[renderEffectName].getPostProcess());
+            }
+        }
+    }
 }

+ 58 - 58
src/PostProcess/RenderPipeline/babylon.postProcessRenderPass.ts

@@ -1,59 +1,59 @@
-module BABYLON {
-    export class PostProcessRenderPass {
-        private _enabled: boolean = true;
-        private _renderList: Mesh[];
-        private _renderTexture: RenderTargetTexture;
-        private _scene: Scene;
-        private _refCount: number = 0;
-
-        // private
-        public _name: string;
-
-        constructor(scene: Scene, name: string, size: number, renderList: Mesh[], beforeRender: () => void, afterRender: () => void) {
-            this._name = name;
-
-            this._renderTexture = new RenderTargetTexture(name, size, scene);
-            this.setRenderList(renderList);
-
-            this._renderTexture.onBeforeRender = beforeRender;
-            this._renderTexture.onAfterRender = afterRender;
-
-            this._scene = scene;
-
-            this._renderList = renderList;
-        }
-
-        // private
-        public _incRefCount(): number {
-            if (this._refCount === 0) {
-                this._scene.customRenderTargets.push(this._renderTexture);
-            }
-
-            return ++this._refCount;
-        }
-
-        public _decRefCount(): number {
-            this._refCount--;
-
-            if (this._refCount <= 0) {
-                this._scene.customRenderTargets.splice(this._scene.customRenderTargets.indexOf(this._renderTexture), 1);
-            }
-
-            return this._refCount;
-        }
-
-        public _update(): void {
-            this.setRenderList(this._renderList);
-        }
-
-        // public
-
-        public setRenderList(renderList: Mesh[]): void {
-            this._renderTexture.renderList = renderList;
-        }
-
-        public getRenderTexture(): RenderTargetTexture {
-            return this._renderTexture;
-        }
-    }
+module BABYLON {
+    export class PostProcessRenderPass {
+        private _enabled: boolean = true;
+        private _renderList: Mesh[];
+        private _renderTexture: RenderTargetTexture;
+        private _scene: Scene;
+        private _refCount: number = 0;
+
+        // private
+        public _name: string;
+
+        constructor(scene: Scene, name: string, size: number, renderList: Mesh[], beforeRender: () => void, afterRender: () => void) {
+            this._name = name;
+
+            this._renderTexture = new RenderTargetTexture(name, size, scene);
+            this.setRenderList(renderList);
+
+            this._renderTexture.onBeforeRender = beforeRender;
+            this._renderTexture.onAfterRender = afterRender;
+
+            this._scene = scene;
+
+            this._renderList = renderList;
+        }
+
+        // private
+        public _incRefCount(): number {
+            if (this._refCount === 0) {
+                this._scene.customRenderTargets.push(this._renderTexture);
+            }
+
+            return ++this._refCount;
+        }
+
+        public _decRefCount(): number {
+            this._refCount--;
+
+            if (this._refCount <= 0) {
+                this._scene.customRenderTargets.splice(this._scene.customRenderTargets.indexOf(this._renderTexture), 1);
+            }
+
+            return this._refCount;
+        }
+
+        public _update(): void {
+            this.setRenderList(this._renderList);
+        }
+
+        // public
+
+        public setRenderList(renderList: Mesh[]): void {
+            this._renderTexture.renderList = renderList;
+        }
+
+        public getRenderTexture(): RenderTargetTexture {
+            return this._renderTexture;
+        }
+    }
 }

+ 180 - 180
src/PostProcess/RenderPipeline/babylon.postProcessRenderPipeline.ts

@@ -1,181 +1,181 @@
-module BABYLON {
-    export class PostProcessRenderPipeline {
-        private _engine: Engine;
-
-        private _renderEffects: any;
-        private _renderEffectsForIsolatedPass: any;
-
-        private _cameras: Camera[];
-
-        // private
-        public _name: string;
-
-        private static PASS_EFFECT_NAME: string = "passEffect";
-        private static PASS_SAMPLER_NAME: string = "passSampler";
-
-        constructor(engine: Engine, name: string) {
-            this._engine = engine;
-            this._name = name;
-
-            this._renderEffects = {};
-            this._renderEffectsForIsolatedPass = {};
-
-            this._cameras = [];
-        }
-
-        public get isSupported(): boolean {
-            for (var renderEffectName in this._renderEffects) {
-                if (!this._renderEffects[renderEffectName].isSupported) {
-                    return false;
-                }
-            }
-
-            return true;
-        }
-
-        public addEffect(renderEffect: PostProcessRenderEffect): void {
-            this._renderEffects[renderEffect._name] = renderEffect;
-        }
-
-        // private
-
-        public _enableEffect(renderEffectName: string, cameras: Camera);
-        public _enableEffect(renderEffectName: string, cameras: Camera[]);
-        public _enableEffect(renderEffectName: string, cameras: any): void {
-            var renderEffects: PostProcessRenderEffect = this._renderEffects[renderEffectName];
-
-            if (!renderEffects) {
-                return;
-            }
-
-            renderEffects._enable(Tools.MakeArray(cameras || this._cameras));
-        }
-
-        public _disableEffect(renderEffectName: string, cameras: Camera);
-        public _disableEffect(renderEffectName: string, cameras: Camera[]);
-        public _disableEffect(renderEffectName: string, cameras): void {
-            var renderEffects: PostProcessRenderEffect = this._renderEffects[renderEffectName];
-
-            if (!renderEffects) {
-                return;
-            }
-
-            renderEffects._disable(Tools.MakeArray(cameras || this._cameras));
-        }
-
-        public _attachCameras(cameras: Camera, unique: boolean);
-        public _attachCameras(cameras: Camera[], unique: boolean);
-        public _attachCameras(cameras: any, unique: boolean): void {
-            var _cam = Tools.MakeArray(cameras || this._cameras);
-
-            var indicesToDelete = [];
-            var i: number;
-            for (i = 0; i < _cam.length; i++) {
-                var camera = _cam[i];
-                var cameraName = camera.name;
-
-                if (this._cameras.indexOf(camera) === -1) {
-                    this._cameras[cameraName] = camera;
-                }
-                else if (unique) {
-                    indicesToDelete.push(i);
-                }
-            }
-
-            for (i = 0; i < indicesToDelete.length; i++) {
-                cameras.splice(indicesToDelete[i], 1);
-            }
-
-            for (var renderEffectName in this._renderEffects) {
-                this._renderEffects[renderEffectName]._attachCameras(_cam);
-            }
-        }
-
-        public _detachCameras(cameras: Camera);
-        public _detachCameras(cameras: Camera[]);
-        public _detachCameras(cameras: any): void {
-            var _cam = Tools.MakeArray(cameras || this._cameras);
-
-            for (var renderEffectName in this._renderEffects) {
-                this._renderEffects[renderEffectName]._detachCameras(_cam);
-            }
-
-            for (var i = 0; i < _cam.length; i++) {
-                this._cameras.splice(this._cameras.indexOf(_cam[i]), 1);
-            }
-        }
-
-        public _enableDisplayOnlyPass(passName, cameras: Camera);
-        public _enableDisplayOnlyPass(passName, cameras: Camera[]);
-        public _enableDisplayOnlyPass(passName, cameras: any): void {
-            var _cam = Tools.MakeArray(cameras || this._cameras);
-
-            var pass = null;
-            var renderEffectName;
-            for (renderEffectName in this._renderEffects) {
-                pass = this._renderEffects[renderEffectName].getPass(passName);
-
-                if (pass != null) {
-                    break;
-                }
-            }
-
-            if (pass === null) {
-                return;
-            }
-
-            for (renderEffectName in this._renderEffects) {
-                this._renderEffects[renderEffectName]._disable(_cam);
-            }
-
-            pass._name = PostProcessRenderPipeline.PASS_SAMPLER_NAME;
-
-            for (var i = 0; i < _cam.length; i++) {
-                var camera = _cam[i];
-                var cameraName = camera.name;
-
-                this._renderEffectsForIsolatedPass[cameraName] = this._renderEffectsForIsolatedPass[cameraName] || new PostProcessRenderEffect(this._engine, PostProcessRenderPipeline.PASS_EFFECT_NAME,
-                    () => {return new DisplayPassPostProcess(PostProcessRenderPipeline.PASS_EFFECT_NAME, 1.0, null, null, this._engine, true) });
-                this._renderEffectsForIsolatedPass[cameraName].emptyPasses();
-                this._renderEffectsForIsolatedPass[cameraName].addPass(pass);
-                this._renderEffectsForIsolatedPass[cameraName]._attachCameras(camera);
-            }
-        }
-
-        public _disableDisplayOnlyPass(cameras: Camera);
-        public _disableDisplayOnlyPass(cameras: Camera[]);
-        public _disableDisplayOnlyPass(cameras: any): void {
-            var _cam = Tools.MakeArray(cameras || this._cameras);
-
-            for (var i = 0; i < _cam.length; i++) {
-                var camera = _cam[i];
-                var cameraName = camera.name;
-
-                this._renderEffectsForIsolatedPass[cameraName] = this._renderEffectsForIsolatedPass[cameraName] || new PostProcessRenderEffect(this._engine, PostProcessRenderPipeline.PASS_EFFECT_NAME, 
-                                    () => {return new DisplayPassPostProcess(PostProcessRenderPipeline.PASS_EFFECT_NAME, 1.0, null, null, this._engine, true) });
-                this._renderEffectsForIsolatedPass[cameraName]._disable(camera);
-            }
-
-            for (var renderEffectName in this._renderEffects) {
-                this._renderEffects[renderEffectName]._enable(_cam);
-            }
-        }
-
-        public _update(): void {
-            for (var renderEffectName in this._renderEffects) {
-                this._renderEffects[renderEffectName]._update();
-            }
-
-            for (var i = 0; i < this._cameras.length; i++) {
-                var cameraName = this._cameras[i].name;
-                if (this._renderEffectsForIsolatedPass[cameraName]) {
-                    this._renderEffectsForIsolatedPass[cameraName]._update();
-                }
-            }
-        }
-
-        public dispose() {
-           // Must be implemented by children 
-        }
-    }
+module BABYLON {
+    export class PostProcessRenderPipeline {
+        private _engine: Engine;
+
+        private _renderEffects: any;
+        private _renderEffectsForIsolatedPass: any;
+
+        private _cameras: Camera[];
+
+        // private
+        public _name: string;
+
+        private static PASS_EFFECT_NAME: string = "passEffect";
+        private static PASS_SAMPLER_NAME: string = "passSampler";
+
+        constructor(engine: Engine, name: string) {
+            this._engine = engine;
+            this._name = name;
+
+            this._renderEffects = {};
+            this._renderEffectsForIsolatedPass = {};
+
+            this._cameras = [];
+        }
+
+        public get isSupported(): boolean {
+            for (var renderEffectName in this._renderEffects) {
+                if (!this._renderEffects[renderEffectName].isSupported) {
+                    return false;
+                }
+            }
+
+            return true;
+        }
+
+        public addEffect(renderEffect: PostProcessRenderEffect): void {
+            this._renderEffects[renderEffect._name] = renderEffect;
+        }
+
+        // private
+
+        public _enableEffect(renderEffectName: string, cameras: Camera);
+        public _enableEffect(renderEffectName: string, cameras: Camera[]);
+        public _enableEffect(renderEffectName: string, cameras: any): void {
+            var renderEffects: PostProcessRenderEffect = this._renderEffects[renderEffectName];
+
+            if (!renderEffects) {
+                return;
+            }
+
+            renderEffects._enable(Tools.MakeArray(cameras || this._cameras));
+        }
+
+        public _disableEffect(renderEffectName: string, cameras: Camera);
+        public _disableEffect(renderEffectName: string, cameras: Camera[]);
+        public _disableEffect(renderEffectName: string, cameras): void {
+            var renderEffects: PostProcessRenderEffect = this._renderEffects[renderEffectName];
+
+            if (!renderEffects) {
+                return;
+            }
+
+            renderEffects._disable(Tools.MakeArray(cameras || this._cameras));
+        }
+
+        public _attachCameras(cameras: Camera, unique: boolean);
+        public _attachCameras(cameras: Camera[], unique: boolean);
+        public _attachCameras(cameras: any, unique: boolean): void {
+            var _cam = Tools.MakeArray(cameras || this._cameras);
+
+            var indicesToDelete = [];
+            var i: number;
+            for (i = 0; i < _cam.length; i++) {
+                var camera = _cam[i];
+                var cameraName = camera.name;
+
+                if (this._cameras.indexOf(camera) === -1) {
+                    this._cameras[cameraName] = camera;
+                }
+                else if (unique) {
+                    indicesToDelete.push(i);
+                }
+            }
+
+            for (i = 0; i < indicesToDelete.length; i++) {
+                cameras.splice(indicesToDelete[i], 1);
+            }
+
+            for (var renderEffectName in this._renderEffects) {
+                this._renderEffects[renderEffectName]._attachCameras(_cam);
+            }
+        }
+
+        public _detachCameras(cameras: Camera);
+        public _detachCameras(cameras: Camera[]);
+        public _detachCameras(cameras: any): void {
+            var _cam = Tools.MakeArray(cameras || this._cameras);
+
+            for (var renderEffectName in this._renderEffects) {
+                this._renderEffects[renderEffectName]._detachCameras(_cam);
+            }
+
+            for (var i = 0; i < _cam.length; i++) {
+                this._cameras.splice(this._cameras.indexOf(_cam[i]), 1);
+            }
+        }
+
+        public _enableDisplayOnlyPass(passName, cameras: Camera);
+        public _enableDisplayOnlyPass(passName, cameras: Camera[]);
+        public _enableDisplayOnlyPass(passName, cameras: any): void {
+            var _cam = Tools.MakeArray(cameras || this._cameras);
+
+            var pass = null;
+            var renderEffectName;
+            for (renderEffectName in this._renderEffects) {
+                pass = this._renderEffects[renderEffectName].getPass(passName);
+
+                if (pass != null) {
+                    break;
+                }
+            }
+
+            if (pass === null) {
+                return;
+            }
+
+            for (renderEffectName in this._renderEffects) {
+                this._renderEffects[renderEffectName]._disable(_cam);
+            }
+
+            pass._name = PostProcessRenderPipeline.PASS_SAMPLER_NAME;
+
+            for (var i = 0; i < _cam.length; i++) {
+                var camera = _cam[i];
+                var cameraName = camera.name;
+
+                this._renderEffectsForIsolatedPass[cameraName] = this._renderEffectsForIsolatedPass[cameraName] || new PostProcessRenderEffect(this._engine, PostProcessRenderPipeline.PASS_EFFECT_NAME,
+                    () => {return new DisplayPassPostProcess(PostProcessRenderPipeline.PASS_EFFECT_NAME, 1.0, null, null, this._engine, true) });
+                this._renderEffectsForIsolatedPass[cameraName].emptyPasses();
+                this._renderEffectsForIsolatedPass[cameraName].addPass(pass);
+                this._renderEffectsForIsolatedPass[cameraName]._attachCameras(camera);
+            }
+        }
+
+        public _disableDisplayOnlyPass(cameras: Camera);
+        public _disableDisplayOnlyPass(cameras: Camera[]);
+        public _disableDisplayOnlyPass(cameras: any): void {
+            var _cam = Tools.MakeArray(cameras || this._cameras);
+
+            for (var i = 0; i < _cam.length; i++) {
+                var camera = _cam[i];
+                var cameraName = camera.name;
+
+                this._renderEffectsForIsolatedPass[cameraName] = this._renderEffectsForIsolatedPass[cameraName] || new PostProcessRenderEffect(this._engine, PostProcessRenderPipeline.PASS_EFFECT_NAME, 
+                                    () => {return new DisplayPassPostProcess(PostProcessRenderPipeline.PASS_EFFECT_NAME, 1.0, null, null, this._engine, true) });
+                this._renderEffectsForIsolatedPass[cameraName]._disable(camera);
+            }
+
+            for (var renderEffectName in this._renderEffects) {
+                this._renderEffects[renderEffectName]._enable(_cam);
+            }
+        }
+
+        public _update(): void {
+            for (var renderEffectName in this._renderEffects) {
+                this._renderEffects[renderEffectName]._update();
+            }
+
+            for (var i = 0; i < this._cameras.length; i++) {
+                var cameraName = this._cameras[i].name;
+                if (this._renderEffectsForIsolatedPass[cameraName]) {
+                    this._renderEffectsForIsolatedPass[cameraName]._update();
+                }
+            }
+        }
+
+        public dispose() {
+           // Must be implemented by children 
+        }
+    }
 }

+ 96 - 96
src/PostProcess/RenderPipeline/babylon.postProcessRenderPipelineManager.ts

@@ -1,97 +1,97 @@
-module BABYLON {
-    export class PostProcessRenderPipelineManager {
-        private _renderPipelines: any;
-
-        constructor() {
-            this._renderPipelines = {};
-        }
-
-        public addPipeline(renderPipeline: PostProcessRenderPipeline): void {
-            this._renderPipelines[renderPipeline._name] = renderPipeline;
-        }
-
-        public attachCamerasToRenderPipeline(renderPipelineName: string, cameras: Camera, unique?: boolean);
-        public attachCamerasToRenderPipeline(renderPipelineName: string, cameras: Camera[], unique?: boolean);
-        public attachCamerasToRenderPipeline(renderPipelineName: string, cameras: any, unique?: boolean): void {
-            var renderPipeline: PostProcessRenderPipeline = this._renderPipelines[renderPipelineName];
-
-            if (!renderPipeline) {
-                return;
-            }
-
-            renderPipeline._attachCameras(cameras, unique);
-        }
-
-        public detachCamerasFromRenderPipeline(renderPipelineName: string, cameras: Camera);
-        public detachCamerasFromRenderPipeline(renderPipelineName: string, cameras: Camera[]);
-        public detachCamerasFromRenderPipeline(renderPipelineName: string, cameras: any): void {
-            var renderPipeline: PostProcessRenderPipeline = this._renderPipelines[renderPipelineName];
-
-            if (!renderPipeline) {
-                return;
-            }
-
-            renderPipeline._detachCameras(cameras);
-        }
-
-        public enableEffectInPipeline(renderPipelineName: string, renderEffectName: string, cameras: Camera);
-        public enableEffectInPipeline(renderPipelineName: string, renderEffectName: string, cameras: Camera[]);
-        public enableEffectInPipeline(renderPipelineName: string, renderEffectName: string, cameras: any): void {
-            var renderPipeline: PostProcessRenderPipeline = this._renderPipelines[renderPipelineName];
-
-            if (!renderPipeline) {
-                return;
-            }
-
-            renderPipeline._enableEffect(renderEffectName, cameras);
-        }
-
-        public disableEffectInPipeline(renderPipelineName: string, renderEffectName: string, cameras: Camera);
-        public disableEffectInPipeline(renderPipelineName: string, renderEffectName: string, cameras: Camera[]);
-        public disableEffectInPipeline(renderPipelineName: string, renderEffectName: string, cameras: any): void {
-            var renderPipeline: PostProcessRenderPipeline = this._renderPipelines[renderPipelineName];
-
-            if (!renderPipeline) {
-                return;
-            }
-
-            renderPipeline._disableEffect(renderEffectName, cameras);
-        }
-
-        public enableDisplayOnlyPassInPipeline(renderPipelineName: string, passName: string, cameras: Camera);
-        public enableDisplayOnlyPassInPipeline(renderPipelineName: string, passName: string, cameras: Camera[]);
-        public enableDisplayOnlyPassInPipeline(renderPipelineName: string, passName: string, cameras: any): void {
-            var renderPipeline: PostProcessRenderPipeline = this._renderPipelines[renderPipelineName];
-
-            if (!renderPipeline) {
-                return;
-            }
-
-            renderPipeline._enableDisplayOnlyPass(passName, cameras);
-        }
-
-        public disableDisplayOnlyPassInPipeline(renderPipelineName: string, cameras: Camera);
-        public disableDisplayOnlyPassInPipeline(renderPipelineName: string, cameras: Camera[]);
-        public disableDisplayOnlyPassInPipeline(renderPipelineName: string, cameras: any): void {
-            var renderPipeline: PostProcessRenderPipeline = this._renderPipelines[renderPipelineName];
-
-            if (!renderPipeline) {
-                return;
-            }
-
-            renderPipeline._disableDisplayOnlyPass(cameras);
-        }
-
-        public update(): void {
-            for (var renderPipelineName in this._renderPipelines) {
-                var pipeline = this._renderPipelines[renderPipelineName];
-                if (!pipeline.isSupported) {
-                    pipeline.dispose();
-                    delete this._renderPipelines[renderPipelineName];
-                } else {
-                    pipeline._update();
-                }
-            }
-        }
-    }
+module BABYLON {
+    export class PostProcessRenderPipelineManager {
+        private _renderPipelines: any;
+
+        constructor() {
+            this._renderPipelines = {};
+        }
+
+        public addPipeline(renderPipeline: PostProcessRenderPipeline): void {
+            this._renderPipelines[renderPipeline._name] = renderPipeline;
+        }
+
+        public attachCamerasToRenderPipeline(renderPipelineName: string, cameras: Camera, unique?: boolean);
+        public attachCamerasToRenderPipeline(renderPipelineName: string, cameras: Camera[], unique?: boolean);
+        public attachCamerasToRenderPipeline(renderPipelineName: string, cameras: any, unique?: boolean): void {
+            var renderPipeline: PostProcessRenderPipeline = this._renderPipelines[renderPipelineName];
+
+            if (!renderPipeline) {
+                return;
+            }
+
+            renderPipeline._attachCameras(cameras, unique);
+        }
+
+        public detachCamerasFromRenderPipeline(renderPipelineName: string, cameras: Camera);
+        public detachCamerasFromRenderPipeline(renderPipelineName: string, cameras: Camera[]);
+        public detachCamerasFromRenderPipeline(renderPipelineName: string, cameras: any): void {
+            var renderPipeline: PostProcessRenderPipeline = this._renderPipelines[renderPipelineName];
+
+            if (!renderPipeline) {
+                return;
+            }
+
+            renderPipeline._detachCameras(cameras);
+        }
+
+        public enableEffectInPipeline(renderPipelineName: string, renderEffectName: string, cameras: Camera);
+        public enableEffectInPipeline(renderPipelineName: string, renderEffectName: string, cameras: Camera[]);
+        public enableEffectInPipeline(renderPipelineName: string, renderEffectName: string, cameras: any): void {
+            var renderPipeline: PostProcessRenderPipeline = this._renderPipelines[renderPipelineName];
+
+            if (!renderPipeline) {
+                return;
+            }
+
+            renderPipeline._enableEffect(renderEffectName, cameras);
+        }
+
+        public disableEffectInPipeline(renderPipelineName: string, renderEffectName: string, cameras: Camera);
+        public disableEffectInPipeline(renderPipelineName: string, renderEffectName: string, cameras: Camera[]);
+        public disableEffectInPipeline(renderPipelineName: string, renderEffectName: string, cameras: any): void {
+            var renderPipeline: PostProcessRenderPipeline = this._renderPipelines[renderPipelineName];
+
+            if (!renderPipeline) {
+                return;
+            }
+
+            renderPipeline._disableEffect(renderEffectName, cameras);
+        }
+
+        public enableDisplayOnlyPassInPipeline(renderPipelineName: string, passName: string, cameras: Camera);
+        public enableDisplayOnlyPassInPipeline(renderPipelineName: string, passName: string, cameras: Camera[]);
+        public enableDisplayOnlyPassInPipeline(renderPipelineName: string, passName: string, cameras: any): void {
+            var renderPipeline: PostProcessRenderPipeline = this._renderPipelines[renderPipelineName];
+
+            if (!renderPipeline) {
+                return;
+            }
+
+            renderPipeline._enableDisplayOnlyPass(passName, cameras);
+        }
+
+        public disableDisplayOnlyPassInPipeline(renderPipelineName: string, cameras: Camera);
+        public disableDisplayOnlyPassInPipeline(renderPipelineName: string, cameras: Camera[]);
+        public disableDisplayOnlyPassInPipeline(renderPipelineName: string, cameras: any): void {
+            var renderPipeline: PostProcessRenderPipeline = this._renderPipelines[renderPipelineName];
+
+            if (!renderPipeline) {
+                return;
+            }
+
+            renderPipeline._disableDisplayOnlyPass(cameras);
+        }
+
+        public update(): void {
+            for (var renderPipelineName in this._renderPipelines) {
+                var pipeline = this._renderPipelines[renderPipelineName];
+                if (!pipeline.isSupported) {
+                    pipeline.dispose();
+                    delete this._renderPipelines[renderPipelineName];
+                } else {
+                    pipeline._update();
+                }
+            }
+        }
+    }
 }

+ 6 - 6
src/PostProcess/babylon.anaglyphPostProcess.ts

@@ -1,7 +1,7 @@
-module BABYLON {
-    export class AnaglyphPostProcess extends PostProcess {
-        constructor(name: string, ratio: number, camera: Camera, samplingMode?: number, engine?: Engine, reusable?: boolean) {
-            super(name, "anaglyph", null, ["leftSampler"], ratio, camera, samplingMode, engine, reusable);
-        }
-    }
+module BABYLON {
+    export class AnaglyphPostProcess extends PostProcess {
+        constructor(name: string, ratio: number, camera: Camera, samplingMode?: number, engine?: Engine, reusable?: boolean) {
+            super(name, "anaglyph", null, ["leftSampler"], ratio, camera, samplingMode, engine, reusable);
+        }
+    }
 } 

+ 6 - 6
src/PostProcess/babylon.blackAndWhitePostProcess.ts

@@ -1,7 +1,7 @@
-module BABYLON {
-    export class BlackAndWhitePostProcess extends PostProcess {
-        constructor(name: string, ratio: number, camera: Camera, samplingMode?: number, engine?: Engine, reusable?: boolean) {
-            super(name, "blackAndWhite", null, null, ratio, camera, samplingMode, engine, reusable);
-        }
-    }
+module BABYLON {
+    export class BlackAndWhitePostProcess extends PostProcess {
+        constructor(name: string, ratio: number, camera: Camera, samplingMode?: number, engine?: Engine, reusable?: boolean) {
+            super(name, "blackAndWhite", null, null, ratio, camera, samplingMode, engine, reusable);
+        }
+    }
 } 

+ 12 - 12
src/PostProcess/babylon.blurPostProcess.ts

@@ -1,13 +1,13 @@
-module BABYLON {
-    export class BlurPostProcess extends PostProcess {
-        constructor(name: string, public direction: Vector2, public blurWidth: number, ratio: number, camera: Camera, samplingMode: number = Texture.BILINEAR_SAMPLINGMODE, engine?: Engine, reusable?: boolean) {
-            super(name, "blur", ["screenSize", "direction", "blurWidth"], null, ratio, camera, samplingMode, engine, reusable);
-            this.onApply = (effect: Effect) => {
-                effect.setFloat2("screenSize", this.width, this.height);
-                effect.setVector2("direction", this.direction);
-                effect.setFloat("blurWidth", this.blurWidth);
-            };
-        }
-    
-    }
+module BABYLON {
+    export class BlurPostProcess extends PostProcess {
+        constructor(name: string, public direction: Vector2, public blurWidth: number, ratio: number, camera: Camera, samplingMode: number = Texture.BILINEAR_SAMPLINGMODE, engine?: Engine, reusable?: boolean) {
+            super(name, "blur", ["screenSize", "direction", "blurWidth"], null, ratio, camera, samplingMode, engine, reusable);
+            this.onApply = (effect: Effect) => {
+                effect.setFloat2("screenSize", this.width, this.height);
+                effect.setVector2("direction", this.direction);
+                effect.setFloat("blurWidth", this.blurWidth);
+            };
+        }
+    
+    }
 } 

+ 32 - 32
src/PostProcess/babylon.colorCorrectionPostProcess.ts

@@ -1,33 +1,33 @@
-//
-//  This post-process allows the modification of rendered colors by using
-//  a 'look-up table' (LUT). This effect is also called Color Grading.
-// 
-//  The object needs to be provided an url to a texture containing the color
-//  look-up table: the texture must be 256 pixels wide and 16 pixels high.
-//  Use an image editing software to tweak the LUT to match your needs.
-// 
-//  For an example of a color LUT, see here:
-//      http://udn.epicgames.com/Three/rsrc/Three/ColorGrading/RGBTable16x1.png
-//  For explanations on color grading, see here:
-//      http://udn.epicgames.com/Three/ColorGrading.html
-//
-
-module BABYLON {
-    export class ColorCorrectionPostProcess extends PostProcess {
-
-        private _colorTableTexture: Texture;
-
-        constructor(name: string, colorTableUrl: string, ratio: number, camera: Camera, samplingMode?: number, engine?: Engine, reusable?: boolean) {
-            super(name, 'colorCorrection', null, ['colorTable'], ratio, camera, samplingMode, engine, reusable);
-
-            this._colorTableTexture = new Texture(colorTableUrl, camera.getScene(), true, false, Texture.TRILINEAR_SAMPLINGMODE);
-            this._colorTableTexture.anisotropicFilteringLevel = 1;
-            this._colorTableTexture.wrapU = Texture.CLAMP_ADDRESSMODE;
-            this._colorTableTexture.wrapV = Texture.CLAMP_ADDRESSMODE;
-
-            this.onApply = (effect: Effect) => {
-                effect.setTexture("colorTable", this._colorTableTexture);
-            };
-        }
-    }
+//
+//  This post-process allows the modification of rendered colors by using
+//  a 'look-up table' (LUT). This effect is also called Color Grading.
+// 
+//  The object needs to be provided an url to a texture containing the color
+//  look-up table: the texture must be 256 pixels wide and 16 pixels high.
+//  Use an image editing software to tweak the LUT to match your needs.
+// 
+//  For an example of a color LUT, see here:
+//      http://udn.epicgames.com/Three/rsrc/Three/ColorGrading/RGBTable16x1.png
+//  For explanations on color grading, see here:
+//      http://udn.epicgames.com/Three/ColorGrading.html
+//
+
+module BABYLON {
+    export class ColorCorrectionPostProcess extends PostProcess {
+
+        private _colorTableTexture: Texture;
+
+        constructor(name: string, colorTableUrl: string, ratio: number, camera: Camera, samplingMode?: number, engine?: Engine, reusable?: boolean) {
+            super(name, 'colorCorrection', null, ['colorTable'], ratio, camera, samplingMode, engine, reusable);
+
+            this._colorTableTexture = new Texture(colorTableUrl, camera.getScene(), true, false, Texture.TRILINEAR_SAMPLINGMODE);
+            this._colorTableTexture.anisotropicFilteringLevel = 1;
+            this._colorTableTexture.wrapU = Texture.CLAMP_ADDRESSMODE;
+            this._colorTableTexture.wrapV = Texture.CLAMP_ADDRESSMODE;
+
+            this.onApply = (effect: Effect) => {
+                effect.setTexture("colorTable", this._colorTableTexture);
+            };
+        }
+    }
 }

+ 21 - 21
src/PostProcess/babylon.convolutionPostProcess.ts

@@ -1,21 +1,21 @@
-module BABYLON {
-    export class ConvolutionPostProcess extends PostProcess{
-        constructor(name: string, public kernel: number[], ratio: number, camera: Camera, samplingMode?: number, engine?: Engine, reusable?: boolean) {
-            super(name, "convolution", ["kernel", "screenSize"], null, ratio, camera, samplingMode, engine, reusable);
-
-            this.onApply = (effect: Effect) => {
-                effect.setFloat2("screenSize", this.width, this.height);
-                effect.setArray("kernel", this.kernel);
-            };
-        }
-
-    // Statics
-    // Based on http://en.wikipedia.org/wiki/Kernel_(image_processing)
-    public static EdgeDetect0Kernel = [1, 0, -1, 0, 0, 0, -1, 0, 1];
-    public static EdgeDetect1Kernel = [0, 1, 0, 1, -4, 1, 0, 1, 0];
-    public static EdgeDetect2Kernel = [-1, -1, -1, -1, 8, -1, -1, -1, -1];
-    public static SharpenKernel = [0, -1, 0, -1, 5, -1, 0, -1, 0];
-    public static EmbossKernel = [-2, -1, 0, -1, 1, 1, 0, 1, 2];
-    public static GaussianKernel = [0, 1, 0, 1, 1, 1, 0, 1, 0];
-    }
-}
+module BABYLON {
+    export class ConvolutionPostProcess extends PostProcess{
+        constructor(name: string, public kernel: number[], ratio: number, camera: Camera, samplingMode?: number, engine?: Engine, reusable?: boolean) {
+            super(name, "convolution", ["kernel", "screenSize"], null, ratio, camera, samplingMode, engine, reusable);
+
+            this.onApply = (effect: Effect) => {
+                effect.setFloat2("screenSize", this.width, this.height);
+                effect.setArray("kernel", this.kernel);
+            };
+        }
+
+    // Statics
+    // Based on http://en.wikipedia.org/wiki/Kernel_(image_processing)
+    public static EdgeDetect0Kernel = [1, 0, -1, 0, 0, 0, -1, 0, 1];
+    public static EdgeDetect1Kernel = [0, 1, 0, 1, -4, 1, 0, 1, 0];
+    public static EdgeDetect2Kernel = [-1, -1, -1, -1, 8, -1, -1, -1, -1];
+    public static SharpenKernel = [0, -1, 0, -1, 5, -1, 0, -1, 0];
+    public static EmbossKernel = [-2, -1, 0, -1, 1, 1, 0, 1, 2];
+    public static GaussianKernel = [0, 1, 0, 1, 1, 1, 0, 1, 0];
+    }
+}

+ 6 - 6
src/PostProcess/babylon.displayPassPostProcess.ts

@@ -1,7 +1,7 @@
-module BABYLON {
-    export class DisplayPassPostProcess extends PostProcess {
-        constructor(name: string, ratio: number, camera: Camera, samplingMode?: number, engine?: Engine, reusable?: boolean) {
-            super(name, "displayPass", ["passSampler"], ["passSampler"], ratio, camera, samplingMode, engine, reusable);
-        }
-    }
+module BABYLON {
+    export class DisplayPassPostProcess extends PostProcess {
+        constructor(name: string, ratio: number, camera: Camera, samplingMode?: number, engine?: Engine, reusable?: boolean) {
+            super(name, "displayPass", ["passSampler"], ["passSampler"], ratio, camera, samplingMode, engine, reusable);
+        }
+    }
 }

+ 10 - 10
src/PostProcess/babylon.filterPostProcess.ts

@@ -1,11 +1,11 @@
-module BABYLON {
-    export class FilterPostProcess extends PostProcess {
-        constructor(name: string, public kernelMatrix: Matrix, ratio: number, camera?: Camera, samplingMode?: number, engine?: Engine, reusable?: boolean) {
-            super(name, "filter", ["kernelMatrix"], null, ratio, camera, samplingMode, engine, reusable);
-
-            this.onApply = (effect: Effect) => {
-                effect.setMatrix("kernelMatrix", this.kernelMatrix);
-            }
-        }
-    }
+module BABYLON {
+    export class FilterPostProcess extends PostProcess {
+        constructor(name: string, public kernelMatrix: Matrix, ratio: number, camera?: Camera, samplingMode?: number, engine?: Engine, reusable?: boolean) {
+            super(name, "filter", ["kernelMatrix"], null, ratio, camera, samplingMode, engine, reusable);
+
+            this.onApply = (effect: Effect) => {
+                effect.setMatrix("kernelMatrix", this.kernelMatrix);
+            }
+        }
+    }
 }

+ 17 - 17
src/PostProcess/babylon.fxaaPostProcess.ts

@@ -1,18 +1,18 @@
-module BABYLON {
-    export class FxaaPostProcess extends PostProcess {
-        public texelWidth: number;
-        public texelHeight: number;
-
-        constructor(name: string, ratio: number, camera: Camera, samplingMode?: number, engine?: Engine, reusable?: boolean) {
-            super(name, "fxaa", ["texelSize"], null, ratio, camera, samplingMode, engine, reusable);
-
-            this.onSizeChanged = () => {
-                this.texelWidth = 1.0 / this.width;
-                this.texelHeight = 1.0 / this.height;
-            };
-            this.onApply = (effect: Effect) => {
-                effect.setFloat2("texelSize", this.texelWidth, this.texelHeight);
-            }
-        }
-    }
+module BABYLON {
+    export class FxaaPostProcess extends PostProcess {
+        public texelWidth: number;
+        public texelHeight: number;
+
+        constructor(name: string, ratio: number, camera: Camera, samplingMode?: number, engine?: Engine, reusable?: boolean) {
+            super(name, "fxaa", ["texelSize"], null, ratio, camera, samplingMode, engine, reusable);
+
+            this.onSizeChanged = () => {
+                this.texelWidth = 1.0 / this.width;
+                this.texelHeight = 1.0 / this.height;
+            };
+            this.onApply = (effect: Effect) => {
+                effect.setFloat2("texelSize", this.texelWidth, this.texelHeight);
+            }
+        }
+    }
 }

+ 450 - 450
src/PostProcess/babylon.hdrRenderingPipeline.ts

@@ -1,451 +1,451 @@
-module BABYLON {
-    export class HDRRenderingPipeline extends PostProcessRenderPipeline implements IDisposable {
-
-        /**
-        * Public members
-        */
-        
-        // Gaussian Blur
-        /**
-        * Gaussian blur coefficient
-        * @type {number}
-        */
-        public gaussCoeff: number = 0.3;
-        /**
-        * Gaussian blur mean
-        * @type {number}
-        */
-        public gaussMean: number = 1.0;
-        /**
-        * Gaussian blur standard deviation
-        * @type {number}
-        */
-        public gaussStandDev: number = 0.8;
-        /**
-        * Gaussian blur multiplier. Multiplies the blur effect
-        * @type {number}
-        */
-        public gaussMultiplier: number = 4.0;
-
-        // HDR
-        /**
-        * Exposure, controls the overall intensity of the pipeline
-        * @type {number}
-        */
-        public exposure: number = 1.0;
-        /**
-        * Minimum luminance that the post-process can output. Luminance is >= 0
-        * @type {number}
-        */
-        public minimumLuminance: number = 1.0;
-        /**
-        * Maximum luminance that the post-process can output. Must be suprerior to minimumLuminance
-        * @type {number}
-        */
-        public maximumLuminance: number = 1e20;
-        /**
-        * Increase rate for luminance: eye adaptation speed to dark
-        * @type {number}
-        */
-        public luminanceIncreaserate: number = 0.5;
-        /**
-        * Decrease rate for luminance: eye adaptation speed to bright
-        * @type {number}
-        */
-        public luminanceDecreaseRate: number = 0.5;
-
-        // Bright pass
-        /**
-        * Minimum luminance needed to compute HDR
-        * @type {number}
-        */
-        public brightThreshold: number = 0.8;
-
-        /**
-        * Private members
-        */
-        // Gaussian blur
-        private _guassianBlurHPostProcess: PostProcess;
-        private _guassianBlurVPostProcess: PostProcess;
-
-        // Bright pass
-        private _brightPassPostProcess: PostProcess;
-
-        // Texture adder
-        private _textureAdderPostProcess: PostProcess;
-
-        // Down Sampling
-        private _downSampleX4PostProcess: PostProcess;
-
-        // Original Post-process
-        private _originalPostProcess: PostProcess;
-
-        // HDR
-        private _hdrPostProcess: PostProcess;
-        private _hdrCurrentLuminance: number;
-        private _hdrOutputLuminance: number;
-
-        // Luminance generator
-        public static LUM_STEPS: number = 6;
-        private _downSamplePostProcesses: Array<PostProcess>;
-
-        // Global
-        private _scene: Scene;
-        private _needUpdate: boolean = true;
-
-        /**
-         * @constructor
-         * @param {string} name - The rendering pipeline name
-         * @param {BABYLON.Scene} scene - The scene linked to this pipeline
-         * @param {any} ratio - The size of the postprocesses (0.5 means that your postprocess will have a width = canvas.width 0.5 and a height = canvas.height 0.5)
-         * @param {BABYLON.PostProcess} originalPostProcess - the custom original color post-process. Must be "reusable". Can be null.
-         * @param {BABYLON.Camera[]} cameras - The array of cameras that the rendering pipeline will be attached to
-         */
-        constructor(name: string, scene: Scene, ratio: number, originalPostProcess: PostProcess = null, cameras?: Camera[]) {
-            super(scene.getEngine(), name);
-
-            this._scene = scene;
-
-            // Bright pass
-            this._createBrightPassPostProcess(scene, ratio);
-
-            // Down sample X4
-            this._createDownSampleX4PostProcess(scene, ratio);
-
-            // Create gaussian blur post-processes
-            this._createGaussianBlurPostProcess(scene, ratio);
-
-            // Texture adder
-            this._createTextureAdderPostProcess(scene, ratio);
-
-            // Luminance generator
-            this._createLuminanceGeneratorPostProcess(scene);
-
-            // HDR
-            this._createHDRPostProcess(scene, ratio);
-
-            // Pass postprocess
-            if (originalPostProcess === null) {
-                this._originalPostProcess = new PassPostProcess("hdr", ratio, null, Texture.BILINEAR_SAMPLINGMODE, scene.getEngine(), false);
-            } else {
-                this._originalPostProcess = originalPostProcess;
-            }
-
-            // Configure pipeline
-            this.addEffect(new PostProcessRenderEffect(scene.getEngine(), "HDRPassPostProcess",() => { return this._originalPostProcess; }, true));
-            this.addEffect(new PostProcessRenderEffect(scene.getEngine(), "HDRBrightPass",() => { return this._brightPassPostProcess; }, true));
-            this.addEffect(new PostProcessRenderEffect(scene.getEngine(), "HDRDownSampleX4",() => { return this._downSampleX4PostProcess; }, true));
-            this.addEffect(new PostProcessRenderEffect(scene.getEngine(), "HDRGaussianBlurH",() => { return this._guassianBlurHPostProcess; }, true));
-            this.addEffect(new PostProcessRenderEffect(scene.getEngine(), "HDRGaussianBlurV",() => { return this._guassianBlurVPostProcess; }, true));
-            this.addEffect(new PostProcessRenderEffect(scene.getEngine(), "HDRTextureAdder",() => { return this._textureAdderPostProcess; }, true));
-
-            var addDownSamplerPostProcess = (id: number) => {
-                this.addEffect(new PostProcessRenderEffect(scene.getEngine(), "HDRDownSampler" + id,() => { return this._downSamplePostProcesses[id]; }, true));
-            };
-            for (var i = HDRRenderingPipeline.LUM_STEPS - 1; i >= 0; i--) {
-                addDownSamplerPostProcess(i);
-            }
-
-            this.addEffect(new PostProcessRenderEffect(scene.getEngine(), "HDR",() => { return this._hdrPostProcess; }, true));
-
-            // Finish
-            scene.postProcessRenderPipelineManager.addPipeline(this);
-
-            if (cameras !== null) {
-                scene.postProcessRenderPipelineManager.attachCamerasToRenderPipeline(name, cameras);
-            }
-
-            this.update();
-        }
-
-        /**
-        * Tells the pipeline to update its post-processes
-        */
-        public update(): void {
-            this._needUpdate = true;
-        }
-
-        /**
-        * Returns the current calculated luminance
-        */
-        public getCurrentLuminance(): number {
-            return this._hdrCurrentLuminance;
-        }
-
-        /**
-        * Returns the currently drawn luminance
-        */
-        public getOutputLuminance(): number {
-            return this._hdrOutputLuminance;
-        }
-
-        /**
-        * Releases the rendering pipeline and its internal effects. Detaches pipeline from cameras
-        */
-        public dispose(): void {
-            this._originalPostProcess = undefined;
-            this._brightPassPostProcess = undefined;
-            this._downSampleX4PostProcess = undefined;
-            this._guassianBlurHPostProcess = undefined;
-            this._guassianBlurVPostProcess = undefined;
-            this._textureAdderPostProcess = undefined;
-            for (var i = HDRRenderingPipeline.LUM_STEPS - 1; i >= 0; i--) {
-                this._downSamplePostProcesses[i] = undefined;
-            }
-            this._hdrPostProcess = undefined;
-
-            this._scene.postProcessRenderPipelineManager.detachCamerasFromRenderPipeline(this._name, this._scene.cameras);
-        }
-
-        /**
-        * Creates the HDR post-process and computes the luminance adaptation
-        */
-        private _createHDRPostProcess(scene: Scene, ratio: number): void {
-            var hdrLastLuminance = 0.0;
-            this._hdrOutputLuminance = -1.0;
-            this._hdrCurrentLuminance = 1.0;
-            this._hdrPostProcess = new PostProcess("hdr", "hdr", ["exposure", "avgLuminance"], ["otherSampler"], ratio, null, Texture.BILINEAR_SAMPLINGMODE, scene.getEngine(), false, "#define HDR");
-
-            this._hdrPostProcess.onApply = (effect: Effect) => {
-                if (this._hdrOutputLuminance < 0.0) {
-                    this._hdrOutputLuminance = this._hdrCurrentLuminance;
-                }
-                else {
-                    var dt = (hdrLastLuminance - (hdrLastLuminance + scene.getEngine().getDeltaTime())) / 1000.0;
-
-                    if (this._hdrCurrentLuminance < this._hdrOutputLuminance + this.luminanceDecreaseRate * dt) {
-                        this._hdrOutputLuminance += this.luminanceDecreaseRate * dt;
-                    }
-                    else if (this._hdrCurrentLuminance > this._hdrOutputLuminance - this.luminanceIncreaserate * dt) {
-                        this._hdrOutputLuminance -= this.luminanceIncreaserate * dt;
-                    }
-                    else {
-                        this._hdrOutputLuminance = this._hdrCurrentLuminance;
-                    }
-                }
-
-                this._hdrOutputLuminance = Tools.Clamp(this._hdrOutputLuminance, this.minimumLuminance, this.maximumLuminance);
-                hdrLastLuminance += scene.getEngine().getDeltaTime();
-
-                effect.setTextureFromPostProcess("textureSampler", this._textureAdderPostProcess);
-                effect.setTextureFromPostProcess("otherSampler", this._originalPostProcess);
-                effect.setFloat("exposure", this.exposure);
-                effect.setFloat("avgLuminance", this._hdrOutputLuminance);
-
-                this._needUpdate = false;
-            };
-
-        }
-
-        /**
-        * Texture Adder post-process
-        */
-        private _createTextureAdderPostProcess(scene: Scene, ratio: number): void {
-            this._textureAdderPostProcess = new PostProcess("hdr", "hdr", [], ["otherSampler"], ratio, null, Texture.BILINEAR_SAMPLINGMODE, scene.getEngine(), false, "#define TEXTURE_ADDER");
-
-            this._textureAdderPostProcess.onApply = (effect: Effect) => {
-                effect.setTextureFromPostProcess("otherSampler", this._originalPostProcess);
-            };
-        }
-
-        /**
-        * Down sample X4 post-process
-        */
-        private _createDownSampleX4PostProcess(scene: Scene, ratio: number): void {
-            var downSampleX4Offsets = new Array<number>(32);
-            this._downSampleX4PostProcess = new PostProcess("hdr", "hdr", ["dsOffsets"], [], ratio / 4, null, Texture.BILINEAR_SAMPLINGMODE, scene.getEngine(), false, "#define DOWN_SAMPLE_X4");
-
-            this._downSampleX4PostProcess.onApply = (effect: Effect) => {
-                if (this._needUpdate) {
-                    var id = 0;
-                    for (var i = -2; i < 2; i++) {
-                        for (var j = -2; j < 2; j++) {
-                            downSampleX4Offsets[id] = (i + 0.5) * (1.0 / this._downSampleX4PostProcess.width);
-                            downSampleX4Offsets[id + 1] = (j + 0.5) * (1.0 / this._downSampleX4PostProcess.height);
-                            id += 2;
-                        }
-                    }
-                }
-
-                effect.setArray2("dsOffsets", downSampleX4Offsets);
-            };
-        }
-
-        /**
-        * Bright pass post-process
-        */
-        private _createBrightPassPostProcess(scene: Scene, ratio: number): void {
-            var brightOffsets = new Array<number>(8);
-
-            var brightPassCallback = (effect: Effect) => {
-                if (this._needUpdate) {
-                    var sU = (1.0 / this._brightPassPostProcess.width);
-                    var sV = (1.0 / this._brightPassPostProcess.height);
-
-                    brightOffsets[0] = -0.5 * sU;
-                    brightOffsets[1] = 0.5 * sV;
-                    brightOffsets[2] = 0.5 * sU;
-                    brightOffsets[3] = 0.5 * sV;
-                    brightOffsets[4] = -0.5 * sU;
-                    brightOffsets[5] = -0.5 * sV;
-                    brightOffsets[6] = 0.5 * sU;
-                    brightOffsets[7] = -0.5 * sV;
-                }
-
-                effect.setArray2("dsOffsets", brightOffsets);
-                effect.setFloat("brightThreshold", this.brightThreshold);
-            };
-
-            this._brightPassPostProcess = new PostProcess("hdr", "hdr", ["dsOffsets", "brightThreshold"], [], ratio, null, Texture.BILINEAR_SAMPLINGMODE, scene.getEngine(), false, "#define BRIGHT_PASS");
-            this._brightPassPostProcess.onApply = brightPassCallback;
-        }
-
-        /**
-        * Luminance generator. Creates the luminance post-process and down sample post-processes
-        */
-        private _createLuminanceGeneratorPostProcess(scene: Scene): void {
-            var lumSteps: number = HDRRenderingPipeline.LUM_STEPS;
-            var luminanceOffsets = new Array<number>(8);
-            var downSampleOffsets = new Array<number>(18);
-            var halfDestPixelSize: number;
-            this._downSamplePostProcesses = new Array<PostProcess>(lumSteps);
-
-            // Utils for luminance
-            var luminanceUpdateSourceOffsets = (width: number, height: number) => {
-                var sU = (1.0 / width);
-                var sV = (1.0 / height);
-
-                luminanceOffsets[0] = -0.5 * sU;
-                luminanceOffsets[1] = 0.5 * sV;
-                luminanceOffsets[2] = 0.5 * sU;
-                luminanceOffsets[3] = 0.5 * sV;
-                luminanceOffsets[4] = -0.5 * sU;
-                luminanceOffsets[5] = -0.5 * sV;
-                luminanceOffsets[6] = 0.5 * sU;
-                luminanceOffsets[7] = -0.5 * sV;
-            };
-
-            var luminanceUpdateDestOffsets = (width: number, height: number) => {
-                var id = 0;
-                for (var x = -1; x < 2; x++) {
-                    for (var y = -1; y < 2; y++) {
-                        downSampleOffsets[id] = (x) / width;
-                        downSampleOffsets[id + 1] = (y) / height;
-                        id += 2;
-                    }
-                }
-            };
-
-            // Luminance callback
-            var luminanceCallback = (effect: Effect) => {
-                if (this._needUpdate) {
-                    luminanceUpdateSourceOffsets(this._textureAdderPostProcess.width, this._textureAdderPostProcess.height);
-                }
-
-                effect.setTextureFromPostProcess("textureSampler", this._textureAdderPostProcess);
-                effect.setArray2("lumOffsets", luminanceOffsets);
-            }
-
-            // Down sample callbacks
-            var downSampleCallback = (indice: number) => {
-                var i = indice;
-                return (effect: Effect) => {
-                    luminanceUpdateSourceOffsets(this._downSamplePostProcesses[i].width, this._downSamplePostProcesses[i].height);
-                    luminanceUpdateDestOffsets(this._downSamplePostProcesses[i].width, this._downSamplePostProcesses[i].height);
-                    halfDestPixelSize = 0.5 / this._downSamplePostProcesses[i].width;
-
-                    effect.setTextureFromPostProcess("textureSampler", this._downSamplePostProcesses[i + 1]);
-                    effect.setFloat("halfDestPixelSize", halfDestPixelSize);
-                    effect.setArray2("dsOffsets", downSampleOffsets);
-                }
-            };
-
-            var downSampleAfterRenderCallback = (effect: Effect) => {
-                // Unpack result
-                var pixel = scene.getEngine().readPixels(0, 0, 1, 1);
-                var bit_shift = new Vector4(1.0 / (255.0 * 255.0 * 255.0), 1.0 / (255.0 * 255.0), 1.0 / 255.0, 1.0);
-                this._hdrCurrentLuminance = (pixel[0] * bit_shift.x + pixel[1] * bit_shift.y + pixel[2] * bit_shift.z + pixel[3] * bit_shift.w) / 100.0;
-            };
-
-            // Create luminance post-process
-            var ratio = { width: Math.pow(3, lumSteps - 1), height: Math.pow(3, lumSteps - 1) };
-            this._downSamplePostProcesses[lumSteps - 1] = new PostProcess("hdr", "hdr", ["lumOffsets"], [], ratio, null, Texture.NEAREST_SAMPLINGMODE, scene.getEngine(), false, "#define LUMINANCE_GENERATOR", Engine.TEXTURETYPE_FLOAT);
-            this._downSamplePostProcesses[lumSteps - 1].onApply = luminanceCallback;
-
-            // Create down sample post-processes
-            for (var i = lumSteps - 2; i >= 0; i--) {
-                var length = Math.pow(3, i);
-                ratio = { width: length, height: length };
-
-                var defines = "#define DOWN_SAMPLE\n";
-                if (i === 0) {
-                    defines += "#define FINAL_DOWN_SAMPLE\n"; // To pack the result
-                }
-
-                this._downSamplePostProcesses[i] = new PostProcess("hdr", "hdr", ["dsOffsets", "halfDestPixelSize"], [], ratio, null, Texture.NEAREST_SAMPLINGMODE, scene.getEngine(), false, defines, Engine.TEXTURETYPE_FLOAT);
-                this._downSamplePostProcesses[i].onApply = downSampleCallback(i);
-
-                if (i === 0) {
-                    this._downSamplePostProcesses[i].onAfterRender = downSampleAfterRenderCallback;
-                }
-            }
-        }
-
-        /**
-        * Gaussian blur post-processes. Horizontal and Vertical
-        */
-        private _createGaussianBlurPostProcess(scene: Scene, ratio: number): void {
-            var blurOffsetsW = new Array<number>(9);
-            var blurOffsetsH = new Array<number>(9);
-            var blurWeights = new Array<number>(9);
-            var uniforms: string[] = ["blurOffsets", "blurWeights", "multiplier"];
-
-            // Utils for gaussian blur
-            var calculateBlurOffsets = (height: boolean) => {
-                var lastOutputDimensions: any = {
-                    width: scene.getEngine().getRenderWidth(),
-                    height: scene.getEngine().getRenderHeight()
-                };
-
-                for (var i = 0; i < 9; i++) {
-                    var value = (i - 4.0) * (1.0 / (height === true ? lastOutputDimensions.height : lastOutputDimensions.width));
-                    if (height) {
-                        blurOffsetsH[i] = value;
-                    } else {
-                        blurOffsetsW[i] = value;
-                    }
-                }
-            };
-
-            var calculateWeights = () => {
-                var x: number = 0.0;
-
-                for (var i = 0; i < 9; i++) {
-                    x = (i - 4.0) / 4.0;
-                    blurWeights[i] = this.gaussCoeff * (1.0 / Math.sqrt(2.0 * Math.PI * this.gaussStandDev)) * Math.exp((-((x - this.gaussMean) * (x - this.gaussMean))) / (2.0 * this.gaussStandDev * this.gaussStandDev));
-                }
-            }
-
-            // Callback
-            var gaussianBlurCallback = (height: boolean) => {
-                return (effect: Effect) => {
-                    if (this._needUpdate) {
-                        calculateWeights();
-                        calculateBlurOffsets(height);
-                    }
-                    effect.setArray("blurOffsets", height ? blurOffsetsH : blurOffsetsW);
-                    effect.setArray("blurWeights", blurWeights);
-                    effect.setFloat("multiplier", this.gaussMultiplier);
-                };
-            };
-
-            // Create horizontal gaussian blur post-processes
-            this._guassianBlurHPostProcess = new PostProcess("hdr", "hdr", uniforms, [], ratio / 4, null, Texture.BILINEAR_SAMPLINGMODE, scene.getEngine(), false, "#define GAUSSIAN_BLUR_H");
-            this._guassianBlurHPostProcess.onApply = gaussianBlurCallback(false);
-
-            // Create vertical gaussian blur post-process
-            this._guassianBlurVPostProcess = new PostProcess("hdr", "hdr", uniforms, [], ratio / 4, null, Texture.BILINEAR_SAMPLINGMODE, scene.getEngine(), false, "#define GAUSSIAN_BLUR_V");
-            this._guassianBlurVPostProcess.onApply = gaussianBlurCallback(true);
-        }
-    }
+module BABYLON {
+    export class HDRRenderingPipeline extends PostProcessRenderPipeline implements IDisposable {
+
+        /**
+        * Public members
+        */
+        
+        // Gaussian Blur
+        /**
+        * Gaussian blur coefficient
+        * @type {number}
+        */
+        public gaussCoeff: number = 0.3;
+        /**
+        * Gaussian blur mean
+        * @type {number}
+        */
+        public gaussMean: number = 1.0;
+        /**
+        * Gaussian blur standard deviation
+        * @type {number}
+        */
+        public gaussStandDev: number = 0.8;
+        /**
+        * Gaussian blur multiplier. Multiplies the blur effect
+        * @type {number}
+        */
+        public gaussMultiplier: number = 4.0;
+
+        // HDR
+        /**
+        * Exposure, controls the overall intensity of the pipeline
+        * @type {number}
+        */
+        public exposure: number = 1.0;
+        /**
+        * Minimum luminance that the post-process can output. Luminance is >= 0
+        * @type {number}
+        */
+        public minimumLuminance: number = 1.0;
+        /**
+        * Maximum luminance that the post-process can output. Must be suprerior to minimumLuminance
+        * @type {number}
+        */
+        public maximumLuminance: number = 1e20;
+        /**
+        * Increase rate for luminance: eye adaptation speed to dark
+        * @type {number}
+        */
+        public luminanceIncreaserate: number = 0.5;
+        /**
+        * Decrease rate for luminance: eye adaptation speed to bright
+        * @type {number}
+        */
+        public luminanceDecreaseRate: number = 0.5;
+
+        // Bright pass
+        /**
+        * Minimum luminance needed to compute HDR
+        * @type {number}
+        */
+        public brightThreshold: number = 0.8;
+
+        /**
+        * Private members
+        */
+        // Gaussian blur
+        private _guassianBlurHPostProcess: PostProcess;
+        private _guassianBlurVPostProcess: PostProcess;
+
+        // Bright pass
+        private _brightPassPostProcess: PostProcess;
+
+        // Texture adder
+        private _textureAdderPostProcess: PostProcess;
+
+        // Down Sampling
+        private _downSampleX4PostProcess: PostProcess;
+
+        // Original Post-process
+        private _originalPostProcess: PostProcess;
+
+        // HDR
+        private _hdrPostProcess: PostProcess;
+        private _hdrCurrentLuminance: number;
+        private _hdrOutputLuminance: number;
+
+        // Luminance generator
+        public static LUM_STEPS: number = 6;
+        private _downSamplePostProcesses: Array<PostProcess>;
+
+        // Global
+        private _scene: Scene;
+        private _needUpdate: boolean = true;
+
+        /**
+         * @constructor
+         * @param {string} name - The rendering pipeline name
+         * @param {BABYLON.Scene} scene - The scene linked to this pipeline
+         * @param {any} ratio - The size of the postprocesses (0.5 means that your postprocess will have a width = canvas.width 0.5 and a height = canvas.height 0.5)
+         * @param {BABYLON.PostProcess} originalPostProcess - the custom original color post-process. Must be "reusable". Can be null.
+         * @param {BABYLON.Camera[]} cameras - The array of cameras that the rendering pipeline will be attached to
+         */
+        constructor(name: string, scene: Scene, ratio: number, originalPostProcess: PostProcess = null, cameras?: Camera[]) {
+            super(scene.getEngine(), name);
+
+            this._scene = scene;
+
+            // Bright pass
+            this._createBrightPassPostProcess(scene, ratio);
+
+            // Down sample X4
+            this._createDownSampleX4PostProcess(scene, ratio);
+
+            // Create gaussian blur post-processes
+            this._createGaussianBlurPostProcess(scene, ratio);
+
+            // Texture adder
+            this._createTextureAdderPostProcess(scene, ratio);
+
+            // Luminance generator
+            this._createLuminanceGeneratorPostProcess(scene);
+
+            // HDR
+            this._createHDRPostProcess(scene, ratio);
+
+            // Pass postprocess
+            if (originalPostProcess === null) {
+                this._originalPostProcess = new PassPostProcess("hdr", ratio, null, Texture.BILINEAR_SAMPLINGMODE, scene.getEngine(), false);
+            } else {
+                this._originalPostProcess = originalPostProcess;
+            }
+
+            // Configure pipeline
+            this.addEffect(new PostProcessRenderEffect(scene.getEngine(), "HDRPassPostProcess",() => { return this._originalPostProcess; }, true));
+            this.addEffect(new PostProcessRenderEffect(scene.getEngine(), "HDRBrightPass",() => { return this._brightPassPostProcess; }, true));
+            this.addEffect(new PostProcessRenderEffect(scene.getEngine(), "HDRDownSampleX4",() => { return this._downSampleX4PostProcess; }, true));
+            this.addEffect(new PostProcessRenderEffect(scene.getEngine(), "HDRGaussianBlurH",() => { return this._guassianBlurHPostProcess; }, true));
+            this.addEffect(new PostProcessRenderEffect(scene.getEngine(), "HDRGaussianBlurV",() => { return this._guassianBlurVPostProcess; }, true));
+            this.addEffect(new PostProcessRenderEffect(scene.getEngine(), "HDRTextureAdder",() => { return this._textureAdderPostProcess; }, true));
+
+            var addDownSamplerPostProcess = (id: number) => {
+                this.addEffect(new PostProcessRenderEffect(scene.getEngine(), "HDRDownSampler" + id,() => { return this._downSamplePostProcesses[id]; }, true));
+            };
+            for (var i = HDRRenderingPipeline.LUM_STEPS - 1; i >= 0; i--) {
+                addDownSamplerPostProcess(i);
+            }
+
+            this.addEffect(new PostProcessRenderEffect(scene.getEngine(), "HDR",() => { return this._hdrPostProcess; }, true));
+
+            // Finish
+            scene.postProcessRenderPipelineManager.addPipeline(this);
+
+            if (cameras !== null) {
+                scene.postProcessRenderPipelineManager.attachCamerasToRenderPipeline(name, cameras);
+            }
+
+            this.update();
+        }
+
+        /**
+        * Tells the pipeline to update its post-processes
+        */
+        public update(): void {
+            this._needUpdate = true;
+        }
+
+        /**
+        * Returns the current calculated luminance
+        */
+        public getCurrentLuminance(): number {
+            return this._hdrCurrentLuminance;
+        }
+
+        /**
+        * Returns the currently drawn luminance
+        */
+        public getOutputLuminance(): number {
+            return this._hdrOutputLuminance;
+        }
+
+        /**
+        * Releases the rendering pipeline and its internal effects. Detaches pipeline from cameras
+        */
+        public dispose(): void {
+            this._originalPostProcess = undefined;
+            this._brightPassPostProcess = undefined;
+            this._downSampleX4PostProcess = undefined;
+            this._guassianBlurHPostProcess = undefined;
+            this._guassianBlurVPostProcess = undefined;
+            this._textureAdderPostProcess = undefined;
+            for (var i = HDRRenderingPipeline.LUM_STEPS - 1; i >= 0; i--) {
+                this._downSamplePostProcesses[i] = undefined;
+            }
+            this._hdrPostProcess = undefined;
+
+            this._scene.postProcessRenderPipelineManager.detachCamerasFromRenderPipeline(this._name, this._scene.cameras);
+        }
+
+        /**
+        * Creates the HDR post-process and computes the luminance adaptation
+        */
+        private _createHDRPostProcess(scene: Scene, ratio: number): void {
+            var hdrLastLuminance = 0.0;
+            this._hdrOutputLuminance = -1.0;
+            this._hdrCurrentLuminance = 1.0;
+            this._hdrPostProcess = new PostProcess("hdr", "hdr", ["exposure", "avgLuminance"], ["otherSampler"], ratio, null, Texture.BILINEAR_SAMPLINGMODE, scene.getEngine(), false, "#define HDR");
+
+            this._hdrPostProcess.onApply = (effect: Effect) => {
+                if (this._hdrOutputLuminance < 0.0) {
+                    this._hdrOutputLuminance = this._hdrCurrentLuminance;
+                }
+                else {
+                    var dt = (hdrLastLuminance - (hdrLastLuminance + scene.getEngine().getDeltaTime())) / 1000.0;
+
+                    if (this._hdrCurrentLuminance < this._hdrOutputLuminance + this.luminanceDecreaseRate * dt) {
+                        this._hdrOutputLuminance += this.luminanceDecreaseRate * dt;
+                    }
+                    else if (this._hdrCurrentLuminance > this._hdrOutputLuminance - this.luminanceIncreaserate * dt) {
+                        this._hdrOutputLuminance -= this.luminanceIncreaserate * dt;
+                    }
+                    else {
+                        this._hdrOutputLuminance = this._hdrCurrentLuminance;
+                    }
+                }
+
+                this._hdrOutputLuminance = Tools.Clamp(this._hdrOutputLuminance, this.minimumLuminance, this.maximumLuminance);
+                hdrLastLuminance += scene.getEngine().getDeltaTime();
+
+                effect.setTextureFromPostProcess("textureSampler", this._textureAdderPostProcess);
+                effect.setTextureFromPostProcess("otherSampler", this._originalPostProcess);
+                effect.setFloat("exposure", this.exposure);
+                effect.setFloat("avgLuminance", this._hdrOutputLuminance);
+
+                this._needUpdate = false;
+            };
+
+        }
+
+        /**
+        * Texture Adder post-process
+        */
+        private _createTextureAdderPostProcess(scene: Scene, ratio: number): void {
+            this._textureAdderPostProcess = new PostProcess("hdr", "hdr", [], ["otherSampler"], ratio, null, Texture.BILINEAR_SAMPLINGMODE, scene.getEngine(), false, "#define TEXTURE_ADDER");
+
+            this._textureAdderPostProcess.onApply = (effect: Effect) => {
+                effect.setTextureFromPostProcess("otherSampler", this._originalPostProcess);
+            };
+        }
+
+        /**
+        * Down sample X4 post-process
+        */
+        private _createDownSampleX4PostProcess(scene: Scene, ratio: number): void {
+            var downSampleX4Offsets = new Array<number>(32);
+            this._downSampleX4PostProcess = new PostProcess("hdr", "hdr", ["dsOffsets"], [], ratio / 4, null, Texture.BILINEAR_SAMPLINGMODE, scene.getEngine(), false, "#define DOWN_SAMPLE_X4");
+
+            this._downSampleX4PostProcess.onApply = (effect: Effect) => {
+                if (this._needUpdate) {
+                    var id = 0;
+                    for (var i = -2; i < 2; i++) {
+                        for (var j = -2; j < 2; j++) {
+                            downSampleX4Offsets[id] = (i + 0.5) * (1.0 / this._downSampleX4PostProcess.width);
+                            downSampleX4Offsets[id + 1] = (j + 0.5) * (1.0 / this._downSampleX4PostProcess.height);
+                            id += 2;
+                        }
+                    }
+                }
+
+                effect.setArray2("dsOffsets", downSampleX4Offsets);
+            };
+        }
+
+        /**
+        * Bright pass post-process
+        */
+        private _createBrightPassPostProcess(scene: Scene, ratio: number): void {
+            var brightOffsets = new Array<number>(8);
+
+            var brightPassCallback = (effect: Effect) => {
+                if (this._needUpdate) {
+                    var sU = (1.0 / this._brightPassPostProcess.width);
+                    var sV = (1.0 / this._brightPassPostProcess.height);
+
+                    brightOffsets[0] = -0.5 * sU;
+                    brightOffsets[1] = 0.5 * sV;
+                    brightOffsets[2] = 0.5 * sU;
+                    brightOffsets[3] = 0.5 * sV;
+                    brightOffsets[4] = -0.5 * sU;
+                    brightOffsets[5] = -0.5 * sV;
+                    brightOffsets[6] = 0.5 * sU;
+                    brightOffsets[7] = -0.5 * sV;
+                }
+
+                effect.setArray2("dsOffsets", brightOffsets);
+                effect.setFloat("brightThreshold", this.brightThreshold);
+            };
+
+            this._brightPassPostProcess = new PostProcess("hdr", "hdr", ["dsOffsets", "brightThreshold"], [], ratio, null, Texture.BILINEAR_SAMPLINGMODE, scene.getEngine(), false, "#define BRIGHT_PASS");
+            this._brightPassPostProcess.onApply = brightPassCallback;
+        }
+
+        /**
+        * Luminance generator. Creates the luminance post-process and down sample post-processes
+        */
+        private _createLuminanceGeneratorPostProcess(scene: Scene): void {
+            var lumSteps: number = HDRRenderingPipeline.LUM_STEPS;
+            var luminanceOffsets = new Array<number>(8);
+            var downSampleOffsets = new Array<number>(18);
+            var halfDestPixelSize: number;
+            this._downSamplePostProcesses = new Array<PostProcess>(lumSteps);
+
+            // Utils for luminance
+            var luminanceUpdateSourceOffsets = (width: number, height: number) => {
+                var sU = (1.0 / width);
+                var sV = (1.0 / height);
+
+                luminanceOffsets[0] = -0.5 * sU;
+                luminanceOffsets[1] = 0.5 * sV;
+                luminanceOffsets[2] = 0.5 * sU;
+                luminanceOffsets[3] = 0.5 * sV;
+                luminanceOffsets[4] = -0.5 * sU;
+                luminanceOffsets[5] = -0.5 * sV;
+                luminanceOffsets[6] = 0.5 * sU;
+                luminanceOffsets[7] = -0.5 * sV;
+            };
+
+            var luminanceUpdateDestOffsets = (width: number, height: number) => {
+                var id = 0;
+                for (var x = -1; x < 2; x++) {
+                    for (var y = -1; y < 2; y++) {
+                        downSampleOffsets[id] = (x) / width;
+                        downSampleOffsets[id + 1] = (y) / height;
+                        id += 2;
+                    }
+                }
+            };
+
+            // Luminance callback
+            var luminanceCallback = (effect: Effect) => {
+                if (this._needUpdate) {
+                    luminanceUpdateSourceOffsets(this._textureAdderPostProcess.width, this._textureAdderPostProcess.height);
+                }
+
+                effect.setTextureFromPostProcess("textureSampler", this._textureAdderPostProcess);
+                effect.setArray2("lumOffsets", luminanceOffsets);
+            }
+
+            // Down sample callbacks
+            var downSampleCallback = (indice: number) => {
+                var i = indice;
+                return (effect: Effect) => {
+                    luminanceUpdateSourceOffsets(this._downSamplePostProcesses[i].width, this._downSamplePostProcesses[i].height);
+                    luminanceUpdateDestOffsets(this._downSamplePostProcesses[i].width, this._downSamplePostProcesses[i].height);
+                    halfDestPixelSize = 0.5 / this._downSamplePostProcesses[i].width;
+
+                    effect.setTextureFromPostProcess("textureSampler", this._downSamplePostProcesses[i + 1]);
+                    effect.setFloat("halfDestPixelSize", halfDestPixelSize);
+                    effect.setArray2("dsOffsets", downSampleOffsets);
+                }
+            };
+
+            var downSampleAfterRenderCallback = (effect: Effect) => {
+                // Unpack result
+                var pixel = scene.getEngine().readPixels(0, 0, 1, 1);
+                var bit_shift = new Vector4(1.0 / (255.0 * 255.0 * 255.0), 1.0 / (255.0 * 255.0), 1.0 / 255.0, 1.0);
+                this._hdrCurrentLuminance = (pixel[0] * bit_shift.x + pixel[1] * bit_shift.y + pixel[2] * bit_shift.z + pixel[3] * bit_shift.w) / 100.0;
+            };
+
+            // Create luminance post-process
+            var ratio = { width: Math.pow(3, lumSteps - 1), height: Math.pow(3, lumSteps - 1) };
+            this._downSamplePostProcesses[lumSteps - 1] = new PostProcess("hdr", "hdr", ["lumOffsets"], [], ratio, null, Texture.NEAREST_SAMPLINGMODE, scene.getEngine(), false, "#define LUMINANCE_GENERATOR", Engine.TEXTURETYPE_FLOAT);
+            this._downSamplePostProcesses[lumSteps - 1].onApply = luminanceCallback;
+
+            // Create down sample post-processes
+            for (var i = lumSteps - 2; i >= 0; i--) {
+                var length = Math.pow(3, i);
+                ratio = { width: length, height: length };
+
+                var defines = "#define DOWN_SAMPLE\n";
+                if (i === 0) {
+                    defines += "#define FINAL_DOWN_SAMPLE\n"; // To pack the result
+                }
+
+                this._downSamplePostProcesses[i] = new PostProcess("hdr", "hdr", ["dsOffsets", "halfDestPixelSize"], [], ratio, null, Texture.NEAREST_SAMPLINGMODE, scene.getEngine(), false, defines, Engine.TEXTURETYPE_FLOAT);
+                this._downSamplePostProcesses[i].onApply = downSampleCallback(i);
+
+                if (i === 0) {
+                    this._downSamplePostProcesses[i].onAfterRender = downSampleAfterRenderCallback;
+                }
+            }
+        }
+
+        /**
+        * Gaussian blur post-processes. Horizontal and Vertical
+        */
+        private _createGaussianBlurPostProcess(scene: Scene, ratio: number): void {
+            var blurOffsetsW = new Array<number>(9);
+            var blurOffsetsH = new Array<number>(9);
+            var blurWeights = new Array<number>(9);
+            var uniforms: string[] = ["blurOffsets", "blurWeights", "multiplier"];
+
+            // Utils for gaussian blur
+            var calculateBlurOffsets = (height: boolean) => {
+                var lastOutputDimensions: any = {
+                    width: scene.getEngine().getRenderWidth(),
+                    height: scene.getEngine().getRenderHeight()
+                };
+
+                for (var i = 0; i < 9; i++) {
+                    var value = (i - 4.0) * (1.0 / (height === true ? lastOutputDimensions.height : lastOutputDimensions.width));
+                    if (height) {
+                        blurOffsetsH[i] = value;
+                    } else {
+                        blurOffsetsW[i] = value;
+                    }
+                }
+            };
+
+            var calculateWeights = () => {
+                var x: number = 0.0;
+
+                for (var i = 0; i < 9; i++) {
+                    x = (i - 4.0) / 4.0;
+                    blurWeights[i] = this.gaussCoeff * (1.0 / Math.sqrt(2.0 * Math.PI * this.gaussStandDev)) * Math.exp((-((x - this.gaussMean) * (x - this.gaussMean))) / (2.0 * this.gaussStandDev * this.gaussStandDev));
+                }
+            }
+
+            // Callback
+            var gaussianBlurCallback = (height: boolean) => {
+                return (effect: Effect) => {
+                    if (this._needUpdate) {
+                        calculateWeights();
+                        calculateBlurOffsets(height);
+                    }
+                    effect.setArray("blurOffsets", height ? blurOffsetsH : blurOffsetsW);
+                    effect.setArray("blurWeights", blurWeights);
+                    effect.setFloat("multiplier", this.gaussMultiplier);
+                };
+            };
+
+            // Create horizontal gaussian blur post-processes
+            this._guassianBlurHPostProcess = new PostProcess("hdr", "hdr", uniforms, [], ratio / 4, null, Texture.BILINEAR_SAMPLINGMODE, scene.getEngine(), false, "#define GAUSSIAN_BLUR_H");
+            this._guassianBlurHPostProcess.onApply = gaussianBlurCallback(false);
+
+            // Create vertical gaussian blur post-process
+            this._guassianBlurVPostProcess = new PostProcess("hdr", "hdr", uniforms, [], ratio / 4, null, Texture.BILINEAR_SAMPLINGMODE, scene.getEngine(), false, "#define GAUSSIAN_BLUR_V");
+            this._guassianBlurVPostProcess.onApply = gaussianBlurCallback(true);
+        }
+    }
 }

+ 278 - 278
src/PostProcess/babylon.lensRenderingPipeline.ts

@@ -1,278 +1,278 @@
-// BABYLON.JS Chromatic Aberration GLSL Shader
-// Author: Olivier Guyot
-// Separates very slightly R, G and B colors on the edges of the screen
-// Inspired by Francois Tarlier & Martins Upitis
-
-
-module BABYLON {
-    export class LensRenderingPipeline extends PostProcessRenderPipeline {
-
-        // Lens effects can be of the following:
-        // - chromatic aberration (slight shift of RGB colors)
-        // - blur on the edge of the lens
-        // - lens distortion
-        // - depth-of-field blur & highlights enhancing
-        // - depth-of-field 'bokeh' effect (shapes appearing in blurred areas)
-        // - grain effect (noise or custom texture)
-
-        // Two additional texture samplers are needed:
-        // - depth map (for depth-of-field)
-        // - grain texture
-
-        /**
-        * The chromatic aberration PostProcess id in the pipeline
-        * @type {string}
-        */
-        public LensChromaticAberrationEffect: string = "LensChromaticAberrationEffect";
-        /**
-        * The highlights enhancing PostProcess id in the pipeline
-        * @type {string}
-        */
-        public HighlightsEnhancingEffect: string = "HighlightsEnhancingEffect";
-        /**
-        * The depth-of-field PostProcess id in the pipeline
-        * @type {string}
-        */
-        public LensDepthOfFieldEffect: string = "LensDepthOfFieldEffect";
-
-        private _scene: Scene;
-        private _depthTexture: RenderTargetTexture;
-        private _grainTexture: Texture;
-
-        private _chromaticAberrationPostProcess: PostProcess;
-        private _highlightsPostProcess: PostProcess;
-        private _depthOfFieldPostProcess: PostProcess;
-
-        private _edgeBlur: number;
-        private _grainAmount: number;
-        private _chromaticAberration: number;
-        private _distortion: number;
-        private _highlightsGain: number;
-        private _highlightsThreshold: number;
-        private _dofDistance: number;
-        private _dofAperture: number;
-        private _dofDarken: number;
-        private _dofPentagon: boolean;
-        private _blurNoise: boolean;
-
-
-        /**
-         * @constructor
-         *
-         * Effect parameters are as follow:
-         * {
-         *      chromatic_aberration: number;       // from 0 to x (1 for realism)
-         *      edge_blur: number;                  // from 0 to x (1 for realism)
-         *      distortion: number;                 // from 0 to x (1 for realism)
-         *      grain_amount: number;               // from 0 to 1
-         *      grain_texture: BABYLON.Texture;     // texture to use for grain effect; if unset, use random B&W noise
-         *      dof_focus_distance: number;         // depth-of-field: focus distance; unset to disable (disabled by default)
-         *      dof_aperture: number;               // depth-of-field: focus blur bias (default: 1)
-         *      dof_darken: number;                 // depth-of-field: darken that which is out of focus (from 0 to 1, disabled by default)
-         *      dof_pentagon: boolean;              // depth-of-field: makes a pentagon-like "bokeh" effect
-         *      dof_gain: number;                   // depth-of-field: highlights gain; unset to disable (disabled by default)
-         *      dof_threshold: number;              // depth-of-field: highlights threshold (default: 1)
-         *      blur_noise: boolean;                // add a little bit of noise to the blur (default: true)
-         * }
-         * Note: if an effect parameter is unset, effect is disabled
-         *
-         * @param {string} name - The rendering pipeline name
-         * @param {object} parameters - An object containing all parameters (see above)
-         * @param {BABYLON.Scene} scene - The scene linked to this pipeline
-         * @param {number} ratio - The size of the postprocesses (0.5 means that your postprocess will have a width = canvas.width 0.5 and a height = canvas.height 0.5)
-         * @param {BABYLON.Camera[]} cameras - The array of cameras that the rendering pipeline will be attached to
-         */
-        constructor(name: string, parameters: any, scene: Scene, ratio: number = 1.0, cameras?: Camera[]) {
-            super(scene.getEngine(), name);
-
-            this._scene = scene;
-
-            // Fetch texture samplers
-            this._depthTexture = scene.enableDepthRenderer().getDepthMap(); // Force depth renderer "on"
-            if (parameters.grain_texture) { this._grainTexture = parameters.grain_texture; }
-            else { this._createGrainTexture(); }
-
-            // save parameters
-            this._edgeBlur = parameters.edge_blur ? parameters.edge_blur : 0;
-            this._grainAmount = parameters.grain_amount ? parameters.grain_amount : 0;
-            this._chromaticAberration = parameters.chromatic_aberration ? parameters.chromatic_aberration : 0;
-            this._distortion = parameters.distortion ? parameters.distortion : 0;
-            this._highlightsGain = parameters.dof_gain !== undefined ? parameters.dof_gain : -1;
-            this._highlightsThreshold = parameters.dof_threshold ? parameters.dof_threshold : 1;
-            this._dofDistance = parameters.dof_focus_distance !== undefined ? parameters.dof_focus_distance : -1;
-            this._dofAperture = parameters.dof_aperture ? parameters.dof_aperture : 1;
-            this._dofDarken = parameters.dof_darken ? parameters.dof_darken : 0;
-            this._dofPentagon = parameters.dof_pentagon !== undefined ? parameters.dof_pentagon : true;
-            this._blurNoise = parameters.blur_noise !== undefined ? parameters.blur_noise : true;
-
-            // Create effects
-            this._createChromaticAberrationPostProcess(ratio);
-            this._createHighlightsPostProcess(ratio);
-            this._createDepthOfFieldPostProcess(ratio / 4);
-
-            // Set up pipeline
-            this.addEffect(new PostProcessRenderEffect(scene.getEngine(), this.LensChromaticAberrationEffect, () => { return this._chromaticAberrationPostProcess; }, true));
-            this.addEffect(new PostProcessRenderEffect(scene.getEngine(), this.HighlightsEnhancingEffect, () => { return this._highlightsPostProcess; }, true));
-            this.addEffect(new PostProcessRenderEffect(scene.getEngine(), this.LensDepthOfFieldEffect, () => { return this._depthOfFieldPostProcess; }, true));
-
-            if (this._highlightsGain === -1) {
-                this._disableEffect(this.HighlightsEnhancingEffect, null);
-            }
-
-            // Finish
-            scene.postProcessRenderPipelineManager.addPipeline(this);
-            if (cameras) {
-                scene.postProcessRenderPipelineManager.attachCamerasToRenderPipeline(name, cameras);
-            }
-        }
-
-        // public methods (self explanatory)
-
-        public setEdgeBlur(amount: number) { this._edgeBlur = amount; }
-        public disableEdgeBlur() { this._edgeBlur = 0; }
-        public setGrainAmount(amount: number) { this._grainAmount = amount; }
-        public disableGrain() { this._grainAmount = 0; }
-        public setChromaticAberration(amount: number) { this._chromaticAberration = amount; }
-        public disableChromaticAberration() { this._chromaticAberration = 0; }
-        public setEdgeDistortion(amount: number) { this._distortion = amount; }
-        public disableEdgeDistortion() { this._distortion = 0; }
-        public setFocusDistance(amount: number) { this._dofDistance = amount; }
-        public disableDepthOfField() { this._dofDistance = -1; }
-        public setAperture(amount: number) { this._dofAperture = amount; }
-        public setDarkenOutOfFocus(amount: number) { this._dofDarken = amount; }
-        public enablePentagonBokeh() {
-            this._highlightsPostProcess.updateEffect("#define PENTAGON\n");
-        }
-        public disablePentagonBokeh() {
-            this._highlightsPostProcess.updateEffect();
-        }
-        public enableNoiseBlur() { this._blurNoise = true; }
-        public disableNoiseBlur() { this._blurNoise = false; }
-        public setHighlightsGain(amount: number) {
-            this._highlightsGain = amount;
-        }
-        public setHighlightsThreshold(amount: number) {
-            if (this._highlightsGain === -1) {
-                this._highlightsGain = 1.0;
-            }
-            this._highlightsThreshold = amount;
-        }
-        public disableHighlights() {
-            this._highlightsGain = -1;
-        }
-
-        /**
-         * Removes the internal pipeline assets and detaches the pipeline from the scene cameras
-         */
-        public dispose(disableDepthRender: boolean = false): void {
-            this._scene.postProcessRenderPipelineManager.detachCamerasFromRenderPipeline(this._name, this._scene.cameras);
-
-            this._chromaticAberrationPostProcess = undefined;
-            this._highlightsPostProcess = undefined;
-            this._depthOfFieldPostProcess = undefined;
-
-            this._grainTexture.dispose();
-
-            if (disableDepthRender)
-                this._scene.disableDepthRenderer();
-        }
-
-        // colors shifting and distortion
-        private _createChromaticAberrationPostProcess(ratio: number): void {
-            this._chromaticAberrationPostProcess = new PostProcess("LensChromaticAberration", "chromaticAberration",
-                ["chromatic_aberration", "screen_width", "screen_height"],      // uniforms
-                [],                                         // samplers
-                ratio, null, Texture.TRILINEAR_SAMPLINGMODE,
-                this._scene.getEngine(), false);
-
-            this._chromaticAberrationPostProcess.onApply = (effect: Effect) => {
-                effect.setFloat('chromatic_aberration', this._chromaticAberration);
-                effect.setFloat('screen_width', this._scene.getEngine().getRenderingCanvas().width);
-                effect.setFloat('screen_height', this._scene.getEngine().getRenderingCanvas().height);
-            };
-        }
-
-        // highlights enhancing
-        private _createHighlightsPostProcess(ratio: number): void {
-            this._highlightsPostProcess = new PostProcess("LensHighlights", "lensHighlights",
-                ["gain", "threshold", "screen_width", "screen_height"],      // uniforms
-                [],     // samplers
-                ratio,
-                null, Texture.TRILINEAR_SAMPLINGMODE,
-                this._scene.getEngine(), false, this._dofPentagon ? "#define PENTAGON\n" : "");
-
-            this._highlightsPostProcess.onApply = (effect: Effect) => {
-                effect.setFloat('gain', this._highlightsGain);
-                effect.setFloat('threshold', this._highlightsThreshold);
-                effect.setTextureFromPostProcess("textureSampler", this._chromaticAberrationPostProcess);
-                effect.setFloat('screen_width', this._scene.getEngine().getRenderingCanvas().width);
-                effect.setFloat('screen_height', this._scene.getEngine().getRenderingCanvas().height);
-            };
-        }
-
-        // colors shifting and distortion
-        private _createDepthOfFieldPostProcess(ratio: number): void {
-            this._depthOfFieldPostProcess = new PostProcess("LensDepthOfField", "depthOfField",
-                [
-                    "grain_amount", "blur_noise", "screen_width", "screen_height", "distortion", "dof_enabled",
-                    "screen_distance", "aperture", "darken", "edge_blur", "highlights", "near", "far"
-                ],
-                ["depthSampler", "grainSampler", "highlightsSampler"],
-                ratio, null, Texture.TRILINEAR_SAMPLINGMODE,
-                this._scene.getEngine(), false);
-
-            this._depthOfFieldPostProcess.onApply = (effect: Effect) => {
-
-                effect.setTexture("depthSampler", this._depthTexture);
-                effect.setTexture("grainSampler", this._grainTexture);
-                effect.setTextureFromPostProcess("textureSampler", this._highlightsPostProcess);
-                effect.setTextureFromPostProcess("highlightsSampler", this._depthOfFieldPostProcess);
-
-                effect.setFloat('grain_amount', this._grainAmount);
-                effect.setBool('blur_noise', this._blurNoise);
-
-                effect.setFloat('screen_width', this._scene.getEngine().getRenderingCanvas().width);
-                effect.setFloat('screen_height', this._scene.getEngine().getRenderingCanvas().height);
-
-                effect.setFloat('distortion', this._distortion);
-
-                effect.setBool('dof_enabled', (this._dofDistance !== -1));
-                effect.setFloat('screen_distance', 1.0 / (0.1 - 1.0 / this._dofDistance));
-                effect.setFloat('aperture', this._dofAperture);
-                effect.setFloat('darken', this._dofDarken);
-
-                effect.setFloat('edge_blur', this._edgeBlur);
-
-                effect.setBool('highlights', (this._highlightsGain !== -1));
-
-                effect.setFloat('near', this._scene.activeCamera.minZ);
-                effect.setFloat('far', this._scene.activeCamera.maxZ);
-            };
-        }
-
-        // creates a black and white random noise texture, 512x512
-        private _createGrainTexture(): void {
-            var size = 512;
-
-            this._grainTexture = new DynamicTexture("LensNoiseTexture", size, this._scene, false, Texture.BILINEAR_SAMPLINGMODE);
-            this._grainTexture.wrapU = Texture.WRAP_ADDRESSMODE;
-            this._grainTexture.wrapV = Texture.WRAP_ADDRESSMODE;
-
-            var context = (<DynamicTexture>this._grainTexture).getContext();
-
-            var rand = (min, max) => {
-                return Math.random() * (max - min) + min;
-            }
-
-            var value;
-            for (var x = 0; x < size; x++) {
-                for (var y = 0; y < size; y++) {
-                    value = Math.floor(rand(0.42, 0.58) * 255);
-                    context.fillStyle = 'rgb(' + value + ', ' + value + ', ' + value + ')';
-                    context.fillRect(x, y, 1, 1);
-                }
-            }
-            (<DynamicTexture>this._grainTexture).update(false);
-        }
-    }
-}
+// BABYLON.JS Chromatic Aberration GLSL Shader
+// Author: Olivier Guyot
+// Separates very slightly R, G and B colors on the edges of the screen
+// Inspired by Francois Tarlier & Martins Upitis
+
+
+module BABYLON {
+    export class LensRenderingPipeline extends PostProcessRenderPipeline {
+
+        // Lens effects can be of the following:
+        // - chromatic aberration (slight shift of RGB colors)
+        // - blur on the edge of the lens
+        // - lens distortion
+        // - depth-of-field blur & highlights enhancing
+        // - depth-of-field 'bokeh' effect (shapes appearing in blurred areas)
+        // - grain effect (noise or custom texture)
+
+        // Two additional texture samplers are needed:
+        // - depth map (for depth-of-field)
+        // - grain texture
+
+        /**
+        * The chromatic aberration PostProcess id in the pipeline
+        * @type {string}
+        */
+        public LensChromaticAberrationEffect: string = "LensChromaticAberrationEffect";
+        /**
+        * The highlights enhancing PostProcess id in the pipeline
+        * @type {string}
+        */
+        public HighlightsEnhancingEffect: string = "HighlightsEnhancingEffect";
+        /**
+        * The depth-of-field PostProcess id in the pipeline
+        * @type {string}
+        */
+        public LensDepthOfFieldEffect: string = "LensDepthOfFieldEffect";
+
+        private _scene: Scene;
+        private _depthTexture: RenderTargetTexture;
+        private _grainTexture: Texture;
+
+        private _chromaticAberrationPostProcess: PostProcess;
+        private _highlightsPostProcess: PostProcess;
+        private _depthOfFieldPostProcess: PostProcess;
+
+        private _edgeBlur: number;
+        private _grainAmount: number;
+        private _chromaticAberration: number;
+        private _distortion: number;
+        private _highlightsGain: number;
+        private _highlightsThreshold: number;
+        private _dofDistance: number;
+        private _dofAperture: number;
+        private _dofDarken: number;
+        private _dofPentagon: boolean;
+        private _blurNoise: boolean;
+
+
+        /**
+         * @constructor
+         *
+         * Effect parameters are as follow:
+         * {
+         *      chromatic_aberration: number;       // from 0 to x (1 for realism)
+         *      edge_blur: number;                  // from 0 to x (1 for realism)
+         *      distortion: number;                 // from 0 to x (1 for realism)
+         *      grain_amount: number;               // from 0 to 1
+         *      grain_texture: BABYLON.Texture;     // texture to use for grain effect; if unset, use random B&W noise
+         *      dof_focus_distance: number;         // depth-of-field: focus distance; unset to disable (disabled by default)
+         *      dof_aperture: number;               // depth-of-field: focus blur bias (default: 1)
+         *      dof_darken: number;                 // depth-of-field: darken that which is out of focus (from 0 to 1, disabled by default)
+         *      dof_pentagon: boolean;              // depth-of-field: makes a pentagon-like "bokeh" effect
+         *      dof_gain: number;                   // depth-of-field: highlights gain; unset to disable (disabled by default)
+         *      dof_threshold: number;              // depth-of-field: highlights threshold (default: 1)
+         *      blur_noise: boolean;                // add a little bit of noise to the blur (default: true)
+         * }
+         * Note: if an effect parameter is unset, effect is disabled
+         *
+         * @param {string} name - The rendering pipeline name
+         * @param {object} parameters - An object containing all parameters (see above)
+         * @param {BABYLON.Scene} scene - The scene linked to this pipeline
+         * @param {number} ratio - The size of the postprocesses (0.5 means that your postprocess will have a width = canvas.width 0.5 and a height = canvas.height 0.5)
+         * @param {BABYLON.Camera[]} cameras - The array of cameras that the rendering pipeline will be attached to
+         */
+        constructor(name: string, parameters: any, scene: Scene, ratio: number = 1.0, cameras?: Camera[]) {
+            super(scene.getEngine(), name);
+
+            this._scene = scene;
+
+            // Fetch texture samplers
+            this._depthTexture = scene.enableDepthRenderer().getDepthMap(); // Force depth renderer "on"
+            if (parameters.grain_texture) { this._grainTexture = parameters.grain_texture; }
+            else { this._createGrainTexture(); }
+
+            // save parameters
+            this._edgeBlur = parameters.edge_blur ? parameters.edge_blur : 0;
+            this._grainAmount = parameters.grain_amount ? parameters.grain_amount : 0;
+            this._chromaticAberration = parameters.chromatic_aberration ? parameters.chromatic_aberration : 0;
+            this._distortion = parameters.distortion ? parameters.distortion : 0;
+            this._highlightsGain = parameters.dof_gain !== undefined ? parameters.dof_gain : -1;
+            this._highlightsThreshold = parameters.dof_threshold ? parameters.dof_threshold : 1;
+            this._dofDistance = parameters.dof_focus_distance !== undefined ? parameters.dof_focus_distance : -1;
+            this._dofAperture = parameters.dof_aperture ? parameters.dof_aperture : 1;
+            this._dofDarken = parameters.dof_darken ? parameters.dof_darken : 0;
+            this._dofPentagon = parameters.dof_pentagon !== undefined ? parameters.dof_pentagon : true;
+            this._blurNoise = parameters.blur_noise !== undefined ? parameters.blur_noise : true;
+
+            // Create effects
+            this._createChromaticAberrationPostProcess(ratio);
+            this._createHighlightsPostProcess(ratio);
+            this._createDepthOfFieldPostProcess(ratio / 4);
+
+            // Set up pipeline
+            this.addEffect(new PostProcessRenderEffect(scene.getEngine(), this.LensChromaticAberrationEffect, () => { return this._chromaticAberrationPostProcess; }, true));
+            this.addEffect(new PostProcessRenderEffect(scene.getEngine(), this.HighlightsEnhancingEffect, () => { return this._highlightsPostProcess; }, true));
+            this.addEffect(new PostProcessRenderEffect(scene.getEngine(), this.LensDepthOfFieldEffect, () => { return this._depthOfFieldPostProcess; }, true));
+
+            if (this._highlightsGain === -1) {
+                this._disableEffect(this.HighlightsEnhancingEffect, null);
+            }
+
+            // Finish
+            scene.postProcessRenderPipelineManager.addPipeline(this);
+            if (cameras) {
+                scene.postProcessRenderPipelineManager.attachCamerasToRenderPipeline(name, cameras);
+            }
+        }
+
+        // public methods (self explanatory)
+
+        public setEdgeBlur(amount: number) { this._edgeBlur = amount; }
+        public disableEdgeBlur() { this._edgeBlur = 0; }
+        public setGrainAmount(amount: number) { this._grainAmount = amount; }
+        public disableGrain() { this._grainAmount = 0; }
+        public setChromaticAberration(amount: number) { this._chromaticAberration = amount; }
+        public disableChromaticAberration() { this._chromaticAberration = 0; }
+        public setEdgeDistortion(amount: number) { this._distortion = amount; }
+        public disableEdgeDistortion() { this._distortion = 0; }
+        public setFocusDistance(amount: number) { this._dofDistance = amount; }
+        public disableDepthOfField() { this._dofDistance = -1; }
+        public setAperture(amount: number) { this._dofAperture = amount; }
+        public setDarkenOutOfFocus(amount: number) { this._dofDarken = amount; }
+        public enablePentagonBokeh() {
+            this._highlightsPostProcess.updateEffect("#define PENTAGON\n");
+        }
+        public disablePentagonBokeh() {
+            this._highlightsPostProcess.updateEffect();
+        }
+        public enableNoiseBlur() { this._blurNoise = true; }
+        public disableNoiseBlur() { this._blurNoise = false; }
+        public setHighlightsGain(amount: number) {
+            this._highlightsGain = amount;
+        }
+        public setHighlightsThreshold(amount: number) {
+            if (this._highlightsGain === -1) {
+                this._highlightsGain = 1.0;
+            }
+            this._highlightsThreshold = amount;
+        }
+        public disableHighlights() {
+            this._highlightsGain = -1;
+        }
+
+        /**
+         * Removes the internal pipeline assets and detaches the pipeline from the scene cameras
+         */
+        public dispose(disableDepthRender: boolean = false): void {
+            this._scene.postProcessRenderPipelineManager.detachCamerasFromRenderPipeline(this._name, this._scene.cameras);
+
+            this._chromaticAberrationPostProcess = undefined;
+            this._highlightsPostProcess = undefined;
+            this._depthOfFieldPostProcess = undefined;
+
+            this._grainTexture.dispose();
+
+            if (disableDepthRender)
+                this._scene.disableDepthRenderer();
+        }
+
+        // colors shifting and distortion
+        private _createChromaticAberrationPostProcess(ratio: number): void {
+            this._chromaticAberrationPostProcess = new PostProcess("LensChromaticAberration", "chromaticAberration",
+                ["chromatic_aberration", "screen_width", "screen_height"],      // uniforms
+                [],                                         // samplers
+                ratio, null, Texture.TRILINEAR_SAMPLINGMODE,
+                this._scene.getEngine(), false);
+
+            this._chromaticAberrationPostProcess.onApply = (effect: Effect) => {
+                effect.setFloat('chromatic_aberration', this._chromaticAberration);
+                effect.setFloat('screen_width', this._scene.getEngine().getRenderingCanvas().width);
+                effect.setFloat('screen_height', this._scene.getEngine().getRenderingCanvas().height);
+            };
+        }
+
+        // highlights enhancing
+        private _createHighlightsPostProcess(ratio: number): void {
+            this._highlightsPostProcess = new PostProcess("LensHighlights", "lensHighlights",
+                ["gain", "threshold", "screen_width", "screen_height"],      // uniforms
+                [],     // samplers
+                ratio,
+                null, Texture.TRILINEAR_SAMPLINGMODE,
+                this._scene.getEngine(), false, this._dofPentagon ? "#define PENTAGON\n" : "");
+
+            this._highlightsPostProcess.onApply = (effect: Effect) => {
+                effect.setFloat('gain', this._highlightsGain);
+                effect.setFloat('threshold', this._highlightsThreshold);
+                effect.setTextureFromPostProcess("textureSampler", this._chromaticAberrationPostProcess);
+                effect.setFloat('screen_width', this._scene.getEngine().getRenderingCanvas().width);
+                effect.setFloat('screen_height', this._scene.getEngine().getRenderingCanvas().height);
+            };
+        }
+
+        // colors shifting and distortion
+        private _createDepthOfFieldPostProcess(ratio: number): void {
+            this._depthOfFieldPostProcess = new PostProcess("LensDepthOfField", "depthOfField",
+                [
+                    "grain_amount", "blur_noise", "screen_width", "screen_height", "distortion", "dof_enabled",
+                    "screen_distance", "aperture", "darken", "edge_blur", "highlights", "near", "far"
+                ],
+                ["depthSampler", "grainSampler", "highlightsSampler"],
+                ratio, null, Texture.TRILINEAR_SAMPLINGMODE,
+                this._scene.getEngine(), false);
+
+            this._depthOfFieldPostProcess.onApply = (effect: Effect) => {
+
+                effect.setTexture("depthSampler", this._depthTexture);
+                effect.setTexture("grainSampler", this._grainTexture);
+                effect.setTextureFromPostProcess("textureSampler", this._highlightsPostProcess);
+                effect.setTextureFromPostProcess("highlightsSampler", this._depthOfFieldPostProcess);
+
+                effect.setFloat('grain_amount', this._grainAmount);
+                effect.setBool('blur_noise', this._blurNoise);
+
+                effect.setFloat('screen_width', this._scene.getEngine().getRenderingCanvas().width);
+                effect.setFloat('screen_height', this._scene.getEngine().getRenderingCanvas().height);
+
+                effect.setFloat('distortion', this._distortion);
+
+                effect.setBool('dof_enabled', (this._dofDistance !== -1));
+                effect.setFloat('screen_distance', 1.0 / (0.1 - 1.0 / this._dofDistance));
+                effect.setFloat('aperture', this._dofAperture);
+                effect.setFloat('darken', this._dofDarken);
+
+                effect.setFloat('edge_blur', this._edgeBlur);
+
+                effect.setBool('highlights', (this._highlightsGain !== -1));
+
+                effect.setFloat('near', this._scene.activeCamera.minZ);
+                effect.setFloat('far', this._scene.activeCamera.maxZ);
+            };
+        }
+
+        // creates a black and white random noise texture, 512x512
+        private _createGrainTexture(): void {
+            var size = 512;
+
+            this._grainTexture = new DynamicTexture("LensNoiseTexture", size, this._scene, false, Texture.BILINEAR_SAMPLINGMODE);
+            this._grainTexture.wrapU = Texture.WRAP_ADDRESSMODE;
+            this._grainTexture.wrapV = Texture.WRAP_ADDRESSMODE;
+
+            var context = (<DynamicTexture>this._grainTexture).getContext();
+
+            var rand = (min, max) => {
+                return Math.random() * (max - min) + min;
+            }
+
+            var value;
+            for (var x = 0; x < size; x++) {
+                for (var y = 0; y < size; y++) {
+                    value = Math.floor(rand(0.42, 0.58) * 255);
+                    context.fillStyle = 'rgb(' + value + ', ' + value + ', ' + value + ')';
+                    context.fillRect(x, y, 1, 1);
+                }
+            }
+            (<DynamicTexture>this._grainTexture).update(false);
+        }
+    }
+}

+ 6 - 6
src/PostProcess/babylon.passPostProcess.ts

@@ -1,7 +1,7 @@
-module BABYLON {
-    export class PassPostProcess extends PostProcess {
-        constructor(name: string, ratio: number, camera: Camera, samplingMode?: number, engine?: Engine, reusable?: boolean) {
-            super(name, "pass", null, null, ratio, camera, samplingMode, engine, reusable);
-        }
-    }
+module BABYLON {
+    export class PassPostProcess extends PostProcess {
+        constructor(name: string, ratio: number, camera: Camera, samplingMode?: number, engine?: Engine, reusable?: boolean) {
+            super(name, "pass", null, null, ratio, camera, samplingMode, engine, reusable);
+        }
+    }
 } 

+ 159 - 159
src/PostProcess/babylon.postProcess.ts

@@ -1,160 +1,160 @@
-module BABYLON {
-    export class PostProcess {
-        public onApply: (effect: Effect) => void;
-        public onBeforeRender: (effect: Effect) => void;
-        public onAfterRender: (effect: Effect) => void;
-        public onSizeChanged: () => void;
-        public onActivate: (camera: Camera) => void;
-        public width = -1;
-        public height = -1;
-        public renderTargetSamplingMode: number;
-        public clearColor: Color4;
-
-        private _camera: Camera;
-        private _scene: Scene;
-        private _engine: Engine;
-        private _renderRatio: number|any;
-        private _reusable = false;
-        private _textureType: number;
-        public _textures = new SmartArray<WebGLTexture>(2);
-        public _currentRenderTextureInd = 0;
-        private _effect: Effect;
-        private _samplers: string[];
-        private _fragmentUrl: string;
-        private _parameters: string[];
-
-        constructor(public name: string, fragmentUrl: string, parameters: string[], samplers: string[], ratio: number|any, camera: Camera, samplingMode: number = Texture.NEAREST_SAMPLINGMODE, engine?: Engine, reusable?: boolean, defines?: string, textureType: number = Engine.TEXTURETYPE_UNSIGNED_INT) {
-            if (camera != null) {
-                this._camera = camera;
-                this._scene = camera.getScene();
-                camera.attachPostProcess(this);
-                this._engine = this._scene.getEngine();
-            }
-            else {
-                this._engine = engine;
-            }
-
-            this._renderRatio = ratio;
-            this.renderTargetSamplingMode = samplingMode ? samplingMode : Texture.NEAREST_SAMPLINGMODE;
-            this._reusable = reusable || false;
-            this._textureType = textureType;
-
-            this._samplers = samplers || [];
-            this._samplers.push("textureSampler");
-
-            this._fragmentUrl = fragmentUrl;
-            this._parameters = parameters || [];
-
-            this.updateEffect(defines);
-        }
-
-        public updateEffect(defines?: string) {
-            this._effect = this._engine.createEffect({ vertex: "postprocess", fragment: this._fragmentUrl },
-                ["position"],
-                this._parameters,
-                this._samplers, defines !== undefined ? defines : "");
-        }
-
-        public isReusable(): boolean {
-            return this._reusable;
-        }
-
-        public activate(camera: Camera, sourceTexture?: WebGLTexture): void {
-            camera = camera || this._camera;
-
-            var scene = camera.getScene();
-            var maxSize = camera.getEngine().getCaps().maxTextureSize;
-
-            var desiredWidth = ((sourceTexture ? sourceTexture._width : this._engine.getRenderingCanvas().width) * this._renderRatio) | 0;
-            var desiredHeight = ((sourceTexture ? sourceTexture._height : this._engine.getRenderingCanvas().height) * this._renderRatio) | 0;
-
-            desiredWidth = this._renderRatio.width || Tools.GetExponentOfTwo(desiredWidth, maxSize);
-            desiredHeight = this._renderRatio.height || Tools.GetExponentOfTwo(desiredHeight, maxSize);
-
-            if (this.width !== desiredWidth || this.height !== desiredHeight) {
-                if (this._textures.length > 0) {
-                    for (var i = 0; i < this._textures.length; i++) {
-                        this._engine._releaseTexture(this._textures.data[i]);
-                    }
-                    this._textures.reset();
-                }
-                this.width = desiredWidth;
-                this.height = desiredHeight;
-                this._textures.push(this._engine.createRenderTargetTexture({ width: this.width, height: this.height }, { generateMipMaps: false, generateDepthBuffer: camera._postProcesses.indexOf(this) === camera._postProcessesTakenIndices[0], samplingMode: this.renderTargetSamplingMode, type: this._textureType }));
-
-                if (this._reusable) {
-                    this._textures.push(this._engine.createRenderTargetTexture({ width: this.width, height: this.height }, { generateMipMaps: false, generateDepthBuffer: camera._postProcesses.indexOf(this) === camera._postProcessesTakenIndices[0], samplingMode: this.renderTargetSamplingMode, type: this._textureType }));
-                }
-
-                if (this.onSizeChanged) {
-                    this.onSizeChanged();
-                }
-            }
-
-            this._engine.bindFramebuffer(this._textures.data[this._currentRenderTextureInd]);
-
-            if (this.onActivate) {
-                this.onActivate(camera);
-            }
-
-            // Clear
-            if (this.clearColor) {
-                this._engine.clear(this.clearColor, true, true);
-            } else {
-                this._engine.clear(scene.clearColor, scene.autoClear || scene.forceWireframe, true);
-            }
-
-            if (this._reusable) {
-                this._currentRenderTextureInd = (this._currentRenderTextureInd + 1) % 2;
-            }
-        }
-
-        public get isSupported(): boolean {
-            return this._effect.isSupported;
-        }
-
-        public apply(): Effect {
-            // Check
-            if (!this._effect.isReady())
-                return null;
-
-            // States
-            this._engine.enableEffect(this._effect);
-            this._engine.setState(false);
-            this._engine.setAlphaMode(Engine.ALPHA_DISABLE);
-            this._engine.setDepthBuffer(false);
-            this._engine.setDepthWrite(false);
-
-            // Texture
-            this._effect._bindTexture("textureSampler", this._textures.data[this._currentRenderTextureInd]);
-
-            // Parameters
-            if (this.onApply) {
-                this.onApply(this._effect);
-            }
-
-            return this._effect;
-        }
-
-        public dispose(camera?: Camera): void {
-            camera = camera || this._camera;
-
-            if (this._textures.length > 0) {
-                for (var i = 0; i < this._textures.length; i++) {
-                    this._engine._releaseTexture(this._textures.data[i]);
-                }
-                this._textures.reset();
-            }
-
-            if (!camera) {
-                return;
-            }
-            camera.detachPostProcess(this);
-
-            var index = camera._postProcesses.indexOf(this);
-            if (index === camera._postProcessesTakenIndices[0] && camera._postProcessesTakenIndices.length > 0) {
-                this._camera._postProcesses[camera._postProcessesTakenIndices[0]].width = -1; // invalidate frameBuffer to hint the postprocess to create a depth buffer
-            }
-        }
-    }
+module BABYLON {
+    export class PostProcess {
+        public onApply: (effect: Effect) => void;
+        public onBeforeRender: (effect: Effect) => void;
+        public onAfterRender: (effect: Effect) => void;
+        public onSizeChanged: () => void;
+        public onActivate: (camera: Camera) => void;
+        public width = -1;
+        public height = -1;
+        public renderTargetSamplingMode: number;
+        public clearColor: Color4;
+
+        private _camera: Camera;
+        private _scene: Scene;
+        private _engine: Engine;
+        private _renderRatio: number|any;
+        private _reusable = false;
+        private _textureType: number;
+        public _textures = new SmartArray<WebGLTexture>(2);
+        public _currentRenderTextureInd = 0;
+        private _effect: Effect;
+        private _samplers: string[];
+        private _fragmentUrl: string;
+        private _parameters: string[];
+
+        constructor(public name: string, fragmentUrl: string, parameters: string[], samplers: string[], ratio: number|any, camera: Camera, samplingMode: number = Texture.NEAREST_SAMPLINGMODE, engine?: Engine, reusable?: boolean, defines?: string, textureType: number = Engine.TEXTURETYPE_UNSIGNED_INT) {
+            if (camera != null) {
+                this._camera = camera;
+                this._scene = camera.getScene();
+                camera.attachPostProcess(this);
+                this._engine = this._scene.getEngine();
+            }
+            else {
+                this._engine = engine;
+            }
+
+            this._renderRatio = ratio;
+            this.renderTargetSamplingMode = samplingMode ? samplingMode : Texture.NEAREST_SAMPLINGMODE;
+            this._reusable = reusable || false;
+            this._textureType = textureType;
+
+            this._samplers = samplers || [];
+            this._samplers.push("textureSampler");
+
+            this._fragmentUrl = fragmentUrl;
+            this._parameters = parameters || [];
+
+            this.updateEffect(defines);
+        }
+
+        public updateEffect(defines?: string) {
+            this._effect = this._engine.createEffect({ vertex: "postprocess", fragment: this._fragmentUrl },
+                ["position"],
+                this._parameters,
+                this._samplers, defines !== undefined ? defines : "");
+        }
+
+        public isReusable(): boolean {
+            return this._reusable;
+        }
+
+        public activate(camera: Camera, sourceTexture?: WebGLTexture): void {
+            camera = camera || this._camera;
+
+            var scene = camera.getScene();
+            var maxSize = camera.getEngine().getCaps().maxTextureSize;
+
+            var desiredWidth = ((sourceTexture ? sourceTexture._width : this._engine.getRenderingCanvas().width) * this._renderRatio) | 0;
+            var desiredHeight = ((sourceTexture ? sourceTexture._height : this._engine.getRenderingCanvas().height) * this._renderRatio) | 0;
+
+            desiredWidth = this._renderRatio.width || Tools.GetExponentOfTwo(desiredWidth, maxSize);
+            desiredHeight = this._renderRatio.height || Tools.GetExponentOfTwo(desiredHeight, maxSize);
+
+            if (this.width !== desiredWidth || this.height !== desiredHeight) {
+                if (this._textures.length > 0) {
+                    for (var i = 0; i < this._textures.length; i++) {
+                        this._engine._releaseTexture(this._textures.data[i]);
+                    }
+                    this._textures.reset();
+                }
+                this.width = desiredWidth;
+                this.height = desiredHeight;
+                this._textures.push(this._engine.createRenderTargetTexture({ width: this.width, height: this.height }, { generateMipMaps: false, generateDepthBuffer: camera._postProcesses.indexOf(this) === camera._postProcessesTakenIndices[0], samplingMode: this.renderTargetSamplingMode, type: this._textureType }));
+
+                if (this._reusable) {
+                    this._textures.push(this._engine.createRenderTargetTexture({ width: this.width, height: this.height }, { generateMipMaps: false, generateDepthBuffer: camera._postProcesses.indexOf(this) === camera._postProcessesTakenIndices[0], samplingMode: this.renderTargetSamplingMode, type: this._textureType }));
+                }
+
+                if (this.onSizeChanged) {
+                    this.onSizeChanged();
+                }
+            }
+
+            this._engine.bindFramebuffer(this._textures.data[this._currentRenderTextureInd]);
+
+            if (this.onActivate) {
+                this.onActivate(camera);
+            }
+
+            // Clear
+            if (this.clearColor) {
+                this._engine.clear(this.clearColor, true, true);
+            } else {
+                this._engine.clear(scene.clearColor, scene.autoClear || scene.forceWireframe, true);
+            }
+
+            if (this._reusable) {
+                this._currentRenderTextureInd = (this._currentRenderTextureInd + 1) % 2;
+            }
+        }
+
+        public get isSupported(): boolean {
+            return this._effect.isSupported;
+        }
+
+        public apply(): Effect {
+            // Check
+            if (!this._effect.isReady())
+                return null;
+
+            // States
+            this._engine.enableEffect(this._effect);
+            this._engine.setState(false);
+            this._engine.setAlphaMode(Engine.ALPHA_DISABLE);
+            this._engine.setDepthBuffer(false);
+            this._engine.setDepthWrite(false);
+
+            // Texture
+            this._effect._bindTexture("textureSampler", this._textures.data[this._currentRenderTextureInd]);
+
+            // Parameters
+            if (this.onApply) {
+                this.onApply(this._effect);
+            }
+
+            return this._effect;
+        }
+
+        public dispose(camera?: Camera): void {
+            camera = camera || this._camera;
+
+            if (this._textures.length > 0) {
+                for (var i = 0; i < this._textures.length; i++) {
+                    this._engine._releaseTexture(this._textures.data[i]);
+                }
+                this._textures.reset();
+            }
+
+            if (!camera) {
+                return;
+            }
+            camera.detachPostProcess(this);
+
+            var index = camera._postProcesses.indexOf(this);
+            if (index === camera._postProcessesTakenIndices[0] && camera._postProcessesTakenIndices.length > 0) {
+                this._camera._postProcesses[camera._postProcessesTakenIndices[0]].width = -1; // invalidate frameBuffer to hint the postprocess to create a depth buffer
+            }
+        }
+    }
 }

+ 153 - 153
src/PostProcess/babylon.postProcessManager.ts

@@ -1,154 +1,154 @@
-module BABYLON {
-    export class PostProcessManager {
-        private _scene: Scene;
-        private _indexBuffer: WebGLBuffer;
-        private _vertexDeclaration = [2];
-        private _vertexStrideSize = 2 * 4;
-        private _vertexBuffer: WebGLBuffer;
-
-        constructor(scene: Scene) {
-            this._scene = scene;
-        }
-
-        private _prepareBuffers(): void {
-            if (this._vertexBuffer) {
-                return;
-            }
-
-            // VBO
-            var vertices = [];
-            vertices.push(1, 1);
-            vertices.push(-1, 1);
-            vertices.push(-1, -1);
-            vertices.push(1, -1);
-            this._vertexBuffer = this._scene.getEngine().createVertexBuffer(vertices);
-
-            // Indices
-            var indices = [];
-            indices.push(0);
-            indices.push(1);
-            indices.push(2);
-
-            indices.push(0);
-            indices.push(2);
-            indices.push(3);
-
-            this._indexBuffer = this._scene.getEngine().createIndexBuffer(indices);
-        }
-
-        // Methods
-        public _prepareFrame(sourceTexture?: WebGLTexture): boolean {
-            var postProcesses = this._scene.activeCamera._postProcesses;
-            var postProcessesTakenIndices = this._scene.activeCamera._postProcessesTakenIndices;
-
-            if (postProcessesTakenIndices.length === 0 || !this._scene.postProcessesEnabled) {
-                return false;
-            }
-
-            postProcesses[this._scene.activeCamera._postProcessesTakenIndices[0]].activate(this._scene.activeCamera, sourceTexture);
-
-            return true;
-        }
-
-        public directRender(postProcesses: PostProcess[], targetTexture?: WebGLTexture): void {
-            var engine = this._scene.getEngine();
-
-            for (var index = 0; index < postProcesses.length; index++) {
-                if (index < postProcesses.length - 1) {
-                    postProcesses[index + 1].activate(this._scene.activeCamera, targetTexture);
-                } else {
-                    if (targetTexture) {
-                        engine.bindFramebuffer(targetTexture);
-                    } else {
-                        engine.restoreDefaultFramebuffer();
-                    }
-                }
-
-                var pp = postProcesses[index];
-                var effect = pp.apply();
-
-                if (effect) {
-                    if (pp.onBeforeRender) {
-                        pp.onBeforeRender(effect);
-                    }
-
-                    // VBOs
-                    this._prepareBuffers();
-                    engine.bindBuffers(this._vertexBuffer, this._indexBuffer, this._vertexDeclaration, this._vertexStrideSize, effect);
-
-                    // Draw order
-                    engine.draw(true, 0, 6);
-
-                    if (pp.onAfterRender) {
-                        pp.onAfterRender(effect);
-                    }
-                }
-            }
-
-            // Restore depth buffer
-            engine.setDepthBuffer(true);
-            engine.setDepthWrite(true);
-        }
-
-        public _finalizeFrame(doNotPresent?: boolean, targetTexture?: WebGLTexture, faceIndex?: number, postProcesses?: PostProcess[]): void {
-            postProcesses = postProcesses || this._scene.activeCamera._postProcesses;
-            var postProcessesTakenIndices = this._scene.activeCamera._postProcessesTakenIndices;
-            if (postProcessesTakenIndices.length === 0 || !this._scene.postProcessesEnabled) {
-                return;
-            }
-            var engine = this._scene.getEngine();
-
-            for (var index = 0; index < postProcessesTakenIndices.length; index++) {
-                if (index < postProcessesTakenIndices.length - 1) {
-                    postProcesses[postProcessesTakenIndices[index + 1]].activate(this._scene.activeCamera);
-                } else {
-                    if (targetTexture) {
-                        engine.bindFramebuffer(targetTexture, faceIndex);
-                    } else {
-                        engine.restoreDefaultFramebuffer();
-                    }
-                }
-
-                if (doNotPresent) {
-                    break;
-                }
-
-                var pp = postProcesses[postProcessesTakenIndices[index]];
-                var effect = pp.apply();
-
-                if (effect) {
-                    if (pp.onBeforeRender) {
-                        pp.onBeforeRender(effect);
-                    }
-
-                    // VBOs
-                    this._prepareBuffers();
-                    engine.bindBuffers(this._vertexBuffer, this._indexBuffer, this._vertexDeclaration, this._vertexStrideSize, effect);
-
-                    // Draw order
-                    engine.draw(true, 0, 6);
-
-                    if (pp.onAfterRender) {
-                        pp.onAfterRender(effect);
-                    }
-                }
-            }
-
-            // Restore depth buffer
-            engine.setDepthBuffer(true);
-            engine.setDepthWrite(true);
-        }
-
-        public dispose(): void {
-            if (this._vertexBuffer) {
-                this._scene.getEngine()._releaseBuffer(this._vertexBuffer);
-                this._vertexBuffer = null;
-            }
-
-            if (this._indexBuffer) {
-                this._scene.getEngine()._releaseBuffer(this._indexBuffer);
-                this._indexBuffer = null;
-            }
-        }
-    }
+module BABYLON {
+    export class PostProcessManager {
+        private _scene: Scene;
+        private _indexBuffer: WebGLBuffer;
+        private _vertexDeclaration = [2];
+        private _vertexStrideSize = 2 * 4;
+        private _vertexBuffer: WebGLBuffer;
+
+        constructor(scene: Scene) {
+            this._scene = scene;
+        }
+
+        private _prepareBuffers(): void {
+            if (this._vertexBuffer) {
+                return;
+            }
+
+            // VBO
+            var vertices = [];
+            vertices.push(1, 1);
+            vertices.push(-1, 1);
+            vertices.push(-1, -1);
+            vertices.push(1, -1);
+            this._vertexBuffer = this._scene.getEngine().createVertexBuffer(vertices);
+
+            // Indices
+            var indices = [];
+            indices.push(0);
+            indices.push(1);
+            indices.push(2);
+
+            indices.push(0);
+            indices.push(2);
+            indices.push(3);
+
+            this._indexBuffer = this._scene.getEngine().createIndexBuffer(indices);
+        }
+
+        // Methods
+        public _prepareFrame(sourceTexture?: WebGLTexture): boolean {
+            var postProcesses = this._scene.activeCamera._postProcesses;
+            var postProcessesTakenIndices = this._scene.activeCamera._postProcessesTakenIndices;
+
+            if (postProcessesTakenIndices.length === 0 || !this._scene.postProcessesEnabled) {
+                return false;
+            }
+
+            postProcesses[this._scene.activeCamera._postProcessesTakenIndices[0]].activate(this._scene.activeCamera, sourceTexture);
+
+            return true;
+        }
+
+        public directRender(postProcesses: PostProcess[], targetTexture?: WebGLTexture): void {
+            var engine = this._scene.getEngine();
+
+            for (var index = 0; index < postProcesses.length; index++) {
+                if (index < postProcesses.length - 1) {
+                    postProcesses[index + 1].activate(this._scene.activeCamera, targetTexture);
+                } else {
+                    if (targetTexture) {
+                        engine.bindFramebuffer(targetTexture);
+                    } else {
+                        engine.restoreDefaultFramebuffer();
+                    }
+                }
+
+                var pp = postProcesses[index];
+                var effect = pp.apply();
+
+                if (effect) {
+                    if (pp.onBeforeRender) {
+                        pp.onBeforeRender(effect);
+                    }
+
+                    // VBOs
+                    this._prepareBuffers();
+                    engine.bindBuffers(this._vertexBuffer, this._indexBuffer, this._vertexDeclaration, this._vertexStrideSize, effect);
+
+                    // Draw order
+                    engine.draw(true, 0, 6);
+
+                    if (pp.onAfterRender) {
+                        pp.onAfterRender(effect);
+                    }
+                }
+            }
+
+            // Restore depth buffer
+            engine.setDepthBuffer(true);
+            engine.setDepthWrite(true);
+        }
+
+        public _finalizeFrame(doNotPresent?: boolean, targetTexture?: WebGLTexture, faceIndex?: number, postProcesses?: PostProcess[]): void {
+            postProcesses = postProcesses || this._scene.activeCamera._postProcesses;
+            var postProcessesTakenIndices = this._scene.activeCamera._postProcessesTakenIndices;
+            if (postProcessesTakenIndices.length === 0 || !this._scene.postProcessesEnabled) {
+                return;
+            }
+            var engine = this._scene.getEngine();
+
+            for (var index = 0; index < postProcessesTakenIndices.length; index++) {
+                if (index < postProcessesTakenIndices.length - 1) {
+                    postProcesses[postProcessesTakenIndices[index + 1]].activate(this._scene.activeCamera);
+                } else {
+                    if (targetTexture) {
+                        engine.bindFramebuffer(targetTexture, faceIndex);
+                    } else {
+                        engine.restoreDefaultFramebuffer();
+                    }
+                }
+
+                if (doNotPresent) {
+                    break;
+                }
+
+                var pp = postProcesses[postProcessesTakenIndices[index]];
+                var effect = pp.apply();
+
+                if (effect) {
+                    if (pp.onBeforeRender) {
+                        pp.onBeforeRender(effect);
+                    }
+
+                    // VBOs
+                    this._prepareBuffers();
+                    engine.bindBuffers(this._vertexBuffer, this._indexBuffer, this._vertexDeclaration, this._vertexStrideSize, effect);
+
+                    // Draw order
+                    engine.draw(true, 0, 6);
+
+                    if (pp.onAfterRender) {
+                        pp.onAfterRender(effect);
+                    }
+                }
+            }
+
+            // Restore depth buffer
+            engine.setDepthBuffer(true);
+            engine.setDepthWrite(true);
+        }
+
+        public dispose(): void {
+            if (this._vertexBuffer) {
+                this._scene.getEngine()._releaseBuffer(this._vertexBuffer);
+                this._vertexBuffer = null;
+            }
+
+            if (this._indexBuffer) {
+                this._scene.getEngine()._releaseBuffer(this._indexBuffer);
+                this._indexBuffer = null;
+            }
+        }
+    }
 } 

+ 28 - 28
src/PostProcess/babylon.refractionPostProcess.ts

@@ -1,29 +1,29 @@
-module BABYLON {
-    export class RefractionPostProcess extends PostProcess {
-        private _refRexture: Texture;
-        constructor(name: string, refractionTextureUrl: string, public color: Color3, public depth: number, public colorLevel: number, ratio: number, camera: Camera, samplingMode?: number, engine?: Engine, reusable?: boolean) {
-            super(name, "refraction", ["baseColor", "depth", "colorLevel"], ["refractionSampler"], ratio, camera, samplingMode, engine, reusable);
-
-            this.onActivate = (cam: Camera) => {
-                this._refRexture = this._refRexture || new Texture(refractionTextureUrl, cam.getScene());
-            };
-
-            this.onApply = (effect: Effect) => {
-                effect.setColor3("baseColor", this.color);
-                effect.setFloat("depth", this.depth);
-                effect.setFloat("colorLevel", this.colorLevel);
-
-                effect.setTexture("refractionSampler", this._refRexture);
-            };
-        }
-
-        // Methods
-        public dispose(camera: Camera): void {
-            if (this._refRexture) {
-                this._refRexture.dispose();
-            }
-
-            super.dispose(camera);
-        }
-    }
+module BABYLON {
+    export class RefractionPostProcess extends PostProcess {
+        private _refRexture: Texture;
+        constructor(name: string, refractionTextureUrl: string, public color: Color3, public depth: number, public colorLevel: number, ratio: number, camera: Camera, samplingMode?: number, engine?: Engine, reusable?: boolean) {
+            super(name, "refraction", ["baseColor", "depth", "colorLevel"], ["refractionSampler"], ratio, camera, samplingMode, engine, reusable);
+
+            this.onActivate = (cam: Camera) => {
+                this._refRexture = this._refRexture || new Texture(refractionTextureUrl, cam.getScene());
+            };
+
+            this.onApply = (effect: Effect) => {
+                effect.setColor3("baseColor", this.color);
+                effect.setFloat("depth", this.depth);
+                effect.setFloat("colorLevel", this.colorLevel);
+
+                effect.setTexture("refractionSampler", this._refRexture);
+            };
+        }
+
+        // Methods
+        public dispose(camera: Camera): void {
+            if (this._refRexture) {
+                this._refRexture.dispose();
+            }
+
+            super.dispose(camera);
+        }
+    }
 }

+ 240 - 240
src/PostProcess/babylon.ssaoRenderingPipeline.ts

@@ -1,241 +1,241 @@
-module BABYLON {
-    export class SSAORenderingPipeline extends PostProcessRenderPipeline {
-        // Members
-
-        /**
-        * The PassPostProcess id in the pipeline that contains the original scene color
-        * @type {string}
-        */
-        public SSAOOriginalSceneColorEffect: string = "SSAOOriginalSceneColorEffect";
-        /**
-        * The SSAO PostProcess id in the pipeline
-        * @type {string}
-        */
-        public SSAORenderEffect: string = "SSAORenderEffect";
-        /**
-        * The horizontal blur PostProcess id in the pipeline
-        * @type {string}
-        */
-        public SSAOBlurHRenderEffect: string = "SSAOBlurHRenderEffect";
-        /**
-        * The vertical blur PostProcess id in the pipeline
-        * @type {string}
-        */
-        public SSAOBlurVRenderEffect: string = "SSAOBlurVRenderEffect";
-        /**
-        * The PostProcess id in the pipeline that combines the SSAO-Blur output with the original scene color (SSAOOriginalSceneColorEffect)
-        * @type {string}
-        */
-        public SSAOCombineRenderEffect: string = "SSAOCombineRenderEffect";
-
-        /**
-        * The output strength of the SSAO post-process. Default value is 1.0.
-        * @type {number}
-        */
-        public totalStrength: number = 1.0;
-
-        /**
-        * The radius around the analyzed pixel used by the SSAO post-process. Default value is 0.0006
-        * @type {number}
-        */
-        public radius: number = 0.0001;
-
-        /**
-        * Related to fallOff, used to interpolate SSAO samples (first interpolate function input) based on the occlusion difference of each pixel
-        * Must not be equal to fallOff and superior to fallOff.
-        * Default value is 0.975
-        * @type {number}
-        */
-        public area: number = 0.0075;
-
-        /**
-        * Related to area, used to interpolate SSAO samples (second interpolate function input) based on the occlusion difference of each pixel
-        * Must not be equal to area and inferior to area.
-        * Default value is 0.0
-        * @type {number}
-        */
-        public fallOff: number = 0.000001;
-
-        /**
-        * The base color of the SSAO post-process
-        * The final result is "base + ssao" between [0, 1]
-        * @type {number}
-        */
-        public base: number = 0.5;
-
-        private _scene: Scene;
-        private _depthTexture: RenderTargetTexture;
-        private _randomTexture: DynamicTexture;
-
-        private _originalColorPostProcess: PassPostProcess;
-        private _ssaoPostProcess: PostProcess;
-        private _blurHPostProcess: BlurPostProcess;
-        private _blurVPostProcess: BlurPostProcess;
-        private _ssaoCombinePostProcess: PostProcess;
-
-        private _firstUpdate: boolean = true;
-
-        /**
-         * @constructor
-         * @param {string} name - The rendering pipeline name
-         * @param {BABYLON.Scene} scene - The scene linked to this pipeline
-         * @param {any} ratio - The size of the postprocesses. Can be a number shared between passes or an object for more precision: { ssaoRatio: 0.5, combineRatio: 1.0 }
-         * @param {BABYLON.Camera[]} cameras - The array of cameras that the rendering pipeline will be attached to
-         */
-        constructor(name: string, scene: Scene, ratio: any, cameras?: Camera[]) {
-            super(scene.getEngine(), name);
-
-            this._scene = scene;
-
-            // Set up assets
-            this._createRandomTexture();
-            this._depthTexture = scene.enableDepthRenderer().getDepthMap(); // Force depth renderer "on"
-
-            var ssaoRatio = ratio.ssaoRatio || ratio;
-            var combineRatio = ratio.combineRatio || ratio;
-
-            this._originalColorPostProcess = new PassPostProcess("SSAOOriginalSceneColor", combineRatio, null, Texture.BILINEAR_SAMPLINGMODE, scene.getEngine(), false);
-            this._createSSAOPostProcess(ssaoRatio);
-            this._blurHPostProcess = new BlurPostProcess("SSAOBlurH", new Vector2(1.0, 0.0), 2.0, ssaoRatio, null, Texture.BILINEAR_SAMPLINGMODE, scene.getEngine(), false);
-            this._blurVPostProcess = new BlurPostProcess("SSAOBlurV", new Vector2(0.0, 1.0), 2.0, ssaoRatio, null, Texture.BILINEAR_SAMPLINGMODE, scene.getEngine(), false);
-            this._createSSAOCombinePostProcess(combineRatio);
-
-            // Set up pipeline
-            this.addEffect(new PostProcessRenderEffect(scene.getEngine(), this.SSAOOriginalSceneColorEffect, () => { return this._originalColorPostProcess; }, true));
-            this.addEffect(new PostProcessRenderEffect(scene.getEngine(), this.SSAORenderEffect, () => { return this._ssaoPostProcess; }, true));
-            this.addEffect(new PostProcessRenderEffect(scene.getEngine(), this.SSAOBlurHRenderEffect, () => { return this._blurHPostProcess; }, true));
-            this.addEffect(new PostProcessRenderEffect(scene.getEngine(), this.SSAOBlurVRenderEffect, () => { return this._blurVPostProcess; }, true));
-            this.addEffect(new PostProcessRenderEffect(scene.getEngine(), this.SSAOCombineRenderEffect, () => { return this._ssaoCombinePostProcess; }, true));
-
-            // Finish
-            scene.postProcessRenderPipelineManager.addPipeline(this);
-            if (cameras)
-                scene.postProcessRenderPipelineManager.attachCamerasToRenderPipeline(name, cameras);
-        }
-
-        // Public Methods
-        /**
-         * Returns the horizontal blur PostProcess
-         * @return {BABYLON.BlurPostProcess} The horizontal blur post-process
-         */
-        public getBlurHPostProcess(): BlurPostProcess {
-            return this._blurHPostProcess;
-        }
-
-        /**
-         * Returns the vertical blur PostProcess
-         * @return {BABYLON.BlurPostProcess} The vertical blur post-process
-         */
-        public getBlurVPostProcess(): BlurPostProcess {
-            return this._blurVPostProcess;
-        }
-
-        /**
-         * Removes the internal pipeline assets and detatches the pipeline from the scene cameras
-         */
-        public dispose(disableDepthRender: boolean = false): void {
-            this._scene.postProcessRenderPipelineManager.detachCamerasFromRenderPipeline(this._name, this._scene.cameras);
-
-            this._originalColorPostProcess = undefined;
-            this._ssaoPostProcess = undefined;
-            this._blurHPostProcess = undefined;
-            this._blurVPostProcess = undefined;
-            this._ssaoCombinePostProcess = undefined;
-
-            this._randomTexture.dispose();
-
-            if (disableDepthRender)
-                this._scene.disableDepthRenderer();
-        }
-
-        // Private Methods
-        private _createSSAOPostProcess(ratio: number): void {
-            var numSamples = 16;
-            var sampleSphere = [
-                0.5381, 0.1856, -0.4319,
-                0.1379, 0.2486, 0.4430,
-                0.3371, 0.5679, -0.0057,
-                -0.6999, -0.0451, -0.0019,
-                0.0689, -0.1598, -0.8547,
-                0.0560, 0.0069, -0.1843,
-                -0.0146, 0.1402, 0.0762,
-                0.0100, -0.1924, -0.0344,
-                -0.3577, -0.5301, -0.4358,
-                -0.3169, 0.1063, 0.0158,
-                0.0103, -0.5869, 0.0046,
-                -0.0897, -0.4940, 0.3287,
-                0.7119, -0.0154, -0.0918,
-                -0.0533, 0.0596, -0.5411,
-                0.0352, -0.0631, 0.5460,
-                -0.4776, 0.2847, -0.0271
-            ];
-            var samplesFactor = 1.0 / numSamples;
-
-            this._ssaoPostProcess = new PostProcess("ssao", "ssao",
-                                                    [
-                                                        "sampleSphere", "samplesFactor", "randTextureTiles", "totalStrength", "radius",
-                                                        "area", "fallOff", "base"
-                                                    ],
-                                                    ["randomSampler"],
-                                                    ratio, null, Texture.BILINEAR_SAMPLINGMODE,
-                                                    this._scene.getEngine(), false,
-                                                    "#define SAMPLES " + numSamples);
-
-            this._ssaoPostProcess.onApply = (effect: Effect) => {
-                if (this._firstUpdate) {
-                    effect.setArray3("sampleSphere", sampleSphere);
-                    effect.setFloat("samplesFactor", samplesFactor);
-                    effect.setFloat("randTextureTiles", 4.0);
-                    this._firstUpdate = false;
-                }
-
-                effect.setFloat("totalStrength", this.totalStrength);
-                effect.setFloat("radius", this.radius);
-                effect.setFloat("area", this.area);
-                effect.setFloat("fallOff", this.fallOff);
-                effect.setFloat("base", this.base);
-
-                effect.setTexture("textureSampler", this._depthTexture);
-                effect.setTexture("randomSampler", this._randomTexture);
-            };
-        }
-
-        private _createSSAOCombinePostProcess(ratio: number): void {
-            this._ssaoCombinePostProcess = new PostProcess("ssaoCombine", "ssaoCombine", [], ["originalColor"],
-                                                           ratio, null, Texture.BILINEAR_SAMPLINGMODE,
-                                                           this._scene.getEngine(), false);
-
-            this._ssaoCombinePostProcess.onApply = (effect: Effect) => {
-                effect.setTextureFromPostProcess("originalColor", this._originalColorPostProcess);
-            };
-        }
-
-        private _createRandomTexture(): void {
-            var size = 512;
-
-            this._randomTexture = new DynamicTexture("SSAORandomTexture", size, this._scene, false, Texture.BILINEAR_SAMPLINGMODE);
-            this._randomTexture.wrapU = Texture.WRAP_ADDRESSMODE;
-            this._randomTexture.wrapV = Texture.WRAP_ADDRESSMODE;
-
-            var context = this._randomTexture.getContext();
-
-            var rand = (min, max) => {
-                return Math.random() * (max - min) + min;
-            }
-
-            var randVector = Vector3.Zero();
-
-            for (var x = 0; x < size; x++) {
-                for (var y = 0; y < size; y++) {
-                    randVector.x = Math.floor(rand(-1.0, 1.0) * 255);
-                    randVector.y = Math.floor(rand(-1.0, 1.0) * 255);
-                    randVector.z = Math.floor(rand(-1.0, 1.0) * 255);
-
-                    context.fillStyle = 'rgb(' + randVector.x + ', ' + randVector.y + ', ' + randVector.z + ')';
-                    context.fillRect(x, y, 1, 1);
-                }
-            }
-            this._randomTexture.update(false);
-        }
-    }
+module BABYLON {
+    export class SSAORenderingPipeline extends PostProcessRenderPipeline {
+        // Members
+
+        /**
+        * The PassPostProcess id in the pipeline that contains the original scene color
+        * @type {string}
+        */
+        public SSAOOriginalSceneColorEffect: string = "SSAOOriginalSceneColorEffect";
+        /**
+        * The SSAO PostProcess id in the pipeline
+        * @type {string}
+        */
+        public SSAORenderEffect: string = "SSAORenderEffect";
+        /**
+        * The horizontal blur PostProcess id in the pipeline
+        * @type {string}
+        */
+        public SSAOBlurHRenderEffect: string = "SSAOBlurHRenderEffect";
+        /**
+        * The vertical blur PostProcess id in the pipeline
+        * @type {string}
+        */
+        public SSAOBlurVRenderEffect: string = "SSAOBlurVRenderEffect";
+        /**
+        * The PostProcess id in the pipeline that combines the SSAO-Blur output with the original scene color (SSAOOriginalSceneColorEffect)
+        * @type {string}
+        */
+        public SSAOCombineRenderEffect: string = "SSAOCombineRenderEffect";
+
+        /**
+        * The output strength of the SSAO post-process. Default value is 1.0.
+        * @type {number}
+        */
+        public totalStrength: number = 1.0;
+
+        /**
+        * The radius around the analyzed pixel used by the SSAO post-process. Default value is 0.0006
+        * @type {number}
+        */
+        public radius: number = 0.0001;
+
+        /**
+        * Related to fallOff, used to interpolate SSAO samples (first interpolate function input) based on the occlusion difference of each pixel
+        * Must not be equal to fallOff and superior to fallOff.
+        * Default value is 0.975
+        * @type {number}
+        */
+        public area: number = 0.0075;
+
+        /**
+        * Related to area, used to interpolate SSAO samples (second interpolate function input) based on the occlusion difference of each pixel
+        * Must not be equal to area and inferior to area.
+        * Default value is 0.0
+        * @type {number}
+        */
+        public fallOff: number = 0.000001;
+
+        /**
+        * The base color of the SSAO post-process
+        * The final result is "base + ssao" between [0, 1]
+        * @type {number}
+        */
+        public base: number = 0.5;
+
+        private _scene: Scene;
+        private _depthTexture: RenderTargetTexture;
+        private _randomTexture: DynamicTexture;
+
+        private _originalColorPostProcess: PassPostProcess;
+        private _ssaoPostProcess: PostProcess;
+        private _blurHPostProcess: BlurPostProcess;
+        private _blurVPostProcess: BlurPostProcess;
+        private _ssaoCombinePostProcess: PostProcess;
+
+        private _firstUpdate: boolean = true;
+
+        /**
+         * @constructor
+         * @param {string} name - The rendering pipeline name
+         * @param {BABYLON.Scene} scene - The scene linked to this pipeline
+         * @param {any} ratio - The size of the postprocesses. Can be a number shared between passes or an object for more precision: { ssaoRatio: 0.5, combineRatio: 1.0 }
+         * @param {BABYLON.Camera[]} cameras - The array of cameras that the rendering pipeline will be attached to
+         */
+        constructor(name: string, scene: Scene, ratio: any, cameras?: Camera[]) {
+            super(scene.getEngine(), name);
+
+            this._scene = scene;
+
+            // Set up assets
+            this._createRandomTexture();
+            this._depthTexture = scene.enableDepthRenderer().getDepthMap(); // Force depth renderer "on"
+
+            var ssaoRatio = ratio.ssaoRatio || ratio;
+            var combineRatio = ratio.combineRatio || ratio;
+
+            this._originalColorPostProcess = new PassPostProcess("SSAOOriginalSceneColor", combineRatio, null, Texture.BILINEAR_SAMPLINGMODE, scene.getEngine(), false);
+            this._createSSAOPostProcess(ssaoRatio);
+            this._blurHPostProcess = new BlurPostProcess("SSAOBlurH", new Vector2(1.0, 0.0), 2.0, ssaoRatio, null, Texture.BILINEAR_SAMPLINGMODE, scene.getEngine(), false);
+            this._blurVPostProcess = new BlurPostProcess("SSAOBlurV", new Vector2(0.0, 1.0), 2.0, ssaoRatio, null, Texture.BILINEAR_SAMPLINGMODE, scene.getEngine(), false);
+            this._createSSAOCombinePostProcess(combineRatio);
+
+            // Set up pipeline
+            this.addEffect(new PostProcessRenderEffect(scene.getEngine(), this.SSAOOriginalSceneColorEffect, () => { return this._originalColorPostProcess; }, true));
+            this.addEffect(new PostProcessRenderEffect(scene.getEngine(), this.SSAORenderEffect, () => { return this._ssaoPostProcess; }, true));
+            this.addEffect(new PostProcessRenderEffect(scene.getEngine(), this.SSAOBlurHRenderEffect, () => { return this._blurHPostProcess; }, true));
+            this.addEffect(new PostProcessRenderEffect(scene.getEngine(), this.SSAOBlurVRenderEffect, () => { return this._blurVPostProcess; }, true));
+            this.addEffect(new PostProcessRenderEffect(scene.getEngine(), this.SSAOCombineRenderEffect, () => { return this._ssaoCombinePostProcess; }, true));
+
+            // Finish
+            scene.postProcessRenderPipelineManager.addPipeline(this);
+            if (cameras)
+                scene.postProcessRenderPipelineManager.attachCamerasToRenderPipeline(name, cameras);
+        }
+
+        // Public Methods
+        /**
+         * Returns the horizontal blur PostProcess
+         * @return {BABYLON.BlurPostProcess} The horizontal blur post-process
+         */
+        public getBlurHPostProcess(): BlurPostProcess {
+            return this._blurHPostProcess;
+        }
+
+        /**
+         * Returns the vertical blur PostProcess
+         * @return {BABYLON.BlurPostProcess} The vertical blur post-process
+         */
+        public getBlurVPostProcess(): BlurPostProcess {
+            return this._blurVPostProcess;
+        }
+
+        /**
+         * Removes the internal pipeline assets and detatches the pipeline from the scene cameras
+         */
+        public dispose(disableDepthRender: boolean = false): void {
+            this._scene.postProcessRenderPipelineManager.detachCamerasFromRenderPipeline(this._name, this._scene.cameras);
+
+            this._originalColorPostProcess = undefined;
+            this._ssaoPostProcess = undefined;
+            this._blurHPostProcess = undefined;
+            this._blurVPostProcess = undefined;
+            this._ssaoCombinePostProcess = undefined;
+
+            this._randomTexture.dispose();
+
+            if (disableDepthRender)
+                this._scene.disableDepthRenderer();
+        }
+
+        // Private Methods
+        private _createSSAOPostProcess(ratio: number): void {
+            var numSamples = 16;
+            var sampleSphere = [
+                0.5381, 0.1856, -0.4319,
+                0.1379, 0.2486, 0.4430,
+                0.3371, 0.5679, -0.0057,
+                -0.6999, -0.0451, -0.0019,
+                0.0689, -0.1598, -0.8547,
+                0.0560, 0.0069, -0.1843,
+                -0.0146, 0.1402, 0.0762,
+                0.0100, -0.1924, -0.0344,
+                -0.3577, -0.5301, -0.4358,
+                -0.3169, 0.1063, 0.0158,
+                0.0103, -0.5869, 0.0046,
+                -0.0897, -0.4940, 0.3287,
+                0.7119, -0.0154, -0.0918,
+                -0.0533, 0.0596, -0.5411,
+                0.0352, -0.0631, 0.5460,
+                -0.4776, 0.2847, -0.0271
+            ];
+            var samplesFactor = 1.0 / numSamples;
+
+            this._ssaoPostProcess = new PostProcess("ssao", "ssao",
+                                                    [
+                                                        "sampleSphere", "samplesFactor", "randTextureTiles", "totalStrength", "radius",
+                                                        "area", "fallOff", "base"
+                                                    ],
+                                                    ["randomSampler"],
+                                                    ratio, null, Texture.BILINEAR_SAMPLINGMODE,
+                                                    this._scene.getEngine(), false,
+                                                    "#define SAMPLES " + numSamples);
+
+            this._ssaoPostProcess.onApply = (effect: Effect) => {
+                if (this._firstUpdate) {
+                    effect.setArray3("sampleSphere", sampleSphere);
+                    effect.setFloat("samplesFactor", samplesFactor);
+                    effect.setFloat("randTextureTiles", 4.0);
+                    this._firstUpdate = false;
+                }
+
+                effect.setFloat("totalStrength", this.totalStrength);
+                effect.setFloat("radius", this.radius);
+                effect.setFloat("area", this.area);
+                effect.setFloat("fallOff", this.fallOff);
+                effect.setFloat("base", this.base);
+
+                effect.setTexture("textureSampler", this._depthTexture);
+                effect.setTexture("randomSampler", this._randomTexture);
+            };
+        }
+
+        private _createSSAOCombinePostProcess(ratio: number): void {
+            this._ssaoCombinePostProcess = new PostProcess("ssaoCombine", "ssaoCombine", [], ["originalColor"],
+                                                           ratio, null, Texture.BILINEAR_SAMPLINGMODE,
+                                                           this._scene.getEngine(), false);
+
+            this._ssaoCombinePostProcess.onApply = (effect: Effect) => {
+                effect.setTextureFromPostProcess("originalColor", this._originalColorPostProcess);
+            };
+        }
+
+        private _createRandomTexture(): void {
+            var size = 512;
+
+            this._randomTexture = new DynamicTexture("SSAORandomTexture", size, this._scene, false, Texture.BILINEAR_SAMPLINGMODE);
+            this._randomTexture.wrapU = Texture.WRAP_ADDRESSMODE;
+            this._randomTexture.wrapV = Texture.WRAP_ADDRESSMODE;
+
+            var context = this._randomTexture.getContext();
+
+            var rand = (min, max) => {
+                return Math.random() * (max - min) + min;
+            }
+
+            var randVector = Vector3.Zero();
+
+            for (var x = 0; x < size; x++) {
+                for (var y = 0; y < size; y++) {
+                    randVector.x = Math.floor(rand(-1.0, 1.0) * 255);
+                    randVector.y = Math.floor(rand(-1.0, 1.0) * 255);
+                    randVector.z = Math.floor(rand(-1.0, 1.0) * 255);
+
+                    context.fillStyle = 'rgb(' + randVector.x + ', ' + randVector.y + ', ' + randVector.z + ')';
+                    context.fillRect(x, y, 1, 1);
+                }
+            }
+            this._randomTexture.update(false);
+        }
+    }
 }

+ 19 - 19
src/PostProcess/babylon.stereoscopicInterlacePostProcess.ts

@@ -1,19 +1,19 @@
-module BABYLON {
-    export class StereoscopicInterlacePostProcess extends PostProcess {
-        private _stepSize : Vector2;
-
-        constructor(name: string, camB: Camera, postProcessA : PostProcess, isStereoscopicHoriz: boolean, samplingMode?: number) {
-            super(name, "stereoscopicInterlace", ['stepSize'], ['camASampler'], 1, camB, samplingMode, camB.getScene().getEngine(), false, isStereoscopicHoriz ? "#define IS_STEREOSCOPIC_HORIZ 1" : undefined);
-            
-            this._stepSize = new Vector2(1 / this.width, 1 / this.height);
-
-            this.onSizeChanged = () => {
-                this._stepSize = new Vector2(1 / this.width, 1 / this.height);
-            };
-            this.onApply = (effect: Effect) => {
-                effect.setTextureFromPostProcess("camASampler", postProcessA);
-                effect.setFloat2("stepSize", this._stepSize.x, this._stepSize.y);
-            };
-        }
-    }
-}
+module BABYLON {
+    export class StereoscopicInterlacePostProcess extends PostProcess {
+        private _stepSize : Vector2;
+
+        constructor(name: string, camB: Camera, postProcessA : PostProcess, isStereoscopicHoriz: boolean, samplingMode?: number) {
+            super(name, "stereoscopicInterlace", ['stepSize'], ['camASampler'], 1, camB, samplingMode, camB.getScene().getEngine(), false, isStereoscopicHoriz ? "#define IS_STEREOSCOPIC_HORIZ 1" : undefined);
+            
+            this._stepSize = new Vector2(1 / this.width, 1 / this.height);
+
+            this.onSizeChanged = () => {
+                this._stepSize = new Vector2(1 / this.width, 1 / this.height);
+            };
+            this.onApply = (effect: Effect) => {
+                effect.setTextureFromPostProcess("camASampler", postProcessA);
+                effect.setFloat2("stepSize", this._stepSize.x, this._stepSize.y);
+            };
+        }
+    }
+}

+ 40 - 40
src/PostProcess/babylon.tonemapPostProcess.ts

@@ -1,41 +1,41 @@
-module BABYLON
-{
-    export enum TonemappingOperator
-    {
-        Hable = 0,
-        Reinhard = 1,
-        HejiDawson = 2,
-        Photographic = 3,
-    };
-
-    export class TonemapPostProcess extends PostProcess
-    {
-        private _operator : TonemappingOperator;
-        private _exposureAdjustment : number;
-
-        constructor(name: string, operator: TonemappingOperator, exposureAdjustment: number, camera: Camera, samplingMode: number = Texture.BILINEAR_SAMPLINGMODE, engine?: Engine, textureFormat = Engine.TEXTURETYPE_UNSIGNED_INT)
-        {
-            this._operator = operator;
-            this._exposureAdjustment = exposureAdjustment;
-
-            var params = ["_ExposureAdjustment"];
-            var defines = "#define ";
-
-            if (operator === TonemappingOperator.Hable)
-                defines += "HABLE_TONEMAPPING";
-            else if (operator === TonemappingOperator.Reinhard)
-                defines += "REINHARD_TONEMAPPING";
-            else if (operator === TonemappingOperator.HejiDawson)
-                defines += "OPTIMIZED_HEJIDAWSON_TONEMAPPING";
-            else if (operator === TonemappingOperator.Photographic)
-                defines += "PHOTOGRAPHIC_TONEMAPPING";
-
-            super(name, "tonemap", params, null, 1.0, camera, samplingMode, engine, true, defines, textureFormat);
-
-            this.onApply = (effect: Effect) =>
-            {
-                effect.setFloat("_ExposureAdjustment", this._exposureAdjustment);
-            };
-        }
-    }
+module BABYLON
+{
+    export enum TonemappingOperator
+    {
+        Hable = 0,
+        Reinhard = 1,
+        HejiDawson = 2,
+        Photographic = 3,
+    };
+
+    export class TonemapPostProcess extends PostProcess
+    {
+        private _operator : TonemappingOperator;
+        private _exposureAdjustment : number;
+
+        constructor(name: string, operator: TonemappingOperator, exposureAdjustment: number, camera: Camera, samplingMode: number = Texture.BILINEAR_SAMPLINGMODE, engine?: Engine, textureFormat = Engine.TEXTURETYPE_UNSIGNED_INT)
+        {
+            this._operator = operator;
+            this._exposureAdjustment = exposureAdjustment;
+
+            var params = ["_ExposureAdjustment"];
+            var defines = "#define ";
+
+            if (operator === TonemappingOperator.Hable)
+                defines += "HABLE_TONEMAPPING";
+            else if (operator === TonemappingOperator.Reinhard)
+                defines += "REINHARD_TONEMAPPING";
+            else if (operator === TonemappingOperator.HejiDawson)
+                defines += "OPTIMIZED_HEJIDAWSON_TONEMAPPING";
+            else if (operator === TonemappingOperator.Photographic)
+                defines += "PHOTOGRAPHIC_TONEMAPPING";
+
+            super(name, "tonemap", params, null, 1.0, camera, samplingMode, engine, true, defines, textureFormat);
+
+            this.onApply = (effect: Effect) =>
+            {
+                effect.setFloat("_ExposureAdjustment", this._exposureAdjustment);
+            };
+        }
+    }
 }

+ 394 - 394
src/PostProcess/babylon.volumetricLightScatteringPostProcess.ts

@@ -1,395 +1,395 @@
-module BABYLON {
-    // Inspired by http://http.developer.nvidia.com/GPUGems3/gpugems3_ch13.html
-    export class VolumetricLightScatteringPostProcess extends PostProcess {
-        // Members
-        private _volumetricLightScatteringPass: Effect;
-        private _volumetricLightScatteringRTT: RenderTargetTexture;
-        private _viewPort: Viewport;
-        private _screenCoordinates: Vector2 = Vector2.Zero();
-        private _cachedDefines: string;
-        private _customMeshPosition: Vector3;
-
-        /**
-        * Set if the post-process should use a custom position for the light source (true) or the internal mesh position (false)
-        * @type {boolean}
-        */
-        public useCustomMeshPosition: boolean = false;
-        /**
-        * If the post-process should inverse the light scattering direction
-        * @type {boolean}
-        */
-        public invert: boolean = true;
-        /**
-        * The internal mesh used by the post-process
-        * @type {boolean}
-        */
-        public mesh: Mesh;
-        /**
-        * Set to true to use the diffuseColor instead of the diffuseTexture
-        * @type {boolean}
-        */
-        public useDiffuseColor: boolean = false;
-
-        /**
-        * Array containing the excluded meshes not rendered in the internal pass
-        */
-        public excludedMeshes = new Array<AbstractMesh>();
-
-        /**
-        * Controls the overall intensity of the post-process
-        * @type {number}
-        */
-        public exposure = 0.3;
-        /**
-        * Dissipates each sample's contribution in range [0, 1]
-        * @type {number}
-        */
-        public decay = 0.96815;
-        /**
-        * Controls the overall intensity of each sample
-        * @type {number}
-        */
-        public weight = 0.58767;
-        /**
-        * Controls the density of each sample
-        * @type {number}
-        */
-        public density = 0.926;
-
-        /**
-         * @constructor
-         * @param {string} name - The post-process name
-         * @param {any} ratio - The size of the post-process and/or internal pass (0.5 means that your postprocess will have a width = canvas.width 0.5 and a height = canvas.height 0.5)
-         * @param {BABYLON.Camera} camera - The camera that the post-process will be attached to
-         * @param {BABYLON.Mesh} mesh - The mesh used to create the light scattering
-         * @param {number} samples - The post-process quality, default 100
-         * @param {number} samplingMode - The post-process filtering mode
-         * @param {BABYLON.Engine} engine - The babylon engine
-         * @param {boolean} reusable - If the post-process is reusable
-         * @param {BABYLON.Scene} scene - The constructor needs a scene reference to initialize internal components. If "camera" is null (RenderPipelineà, "scene" must be provided
-         */
-        constructor(name: string, ratio: any, camera: Camera, mesh?: Mesh, samples: number = 100, samplingMode: number = Texture.BILINEAR_SAMPLINGMODE, engine?: Engine, reusable?: boolean, scene?: Scene) {
-            super(name, "volumetricLightScattering", ["decay", "exposure", "weight", "meshPositionOnScreen", "density"], ["lightScatteringSampler"], ratio.postProcessRatio || ratio, camera, samplingMode, engine, reusable, "#define NUM_SAMPLES " + samples);
-            scene = (camera === null) ? scene : camera.getScene(); // parameter "scene" can be null.
-
-            this._viewPort = new Viewport(0, 0, 1, 1).toGlobal(scene.getEngine());
-
-            // Configure mesh
-            this.mesh = (mesh !== null) ? mesh : VolumetricLightScatteringPostProcess.CreateDefaultMesh("VolumetricLightScatteringMesh", scene);
-
-            // Configure
-            this._createPass(scene, ratio.passRatio || ratio);
-
-            this.onActivate = (camera: Camera) => {
-                if (!this.isSupported) {
-                    this.dispose(camera);
-                }
-
-                this.onActivate = null;
-            };
-
-            this.onApply = (effect: Effect) => {
-                this._updateMeshScreenCoordinates(scene);
-
-                effect.setTexture("lightScatteringSampler", this._volumetricLightScatteringRTT);
-                effect.setFloat("exposure", this.exposure);
-                effect.setFloat("decay", this.decay);
-                effect.setFloat("weight", this.weight);
-                effect.setFloat("density", this.density);
-                effect.setVector2("meshPositionOnScreen", this._screenCoordinates);
-            };
-        }
-
-        public isReady(subMesh: SubMesh, useInstances: boolean): boolean {
-            var mesh = subMesh.getMesh();
-
-            var defines = [];
-            var attribs = [VertexBuffer.PositionKind];
-            var material: any = subMesh.getMaterial();
-            var needUV: boolean = false;
-
-            // Render this.mesh as default
-            if (mesh === this.mesh) {
-                if (this.useDiffuseColor) {
-                    defines.push("#define DIFFUSE_COLOR_RENDER");
-                }
-                else if (material) {
-                    if (material.diffuseTexture !== undefined) {
-                        defines.push("#define BASIC_RENDER");
-                    } else {
-                        defines.push("#define DIFFUSE_COLOR_RENDER");
-                    }
-                }
-                defines.push("#define NEED_UV");
-                needUV = true;
-            }
-
-            // Alpha test
-            if (material) {
-                if (material.needAlphaTesting()) {
-                    defines.push("#define ALPHATEST");
-                }
-
-                if (material.opacityTexture !== undefined) {
-                    defines.push("#define OPACITY");
-                    if (material.opacityTexture.getAlphaFromRGB) {
-                        defines.push("#define OPACITYRGB");
-                    }
-                    if (!needUV) {
-                        defines.push("#define NEED_UV");
-                    }
-                }
-
-                if (mesh.isVerticesDataPresent(VertexBuffer.UVKind)) {
-                    attribs.push(VertexBuffer.UVKind);
-                    defines.push("#define UV1");
-                }
-                if (mesh.isVerticesDataPresent(VertexBuffer.UV2Kind)) {
-                    attribs.push(VertexBuffer.UV2Kind);
-                    defines.push("#define UV2");
-                }
-            }
-
-            // Bones
-            if (mesh.useBones && mesh.computeBonesUsingShaders) {
-                attribs.push(VertexBuffer.MatricesIndicesKind);
-                attribs.push(VertexBuffer.MatricesWeightsKind);
-                defines.push("#define NUM_BONE_INFLUENCERS " + mesh.numBoneInfluencers);
-                defines.push("#define BonesPerMesh " + (mesh.skeleton.bones.length + 1));
-            } else {
-                defines.push("#define NUM_BONE_INFLUENCERS 0"); 
-            }
-            
-
-            // Instances
-            if (useInstances) {
-                defines.push("#define INSTANCES");
-                attribs.push("world0");
-                attribs.push("world1");
-                attribs.push("world2");
-                attribs.push("world3");
-            }
-
-            // Get correct effect      
-            var join = defines.join("\n");
-            if (this._cachedDefines !== join) {
-                this._cachedDefines = join;
-                this._volumetricLightScatteringPass = mesh.getScene().getEngine().createEffect(
-                    { vertexElement: "depth", fragmentElement: "volumetricLightScatteringPass" },
-                    attribs,
-                    ["world", "mBones", "viewProjection", "diffuseMatrix", "opacityLevel", "color"],
-                    ["diffuseSampler", "opacitySampler"], join);
-            }
-
-            return this._volumetricLightScatteringPass.isReady();
-        }
-
-        /**
-         * Sets the new light position for light scattering effect
-         * @param {BABYLON.Vector3} The new custom light position
-         */
-        public setCustomMeshPosition(position: Vector3): void {
-            this._customMeshPosition = position;
-        }
-
-        /**
-         * Returns the light position for light scattering effect
-         * @return {BABYLON.Vector3} The custom light position
-         */
-        public getCustomMeshPosition(): Vector3 {
-            return this._customMeshPosition;
-        }
-
-        /**
-         * Disposes the internal assets and detaches the post-process from the camera
-         */
-        public dispose(camera: Camera): void {
-            var rttIndex = camera.getScene().customRenderTargets.indexOf(this._volumetricLightScatteringRTT);
-            if (rttIndex !== -1) {
-                camera.getScene().customRenderTargets.splice(rttIndex, 1);
-            }
-                
-            this._volumetricLightScatteringRTT.dispose();
-            super.dispose(camera);
-        }
-
-        /**
-         * Returns the render target texture used by the post-process
-         * @return {BABYLON.RenderTargetTexture} The render target texture used by the post-process
-         */
-        public getPass(): RenderTargetTexture {
-            return this._volumetricLightScatteringRTT;
-        }
-
-        // Private methods
-        private _meshExcluded(mesh: AbstractMesh) {
-            if (this.excludedMeshes.length > 0 && this.excludedMeshes.indexOf(mesh) !== -1) {
-                return true;
-            }
-
-            return false;
-        }
-
-        private _createPass(scene: Scene, ratio: number): void {
-            var engine = scene.getEngine();
-
-            this._volumetricLightScatteringRTT = new RenderTargetTexture("volumetricLightScatteringMap", { width: engine.getRenderWidth() * ratio, height: engine.getRenderHeight() * ratio }, scene, false, true, Engine.TEXTURETYPE_UNSIGNED_INT);
-            this._volumetricLightScatteringRTT.wrapU = Texture.CLAMP_ADDRESSMODE;
-            this._volumetricLightScatteringRTT.wrapV = Texture.CLAMP_ADDRESSMODE;
-            this._volumetricLightScatteringRTT.renderList = null;
-            this._volumetricLightScatteringRTT.renderParticles = false;
-            scene.customRenderTargets.push(this._volumetricLightScatteringRTT);
-
-            // Custom render function for submeshes
-            var renderSubMesh = (subMesh: SubMesh): void => {
-                var mesh = subMesh.getRenderingMesh();
-                if (this._meshExcluded(mesh)) {
-                    return;
-                }
-
-                var scene = mesh.getScene();
-                var engine = scene.getEngine();
-
-                // Culling
-                engine.setState(subMesh.getMaterial().backFaceCulling);
-
-                // Managing instances
-                var batch = mesh._getInstancesRenderList(subMesh._id);
-
-                if (batch.mustReturn) {
-                    return;
-                }
-
-                var hardwareInstancedRendering = (engine.getCaps().instancedArrays !== null) && (batch.visibleInstances[subMesh._id] !== null);
-
-                if (this.isReady(subMesh, hardwareInstancedRendering)) {
-                    engine.enableEffect(this._volumetricLightScatteringPass);
-                    mesh._bind(subMesh, this._volumetricLightScatteringPass, Material.TriangleFillMode);
-                    var material: any = subMesh.getMaterial();
-
-                    this._volumetricLightScatteringPass.setMatrix("viewProjection", scene.getTransformMatrix());
-
-                    // Alpha test
-                    if (material && (mesh === this.mesh || material.needAlphaTesting() || material.opacityTexture !== undefined)) {
-                        var alphaTexture = material.getAlphaTestTexture();
-
-                        if ((this.useDiffuseColor || alphaTexture === undefined) && mesh === this.mesh) {
-                            this._volumetricLightScatteringPass.setColor3("color", material.diffuseColor);
-                        }
-                        if (material.needAlphaTesting() || (mesh === this.mesh && alphaTexture && !this.useDiffuseColor)) {
-                            this._volumetricLightScatteringPass.setTexture("diffuseSampler", alphaTexture);
-                            if (alphaTexture) {
-                                this._volumetricLightScatteringPass.setMatrix("diffuseMatrix", alphaTexture.getTextureMatrix());
-                            }
-                        }
-
-                        if (material.opacityTexture !== undefined) {
-                            this._volumetricLightScatteringPass.setTexture("opacitySampler", material.opacityTexture);
-                            this._volumetricLightScatteringPass.setFloat("opacityLevel", material.opacityTexture.level);
-                        }
-                    }
-
-                    // Bones
-                    if (mesh.useBones && mesh.computeBonesUsingShaders) {
-                        this._volumetricLightScatteringPass.setMatrices("mBones", mesh.skeleton.getTransformMatrices());
-                    }
-
-                    // Draw
-                    mesh._processRendering(subMesh, this._volumetricLightScatteringPass, Material.TriangleFillMode, batch, hardwareInstancedRendering,
-                        (isInstance, world) => this._volumetricLightScatteringPass.setMatrix("world", world));
-                }
-            };
-
-            // Render target texture callbacks
-            var savedSceneClearColor: Color4;
-            var sceneClearColor = new Color4(0.0, 0.0, 0.0, 1.0);
-
-            this._volumetricLightScatteringRTT.onBeforeRender = (): void => {
-                savedSceneClearColor = scene.clearColor;
-                scene.clearColor = sceneClearColor;
-            };
-
-            this._volumetricLightScatteringRTT.onAfterRender = (): void => {
-                scene.clearColor = savedSceneClearColor;
-            };
-            
-            this._volumetricLightScatteringRTT.customRenderFunction = (opaqueSubMeshes: SmartArray<SubMesh>, alphaTestSubMeshes: SmartArray<SubMesh>, transparentSubMeshes: SmartArray<SubMesh>): void => {
-                var engine = scene.getEngine();
-                var index: number;
-
-                for (index = 0; index < opaqueSubMeshes.length; index++) {
-                    renderSubMesh(opaqueSubMeshes.data[index]);
-                }
-
-                engine.setAlphaTesting(true);
-                for (index = 0; index < alphaTestSubMeshes.length; index++) {
-                    renderSubMesh(alphaTestSubMeshes.data[index]);
-                }
-                engine.setAlphaTesting(false);
-
-                if (transparentSubMeshes.length) {
-                    // Sort sub meshes
-                    for (index = 0; index < transparentSubMeshes.length; index++) {
-                        var submesh = transparentSubMeshes.data[index];
-                        submesh._alphaIndex = submesh.getMesh().alphaIndex;
-                        submesh._distanceToCamera = submesh.getBoundingInfo().boundingSphere.centerWorld.subtract(scene.activeCamera.position).length();
-                    }
-
-                    var sortedArray = transparentSubMeshes.data.slice(0, transparentSubMeshes.length);
-                    sortedArray.sort((a, b) => {
-                        // Alpha index first
-                        if (a._alphaIndex > b._alphaIndex) {
-                            return 1;
-                        }
-                        if (a._alphaIndex < b._alphaIndex) {
-                            return -1;
-                        }
-
-                        // Then distance to camera
-                        if (a._distanceToCamera < b._distanceToCamera) {
-                            return 1;
-                        }
-                        if (a._distanceToCamera > b._distanceToCamera) {
-                            return -1;
-                        }
-
-                        return 0;
-                    });
-
-                    // Render sub meshes
-                    engine.setAlphaMode(BABYLON.Engine.ALPHA_COMBINE);
-                    for (index = 0; index < sortedArray.length; index++) {
-                        renderSubMesh(sortedArray[index]);
-                    }
-                    engine.setAlphaMode(BABYLON.Engine.ALPHA_DISABLE);
-                }
-            };
-        }
-
-        private _updateMeshScreenCoordinates(scene: Scene): void {
-            var transform = scene.getTransformMatrix();
-            var meshPosition = this.mesh.parent ? this.mesh.getAbsolutePosition() : this.mesh.position;
-            var pos = Vector3.Project(this.useCustomMeshPosition ? this._customMeshPosition : meshPosition, Matrix.Identity(), transform, this._viewPort);
-
-            this._screenCoordinates.x = pos.x / this._viewPort.width;
-            this._screenCoordinates.y = pos.y / this._viewPort.height;
-
-            if (this.invert)
-                this._screenCoordinates.y = 1.0 - this._screenCoordinates.y;
-        }
-
-        // Static methods
-        /**
-        * Creates a default mesh for the Volumeric Light Scattering post-process
-        * @param {string} The mesh name
-        * @param {BABYLON.Scene} The scene where to create the mesh
-        * @return {BABYLON.Mesh} the default mesh
-        */
-        public static CreateDefaultMesh(name: string, scene: Scene): Mesh {
-            var mesh = Mesh.CreatePlane(name, 1, scene);
-            mesh.billboardMode = AbstractMesh.BILLBOARDMODE_ALL;
-            mesh.material = new StandardMaterial(name + "Material", scene);
-            return mesh;
-        }
-    }
+module BABYLON {
+    // Inspired by http://http.developer.nvidia.com/GPUGems3/gpugems3_ch13.html
+    export class VolumetricLightScatteringPostProcess extends PostProcess {
+        // Members
+        private _volumetricLightScatteringPass: Effect;
+        private _volumetricLightScatteringRTT: RenderTargetTexture;
+        private _viewPort: Viewport;
+        private _screenCoordinates: Vector2 = Vector2.Zero();
+        private _cachedDefines: string;
+        private _customMeshPosition: Vector3;
+
+        /**
+        * Set if the post-process should use a custom position for the light source (true) or the internal mesh position (false)
+        * @type {boolean}
+        */
+        public useCustomMeshPosition: boolean = false;
+        /**
+        * If the post-process should inverse the light scattering direction
+        * @type {boolean}
+        */
+        public invert: boolean = true;
+        /**
+        * The internal mesh used by the post-process
+        * @type {boolean}
+        */
+        public mesh: Mesh;
+        /**
+        * Set to true to use the diffuseColor instead of the diffuseTexture
+        * @type {boolean}
+        */
+        public useDiffuseColor: boolean = false;
+
+        /**
+        * Array containing the excluded meshes not rendered in the internal pass
+        */
+        public excludedMeshes = new Array<AbstractMesh>();
+
+        /**
+        * Controls the overall intensity of the post-process
+        * @type {number}
+        */
+        public exposure = 0.3;
+        /**
+        * Dissipates each sample's contribution in range [0, 1]
+        * @type {number}
+        */
+        public decay = 0.96815;
+        /**
+        * Controls the overall intensity of each sample
+        * @type {number}
+        */
+        public weight = 0.58767;
+        /**
+        * Controls the density of each sample
+        * @type {number}
+        */
+        public density = 0.926;
+
+        /**
+         * @constructor
+         * @param {string} name - The post-process name
+         * @param {any} ratio - The size of the post-process and/or internal pass (0.5 means that your postprocess will have a width = canvas.width 0.5 and a height = canvas.height 0.5)
+         * @param {BABYLON.Camera} camera - The camera that the post-process will be attached to
+         * @param {BABYLON.Mesh} mesh - The mesh used to create the light scattering
+         * @param {number} samples - The post-process quality, default 100
+         * @param {number} samplingMode - The post-process filtering mode
+         * @param {BABYLON.Engine} engine - The babylon engine
+         * @param {boolean} reusable - If the post-process is reusable
+         * @param {BABYLON.Scene} scene - The constructor needs a scene reference to initialize internal components. If "camera" is null (RenderPipelineà, "scene" must be provided
+         */
+        constructor(name: string, ratio: any, camera: Camera, mesh?: Mesh, samples: number = 100, samplingMode: number = Texture.BILINEAR_SAMPLINGMODE, engine?: Engine, reusable?: boolean, scene?: Scene) {
+            super(name, "volumetricLightScattering", ["decay", "exposure", "weight", "meshPositionOnScreen", "density"], ["lightScatteringSampler"], ratio.postProcessRatio || ratio, camera, samplingMode, engine, reusable, "#define NUM_SAMPLES " + samples);
+            scene = (camera === null) ? scene : camera.getScene(); // parameter "scene" can be null.
+
+            this._viewPort = new Viewport(0, 0, 1, 1).toGlobal(scene.getEngine());
+
+            // Configure mesh
+            this.mesh = (mesh !== null) ? mesh : VolumetricLightScatteringPostProcess.CreateDefaultMesh("VolumetricLightScatteringMesh", scene);
+
+            // Configure
+            this._createPass(scene, ratio.passRatio || ratio);
+
+            this.onActivate = (camera: Camera) => {
+                if (!this.isSupported) {
+                    this.dispose(camera);
+                }
+
+                this.onActivate = null;
+            };
+
+            this.onApply = (effect: Effect) => {
+                this._updateMeshScreenCoordinates(scene);
+
+                effect.setTexture("lightScatteringSampler", this._volumetricLightScatteringRTT);
+                effect.setFloat("exposure", this.exposure);
+                effect.setFloat("decay", this.decay);
+                effect.setFloat("weight", this.weight);
+                effect.setFloat("density", this.density);
+                effect.setVector2("meshPositionOnScreen", this._screenCoordinates);
+            };
+        }
+
+        public isReady(subMesh: SubMesh, useInstances: boolean): boolean {
+            var mesh = subMesh.getMesh();
+
+            var defines = [];
+            var attribs = [VertexBuffer.PositionKind];
+            var material: any = subMesh.getMaterial();
+            var needUV: boolean = false;
+
+            // Render this.mesh as default
+            if (mesh === this.mesh) {
+                if (this.useDiffuseColor) {
+                    defines.push("#define DIFFUSE_COLOR_RENDER");
+                }
+                else if (material) {
+                    if (material.diffuseTexture !== undefined) {
+                        defines.push("#define BASIC_RENDER");
+                    } else {
+                        defines.push("#define DIFFUSE_COLOR_RENDER");
+                    }
+                }
+                defines.push("#define NEED_UV");
+                needUV = true;
+            }
+
+            // Alpha test
+            if (material) {
+                if (material.needAlphaTesting()) {
+                    defines.push("#define ALPHATEST");
+                }
+
+                if (material.opacityTexture !== undefined) {
+                    defines.push("#define OPACITY");
+                    if (material.opacityTexture.getAlphaFromRGB) {
+                        defines.push("#define OPACITYRGB");
+                    }
+                    if (!needUV) {
+                        defines.push("#define NEED_UV");
+                    }
+                }
+
+                if (mesh.isVerticesDataPresent(VertexBuffer.UVKind)) {
+                    attribs.push(VertexBuffer.UVKind);
+                    defines.push("#define UV1");
+                }
+                if (mesh.isVerticesDataPresent(VertexBuffer.UV2Kind)) {
+                    attribs.push(VertexBuffer.UV2Kind);
+                    defines.push("#define UV2");
+                }
+            }
+
+            // Bones
+            if (mesh.useBones && mesh.computeBonesUsingShaders) {
+                attribs.push(VertexBuffer.MatricesIndicesKind);
+                attribs.push(VertexBuffer.MatricesWeightsKind);
+                defines.push("#define NUM_BONE_INFLUENCERS " + mesh.numBoneInfluencers);
+                defines.push("#define BonesPerMesh " + (mesh.skeleton.bones.length + 1));
+            } else {
+                defines.push("#define NUM_BONE_INFLUENCERS 0"); 
+            }
+            
+
+            // Instances
+            if (useInstances) {
+                defines.push("#define INSTANCES");
+                attribs.push("world0");
+                attribs.push("world1");
+                attribs.push("world2");
+                attribs.push("world3");
+            }
+
+            // Get correct effect      
+            var join = defines.join("\n");
+            if (this._cachedDefines !== join) {
+                this._cachedDefines = join;
+                this._volumetricLightScatteringPass = mesh.getScene().getEngine().createEffect(
+                    { vertexElement: "depth", fragmentElement: "volumetricLightScatteringPass" },
+                    attribs,
+                    ["world", "mBones", "viewProjection", "diffuseMatrix", "opacityLevel", "color"],
+                    ["diffuseSampler", "opacitySampler"], join);
+            }
+
+            return this._volumetricLightScatteringPass.isReady();
+        }
+
+        /**
+         * Sets the new light position for light scattering effect
+         * @param {BABYLON.Vector3} The new custom light position
+         */
+        public setCustomMeshPosition(position: Vector3): void {
+            this._customMeshPosition = position;
+        }
+
+        /**
+         * Returns the light position for light scattering effect
+         * @return {BABYLON.Vector3} The custom light position
+         */
+        public getCustomMeshPosition(): Vector3 {
+            return this._customMeshPosition;
+        }
+
+        /**
+         * Disposes the internal assets and detaches the post-process from the camera
+         */
+        public dispose(camera: Camera): void {
+            var rttIndex = camera.getScene().customRenderTargets.indexOf(this._volumetricLightScatteringRTT);
+            if (rttIndex !== -1) {
+                camera.getScene().customRenderTargets.splice(rttIndex, 1);
+            }
+                
+            this._volumetricLightScatteringRTT.dispose();
+            super.dispose(camera);
+        }
+
+        /**
+         * Returns the render target texture used by the post-process
+         * @return {BABYLON.RenderTargetTexture} The render target texture used by the post-process
+         */
+        public getPass(): RenderTargetTexture {
+            return this._volumetricLightScatteringRTT;
+        }
+
+        // Private methods
+        private _meshExcluded(mesh: AbstractMesh) {
+            if (this.excludedMeshes.length > 0 && this.excludedMeshes.indexOf(mesh) !== -1) {
+                return true;
+            }
+
+            return false;
+        }
+
+        private _createPass(scene: Scene, ratio: number): void {
+            var engine = scene.getEngine();
+
+            this._volumetricLightScatteringRTT = new RenderTargetTexture("volumetricLightScatteringMap", { width: engine.getRenderWidth() * ratio, height: engine.getRenderHeight() * ratio }, scene, false, true, Engine.TEXTURETYPE_UNSIGNED_INT);
+            this._volumetricLightScatteringRTT.wrapU = Texture.CLAMP_ADDRESSMODE;
+            this._volumetricLightScatteringRTT.wrapV = Texture.CLAMP_ADDRESSMODE;
+            this._volumetricLightScatteringRTT.renderList = null;
+            this._volumetricLightScatteringRTT.renderParticles = false;
+            scene.customRenderTargets.push(this._volumetricLightScatteringRTT);
+
+            // Custom render function for submeshes
+            var renderSubMesh = (subMesh: SubMesh): void => {
+                var mesh = subMesh.getRenderingMesh();
+                if (this._meshExcluded(mesh)) {
+                    return;
+                }
+
+                var scene = mesh.getScene();
+                var engine = scene.getEngine();
+
+                // Culling
+                engine.setState(subMesh.getMaterial().backFaceCulling);
+
+                // Managing instances
+                var batch = mesh._getInstancesRenderList(subMesh._id);
+
+                if (batch.mustReturn) {
+                    return;
+                }
+
+                var hardwareInstancedRendering = (engine.getCaps().instancedArrays !== null) && (batch.visibleInstances[subMesh._id] !== null);
+
+                if (this.isReady(subMesh, hardwareInstancedRendering)) {
+                    engine.enableEffect(this._volumetricLightScatteringPass);
+                    mesh._bind(subMesh, this._volumetricLightScatteringPass, Material.TriangleFillMode);
+                    var material: any = subMesh.getMaterial();
+
+                    this._volumetricLightScatteringPass.setMatrix("viewProjection", scene.getTransformMatrix());
+
+                    // Alpha test
+                    if (material && (mesh === this.mesh || material.needAlphaTesting() || material.opacityTexture !== undefined)) {
+                        var alphaTexture = material.getAlphaTestTexture();
+
+                        if ((this.useDiffuseColor || alphaTexture === undefined) && mesh === this.mesh) {
+                            this._volumetricLightScatteringPass.setColor3("color", material.diffuseColor);
+                        }
+                        if (material.needAlphaTesting() || (mesh === this.mesh && alphaTexture && !this.useDiffuseColor)) {
+                            this._volumetricLightScatteringPass.setTexture("diffuseSampler", alphaTexture);
+                            if (alphaTexture) {
+                                this._volumetricLightScatteringPass.setMatrix("diffuseMatrix", alphaTexture.getTextureMatrix());
+                            }
+                        }
+
+                        if (material.opacityTexture !== undefined) {
+                            this._volumetricLightScatteringPass.setTexture("opacitySampler", material.opacityTexture);
+                            this._volumetricLightScatteringPass.setFloat("opacityLevel", material.opacityTexture.level);
+                        }
+                    }
+
+                    // Bones
+                    if (mesh.useBones && mesh.computeBonesUsingShaders) {
+                        this._volumetricLightScatteringPass.setMatrices("mBones", mesh.skeleton.getTransformMatrices());
+                    }
+
+                    // Draw
+                    mesh._processRendering(subMesh, this._volumetricLightScatteringPass, Material.TriangleFillMode, batch, hardwareInstancedRendering,
+                        (isInstance, world) => this._volumetricLightScatteringPass.setMatrix("world", world));
+                }
+            };
+
+            // Render target texture callbacks
+            var savedSceneClearColor: Color4;
+            var sceneClearColor = new Color4(0.0, 0.0, 0.0, 1.0);
+
+            this._volumetricLightScatteringRTT.onBeforeRender = (): void => {
+                savedSceneClearColor = scene.clearColor;
+                scene.clearColor = sceneClearColor;
+            };
+
+            this._volumetricLightScatteringRTT.onAfterRender = (): void => {
+                scene.clearColor = savedSceneClearColor;
+            };
+            
+            this._volumetricLightScatteringRTT.customRenderFunction = (opaqueSubMeshes: SmartArray<SubMesh>, alphaTestSubMeshes: SmartArray<SubMesh>, transparentSubMeshes: SmartArray<SubMesh>): void => {
+                var engine = scene.getEngine();
+                var index: number;
+
+                for (index = 0; index < opaqueSubMeshes.length; index++) {
+                    renderSubMesh(opaqueSubMeshes.data[index]);
+                }
+
+                engine.setAlphaTesting(true);
+                for (index = 0; index < alphaTestSubMeshes.length; index++) {
+                    renderSubMesh(alphaTestSubMeshes.data[index]);
+                }
+                engine.setAlphaTesting(false);
+
+                if (transparentSubMeshes.length) {
+                    // Sort sub meshes
+                    for (index = 0; index < transparentSubMeshes.length; index++) {
+                        var submesh = transparentSubMeshes.data[index];
+                        submesh._alphaIndex = submesh.getMesh().alphaIndex;
+                        submesh._distanceToCamera = submesh.getBoundingInfo().boundingSphere.centerWorld.subtract(scene.activeCamera.position).length();
+                    }
+
+                    var sortedArray = transparentSubMeshes.data.slice(0, transparentSubMeshes.length);
+                    sortedArray.sort((a, b) => {
+                        // Alpha index first
+                        if (a._alphaIndex > b._alphaIndex) {
+                            return 1;
+                        }
+                        if (a._alphaIndex < b._alphaIndex) {
+                            return -1;
+                        }
+
+                        // Then distance to camera
+                        if (a._distanceToCamera < b._distanceToCamera) {
+                            return 1;
+                        }
+                        if (a._distanceToCamera > b._distanceToCamera) {
+                            return -1;
+                        }
+
+                        return 0;
+                    });
+
+                    // Render sub meshes
+                    engine.setAlphaMode(BABYLON.Engine.ALPHA_COMBINE);
+                    for (index = 0; index < sortedArray.length; index++) {
+                        renderSubMesh(sortedArray[index]);
+                    }
+                    engine.setAlphaMode(BABYLON.Engine.ALPHA_DISABLE);
+                }
+            };
+        }
+
+        private _updateMeshScreenCoordinates(scene: Scene): void {
+            var transform = scene.getTransformMatrix();
+            var meshPosition = this.mesh.parent ? this.mesh.getAbsolutePosition() : this.mesh.position;
+            var pos = Vector3.Project(this.useCustomMeshPosition ? this._customMeshPosition : meshPosition, Matrix.Identity(), transform, this._viewPort);
+
+            this._screenCoordinates.x = pos.x / this._viewPort.width;
+            this._screenCoordinates.y = pos.y / this._viewPort.height;
+
+            if (this.invert)
+                this._screenCoordinates.y = 1.0 - this._screenCoordinates.y;
+        }
+
+        // Static methods
+        /**
+        * Creates a default mesh for the Volumeric Light Scattering post-process
+        * @param {string} The mesh name
+        * @param {BABYLON.Scene} The scene where to create the mesh
+        * @return {BABYLON.Mesh} the default mesh
+        */
+        public static CreateDefaultMesh(name: string, scene: Scene): Mesh {
+            var mesh = Mesh.CreatePlane(name, 1, scene);
+            mesh.billboardMode = AbstractMesh.BILLBOARDMODE_ALL;
+            mesh.material = new StandardMaterial(name + "Material", scene);
+            return mesh;
+        }
+    }
 }  

+ 41 - 41
src/PostProcess/babylon.vrDistortionCorrectionPostProcess.ts

@@ -1,41 +1,41 @@
-module BABYLON {
-    export class VRDistortionCorrectionPostProcess extends PostProcess {
-        public aspectRatio: number;
-
-        private _isRightEye: boolean;
-        private _distortionFactors: number[];
-        private _postProcessScaleFactor: number;
-        private _lensCenterOffset: number;
-        private _scaleIn: Vector2;
-        private _scaleFactor: Vector2;
-        private _lensCenter: Vector2;
-
-        //ANY
-        constructor(name: string, camera: Camera, isRightEye: boolean, vrMetrics: VRCameraMetrics) {
-            super(name, "vrDistortionCorrection", [
-                'LensCenter',
-                'Scale',
-                'ScaleIn',
-                'HmdWarpParam'
-            ], null, vrMetrics.postProcessScaleFactor, camera, Texture.BILINEAR_SAMPLINGMODE, null, null);
-
-            this._isRightEye = isRightEye;
-            this._distortionFactors = vrMetrics.distortionK;
-            this._postProcessScaleFactor = vrMetrics.postProcessScaleFactor;
-            this._lensCenterOffset = vrMetrics.lensCenterOffset;
-
-            this.onSizeChanged = () => {
-                this.aspectRatio = this.width * .5 / this.height;
-                this._scaleIn = new Vector2(2, 2 / this.aspectRatio);
-                this._scaleFactor = new Vector2(.5 * (1 / this._postProcessScaleFactor), .5 * (1 / this._postProcessScaleFactor) * this.aspectRatio);
-                this._lensCenter = new Vector2(this._isRightEye ? 0.5 - this._lensCenterOffset * 0.5 : 0.5 + this._lensCenterOffset * 0.5, 0.5);
-            };
-            this.onApply = (effect: Effect) => {
-                effect.setFloat2("LensCenter", this._lensCenter.x, this._lensCenter.y);
-                effect.setFloat2("Scale", this._scaleFactor.x, this._scaleFactor.y);
-                effect.setFloat2("ScaleIn", this._scaleIn.x, this._scaleIn.y);
-                effect.setFloat4("HmdWarpParam", this._distortionFactors[0], this._distortionFactors[1], this._distortionFactors[2], this._distortionFactors[3]);
-            };
-        }
-    }
-}
+module BABYLON {
+    export class VRDistortionCorrectionPostProcess extends PostProcess {
+        public aspectRatio: number;
+
+        private _isRightEye: boolean;
+        private _distortionFactors: number[];
+        private _postProcessScaleFactor: number;
+        private _lensCenterOffset: number;
+        private _scaleIn: Vector2;
+        private _scaleFactor: Vector2;
+        private _lensCenter: Vector2;
+
+        //ANY
+        constructor(name: string, camera: Camera, isRightEye: boolean, vrMetrics: VRCameraMetrics) {
+            super(name, "vrDistortionCorrection", [
+                'LensCenter',
+                'Scale',
+                'ScaleIn',
+                'HmdWarpParam'
+            ], null, vrMetrics.postProcessScaleFactor, camera, Texture.BILINEAR_SAMPLINGMODE, null, null);
+
+            this._isRightEye = isRightEye;
+            this._distortionFactors = vrMetrics.distortionK;
+            this._postProcessScaleFactor = vrMetrics.postProcessScaleFactor;
+            this._lensCenterOffset = vrMetrics.lensCenterOffset;
+
+            this.onSizeChanged = () => {
+                this.aspectRatio = this.width * .5 / this.height;
+                this._scaleIn = new Vector2(2, 2 / this.aspectRatio);
+                this._scaleFactor = new Vector2(.5 * (1 / this._postProcessScaleFactor), .5 * (1 / this._postProcessScaleFactor) * this.aspectRatio);
+                this._lensCenter = new Vector2(this._isRightEye ? 0.5 - this._lensCenterOffset * 0.5 : 0.5 + this._lensCenterOffset * 0.5, 0.5);
+            };
+            this.onApply = (effect: Effect) => {
+                effect.setFloat2("LensCenter", this._lensCenter.x, this._lensCenter.y);
+                effect.setFloat2("Scale", this._scaleFactor.x, this._scaleFactor.y);
+                effect.setFloat2("ScaleIn", this._scaleIn.x, this._scaleIn.y);
+                effect.setFloat4("HmdWarpParam", this._distortionFactors[0], this._distortionFactors[1], this._distortionFactors[2], this._distortionFactors[3]);
+            };
+        }
+    }
+}

+ 93 - 93
src/Probes/babylon.reflectionProbe.ts

@@ -1,94 +1,94 @@
-module BABYLON {
-    export class ReflectionProbe{  
-        private _scene: Scene;
-        private _renderTargetTexture: RenderTargetTexture;
-        private _projectionMatrix: Matrix;
-        private _viewMatrix = Matrix.Identity();
-        private _target = Vector3.Zero();
-        private _add = Vector3.Zero();
-        private _attachedMesh: AbstractMesh;
-
-        public position = Vector3.Zero();
-          
-        constructor(public name: string, size: number, scene: Scene, generateMipMaps = true) {
-            this._scene = scene;
-
-            this._scene.reflectionProbes.push(this);
-
-            this._renderTargetTexture = new RenderTargetTexture(name, size, scene, generateMipMaps, true, Engine.TEXTURETYPE_UNSIGNED_INT, true);
-
-            this._renderTargetTexture.onBeforeRender = (faceIndex: number) => {
-                switch (faceIndex) {
-                    case 0:
-                        this._add.copyFromFloats(1, 0, 0);
-                        break;
-                    case 1:
-                        this._add.copyFromFloats(-1, 0, 0);
-                        break;
-                    case 2:
-                        this._add.copyFromFloats(0, -1, 0);
-                        break;
-                    case 3:
-                        this._add.copyFromFloats(0, 1, 0);
-                        break;
-                    case 4:
-                        this._add.copyFromFloats(0, 0, 1);
-                        break;
-                    case 5:
-                        this._add.copyFromFloats(0, 0, -1);
-                        break;
-
-                }
-
-                if (this._attachedMesh) {
-                    this.position.copyFrom(this._attachedMesh.getAbsolutePosition());
-                }
-
-                this.position.addToRef(this._add, this._target);
-
-                Matrix.LookAtLHToRef(this.position, this._target, Vector3.Up(), this._viewMatrix);
-
-                scene.setTransformMatrix(this._viewMatrix, this._projectionMatrix);
-            }
-
-            this._renderTargetTexture.onAfterUnbind = () => {
-                scene.updateTransformMatrix(true);
-            }
-
-            this._projectionMatrix = Matrix.PerspectiveFovLH(Math.PI / 2, 1, scene.activeCamera.minZ, scene.activeCamera.maxZ);
-        }
-
-        public get refreshRate(): number {
-            return this._renderTargetTexture.refreshRate;
-        }
-
-        public set refreshRate(value: number) {
-            this._renderTargetTexture.refreshRate = value;
-        }
-
-        public getScene(): Scene {
-            return this._scene;
-        }
-
-        public get cubeTexture(): RenderTargetTexture {
-            return this._renderTargetTexture;
-        }
-
-        public get renderList(): AbstractMesh[] {
-            return this._renderTargetTexture.renderList;
-        }
-
-        public attachToMesh(mesh: AbstractMesh): void {
-            this._attachedMesh = mesh;
-        }
-        
-        public dispose() {
-            var index = this._scene.reflectionProbes.indexOf(this);
-
-            if (index !== -1) {
-                // Remove from the scene if found 
-                this._scene.reflectionProbes.splice(index, 1);
-            }            
-        }
-    }    
+module BABYLON {
+    export class ReflectionProbe{  
+        private _scene: Scene;
+        private _renderTargetTexture: RenderTargetTexture;
+        private _projectionMatrix: Matrix;
+        private _viewMatrix = Matrix.Identity();
+        private _target = Vector3.Zero();
+        private _add = Vector3.Zero();
+        private _attachedMesh: AbstractMesh;
+
+        public position = Vector3.Zero();
+          
+        constructor(public name: string, size: number, scene: Scene, generateMipMaps = true) {
+            this._scene = scene;
+
+            this._scene.reflectionProbes.push(this);
+
+            this._renderTargetTexture = new RenderTargetTexture(name, size, scene, generateMipMaps, true, Engine.TEXTURETYPE_UNSIGNED_INT, true);
+
+            this._renderTargetTexture.onBeforeRender = (faceIndex: number) => {
+                switch (faceIndex) {
+                    case 0:
+                        this._add.copyFromFloats(1, 0, 0);
+                        break;
+                    case 1:
+                        this._add.copyFromFloats(-1, 0, 0);
+                        break;
+                    case 2:
+                        this._add.copyFromFloats(0, -1, 0);
+                        break;
+                    case 3:
+                        this._add.copyFromFloats(0, 1, 0);
+                        break;
+                    case 4:
+                        this._add.copyFromFloats(0, 0, 1);
+                        break;
+                    case 5:
+                        this._add.copyFromFloats(0, 0, -1);
+                        break;
+
+                }
+
+                if (this._attachedMesh) {
+                    this.position.copyFrom(this._attachedMesh.getAbsolutePosition());
+                }
+
+                this.position.addToRef(this._add, this._target);
+
+                Matrix.LookAtLHToRef(this.position, this._target, Vector3.Up(), this._viewMatrix);
+
+                scene.setTransformMatrix(this._viewMatrix, this._projectionMatrix);
+            }
+
+            this._renderTargetTexture.onAfterUnbind = () => {
+                scene.updateTransformMatrix(true);
+            }
+
+            this._projectionMatrix = Matrix.PerspectiveFovLH(Math.PI / 2, 1, scene.activeCamera.minZ, scene.activeCamera.maxZ);
+        }
+
+        public get refreshRate(): number {
+            return this._renderTargetTexture.refreshRate;
+        }
+
+        public set refreshRate(value: number) {
+            this._renderTargetTexture.refreshRate = value;
+        }
+
+        public getScene(): Scene {
+            return this._scene;
+        }
+
+        public get cubeTexture(): RenderTargetTexture {
+            return this._renderTargetTexture;
+        }
+
+        public get renderList(): AbstractMesh[] {
+            return this._renderTargetTexture.renderList;
+        }
+
+        public attachToMesh(mesh: AbstractMesh): void {
+            this._attachedMesh = mesh;
+        }
+        
+        public dispose() {
+            var index = this._scene.reflectionProbes.indexOf(this);
+
+            if (index !== -1) {
+                // Remove from the scene if found 
+                this._scene.reflectionProbes.splice(index, 1);
+            }            
+        }
+    }    
 }

+ 101 - 101
src/Rendering/babylon.boundingBoxRenderer.ts

@@ -1,102 +1,102 @@
-module BABYLON {
-    export class BoundingBoxRenderer {
-        public frontColor = new Color3(1, 1, 1);
-        public backColor = new Color3(0.1, 0.1, 0.1);
-        public showBackLines = true;
-        public renderList = new SmartArray<BoundingBox>(32);
-
-        private _scene: Scene;
-        private _colorShader: ShaderMaterial;
-        private _vb: VertexBuffer;
-        private _ib: WebGLBuffer;
-
-        constructor(scene: Scene) {
-            this._scene = scene;
-        }
-
-        private _prepareRessources(): void {
-            if (this._colorShader) {
-                return;
-            }
-
-            this._colorShader = new ShaderMaterial("colorShader", this._scene, "color",
-                {
-                    attributes: ["position"],
-                    uniforms: ["worldViewProjection", "color"]
-                });
-
-
-            var engine = this._scene.getEngine();
-            var boxdata = VertexData.CreateBox(1.0);
-            this._vb = new VertexBuffer(engine, boxdata.positions, VertexBuffer.PositionKind, false);
-            this._ib = engine.createIndexBuffer([0, 1, 1, 2, 2, 3, 3, 0, 4, 5, 5, 6, 6, 7, 7, 4, 0, 7, 1, 6, 2, 5, 3, 4]);
-        }
-
-        public reset(): void {
-            this.renderList.reset();
-        }
-
-        public render(): void {
-            if (this.renderList.length === 0) {
-                return;
-            }
-
-            this._prepareRessources();
-
-            if (!this._colorShader.isReady()) {
-                return;
-            }
-
-            var engine = this._scene.getEngine();
-            engine.setDepthWrite(false);
-            this._colorShader._preBind();
-            for (var boundingBoxIndex = 0; boundingBoxIndex < this.renderList.length; boundingBoxIndex++) {
-                var boundingBox = this.renderList.data[boundingBoxIndex];
-                var min = boundingBox.minimum;
-                var max = boundingBox.maximum;
-                var diff = max.subtract(min);
-                var median = min.add(diff.scale(0.5));
-
-                var worldMatrix = Matrix.Scaling(diff.x, diff.y, diff.z)
-                    .multiply(Matrix.Translation(median.x, median.y, median.z))
-                    .multiply(boundingBox.getWorldMatrix());
-
-                // VBOs
-                engine.bindBuffers(this._vb.getBuffer(), this._ib, [3], 3 * 4, this._colorShader.getEffect());
-
-                if (this.showBackLines) {
-                    // Back
-                    engine.setDepthFunctionToGreaterOrEqual();
-                    this._scene.resetCachedMaterial();
-                    this._colorShader.setColor4("color", this.backColor.toColor4());
-                    this._colorShader.bind(worldMatrix);
-
-                    // Draw order
-                    engine.draw(false, 0, 24);
-                }
-
-                // Front
-                engine.setDepthFunctionToLess();
-                this._scene.resetCachedMaterial();
-                this._colorShader.setColor4("color", this.frontColor.toColor4());
-                this._colorShader.bind(worldMatrix);
-
-                // Draw order
-                engine.draw(false, 0, 24);
-            }
-            this._colorShader.unbind();
-            engine.setDepthFunctionToLessOrEqual();
-            engine.setDepthWrite(true);
-        }
-
-        public dispose(): void {
-            if (!this._colorShader) {
-                return;
-            }
-
-            this._colorShader.dispose();
-            this._vb.dispose();
-            this._scene.getEngine()._releaseBuffer(this._ib);
-        }
-    }
+module BABYLON {
+    export class BoundingBoxRenderer {
+        public frontColor = new Color3(1, 1, 1);
+        public backColor = new Color3(0.1, 0.1, 0.1);
+        public showBackLines = true;
+        public renderList = new SmartArray<BoundingBox>(32);
+
+        private _scene: Scene;
+        private _colorShader: ShaderMaterial;
+        private _vb: VertexBuffer;
+        private _ib: WebGLBuffer;
+
+        constructor(scene: Scene) {
+            this._scene = scene;
+        }
+
+        private _prepareRessources(): void {
+            if (this._colorShader) {
+                return;
+            }
+
+            this._colorShader = new ShaderMaterial("colorShader", this._scene, "color",
+                {
+                    attributes: ["position"],
+                    uniforms: ["worldViewProjection", "color"]
+                });
+
+
+            var engine = this._scene.getEngine();
+            var boxdata = VertexData.CreateBox(1.0);
+            this._vb = new VertexBuffer(engine, boxdata.positions, VertexBuffer.PositionKind, false);
+            this._ib = engine.createIndexBuffer([0, 1, 1, 2, 2, 3, 3, 0, 4, 5, 5, 6, 6, 7, 7, 4, 0, 7, 1, 6, 2, 5, 3, 4]);
+        }
+
+        public reset(): void {
+            this.renderList.reset();
+        }
+
+        public render(): void {
+            if (this.renderList.length === 0) {
+                return;
+            }
+
+            this._prepareRessources();
+
+            if (!this._colorShader.isReady()) {
+                return;
+            }
+
+            var engine = this._scene.getEngine();
+            engine.setDepthWrite(false);
+            this._colorShader._preBind();
+            for (var boundingBoxIndex = 0; boundingBoxIndex < this.renderList.length; boundingBoxIndex++) {
+                var boundingBox = this.renderList.data[boundingBoxIndex];
+                var min = boundingBox.minimum;
+                var max = boundingBox.maximum;
+                var diff = max.subtract(min);
+                var median = min.add(diff.scale(0.5));
+
+                var worldMatrix = Matrix.Scaling(diff.x, diff.y, diff.z)
+                    .multiply(Matrix.Translation(median.x, median.y, median.z))
+                    .multiply(boundingBox.getWorldMatrix());
+
+                // VBOs
+                engine.bindBuffers(this._vb.getBuffer(), this._ib, [3], 3 * 4, this._colorShader.getEffect());
+
+                if (this.showBackLines) {
+                    // Back
+                    engine.setDepthFunctionToGreaterOrEqual();
+                    this._scene.resetCachedMaterial();
+                    this._colorShader.setColor4("color", this.backColor.toColor4());
+                    this._colorShader.bind(worldMatrix);
+
+                    // Draw order
+                    engine.draw(false, 0, 24);
+                }
+
+                // Front
+                engine.setDepthFunctionToLess();
+                this._scene.resetCachedMaterial();
+                this._colorShader.setColor4("color", this.frontColor.toColor4());
+                this._colorShader.bind(worldMatrix);
+
+                // Draw order
+                engine.draw(false, 0, 24);
+            }
+            this._colorShader.unbind();
+            engine.setDepthFunctionToLessOrEqual();
+            engine.setDepthWrite(true);
+        }
+
+        public dispose(): void {
+            if (!this._colorShader) {
+                return;
+            }
+
+            this._colorShader.dispose();
+            this._vb.dispose();
+            this._scene.getEngine()._releaseBuffer(this._ib);
+        }
+    }
 } 

+ 155 - 155
src/Rendering/babylon.depthRenderer.ts

@@ -1,156 +1,156 @@
-module BABYLON {
-    export class DepthRenderer {
-        private _scene: Scene;
-        private _depthMap: RenderTargetTexture;
-        private _effect: Effect;
-
-        private _viewMatrix = Matrix.Zero();
-        private _projectionMatrix = Matrix.Zero();
-        private _transformMatrix = Matrix.Zero();
-        private _worldViewProjection = Matrix.Zero();
-
-        private _cachedDefines: string;
-
-        constructor(scene: Scene, type: number = Engine.TEXTURETYPE_FLOAT) {
-            this._scene = scene;
-            var engine = scene.getEngine();
-
-            // Render target
-            this._depthMap = new RenderTargetTexture("depthMap", { width: engine.getRenderWidth(), height: engine.getRenderHeight() }, this._scene, false, true, type);
-            this._depthMap.wrapU = Texture.CLAMP_ADDRESSMODE;
-            this._depthMap.wrapV = Texture.CLAMP_ADDRESSMODE;
-            this._depthMap.refreshRate = 1;
-            this._depthMap.renderParticles = false;
-            this._depthMap.renderList = null;
-            
-            // set default depth value to 1.0 (far away)
-            this._depthMap.onClear = (engine: Engine) => {
-                engine.clear(new Color4(1.0, 1.0, 1.0, 1.0), true, true);
-            }
-
-            // Custom render function
-            var renderSubMesh = (subMesh: SubMesh): void => {
-                var mesh = subMesh.getRenderingMesh();
-                var scene = this._scene;
-                var engine = scene.getEngine();
-
-                // Culling
-                engine.setState(subMesh.getMaterial().backFaceCulling);
-
-                // Managing instances
-                var batch = mesh._getInstancesRenderList(subMesh._id);
-
-                if (batch.mustReturn) {
-                    return;
-                }
-
-                var hardwareInstancedRendering = (engine.getCaps().instancedArrays !== null) && (batch.visibleInstances[subMesh._id] !== null);
-
-                if (this.isReady(subMesh, hardwareInstancedRendering)) {
-                    engine.enableEffect(this._effect);
-                    mesh._bind(subMesh, this._effect, Material.TriangleFillMode);
-                    var material = subMesh.getMaterial();
-
-                    this._effect.setMatrix("viewProjection", scene.getTransformMatrix());
-
-                    this._effect.setFloat("far", scene.activeCamera.maxZ);
-
-                    // Alpha test
-                    if (material && material.needAlphaTesting()) {
-                        var alphaTexture = material.getAlphaTestTexture();
-                        this._effect.setTexture("diffuseSampler", alphaTexture);
-                        this._effect.setMatrix("diffuseMatrix", alphaTexture.getTextureMatrix());
-                    }
-
-                    // Bones
-                    if (mesh.useBones && mesh.computeBonesUsingShaders) {
-                        this._effect.setMatrices("mBones", mesh.skeleton.getTransformMatrices());
-                    }
-
-                    // Draw
-                    mesh._processRendering(subMesh, this._effect, Material.TriangleFillMode, batch, hardwareInstancedRendering,
-                        (isInstance, world) => this._effect.setMatrix("world", world));
-                }
-            };
-
-            this._depthMap.customRenderFunction = (opaqueSubMeshes: SmartArray<SubMesh>, alphaTestSubMeshes: SmartArray<SubMesh>): void => {
-                var index;
-
-                for (index = 0; index < opaqueSubMeshes.length; index++) {
-                    renderSubMesh(opaqueSubMeshes.data[index]);
-                }
-
-                for (index = 0; index < alphaTestSubMeshes.length; index++) {
-                    renderSubMesh(alphaTestSubMeshes.data[index]);
-                }
-            };
-        }
-
-        public isReady(subMesh: SubMesh, useInstances: boolean): boolean {
-            var defines = [];
-
-            var attribs = [VertexBuffer.PositionKind];
-
-            var mesh = subMesh.getMesh();
-            var scene = mesh.getScene();
-            var material = subMesh.getMaterial();
-
-            // Alpha test
-            if (material && material.needAlphaTesting()) {
-                defines.push("#define ALPHATEST");
-                if (mesh.isVerticesDataPresent(VertexBuffer.UVKind)) {
-                    attribs.push(VertexBuffer.UVKind);
-                    defines.push("#define UV1");
-                }
-                if (mesh.isVerticesDataPresent(VertexBuffer.UV2Kind)) {
-                    attribs.push(VertexBuffer.UV2Kind);
-                    defines.push("#define UV2");
-                }
-            }
-
-            // Bones
-            if (mesh.useBones && mesh.computeBonesUsingShaders) {
-                attribs.push(VertexBuffer.MatricesIndicesKind);
-                attribs.push(VertexBuffer.MatricesWeightsKind);
-                if (mesh.numBoneInfluencers > 4) {
-                    attribs.push(VertexBuffer.MatricesIndicesExtraKind);
-                    attribs.push(VertexBuffer.MatricesWeightsExtraKind);
-                }
-                defines.push("#define NUM_BONE_INFLUENCERS " + mesh.numBoneInfluencers);
-                defines.push("#define BonesPerMesh " + (mesh.skeleton.bones.length + 1));
-            } else {
-                defines.push("#define NUM_BONE_INFLUENCERS 0");
-            }
-
-            // Instances
-            if (useInstances) {
-                defines.push("#define INSTANCES");
-                attribs.push("world0");
-                attribs.push("world1");
-                attribs.push("world2");
-                attribs.push("world3");
-            }
-
-            // Get correct effect      
-            var join = defines.join("\n");
-            if (this._cachedDefines !== join) {
-                this._cachedDefines = join;
-                this._effect = this._scene.getEngine().createEffect("depth",
-                    attribs,
-                    ["world", "mBones", "viewProjection", "diffuseMatrix", "far"],
-                    ["diffuseSampler"], join);
-            }
-
-            return this._effect.isReady();
-        }
-
-        public getDepthMap(): RenderTargetTexture {
-            return this._depthMap;
-        }
-
-        // Methods
-        public dispose(): void {
-            this._depthMap.dispose();
-        }
-    }
+module BABYLON {
+    export class DepthRenderer {
+        private _scene: Scene;
+        private _depthMap: RenderTargetTexture;
+        private _effect: Effect;
+
+        private _viewMatrix = Matrix.Zero();
+        private _projectionMatrix = Matrix.Zero();
+        private _transformMatrix = Matrix.Zero();
+        private _worldViewProjection = Matrix.Zero();
+
+        private _cachedDefines: string;
+
+        constructor(scene: Scene, type: number = Engine.TEXTURETYPE_FLOAT) {
+            this._scene = scene;
+            var engine = scene.getEngine();
+
+            // Render target
+            this._depthMap = new RenderTargetTexture("depthMap", { width: engine.getRenderWidth(), height: engine.getRenderHeight() }, this._scene, false, true, type);
+            this._depthMap.wrapU = Texture.CLAMP_ADDRESSMODE;
+            this._depthMap.wrapV = Texture.CLAMP_ADDRESSMODE;
+            this._depthMap.refreshRate = 1;
+            this._depthMap.renderParticles = false;
+            this._depthMap.renderList = null;
+            
+            // set default depth value to 1.0 (far away)
+            this._depthMap.onClear = (engine: Engine) => {
+                engine.clear(new Color4(1.0, 1.0, 1.0, 1.0), true, true);
+            }
+
+            // Custom render function
+            var renderSubMesh = (subMesh: SubMesh): void => {
+                var mesh = subMesh.getRenderingMesh();
+                var scene = this._scene;
+                var engine = scene.getEngine();
+
+                // Culling
+                engine.setState(subMesh.getMaterial().backFaceCulling);
+
+                // Managing instances
+                var batch = mesh._getInstancesRenderList(subMesh._id);
+
+                if (batch.mustReturn) {
+                    return;
+                }
+
+                var hardwareInstancedRendering = (engine.getCaps().instancedArrays !== null) && (batch.visibleInstances[subMesh._id] !== null);
+
+                if (this.isReady(subMesh, hardwareInstancedRendering)) {
+                    engine.enableEffect(this._effect);
+                    mesh._bind(subMesh, this._effect, Material.TriangleFillMode);
+                    var material = subMesh.getMaterial();
+
+                    this._effect.setMatrix("viewProjection", scene.getTransformMatrix());
+
+                    this._effect.setFloat("far", scene.activeCamera.maxZ);
+
+                    // Alpha test
+                    if (material && material.needAlphaTesting()) {
+                        var alphaTexture = material.getAlphaTestTexture();
+                        this._effect.setTexture("diffuseSampler", alphaTexture);
+                        this._effect.setMatrix("diffuseMatrix", alphaTexture.getTextureMatrix());
+                    }
+
+                    // Bones
+                    if (mesh.useBones && mesh.computeBonesUsingShaders) {
+                        this._effect.setMatrices("mBones", mesh.skeleton.getTransformMatrices());
+                    }
+
+                    // Draw
+                    mesh._processRendering(subMesh, this._effect, Material.TriangleFillMode, batch, hardwareInstancedRendering,
+                        (isInstance, world) => this._effect.setMatrix("world", world));
+                }
+            };
+
+            this._depthMap.customRenderFunction = (opaqueSubMeshes: SmartArray<SubMesh>, alphaTestSubMeshes: SmartArray<SubMesh>): void => {
+                var index;
+
+                for (index = 0; index < opaqueSubMeshes.length; index++) {
+                    renderSubMesh(opaqueSubMeshes.data[index]);
+                }
+
+                for (index = 0; index < alphaTestSubMeshes.length; index++) {
+                    renderSubMesh(alphaTestSubMeshes.data[index]);
+                }
+            };
+        }
+
+        public isReady(subMesh: SubMesh, useInstances: boolean): boolean {
+            var defines = [];
+
+            var attribs = [VertexBuffer.PositionKind];
+
+            var mesh = subMesh.getMesh();
+            var scene = mesh.getScene();
+            var material = subMesh.getMaterial();
+
+            // Alpha test
+            if (material && material.needAlphaTesting()) {
+                defines.push("#define ALPHATEST");
+                if (mesh.isVerticesDataPresent(VertexBuffer.UVKind)) {
+                    attribs.push(VertexBuffer.UVKind);
+                    defines.push("#define UV1");
+                }
+                if (mesh.isVerticesDataPresent(VertexBuffer.UV2Kind)) {
+                    attribs.push(VertexBuffer.UV2Kind);
+                    defines.push("#define UV2");
+                }
+            }
+
+            // Bones
+            if (mesh.useBones && mesh.computeBonesUsingShaders) {
+                attribs.push(VertexBuffer.MatricesIndicesKind);
+                attribs.push(VertexBuffer.MatricesWeightsKind);
+                if (mesh.numBoneInfluencers > 4) {
+                    attribs.push(VertexBuffer.MatricesIndicesExtraKind);
+                    attribs.push(VertexBuffer.MatricesWeightsExtraKind);
+                }
+                defines.push("#define NUM_BONE_INFLUENCERS " + mesh.numBoneInfluencers);
+                defines.push("#define BonesPerMesh " + (mesh.skeleton.bones.length + 1));
+            } else {
+                defines.push("#define NUM_BONE_INFLUENCERS 0");
+            }
+
+            // Instances
+            if (useInstances) {
+                defines.push("#define INSTANCES");
+                attribs.push("world0");
+                attribs.push("world1");
+                attribs.push("world2");
+                attribs.push("world3");
+            }
+
+            // Get correct effect      
+            var join = defines.join("\n");
+            if (this._cachedDefines !== join) {
+                this._cachedDefines = join;
+                this._effect = this._scene.getEngine().createEffect("depth",
+                    attribs,
+                    ["world", "mBones", "viewProjection", "diffuseMatrix", "far"],
+                    ["diffuseSampler"], join);
+            }
+
+            return this._effect.isReady();
+        }
+
+        public getDepthMap(): RenderTargetTexture {
+            return this._depthMap;
+        }
+
+        // Methods
+        public dispose(): void {
+            this._depthMap.dispose();
+        }
+    }
 } 

+ 296 - 296
src/Rendering/babylon.edgesRenderer.ts

@@ -1,297 +1,297 @@
-module BABYLON {
-
-    class FaceAdjacencies {
-        public edges = new Array<number>();
-        public p0: Vector3;
-        public p1: Vector3;
-        public p2: Vector3;
-        public edgesConnectedCount = 0;
-    }
-
-    export class EdgesRenderer {
-        private _source: AbstractMesh;
-        private _linesPositions = new Array<number>();
-        private _linesNormals = new Array<number>();
-        private _linesIndices = new Array<number>();
-        private _epsilon: number;
-        private _indicesCount: number;
-
-        private _lineShader: ShaderMaterial;
-        private _vb0: VertexBuffer;
-        private _vb1: VertexBuffer;
-        private _ib: WebGLBuffer;
-        private _buffers = new Array<VertexBuffer>();
-        private _checkVerticesInsteadOfIndices = false;
-
-        // Beware when you use this class with complex objects as the adjacencies computation can be really long
-        constructor(source: AbstractMesh, epsilon = 0.95, checkVerticesInsteadOfIndices = false) {
-            this._source = source;
-            this._checkVerticesInsteadOfIndices = checkVerticesInsteadOfIndices;
-
-            this._epsilon = epsilon;
-
-            this._prepareRessources();
-            this._generateEdgesLines();
-        }
-
-        private _prepareRessources(): void {
-            if (this._lineShader) {
-                return;
-            }
-
-            this._lineShader = new ShaderMaterial("lineShader", this._source.getScene(), "line",
-                {
-                    attributes: ["position", "normal"],
-                    uniforms: ["worldViewProjection", "color", "width", "aspectRatio"]
-                });
-
-            this._lineShader.disableDepthWrite = true;
-            this._lineShader.backFaceCulling = false;
-        }
-
-        public dispose(): void {
-            this._vb0.dispose();
-            this._vb1.dispose();
-            this._source.getScene().getEngine()._releaseBuffer(this._ib);
-            this._lineShader.dispose();
-        }
-
-        private _processEdgeForAdjacencies(pa: number, pb: number, p0: number, p1: number, p2: number): number {
-            if (pa === p0 && pb === p1 || pa === p1 && pb === p0) {
-                return 0;
-            }
-
-            if (pa === p1 && pb === p2 || pa === p2 && pb === p1) {
-                return 1;
-            }
-
-            if (pa === p2 && pb === p0 || pa === p0 && pb === p2) {
-                return 2;
-            }
-
-            return -1;
-        }
-
-        private _processEdgeForAdjacenciesWithVertices(pa: Vector3, pb: Vector3, p0: Vector3, p1: Vector3, p2: Vector3): number {
-            if (pa.equalsWithEpsilon(p0) && pb.equalsWithEpsilon(p1) || pa.equalsWithEpsilon(p1) && pb.equalsWithEpsilon(p0)) {
-                return 0;
-            }
-
-            if (pa.equalsWithEpsilon(p1) && pb.equalsWithEpsilon(p2) || pa.equalsWithEpsilon(p2) && pb.equalsWithEpsilon(p1)) {
-                return 1;
-            }
-
-            if (pa.equalsWithEpsilon(p2) && pb.equalsWithEpsilon(p0) || pa.equalsWithEpsilon(p0) && pb.equalsWithEpsilon(p2)) {
-                return 2;
-            }
-
-            return -1;
-        }
-
-        private _checkEdge(faceIndex: number, edge: number, faceNormals: Array<Vector3>, p0: Vector3, p1: Vector3): void {
-            var needToCreateLine;
-
-            if (edge === undefined) {
-                needToCreateLine = true;
-            } else {
-                var dotProduct = Vector3.Dot(faceNormals[faceIndex], faceNormals[edge]);
-
-                needToCreateLine = dotProduct < this._epsilon;
-            }
-
-            if (needToCreateLine) {
-                var offset = this._linesPositions.length / 3;
-                var normal = p0.subtract(p1);
-                normal.normalize();
-
-                // Positions
-                this._linesPositions.push(p0.x);
-                this._linesPositions.push(p0.y);
-                this._linesPositions.push(p0.z);
-
-                this._linesPositions.push(p0.x);
-                this._linesPositions.push(p0.y);
-                this._linesPositions.push(p0.z);
-
-                this._linesPositions.push(p1.x);
-                this._linesPositions.push(p1.y);
-                this._linesPositions.push(p1.z);
-
-                this._linesPositions.push(p1.x);
-                this._linesPositions.push(p1.y);
-                this._linesPositions.push(p1.z);
-
-                // Normals
-                this._linesNormals.push(p1.x);
-                this._linesNormals.push(p1.y);
-                this._linesNormals.push(p1.z);
-                this._linesNormals.push(-1);
-
-                this._linesNormals.push(p1.x);
-                this._linesNormals.push(p1.y);
-                this._linesNormals.push(p1.z);
-                this._linesNormals.push(1);
-
-                this._linesNormals.push(p0.x);
-                this._linesNormals.push(p0.y);
-                this._linesNormals.push(p0.z);
-                this._linesNormals.push(-1);
-
-                this._linesNormals.push(p0.x);
-                this._linesNormals.push(p0.y);
-                this._linesNormals.push(p0.z);
-                this._linesNormals.push(1);
-
-                // Indices
-                this._linesIndices.push(offset);
-                this._linesIndices.push(offset + 1);
-                this._linesIndices.push(offset + 2);
-                this._linesIndices.push(offset);
-                this._linesIndices.push(offset + 2);
-                this._linesIndices.push(offset + 3);
-            }
-        }
-
-        _generateEdgesLines(): void {
-            var positions = this._source.getVerticesData(VertexBuffer.PositionKind);
-            var indices = this._source.getIndices();
-
-            // First let's find adjacencies
-            var adjacencies = new Array<FaceAdjacencies>();
-            var faceNormals = new Array<Vector3>();
-            var index: number;
-            var faceAdjacencies: FaceAdjacencies;
-
-            // Prepare faces
-            for (index = 0; index < indices.length; index += 3) {
-                faceAdjacencies = new FaceAdjacencies();
-                var p0Index = indices[index];
-                var p1Index = indices[index + 1];
-                var p2Index = indices[index + 2];
-
-                faceAdjacencies.p0 = new Vector3(positions[p0Index * 3], positions[p0Index * 3 + 1], positions[p0Index * 3 + 2]);
-                faceAdjacencies.p1 = new Vector3(positions[p1Index * 3], positions[p1Index * 3 + 1], positions[p1Index * 3 + 2]);
-                faceAdjacencies.p2 = new Vector3(positions[p2Index * 3], positions[p2Index * 3 + 1], positions[p2Index * 3 + 2]);
-                var faceNormal = Vector3.Cross(faceAdjacencies.p1.subtract(faceAdjacencies.p0), faceAdjacencies.p2.subtract(faceAdjacencies.p1));
-
-                faceNormal.normalize();
-
-                faceNormals.push(faceNormal);
-                adjacencies.push(faceAdjacencies);
-            }
-
-            // Scan
-            for (index = 0; index < adjacencies.length; index++) {
-                faceAdjacencies = adjacencies[index];
-
-                for (var otherIndex = index + 1; otherIndex < adjacencies.length; otherIndex++) {
-                    var otherFaceAdjacencies = adjacencies[otherIndex];
-
-                    if (faceAdjacencies.edgesConnectedCount === 3) { // Full
-                        break;
-                    }
-
-                    if (otherFaceAdjacencies.edgesConnectedCount === 3) { // Full
-                        continue;
-                    }
-
-                    var otherP0 = indices[otherIndex * 3];
-                    var otherP1 = indices[otherIndex * 3 + 1];
-                    var otherP2 = indices[otherIndex * 3 + 2];
-
-                    for (var edgeIndex = 0; edgeIndex < 3; edgeIndex++) {
-                        var otherEdgeIndex: number;
-
-                        if (faceAdjacencies.edges[edgeIndex] !== undefined) {
-                            continue;
-                        }
-
-                        switch (edgeIndex) {
-                            case 0:
-                                if (this._checkVerticesInsteadOfIndices) {
-                                    otherEdgeIndex = this._processEdgeForAdjacenciesWithVertices(faceAdjacencies.p0, faceAdjacencies.p1, otherFaceAdjacencies.p0, otherFaceAdjacencies.p1, otherFaceAdjacencies.p2);
-                                } else {
-                                    otherEdgeIndex = this._processEdgeForAdjacencies(indices[index * 3], indices[index * 3 + 1], otherP0, otherP1, otherP2);
-                                }
-                                break;
-                            case 1:
-                                if (this._checkVerticesInsteadOfIndices) {
-                                    otherEdgeIndex = this._processEdgeForAdjacenciesWithVertices(faceAdjacencies.p1, faceAdjacencies.p2, otherFaceAdjacencies.p0, otherFaceAdjacencies.p1, otherFaceAdjacencies.p2);
-                                } else {
-                                    otherEdgeIndex = this._processEdgeForAdjacencies(indices[index * 3 + 1], indices[index * 3 + 2], otherP0, otherP1, otherP2);
-                                }
-                                break;
-                            case 2:
-                                if (this._checkVerticesInsteadOfIndices) {
-                                    otherEdgeIndex = this._processEdgeForAdjacenciesWithVertices(faceAdjacencies.p2, faceAdjacencies.p0, otherFaceAdjacencies.p0, otherFaceAdjacencies.p1, otherFaceAdjacencies.p2);
-                                } else {
-                                    otherEdgeIndex = this._processEdgeForAdjacencies(indices[index * 3 + 2], indices[index * 3], otherP0, otherP1, otherP2);
-                                }
-                                break;
-                        }
-
-                        if (otherEdgeIndex === -1) {
-                            continue;
-                        }
-
-                        faceAdjacencies.edges[edgeIndex] = otherIndex;
-                        otherFaceAdjacencies.edges[otherEdgeIndex] = index;
-
-                        faceAdjacencies.edgesConnectedCount++;
-                        otherFaceAdjacencies.edgesConnectedCount++;
-
-                        if (faceAdjacencies.edgesConnectedCount === 3) {
-                            break;
-                        }
-                    }
-                }
-            }
-            
-            // Create lines
-            for (index = 0; index < adjacencies.length; index++) {
-                // We need a line when a face has no adjacency on a specific edge or if all the adjacencies has an angle greater than epsilon
-                var current = adjacencies[index];
-
-                this._checkEdge(index, current.edges[0], faceNormals, current.p0, current.p1);
-                this._checkEdge(index, current.edges[1], faceNormals, current.p1, current.p2);
-                this._checkEdge(index, current.edges[2], faceNormals, current.p2, current.p0);
-            }
-
-            // Merge into a single mesh
-            var engine = this._source.getScene().getEngine();
-            this._vb0 = new VertexBuffer(engine, this._linesPositions, VertexBuffer.PositionKind, false);
-            this._vb1 = new VertexBuffer(engine, this._linesNormals, VertexBuffer.NormalKind, false, false, 4);
-
-            this._buffers[VertexBuffer.PositionKind] = this._vb0;
-            this._buffers[VertexBuffer.NormalKind] = this._vb1;
-
-            this._ib = engine.createIndexBuffer(this._linesIndices);
-
-            this._indicesCount = this._linesIndices.length;
-        }
-
-        public render(): void {
-            if (!this._lineShader.isReady()) {
-                return;
-            }
-
-            var scene = this._source.getScene();
-            var engine = scene.getEngine();
-            this._lineShader._preBind();
-
-            // VBOs
-            engine.bindMultiBuffers(this._buffers, this._ib, this._lineShader.getEffect());
-
-            scene.resetCachedMaterial();
-            this._lineShader.setColor4("color", this._source.edgesColor);
-            this._lineShader.setFloat("width", this._source.edgesWidth / 50.0);
-            this._lineShader.setFloat("aspectRatio", engine.getAspectRatio(scene.activeCamera));
-            this._lineShader.bind(this._source.getWorldMatrix());
-
-            // Draw order
-            engine.draw(true, 0, this._indicesCount);
-            this._lineShader.unbind();
-            engine.setDepthWrite(true);
-        }
-    }
+module BABYLON {
+
+    class FaceAdjacencies {
+        public edges = new Array<number>();
+        public p0: Vector3;
+        public p1: Vector3;
+        public p2: Vector3;
+        public edgesConnectedCount = 0;
+    }
+
+    export class EdgesRenderer {
+        private _source: AbstractMesh;
+        private _linesPositions = new Array<number>();
+        private _linesNormals = new Array<number>();
+        private _linesIndices = new Array<number>();
+        private _epsilon: number;
+        private _indicesCount: number;
+
+        private _lineShader: ShaderMaterial;
+        private _vb0: VertexBuffer;
+        private _vb1: VertexBuffer;
+        private _ib: WebGLBuffer;
+        private _buffers = new Array<VertexBuffer>();
+        private _checkVerticesInsteadOfIndices = false;
+
+        // Beware when you use this class with complex objects as the adjacencies computation can be really long
+        constructor(source: AbstractMesh, epsilon = 0.95, checkVerticesInsteadOfIndices = false) {
+            this._source = source;
+            this._checkVerticesInsteadOfIndices = checkVerticesInsteadOfIndices;
+
+            this._epsilon = epsilon;
+
+            this._prepareRessources();
+            this._generateEdgesLines();
+        }
+
+        private _prepareRessources(): void {
+            if (this._lineShader) {
+                return;
+            }
+
+            this._lineShader = new ShaderMaterial("lineShader", this._source.getScene(), "line",
+                {
+                    attributes: ["position", "normal"],
+                    uniforms: ["worldViewProjection", "color", "width", "aspectRatio"]
+                });
+
+            this._lineShader.disableDepthWrite = true;
+            this._lineShader.backFaceCulling = false;
+        }
+
+        public dispose(): void {
+            this._vb0.dispose();
+            this._vb1.dispose();
+            this._source.getScene().getEngine()._releaseBuffer(this._ib);
+            this._lineShader.dispose();
+        }
+
+        private _processEdgeForAdjacencies(pa: number, pb: number, p0: number, p1: number, p2: number): number {
+            if (pa === p0 && pb === p1 || pa === p1 && pb === p0) {
+                return 0;
+            }
+
+            if (pa === p1 && pb === p2 || pa === p2 && pb === p1) {
+                return 1;
+            }
+
+            if (pa === p2 && pb === p0 || pa === p0 && pb === p2) {
+                return 2;
+            }
+
+            return -1;
+        }
+
+        private _processEdgeForAdjacenciesWithVertices(pa: Vector3, pb: Vector3, p0: Vector3, p1: Vector3, p2: Vector3): number {
+            if (pa.equalsWithEpsilon(p0) && pb.equalsWithEpsilon(p1) || pa.equalsWithEpsilon(p1) && pb.equalsWithEpsilon(p0)) {
+                return 0;
+            }
+
+            if (pa.equalsWithEpsilon(p1) && pb.equalsWithEpsilon(p2) || pa.equalsWithEpsilon(p2) && pb.equalsWithEpsilon(p1)) {
+                return 1;
+            }
+
+            if (pa.equalsWithEpsilon(p2) && pb.equalsWithEpsilon(p0) || pa.equalsWithEpsilon(p0) && pb.equalsWithEpsilon(p2)) {
+                return 2;
+            }
+
+            return -1;
+        }
+
+        private _checkEdge(faceIndex: number, edge: number, faceNormals: Array<Vector3>, p0: Vector3, p1: Vector3): void {
+            var needToCreateLine;
+
+            if (edge === undefined) {
+                needToCreateLine = true;
+            } else {
+                var dotProduct = Vector3.Dot(faceNormals[faceIndex], faceNormals[edge]);
+
+                needToCreateLine = dotProduct < this._epsilon;
+            }
+
+            if (needToCreateLine) {
+                var offset = this._linesPositions.length / 3;
+                var normal = p0.subtract(p1);
+                normal.normalize();
+
+                // Positions
+                this._linesPositions.push(p0.x);
+                this._linesPositions.push(p0.y);
+                this._linesPositions.push(p0.z);
+
+                this._linesPositions.push(p0.x);
+                this._linesPositions.push(p0.y);
+                this._linesPositions.push(p0.z);
+
+                this._linesPositions.push(p1.x);
+                this._linesPositions.push(p1.y);
+                this._linesPositions.push(p1.z);
+
+                this._linesPositions.push(p1.x);
+                this._linesPositions.push(p1.y);
+                this._linesPositions.push(p1.z);
+
+                // Normals
+                this._linesNormals.push(p1.x);
+                this._linesNormals.push(p1.y);
+                this._linesNormals.push(p1.z);
+                this._linesNormals.push(-1);
+
+                this._linesNormals.push(p1.x);
+                this._linesNormals.push(p1.y);
+                this._linesNormals.push(p1.z);
+                this._linesNormals.push(1);
+
+                this._linesNormals.push(p0.x);
+                this._linesNormals.push(p0.y);
+                this._linesNormals.push(p0.z);
+                this._linesNormals.push(-1);
+
+                this._linesNormals.push(p0.x);
+                this._linesNormals.push(p0.y);
+                this._linesNormals.push(p0.z);
+                this._linesNormals.push(1);
+
+                // Indices
+                this._linesIndices.push(offset);
+                this._linesIndices.push(offset + 1);
+                this._linesIndices.push(offset + 2);
+                this._linesIndices.push(offset);
+                this._linesIndices.push(offset + 2);
+                this._linesIndices.push(offset + 3);
+            }
+        }
+
+        _generateEdgesLines(): void {
+            var positions = this._source.getVerticesData(VertexBuffer.PositionKind);
+            var indices = this._source.getIndices();
+
+            // First let's find adjacencies
+            var adjacencies = new Array<FaceAdjacencies>();
+            var faceNormals = new Array<Vector3>();
+            var index: number;
+            var faceAdjacencies: FaceAdjacencies;
+
+            // Prepare faces
+            for (index = 0; index < indices.length; index += 3) {
+                faceAdjacencies = new FaceAdjacencies();
+                var p0Index = indices[index];
+                var p1Index = indices[index + 1];
+                var p2Index = indices[index + 2];
+
+                faceAdjacencies.p0 = new Vector3(positions[p0Index * 3], positions[p0Index * 3 + 1], positions[p0Index * 3 + 2]);
+                faceAdjacencies.p1 = new Vector3(positions[p1Index * 3], positions[p1Index * 3 + 1], positions[p1Index * 3 + 2]);
+                faceAdjacencies.p2 = new Vector3(positions[p2Index * 3], positions[p2Index * 3 + 1], positions[p2Index * 3 + 2]);
+                var faceNormal = Vector3.Cross(faceAdjacencies.p1.subtract(faceAdjacencies.p0), faceAdjacencies.p2.subtract(faceAdjacencies.p1));
+
+                faceNormal.normalize();
+
+                faceNormals.push(faceNormal);
+                adjacencies.push(faceAdjacencies);
+            }
+
+            // Scan
+            for (index = 0; index < adjacencies.length; index++) {
+                faceAdjacencies = adjacencies[index];
+
+                for (var otherIndex = index + 1; otherIndex < adjacencies.length; otherIndex++) {
+                    var otherFaceAdjacencies = adjacencies[otherIndex];
+
+                    if (faceAdjacencies.edgesConnectedCount === 3) { // Full
+                        break;
+                    }
+
+                    if (otherFaceAdjacencies.edgesConnectedCount === 3) { // Full
+                        continue;
+                    }
+
+                    var otherP0 = indices[otherIndex * 3];
+                    var otherP1 = indices[otherIndex * 3 + 1];
+                    var otherP2 = indices[otherIndex * 3 + 2];
+
+                    for (var edgeIndex = 0; edgeIndex < 3; edgeIndex++) {
+                        var otherEdgeIndex: number;
+
+                        if (faceAdjacencies.edges[edgeIndex] !== undefined) {
+                            continue;
+                        }
+
+                        switch (edgeIndex) {
+                            case 0:
+                                if (this._checkVerticesInsteadOfIndices) {
+                                    otherEdgeIndex = this._processEdgeForAdjacenciesWithVertices(faceAdjacencies.p0, faceAdjacencies.p1, otherFaceAdjacencies.p0, otherFaceAdjacencies.p1, otherFaceAdjacencies.p2);
+                                } else {
+                                    otherEdgeIndex = this._processEdgeForAdjacencies(indices[index * 3], indices[index * 3 + 1], otherP0, otherP1, otherP2);
+                                }
+                                break;
+                            case 1:
+                                if (this._checkVerticesInsteadOfIndices) {
+                                    otherEdgeIndex = this._processEdgeForAdjacenciesWithVertices(faceAdjacencies.p1, faceAdjacencies.p2, otherFaceAdjacencies.p0, otherFaceAdjacencies.p1, otherFaceAdjacencies.p2);
+                                } else {
+                                    otherEdgeIndex = this._processEdgeForAdjacencies(indices[index * 3 + 1], indices[index * 3 + 2], otherP0, otherP1, otherP2);
+                                }
+                                break;
+                            case 2:
+                                if (this._checkVerticesInsteadOfIndices) {
+                                    otherEdgeIndex = this._processEdgeForAdjacenciesWithVertices(faceAdjacencies.p2, faceAdjacencies.p0, otherFaceAdjacencies.p0, otherFaceAdjacencies.p1, otherFaceAdjacencies.p2);
+                                } else {
+                                    otherEdgeIndex = this._processEdgeForAdjacencies(indices[index * 3 + 2], indices[index * 3], otherP0, otherP1, otherP2);
+                                }
+                                break;
+                        }
+
+                        if (otherEdgeIndex === -1) {
+                            continue;
+                        }
+
+                        faceAdjacencies.edges[edgeIndex] = otherIndex;
+                        otherFaceAdjacencies.edges[otherEdgeIndex] = index;
+
+                        faceAdjacencies.edgesConnectedCount++;
+                        otherFaceAdjacencies.edgesConnectedCount++;
+
+                        if (faceAdjacencies.edgesConnectedCount === 3) {
+                            break;
+                        }
+                    }
+                }
+            }
+            
+            // Create lines
+            for (index = 0; index < adjacencies.length; index++) {
+                // We need a line when a face has no adjacency on a specific edge or if all the adjacencies has an angle greater than epsilon
+                var current = adjacencies[index];
+
+                this._checkEdge(index, current.edges[0], faceNormals, current.p0, current.p1);
+                this._checkEdge(index, current.edges[1], faceNormals, current.p1, current.p2);
+                this._checkEdge(index, current.edges[2], faceNormals, current.p2, current.p0);
+            }
+
+            // Merge into a single mesh
+            var engine = this._source.getScene().getEngine();
+            this._vb0 = new VertexBuffer(engine, this._linesPositions, VertexBuffer.PositionKind, false);
+            this._vb1 = new VertexBuffer(engine, this._linesNormals, VertexBuffer.NormalKind, false, false, 4);
+
+            this._buffers[VertexBuffer.PositionKind] = this._vb0;
+            this._buffers[VertexBuffer.NormalKind] = this._vb1;
+
+            this._ib = engine.createIndexBuffer(this._linesIndices);
+
+            this._indicesCount = this._linesIndices.length;
+        }
+
+        public render(): void {
+            if (!this._lineShader.isReady()) {
+                return;
+            }
+
+            var scene = this._source.getScene();
+            var engine = scene.getEngine();
+            this._lineShader._preBind();
+
+            // VBOs
+            engine.bindMultiBuffers(this._buffers, this._ib, this._lineShader.getEffect());
+
+            scene.resetCachedMaterial();
+            this._lineShader.setColor4("color", this._source.edgesColor);
+            this._lineShader.setFloat("width", this._source.edgesWidth / 50.0);
+            this._lineShader.setFloat("aspectRatio", engine.getAspectRatio(scene.activeCamera));
+            this._lineShader.bind(this._source.getWorldMatrix());
+
+            // Draw order
+            engine.draw(true, 0, this._indicesCount);
+            this._lineShader.unbind();
+            engine.setDepthWrite(true);
+        }
+    }
 } 

+ 102 - 102
src/Rendering/babylon.outlineRenderer.ts

@@ -1,103 +1,103 @@
-module BABYLON {
-    export class OutlineRenderer {
-        private _scene: Scene;
-        private _effect: Effect;
-        private _cachedDefines: string;
-
-        constructor(scene: Scene) {
-            this._scene = scene;
-        }
-
-        public render(subMesh: SubMesh, batch: _InstancesBatch, useOverlay: boolean = false) {
-            var scene = this._scene;
-            var engine = this._scene.getEngine();
-
-            var hardwareInstancedRendering = (engine.getCaps().instancedArrays !== null) && (batch.visibleInstances[subMesh._id] !== null) && (batch.visibleInstances[subMesh._id] !== undefined);
-
-            if (!this.isReady(subMesh, hardwareInstancedRendering)) {
-                return;
-            }
-
-            var mesh = subMesh.getRenderingMesh();
-            var material = subMesh.getMaterial();
-
-            engine.enableEffect(this._effect);
-            this._effect.setFloat("offset", useOverlay ? 0 : mesh.outlineWidth);
-            this._effect.setColor4("color", useOverlay ? mesh.overlayColor : mesh.outlineColor, useOverlay ? mesh.overlayAlpha : 1.0);
-            this._effect.setMatrix("viewProjection", scene.getTransformMatrix());
-
-            // Bones
-            if (mesh.useBones && mesh.computeBonesUsingShaders) {
-                this._effect.setMatrices("mBones", mesh.skeleton.getTransformMatrices());
-            }
-
-            mesh._bind(subMesh, this._effect, Material.TriangleFillMode);
-
-            // Alpha test
-            if (material && material.needAlphaTesting()) {
-                var alphaTexture = material.getAlphaTestTexture();
-                this._effect.setTexture("diffuseSampler", alphaTexture);
-                this._effect.setMatrix("diffuseMatrix", alphaTexture.getTextureMatrix());
-            }
-
-            mesh._processRendering(subMesh, this._effect, Material.TriangleFillMode, batch, hardwareInstancedRendering,
-                (isInstance, world) => { this._effect.setMatrix("world", world)});
-        }
-
-        public isReady(subMesh: SubMesh, useInstances: boolean): boolean {
-            var defines = [];
-            var attribs = [VertexBuffer.PositionKind, VertexBuffer.NormalKind];
-
-            var mesh = subMesh.getMesh();
-            var material = subMesh.getMaterial();
-
-            // Alpha test
-            if (material && material.needAlphaTesting()) {
-                defines.push("#define ALPHATEST");
-                if (mesh.isVerticesDataPresent(VertexBuffer.UVKind)) {
-                    attribs.push(VertexBuffer.UVKind);
-                    defines.push("#define UV1");
-                }
-                if (mesh.isVerticesDataPresent(VertexBuffer.UV2Kind)) {
-                    attribs.push(VertexBuffer.UV2Kind);
-                    defines.push("#define UV2");
-                }
-            }
-
-            // Bones
-            if (mesh.useBones && mesh.computeBonesUsingShaders) {
-                attribs.push(VertexBuffer.MatricesIndicesKind);
-                attribs.push(VertexBuffer.MatricesWeightsKind);
-                if (mesh.numBoneInfluencers > 4) {
-                    attribs.push(VertexBuffer.MatricesIndicesExtraKind);
-                    attribs.push(VertexBuffer.MatricesWeightsExtraKind);
-                }
-                defines.push("#define NUM_BONE_INFLUENCERS " + mesh.numBoneInfluencers);
-                defines.push("#define BonesPerMesh " + (mesh.skeleton.bones.length + 1));
-            } else {
-                defines.push("#define NUM_BONE_INFLUENCERS 0");
-            }
-
-            // Instances
-            if (useInstances) {
-                defines.push("#define INSTANCES");
-                attribs.push("world0");
-                attribs.push("world1");
-                attribs.push("world2");
-                attribs.push("world3");
-            }
-
-            // Get correct effect      
-            var join = defines.join("\n");
-            if (this._cachedDefines !== join) {
-                this._cachedDefines = join;
-                this._effect = this._scene.getEngine().createEffect("outline",
-                    attribs,
-                    ["world", "mBones", "viewProjection", "diffuseMatrix", "offset", "color"],
-                    ["diffuseSampler"], join);
-            }
-
-            return this._effect.isReady();
-        }
-    }
+module BABYLON {
+    export class OutlineRenderer {
+        private _scene: Scene;
+        private _effect: Effect;
+        private _cachedDefines: string;
+
+        constructor(scene: Scene) {
+            this._scene = scene;
+        }
+
+        public render(subMesh: SubMesh, batch: _InstancesBatch, useOverlay: boolean = false) {
+            var scene = this._scene;
+            var engine = this._scene.getEngine();
+
+            var hardwareInstancedRendering = (engine.getCaps().instancedArrays !== null) && (batch.visibleInstances[subMesh._id] !== null) && (batch.visibleInstances[subMesh._id] !== undefined);
+
+            if (!this.isReady(subMesh, hardwareInstancedRendering)) {
+                return;
+            }
+
+            var mesh = subMesh.getRenderingMesh();
+            var material = subMesh.getMaterial();
+
+            engine.enableEffect(this._effect);
+            this._effect.setFloat("offset", useOverlay ? 0 : mesh.outlineWidth);
+            this._effect.setColor4("color", useOverlay ? mesh.overlayColor : mesh.outlineColor, useOverlay ? mesh.overlayAlpha : 1.0);
+            this._effect.setMatrix("viewProjection", scene.getTransformMatrix());
+
+            // Bones
+            if (mesh.useBones && mesh.computeBonesUsingShaders) {
+                this._effect.setMatrices("mBones", mesh.skeleton.getTransformMatrices());
+            }
+
+            mesh._bind(subMesh, this._effect, Material.TriangleFillMode);
+
+            // Alpha test
+            if (material && material.needAlphaTesting()) {
+                var alphaTexture = material.getAlphaTestTexture();
+                this._effect.setTexture("diffuseSampler", alphaTexture);
+                this._effect.setMatrix("diffuseMatrix", alphaTexture.getTextureMatrix());
+            }
+
+            mesh._processRendering(subMesh, this._effect, Material.TriangleFillMode, batch, hardwareInstancedRendering,
+                (isInstance, world) => { this._effect.setMatrix("world", world)});
+        }
+
+        public isReady(subMesh: SubMesh, useInstances: boolean): boolean {
+            var defines = [];
+            var attribs = [VertexBuffer.PositionKind, VertexBuffer.NormalKind];
+
+            var mesh = subMesh.getMesh();
+            var material = subMesh.getMaterial();
+
+            // Alpha test
+            if (material && material.needAlphaTesting()) {
+                defines.push("#define ALPHATEST");
+                if (mesh.isVerticesDataPresent(VertexBuffer.UVKind)) {
+                    attribs.push(VertexBuffer.UVKind);
+                    defines.push("#define UV1");
+                }
+                if (mesh.isVerticesDataPresent(VertexBuffer.UV2Kind)) {
+                    attribs.push(VertexBuffer.UV2Kind);
+                    defines.push("#define UV2");
+                }
+            }
+
+            // Bones
+            if (mesh.useBones && mesh.computeBonesUsingShaders) {
+                attribs.push(VertexBuffer.MatricesIndicesKind);
+                attribs.push(VertexBuffer.MatricesWeightsKind);
+                if (mesh.numBoneInfluencers > 4) {
+                    attribs.push(VertexBuffer.MatricesIndicesExtraKind);
+                    attribs.push(VertexBuffer.MatricesWeightsExtraKind);
+                }
+                defines.push("#define NUM_BONE_INFLUENCERS " + mesh.numBoneInfluencers);
+                defines.push("#define BonesPerMesh " + (mesh.skeleton.bones.length + 1));
+            } else {
+                defines.push("#define NUM_BONE_INFLUENCERS 0");
+            }
+
+            // Instances
+            if (useInstances) {
+                defines.push("#define INSTANCES");
+                attribs.push("world0");
+                attribs.push("world1");
+                attribs.push("world2");
+                attribs.push("world3");
+            }
+
+            // Get correct effect      
+            var join = defines.join("\n");
+            if (this._cachedDefines !== join) {
+                this._cachedDefines = join;
+                this._effect = this._scene.getEngine().createEffect("outline",
+                    attribs,
+                    ["world", "mBones", "viewProjection", "diffuseMatrix", "offset", "color"],
+                    ["diffuseSampler"], join);
+            }
+
+            return this._effect.isReady();
+        }
+    }
 } 

+ 112 - 112
src/Rendering/babylon.renderingGroup.ts

@@ -1,113 +1,113 @@
-module BABYLON {
-    export class RenderingGroup {
-        private _scene: Scene
-        private _opaqueSubMeshes = new SmartArray<SubMesh>(256);
-        private _transparentSubMeshes = new SmartArray<SubMesh>(256);
-        private _alphaTestSubMeshes = new SmartArray<SubMesh>(256);
-        private _activeVertices: number;
-
-        public onBeforeTransparentRendering: () => void;
-
-        constructor(public index: number, scene: Scene) {
-            this._scene = scene;
-        }
-
-        public render(customRenderFunction: (opaqueSubMeshes: SmartArray<SubMesh>, transparentSubMeshes: SmartArray<SubMesh>, alphaTestSubMeshes: SmartArray<SubMesh>) => void): boolean {
-            if (customRenderFunction) {
-                customRenderFunction(this._opaqueSubMeshes, this._alphaTestSubMeshes, this._transparentSubMeshes);
-                return true;
-            }
-
-            if (this._opaqueSubMeshes.length === 0 && this._alphaTestSubMeshes.length === 0 && this._transparentSubMeshes.length === 0) {
-                if (this.onBeforeTransparentRendering) {
-                    this.onBeforeTransparentRendering();
-                }
-                return false;
-            }
-            var engine = this._scene.getEngine();
-            // Opaque
-            var subIndex: number;
-            var submesh: SubMesh;
-
-            for (subIndex = 0; subIndex < this._opaqueSubMeshes.length; subIndex++) {
-                submesh = this._opaqueSubMeshes.data[subIndex];
-
-                submesh.render(false);
-            }
-
-            // Alpha test
-            engine.setAlphaTesting(true);
-            for (subIndex = 0; subIndex < this._alphaTestSubMeshes.length; subIndex++) {
-                submesh = this._alphaTestSubMeshes.data[subIndex];
-
-                submesh.render(false);
-            }
-            engine.setAlphaTesting(false);
-
-            if (this.onBeforeTransparentRendering) {
-                this.onBeforeTransparentRendering();
-            }
-
-            // Transparent
-            if (this._transparentSubMeshes.length) {
-                // Sorting
-                for (subIndex = 0; subIndex < this._transparentSubMeshes.length; subIndex++) {
-                    submesh = this._transparentSubMeshes.data[subIndex];
-                    submesh._alphaIndex = submesh.getMesh().alphaIndex;
-                    submesh._distanceToCamera = submesh.getBoundingInfo().boundingSphere.centerWorld.subtract(this._scene.activeCamera.globalPosition).length();
-                }
-
-                var sortedArray = this._transparentSubMeshes.data.slice(0, this._transparentSubMeshes.length);
-
-                sortedArray.sort((a, b) => {
-                    // Alpha index first
-                    if (a._alphaIndex > b._alphaIndex) {
-                        return 1;
-                    }
-                    if (a._alphaIndex < b._alphaIndex) {
-                        return -1;
-                    }
-
-                    // Then distance to camera
-                    if (a._distanceToCamera < b._distanceToCamera) {
-                        return 1;
-                    }
-                    if (a._distanceToCamera > b._distanceToCamera) {
-                        return -1;
-                    }
-
-                    return 0;
-                });
-
-                // Rendering                
-                for (subIndex = 0; subIndex < sortedArray.length; subIndex++) {
-                    submesh = sortedArray[subIndex];
-
-                    submesh.render(true);
-                }
-                engine.setAlphaMode(Engine.ALPHA_DISABLE);
-            }
-            return true;
-        }
-
-
-        public prepare(): void {
-            this._opaqueSubMeshes.reset();
-            this._transparentSubMeshes.reset();
-            this._alphaTestSubMeshes.reset();
-        }
-
-        public dispatch(subMesh: SubMesh): void {
-            var material = subMesh.getMaterial();
-            var mesh = subMesh.getMesh();
-
-            if (material.needAlphaBlending() || mesh.visibility < 1.0 || mesh.hasVertexAlpha) { // Transparent
-                this._transparentSubMeshes.push(subMesh);
-            } else if (material.needAlphaTesting()) { // Alpha test
-                this._alphaTestSubMeshes.push(subMesh);
-            } else {
-                this._opaqueSubMeshes.push(subMesh); // Opaque
-            }
-        }
-    }
+module BABYLON {
+    export class RenderingGroup {
+        private _scene: Scene
+        private _opaqueSubMeshes = new SmartArray<SubMesh>(256);
+        private _transparentSubMeshes = new SmartArray<SubMesh>(256);
+        private _alphaTestSubMeshes = new SmartArray<SubMesh>(256);
+        private _activeVertices: number;
+
+        public onBeforeTransparentRendering: () => void;
+
+        constructor(public index: number, scene: Scene) {
+            this._scene = scene;
+        }
+
+        public render(customRenderFunction: (opaqueSubMeshes: SmartArray<SubMesh>, transparentSubMeshes: SmartArray<SubMesh>, alphaTestSubMeshes: SmartArray<SubMesh>) => void): boolean {
+            if (customRenderFunction) {
+                customRenderFunction(this._opaqueSubMeshes, this._alphaTestSubMeshes, this._transparentSubMeshes);
+                return true;
+            }
+
+            if (this._opaqueSubMeshes.length === 0 && this._alphaTestSubMeshes.length === 0 && this._transparentSubMeshes.length === 0) {
+                if (this.onBeforeTransparentRendering) {
+                    this.onBeforeTransparentRendering();
+                }
+                return false;
+            }
+            var engine = this._scene.getEngine();
+            // Opaque
+            var subIndex: number;
+            var submesh: SubMesh;
+
+            for (subIndex = 0; subIndex < this._opaqueSubMeshes.length; subIndex++) {
+                submesh = this._opaqueSubMeshes.data[subIndex];
+
+                submesh.render(false);
+            }
+
+            // Alpha test
+            engine.setAlphaTesting(true);
+            for (subIndex = 0; subIndex < this._alphaTestSubMeshes.length; subIndex++) {
+                submesh = this._alphaTestSubMeshes.data[subIndex];
+
+                submesh.render(false);
+            }
+            engine.setAlphaTesting(false);
+
+            if (this.onBeforeTransparentRendering) {
+                this.onBeforeTransparentRendering();
+            }
+
+            // Transparent
+            if (this._transparentSubMeshes.length) {
+                // Sorting
+                for (subIndex = 0; subIndex < this._transparentSubMeshes.length; subIndex++) {
+                    submesh = this._transparentSubMeshes.data[subIndex];
+                    submesh._alphaIndex = submesh.getMesh().alphaIndex;
+                    submesh._distanceToCamera = submesh.getBoundingInfo().boundingSphere.centerWorld.subtract(this._scene.activeCamera.globalPosition).length();
+                }
+
+                var sortedArray = this._transparentSubMeshes.data.slice(0, this._transparentSubMeshes.length);
+
+                sortedArray.sort((a, b) => {
+                    // Alpha index first
+                    if (a._alphaIndex > b._alphaIndex) {
+                        return 1;
+                    }
+                    if (a._alphaIndex < b._alphaIndex) {
+                        return -1;
+                    }
+
+                    // Then distance to camera
+                    if (a._distanceToCamera < b._distanceToCamera) {
+                        return 1;
+                    }
+                    if (a._distanceToCamera > b._distanceToCamera) {
+                        return -1;
+                    }
+
+                    return 0;
+                });
+
+                // Rendering                
+                for (subIndex = 0; subIndex < sortedArray.length; subIndex++) {
+                    submesh = sortedArray[subIndex];
+
+                    submesh.render(true);
+                }
+                engine.setAlphaMode(Engine.ALPHA_DISABLE);
+            }
+            return true;
+        }
+
+
+        public prepare(): void {
+            this._opaqueSubMeshes.reset();
+            this._transparentSubMeshes.reset();
+            this._alphaTestSubMeshes.reset();
+        }
+
+        public dispatch(subMesh: SubMesh): void {
+            var material = subMesh.getMaterial();
+            var mesh = subMesh.getMesh();
+
+            if (material.needAlphaBlending() || mesh.visibility < 1.0 || mesh.hasVertexAlpha) { // Transparent
+                this._transparentSubMeshes.push(subMesh);
+            } else if (material.needAlphaTesting()) { // Alpha test
+                this._alphaTestSubMeshes.push(subMesh);
+            } else {
+                this._opaqueSubMeshes.push(subMesh); // Opaque
+            }
+        }
+    }
 } 

+ 139 - 139
src/Rendering/babylon.renderingManager.ts

@@ -1,140 +1,140 @@
-module BABYLON {
-    export class RenderingManager {
-        public static MAX_RENDERINGGROUPS = 4;
-
-        private _scene: Scene;
-        private _renderingGroups = new Array<RenderingGroup>();
-        private _depthBufferAlreadyCleaned: boolean;
-
-        private _currentIndex: number;
-        private _currentActiveMeshes: AbstractMesh[];
-        private _currentRenderParticles: boolean;
-        private _currentRenderSprites: boolean;
-
-        constructor(scene: Scene) {
-            this._scene = scene;
-        }
-
-        private _renderParticles(index: number, activeMeshes: AbstractMesh[]): void {
-            if (this._scene._activeParticleSystems.length === 0) {
-                return;
-            }
-
-            // Particles
-            var activeCamera = this._scene.activeCamera;
-            var beforeParticlesDate = Tools.Now;
-            for (var particleIndex = 0; particleIndex < this._scene._activeParticleSystems.length; particleIndex++) {
-                var particleSystem = this._scene._activeParticleSystems.data[particleIndex];
-
-                if (particleSystem.renderingGroupId !== index) {
-                    continue;
-                }
-
-                if ((activeCamera.layerMask & particleSystem.layerMask) === 0) {
-                    continue;
-                }
-
-                this._clearDepthBuffer();
-
-                if (!particleSystem.emitter.position || !activeMeshes || activeMeshes.indexOf(particleSystem.emitter) !== -1) {
-                    this._scene._activeParticles += particleSystem.render();
-                }
-            }
-            this._scene._particlesDuration += Tools.Now - beforeParticlesDate;
-        }
-
-        private _renderSprites(index: number): void {
-            if (!this._scene.spritesEnabled || this._scene.spriteManagers.length === 0) {
-                return;
-            }
-
-            // Sprites       
-            var activeCamera = this._scene.activeCamera;
-            var beforeSpritessDate = Tools.Now;
-            for (var id = 0; id < this._scene.spriteManagers.length; id++) {
-                var spriteManager = this._scene.spriteManagers[id];
-
-                if (spriteManager.renderingGroupId === index && ((activeCamera.layerMask & spriteManager.layerMask) !== 0)) {
-                    this._clearDepthBuffer();
-                    spriteManager.render();
-                }
-            }
-            this._scene._spritesDuration += Tools.Now - beforeSpritessDate;
-        }
-
-        private _clearDepthBuffer(): void {
-            if (this._depthBufferAlreadyCleaned) {
-                return;
-            }
-
-            this._scene.getEngine().clear(0, false, true);
-            this._depthBufferAlreadyCleaned = true;
-        }
-
-        private _renderSpritesAndParticles() {
-            if (this._currentRenderSprites) {
-                this._renderSprites(this._currentIndex);
-            }
-
-            if (this._currentRenderParticles) {
-                this._renderParticles(this._currentIndex, this._currentActiveMeshes);
-            }
-        }
-
-        public render(customRenderFunction: (opaqueSubMeshes: SmartArray<SubMesh>, transparentSubMeshes: SmartArray<SubMesh>, alphaTestSubMeshes: SmartArray<SubMesh>) => void,
-            activeMeshes: AbstractMesh[], renderParticles: boolean, renderSprites: boolean): void {
-
-            this._currentActiveMeshes = activeMeshes;
-            this._currentRenderParticles = renderParticles;
-            this._currentRenderSprites = renderSprites;
-
-            for (var index = 0; index < RenderingManager.MAX_RENDERINGGROUPS; index++) {
-                this._depthBufferAlreadyCleaned = false;
-                var renderingGroup = this._renderingGroups[index];
-                var needToStepBack = false;
-
-                this._currentIndex = index;
-
-                if (renderingGroup) {
-                    this._clearDepthBuffer();
-
-                    if (!renderingGroup.onBeforeTransparentRendering) {
-                        renderingGroup.onBeforeTransparentRendering = this._renderSpritesAndParticles.bind(this);
-                    }
-
-                    if (!renderingGroup.render(customRenderFunction)) {
-                        this._renderingGroups.splice(index, 1);
-                        needToStepBack = true;
-                        this._renderSpritesAndParticles();
-                    }
-                } else {
-                    this._renderSpritesAndParticles();
-                }
-
-                if (needToStepBack) {
-                    index--;
-                }
-            }
-        }
-
-        public reset(): void {
-            this._renderingGroups.forEach((renderingGroup, index, array) => {
-                if (renderingGroup) {
-                    renderingGroup.prepare();
-                }
-            });
-        }
-
-        public dispatch(subMesh: SubMesh): void {
-            var mesh = subMesh.getMesh();
-            var renderingGroupId = mesh.renderingGroupId || 0;
-
-            if (!this._renderingGroups[renderingGroupId]) {
-                this._renderingGroups[renderingGroupId] = new RenderingGroup(renderingGroupId, this._scene);
-            }
-
-            this._renderingGroups[renderingGroupId].dispatch(subMesh);
-        }
-
-    }
+module BABYLON {
+    export class RenderingManager {
+        public static MAX_RENDERINGGROUPS = 4;
+
+        private _scene: Scene;
+        private _renderingGroups = new Array<RenderingGroup>();
+        private _depthBufferAlreadyCleaned: boolean;
+
+        private _currentIndex: number;
+        private _currentActiveMeshes: AbstractMesh[];
+        private _currentRenderParticles: boolean;
+        private _currentRenderSprites: boolean;
+
+        constructor(scene: Scene) {
+            this._scene = scene;
+        }
+
+        private _renderParticles(index: number, activeMeshes: AbstractMesh[]): void {
+            if (this._scene._activeParticleSystems.length === 0) {
+                return;
+            }
+
+            // Particles
+            var activeCamera = this._scene.activeCamera;
+            var beforeParticlesDate = Tools.Now;
+            for (var particleIndex = 0; particleIndex < this._scene._activeParticleSystems.length; particleIndex++) {
+                var particleSystem = this._scene._activeParticleSystems.data[particleIndex];
+
+                if (particleSystem.renderingGroupId !== index) {
+                    continue;
+                }
+
+                if ((activeCamera.layerMask & particleSystem.layerMask) === 0) {
+                    continue;
+                }
+
+                this._clearDepthBuffer();
+
+                if (!particleSystem.emitter.position || !activeMeshes || activeMeshes.indexOf(particleSystem.emitter) !== -1) {
+                    this._scene._activeParticles += particleSystem.render();
+                }
+            }
+            this._scene._particlesDuration += Tools.Now - beforeParticlesDate;
+        }
+
+        private _renderSprites(index: number): void {
+            if (!this._scene.spritesEnabled || this._scene.spriteManagers.length === 0) {
+                return;
+            }
+
+            // Sprites       
+            var activeCamera = this._scene.activeCamera;
+            var beforeSpritessDate = Tools.Now;
+            for (var id = 0; id < this._scene.spriteManagers.length; id++) {
+                var spriteManager = this._scene.spriteManagers[id];
+
+                if (spriteManager.renderingGroupId === index && ((activeCamera.layerMask & spriteManager.layerMask) !== 0)) {
+                    this._clearDepthBuffer();
+                    spriteManager.render();
+                }
+            }
+            this._scene._spritesDuration += Tools.Now - beforeSpritessDate;
+        }
+
+        private _clearDepthBuffer(): void {
+            if (this._depthBufferAlreadyCleaned) {
+                return;
+            }
+
+            this._scene.getEngine().clear(0, false, true);
+            this._depthBufferAlreadyCleaned = true;
+        }
+
+        private _renderSpritesAndParticles() {
+            if (this._currentRenderSprites) {
+                this._renderSprites(this._currentIndex);
+            }
+
+            if (this._currentRenderParticles) {
+                this._renderParticles(this._currentIndex, this._currentActiveMeshes);
+            }
+        }
+
+        public render(customRenderFunction: (opaqueSubMeshes: SmartArray<SubMesh>, transparentSubMeshes: SmartArray<SubMesh>, alphaTestSubMeshes: SmartArray<SubMesh>) => void,
+            activeMeshes: AbstractMesh[], renderParticles: boolean, renderSprites: boolean): void {
+
+            this._currentActiveMeshes = activeMeshes;
+            this._currentRenderParticles = renderParticles;
+            this._currentRenderSprites = renderSprites;
+
+            for (var index = 0; index < RenderingManager.MAX_RENDERINGGROUPS; index++) {
+                this._depthBufferAlreadyCleaned = false;
+                var renderingGroup = this._renderingGroups[index];
+                var needToStepBack = false;
+
+                this._currentIndex = index;
+
+                if (renderingGroup) {
+                    this._clearDepthBuffer();
+
+                    if (!renderingGroup.onBeforeTransparentRendering) {
+                        renderingGroup.onBeforeTransparentRendering = this._renderSpritesAndParticles.bind(this);
+                    }
+
+                    if (!renderingGroup.render(customRenderFunction)) {
+                        this._renderingGroups.splice(index, 1);
+                        needToStepBack = true;
+                        this._renderSpritesAndParticles();
+                    }
+                } else {
+                    this._renderSpritesAndParticles();
+                }
+
+                if (needToStepBack) {
+                    index--;
+                }
+            }
+        }
+
+        public reset(): void {
+            this._renderingGroups.forEach((renderingGroup, index, array) => {
+                if (renderingGroup) {
+                    renderingGroup.prepare();
+                }
+            });
+        }
+
+        public dispatch(subMesh: SubMesh): void {
+            var mesh = subMesh.getMesh();
+            var renderingGroupId = mesh.renderingGroupId || 0;
+
+            if (!this._renderingGroups[renderingGroupId]) {
+                this._renderingGroups[renderingGroupId] = new RenderingGroup(renderingGroupId, this._scene);
+            }
+
+            this._renderingGroups[renderingGroupId].dispatch(subMesh);
+        }
+
+    }
 } 

+ 16 - 16
src/Shaders/anaglyph.fragment.fx

@@ -1,17 +1,17 @@
-precision highp float;
-
-// Samplers
-varying vec2 vUV;
-uniform sampler2D textureSampler;
-uniform sampler2D leftSampler;
-
-void main(void)
-{
-    vec4 leftFrag = texture2D(leftSampler, vUV);
-    leftFrag = vec4(1.0, leftFrag.g, leftFrag.b, 1.0);
-
-	vec4 rightFrag = texture2D(textureSampler, vUV);
-    rightFrag = vec4(rightFrag.r, 1.0, 1.0, 1.0);
-
-    gl_FragColor = vec4(rightFrag.rgb * leftFrag.rgb, 1.0);
+precision highp float;
+
+// Samplers
+varying vec2 vUV;
+uniform sampler2D textureSampler;
+uniform sampler2D leftSampler;
+
+void main(void)
+{
+    vec4 leftFrag = texture2D(leftSampler, vUV);
+    leftFrag = vec4(1.0, leftFrag.g, leftFrag.b, 1.0);
+
+	vec4 rightFrag = texture2D(textureSampler, vUV);
+    rightFrag = vec4(rightFrag.r, 1.0, 1.0, 1.0);
+
+    gl_FragColor = vec4(rightFrag.rgb * leftFrag.rgb, 1.0);
 }

+ 10 - 10
src/Shaders/blackAndWhite.fragment.fx

@@ -1,11 +1,11 @@
-precision highp float;
-
-// Samplers
-varying vec2 vUV;
-uniform sampler2D textureSampler;
-
-void main(void) 
-{
-	float luminance = dot(texture2D(textureSampler, vUV).rgb, vec3(0.3, 0.59, 0.11));
-	gl_FragColor = vec4(luminance, luminance, luminance, 1.0);
+precision highp float;
+
+// Samplers
+varying vec2 vUV;
+uniform sampler2D textureSampler;
+
+void main(void) 
+{
+	float luminance = dot(texture2D(textureSampler, vUV).rgb, vec3(0.3, 0.59, 0.11));
+	gl_FragColor = vec4(luminance, luminance, luminance, 1.0);
 }

+ 36 - 36
src/Shaders/blur.fragment.fx

@@ -1,37 +1,37 @@
-precision highp float;
-
-// Samplers
-varying vec2 vUV;
-uniform sampler2D textureSampler;
-
-// Parameters
-uniform vec2 screenSize;
-uniform vec2 direction;
-uniform float blurWidth;
-
-void main(void)
-{
-	float weights[7];
-	weights[0] = 0.05;
-	weights[1] = 0.1;
-	weights[2] = 0.2;
-	weights[3] = 0.3;
-	weights[4] = 0.2;
-	weights[5] = 0.1;
-	weights[6] = 0.05;
-
-	vec2 texelSize = vec2(1.0 / screenSize.x, 1.0 / screenSize.y);
-	vec2 texelStep = texelSize * direction * blurWidth;
-	vec2 start = vUV - 3.0 * texelStep;
-
-	vec4 baseColor = vec4(0., 0., 0., 0.);
-	vec2 texelOffset = vec2(0., 0.);
-
-	for (int i = 0; i < 7; i++)
-	{
-		baseColor += texture2D(textureSampler, start + texelOffset) * weights[i];
-		texelOffset += texelStep;
-	}
-
-	gl_FragColor = baseColor;
+precision highp float;
+
+// Samplers
+varying vec2 vUV;
+uniform sampler2D textureSampler;
+
+// Parameters
+uniform vec2 screenSize;
+uniform vec2 direction;
+uniform float blurWidth;
+
+void main(void)
+{
+	float weights[7];
+	weights[0] = 0.05;
+	weights[1] = 0.1;
+	weights[2] = 0.2;
+	weights[3] = 0.3;
+	weights[4] = 0.2;
+	weights[5] = 0.1;
+	weights[6] = 0.05;
+
+	vec2 texelSize = vec2(1.0 / screenSize.x, 1.0 / screenSize.y);
+	vec2 texelStep = texelSize * direction * blurWidth;
+	vec2 start = vUV - 3.0 * texelStep;
+
+	vec4 baseColor = vec4(0., 0., 0., 0.);
+	vec2 texelOffset = vec2(0., 0.);
+
+	for (int i = 0; i < 7; i++)
+	{
+		baseColor += texture2D(textureSampler, start + texelOffset) * weights[i];
+		texelOffset += texelStep;
+	}
+
+	gl_FragColor = baseColor;
 }

+ 39 - 39
src/Shaders/chromaticAberration.fragment.fx

@@ -1,40 +1,40 @@
-precision highp float;
-
-// samplers
-uniform sampler2D textureSampler;	// original color
-
-// uniforms
-uniform float chromatic_aberration;
-uniform float screen_width;
-uniform float screen_height;
-
-// varyings
-varying vec2 vUV;
-
-void main(void)
-{
-	vec2 centered_screen_pos = vec2(vUV.x - 0.5, vUV.y - 0.5);
-	float radius2 = centered_screen_pos.x*centered_screen_pos.x
-		+ centered_screen_pos.y*centered_screen_pos.y;
-	float radius = sqrt(radius2);
-
-	vec4 original = texture2D(textureSampler, vUV);
-
-	if (chromatic_aberration > 0.0) {
-		//index of refraction of each color channel, causing chromatic dispersion
-		vec3 ref_indices = vec3(-0.3, 0.0, 0.3);
-		float ref_shiftX = chromatic_aberration * radius * 17.0 / screen_width;
-		float ref_shiftY = chromatic_aberration * radius * 17.0 / screen_height;
-
-		// shifts for red, green & blue
-		vec2 ref_coords_r = vec2(vUV.x + ref_indices.r*ref_shiftX, vUV.y + ref_indices.r*ref_shiftY*0.5);
-		vec2 ref_coords_g = vec2(vUV.x + ref_indices.g*ref_shiftX, vUV.y + ref_indices.g*ref_shiftY*0.5);
-		vec2 ref_coords_b = vec2(vUV.x + ref_indices.b*ref_shiftX, vUV.y + ref_indices.b*ref_shiftY*0.5);
-
-		original.r = texture2D(textureSampler, ref_coords_r).r;
-		original.g = texture2D(textureSampler, ref_coords_g).g;
-		original.b = texture2D(textureSampler, ref_coords_b).b;
-	}
-
-	gl_FragColor = original;
+precision highp float;
+
+// samplers
+uniform sampler2D textureSampler;	// original color
+
+// uniforms
+uniform float chromatic_aberration;
+uniform float screen_width;
+uniform float screen_height;
+
+// varyings
+varying vec2 vUV;
+
+void main(void)
+{
+	vec2 centered_screen_pos = vec2(vUV.x - 0.5, vUV.y - 0.5);
+	float radius2 = centered_screen_pos.x*centered_screen_pos.x
+		+ centered_screen_pos.y*centered_screen_pos.y;
+	float radius = sqrt(radius2);
+
+	vec4 original = texture2D(textureSampler, vUV);
+
+	if (chromatic_aberration > 0.0) {
+		//index of refraction of each color channel, causing chromatic dispersion
+		vec3 ref_indices = vec3(-0.3, 0.0, 0.3);
+		float ref_shiftX = chromatic_aberration * radius * 17.0 / screen_width;
+		float ref_shiftY = chromatic_aberration * radius * 17.0 / screen_height;
+
+		// shifts for red, green & blue
+		vec2 ref_coords_r = vec2(vUV.x + ref_indices.r*ref_shiftX, vUV.y + ref_indices.r*ref_shiftY*0.5);
+		vec2 ref_coords_g = vec2(vUV.x + ref_indices.g*ref_shiftX, vUV.y + ref_indices.g*ref_shiftY*0.5);
+		vec2 ref_coords_b = vec2(vUV.x + ref_indices.b*ref_shiftX, vUV.y + ref_indices.b*ref_shiftY*0.5);
+
+		original.r = texture2D(textureSampler, ref_coords_r).r;
+		original.g = texture2D(textureSampler, ref_coords_g).g;
+		original.b = texture2D(textureSampler, ref_coords_b).b;
+	}
+
+	gl_FragColor = original;
 }

+ 6 - 6
src/Shaders/color.fragment.fx

@@ -1,7 +1,7 @@
-precision highp float;
-
-uniform vec4 color;
-
-void main(void) {
-	gl_FragColor = color;
+precision highp float;
+
+uniform vec4 color;
+
+void main(void) {
+	gl_FragColor = color;
 }

+ 0 - 0
src/Shaders/color.vertex.fx


Некоторые файлы не были показаны из-за большого количества измененных файлов