Bladeren bron

Merge remote-tracking branch 'upstream/master' into PosEngineFinal

nockawa 8 jaren geleden
bovenliggende
commit
384d477ba7
56 gewijzigde bestanden met toevoegingen van 9914 en 7287 verwijderingen
  1. 1 1
      .travis.yml
  2. 1734 579
      Exporters/3ds Max/ActionsBuilder/Sources/babylon.max.js
  3. 3 0
      Exporters/3ds Max/BabylonExport.Entities/BabylonAbstractMesh.cs
  4. 0 3
      Exporters/3ds Max/BabylonExport.Entities/BabylonMesh.cs
  5. 5 0
      Exporters/3ds Max/BabylonExport.Entities/BabylonPBRMaterial.cs
  6. BIN
      Exporters/3ds Max/Max2Babylon-0.6.0.zip
  7. BIN
      Exporters/3ds Max/Max2Babylon-0.7.0.zip
  8. 1 0
      Exporters/3ds Max/Max2Babylon/Exporter/BabylonExporter.Mesh.cs
  9. 3 0
      Playground/index-local.html
  10. 7 0
      Tools/Gulp/config.json
  11. 33 0
      contributing.md
  12. 25 25
      dist/preview release/babylon.core.js
  13. 3093 2955
      dist/preview release/babylon.d.ts
  14. 38 38
      dist/preview release/babylon.js
  15. 646 134
      dist/preview release/babylon.max.js
  16. 3093 2955
      dist/preview release/babylon.module.d.ts
  17. 38 38
      dist/preview release/babylon.noworker.js
  18. 25 25
      dist/preview release/canvas2D/babylon.canvas2d.js
  19. 9 9
      dist/preview release/canvas2D/babylon.canvas2d.min.js
  20. 248 248
      dist/preview release/inspector/babylon.inspector.bundle.js
  21. 1 1
      dist/preview release/materialsLibrary/babylon.furMaterial.js
  22. 1 1
      dist/preview release/materialsLibrary/babylon.furMaterial.min.js
  23. 11 0
      dist/preview release/proceduralTexturesLibrary/babylon.normalMapProceduralTexture.d.ts
  24. 46 0
      dist/preview release/proceduralTexturesLibrary/babylon.normalMapProceduralTexture.js
  25. 1 0
      dist/preview release/proceduralTexturesLibrary/babylon.normalMapProceduralTexture.min.js
  26. 8 0
      dist/preview release/proceduralTexturesLibrary/babylon.waterProceduralTexture.d.ts
  27. 28 0
      dist/preview release/proceduralTexturesLibrary/babylon.waterProceduralTexture.js
  28. 1 0
      dist/preview release/proceduralTexturesLibrary/babylon.waterProceduralTexture.min.js
  29. 2 0
      dist/preview release/what's new.md
  30. 9 1
      proceduralTexturesLibrary/index.html
  31. 37 0
      proceduralTexturesLibrary/src/normalMap/babylon.normalMapProceduralTexture.ts
  32. 30 0
      proceduralTexturesLibrary/src/normalMap/normalMapProceduralTexture.fragment.fx
  33. 6 0
      proceduralTexturesLibrary/test/addNormalMapPT.js
  34. 3 9
      readme.md
  35. 432 180
      src/Bones/babylon.boneLookController.ts
  36. 1 1
      src/Bones/babylon.skeleton.ts
  37. 31 18
      src/Cameras/Inputs/babylon.freecamera.input.gamepad.ts
  38. 1 1
      src/Cameras/babylon.arcRotateCamera.ts
  39. 8 0
      src/Cameras/babylon.camera.ts
  40. 1 1
      src/Cameras/babylon.freeCamera.ts
  41. 10 0
      src/Cameras/babylon.targetCamera.ts
  42. 4 1
      src/Debug/babylon.debugLayer.ts
  43. 40 35
      src/Lights/babylon.directionalLight.ts
  44. 2 0
      src/Lights/babylon.light.ts
  45. 8 2
      src/Lights/babylon.pointLight.ts
  46. 8 2
      src/Lights/babylon.spotLight.ts
  47. 8 3
      src/Materials/babylon.effect.ts
  48. 67 1
      src/Math/babylon.math.ts
  49. 3 1
      src/Mesh/babylon.geometry.ts
  50. 8 0
      src/PostProcess/babylon.postProcess.ts
  51. 76 14
      src/PostProcess/babylon.standardRenderingPipeline.ts
  52. 2 2
      src/Tools/babylon.database.ts
  53. 6 0
      src/Tools/babylon.smartArray.ts
  54. 2 2
      src/Tools/babylon.tools.ts
  55. 9 1
      src/babylon.engine.ts
  56. 1 0
      src/babylon.mixins.ts

+ 1 - 1
.travis.yml

@@ -1,6 +1,6 @@
 language: node_js
 node_js:
-  - "4.1"
+  - "6"
 before_script:
   - npm install -g gulp
   - cd ./Tools/Gulp

File diff suppressed because it is too large
+ 1734 - 579
Exporters/3ds Max/ActionsBuilder/Sources/babylon.max.js


+ 3 - 0
Exporters/3ds Max/BabylonExport.Entities/BabylonAbstractMesh.cs

@@ -6,6 +6,9 @@ namespace BabylonExport.Entities
     public class BabylonAbstractMesh: BabylonIAnimatable
     {
         [DataMember]
+        public string id { get; set; }
+
+        [DataMember]
         public string name { get; set; }
         
         [DataMember]

+ 0 - 3
Exporters/3ds Max/BabylonExport.Entities/BabylonMesh.cs

@@ -6,9 +6,6 @@ namespace BabylonExport.Entities
     public class BabylonMesh : BabylonAbstractMesh
     {
         [DataMember]
-        public string id { get; set; }
-
-        [DataMember]
         public string materialId { get; set; }
 
         [DataMember]

+ 5 - 0
Exporters/3ds Max/BabylonExport.Entities/BabylonPBRMaterial.cs

@@ -209,5 +209,10 @@ namespace BabylonExport.Entities
             overloadedEmissive = new[] {1f, 1f, 1f };
             overloadedReflection = new[] { 1f, 1f, 1f };
         }
+
+        public void SetCustomType(string type)
+        {
+            this.customType = type;
+        }
     }
 }

BIN
Exporters/3ds Max/Max2Babylon-0.6.0.zip


BIN
Exporters/3ds Max/Max2Babylon-0.7.0.zip


+ 1 - 0
Exporters/3ds Max/Max2Babylon/Exporter/BabylonExporter.Mesh.cs

@@ -478,6 +478,7 @@ namespace Max2Babylon
                     var instanceRotation = instanceLocalTM.Rotation;
                     var instanceScale = instanceLocalTM.Scaling;
 
+                    instance.id = instanceGameNode.MaxNode.GetGuid().ToString();
                     instance.position = new[] { instanceTrans.X, instanceTrans.Y, instanceTrans.Z };
 
                     if (exportQuaternions)

+ 3 - 0
Playground/index-local.html

@@ -16,6 +16,9 @@
     <link href="bootstrap/css/bootstrap.min.css" rel="stylesheet">
     <script src="node_modules/monaco-editor/min/vs/loader.js"></script>
     <!-- Babylon.js -->    
+    
+    <script src="https://babylonjs.azurewebsites.net/cannon.js"></script>
+    <script src="https://babylonjs.azurewebsites.net/Oimo.js"></script>
 	<script src="../tools/DevLoader/BabylonLoader.js"></script>
     <link href="index.css" rel="stylesheet" />
 </head>

+ 7 - 0
Tools/Gulp/config.json

@@ -411,6 +411,13 @@
           "../../proceduralTexturesLibrary/src/starfield/starfieldProceduralTexture.fragment.fx"
         ],
         "output": "babylon.starfieldProceduralTexture.js"
+      },
+      {
+        "files": ["../../proceduralTexturesLibrary/src/normalMap/babylon.normalMapProceduralTexture.ts"],
+        "shaderFiles": [
+          "../../proceduralTexturesLibrary/src/normalMap/normalMapProceduralTexture.fragment.fx"
+        ],
+        "output": "babylon.normalMapProceduralTexture.js"
       }
     ],
     "build": {

+ 33 - 0
contributing.md

@@ -0,0 +1,33 @@
+# Contributing to Babylon.js
+
+The foundation of **Babylon.js** is simplicity. 
+
+A developer should be able to quickly and easily learn to use the API. 
+
+Simplicity and a low barrier to entry are must-have features of every API. If you have any second thoughts about the complexity of a design, it is almost always much better to cut the feature from the current release and spend more time to get the design right for the next release. 
+
+You can always add to an API, you cannot ever remove anything from one. If the design does not feel right, and you ship it anyway, you are likely to regret having done so.
+
+That's why many of the guidelines of this document are obvious and serve only one purpose: Simplicity.
+
+## Forum and Github issues
+
+Since the very beginning, Babylon.js relies on a great forum and a tremendous community: http://www.html5gamedevs.com/forum/16-babylonjs/.
+Please use the forum for **ANY questions you may have**.
+
+Please use the Github issues **only** for:
+- Bugs
+- Feature requests
+
+We will try to enforce these rules as we consider the forum is a better place for discussions and learnings.
+
+## Pull requests
+
+We are not complicated people, but we still have some [coding guidelines](http://doc.babylonjs.com/generals/Approved_Naming_Conventions)
+Before submitting your PR, just check that everything goes well by [creating the minified version](http://doc.babylonjs.com/generals/Creating_the_Mini-fied_Version)
+
+Need help contributing, here are some links:
+  - [Gulp](https://github.com/BabylonJS/Babylon.js/tree/master/Tools/Gulp) to build from command line.
+  - [VSCode Editor](https://code.visualstudio.com/), Microsoft Code editor, see [Julian Chenard's post](http://pixelcodr.com/tutos/contribute/contribute.html) a Microsoft code editor.
+  - [Visual Studio](http://doc.babylonjs.com/generals/setup_visualStudio), Microsoft's IDE.
+  - [Forum thread](http://www.html5gamedevs.com/topic/20456-contributing-on-babylonjs/) for assistance from our very helpful family.

File diff suppressed because it is too large
+ 25 - 25
dist/preview release/babylon.core.js


File diff suppressed because it is too large
+ 3093 - 2955
dist/preview release/babylon.d.ts


File diff suppressed because it is too large
+ 38 - 38
dist/preview release/babylon.js


File diff suppressed because it is too large
+ 646 - 134
dist/preview release/babylon.max.js


File diff suppressed because it is too large
+ 3093 - 2955
dist/preview release/babylon.module.d.ts


File diff suppressed because it is too large
+ 38 - 38
dist/preview release/babylon.noworker.js


+ 25 - 25
dist/preview release/canvas2D/babylon.canvas2d.js

@@ -3844,14 +3844,14 @@ var BABYLON;
     var RowDefinition = (function (_super) {
         __extends(RowDefinition, _super);
         function RowDefinition() {
-            return _super !== null && _super.apply(this, arguments) || this;
+            return _super.apply(this, arguments) || this;
         }
         return RowDefinition;
     }(GridDimensionDefinition));
     var ColumnDefinition = (function (_super) {
         __extends(ColumnDefinition, _super);
         function ColumnDefinition() {
-            return _super !== null && _super.apply(this, arguments) || this;
+            return _super.apply(this, arguments) || this;
         }
         return ColumnDefinition;
     }(GridDimensionDefinition));
@@ -6897,7 +6897,7 @@ var BABYLON;
     var Prim2DBase = Prim2DBase_1 = (function (_super) {
         __extends(Prim2DBase, _super);
         function Prim2DBase(settings) {
-            var _this = this;
+            var _this;
             // Avoid checking every time if the object exists
             if (settings == null) {
                 settings = {};
@@ -11025,7 +11025,7 @@ var BABYLON;
     var Shape2DInstanceData = (function (_super) {
         __extends(Shape2DInstanceData, _super);
         function Shape2DInstanceData() {
-            return _super !== null && _super.apply(this, arguments) || this;
+            return _super.apply(this, arguments) || this;
         }
         Object.defineProperty(Shape2DInstanceData.prototype, "fillSolidColor", {
             // FILL ATTRIBUTES
@@ -11200,7 +11200,7 @@ var BABYLON;
          * - padding: top, left, right and bottom padding formatted as a single string (see PrimitiveThickness.fromString)
          */
         function Group2D(settings) {
-            var _this = this;
+            var _this;
             if (settings == null) {
                 settings = {};
             }
@@ -12139,7 +12139,7 @@ var BABYLON;
     var WireFrame2DRenderCache = (function (_super) {
         __extends(WireFrame2DRenderCache, _super);
         function WireFrame2DRenderCache() {
-            var _this = _super !== null && _super.apply(this, arguments) || this;
+            var _this = _super.apply(this, arguments) || this;
             _this.effectsReady = false;
             _this.vb = null;
             _this.vtxCount = 0;
@@ -12365,7 +12365,7 @@ var BABYLON;
          * - padding: top, left, right and bottom padding formatted as a single string (see PrimitiveThickness.fromString)
          */
         function WireFrame2D(wireFrameGroups, settings) {
-            var _this = this;
+            var _this;
             if (!settings) {
                 settings = {};
             }
@@ -12745,7 +12745,7 @@ var BABYLON;
          * - padding: top, left, right and bottom padding formatted as a single string (see PrimitiveThickness.fromString)
          */
         function Rectangle2D(settings) {
-            var _this = this;
+            var _this;
             // Avoid checking every time if the object exists
             if (settings == null) {
                 settings = {};
@@ -13260,7 +13260,7 @@ var BABYLON;
          * - padding: top, left, right and bottom padding formatted as a single string (see PrimitiveThickness.fromString)
          */
         function Ellipse2D(settings) {
-            var _this = this;
+            var _this;
             // Avoid checking every time if the object exists
             if (settings == null) {
                 settings = {};
@@ -13444,7 +13444,7 @@ var BABYLON;
     var Sprite2DRenderCache = (function (_super) {
         __extends(Sprite2DRenderCache, _super);
         function Sprite2DRenderCache() {
-            var _this = _super !== null && _super.apply(this, arguments) || this;
+            var _this = _super.apply(this, arguments) || this;
             _this.effectsReady = false;
             _this.vb = null;
             _this.ib = null;
@@ -13564,7 +13564,7 @@ var BABYLON;
          * - padding: top, left, right and bottom padding formatted as a single string (see PrimitiveThickness.fromString)
          */
         function Sprite2D(texture, settings) {
-            var _this = this;
+            var _this;
             if (!settings) {
                 settings = {};
             }
@@ -14202,7 +14202,7 @@ var BABYLON;
     var Text2DRenderCache = (function (_super) {
         __extends(Text2DRenderCache, _super);
         function Text2DRenderCache() {
-            var _this = _super !== null && _super.apply(this, arguments) || this;
+            var _this = _super.apply(this, arguments) || this;
             _this.effectsReady = false;
             _this.vb = null;
             _this.ib = null;
@@ -14400,7 +14400,7 @@ var BABYLON;
          * - wordWrap: if true the text will wrap inside content area
          */
         function Text2D(text, settings) {
-            var _this = this;
+            var _this;
             if (!settings) {
                 settings = {};
             }
@@ -15237,7 +15237,7 @@ var BABYLON;
          * - padding: top, left, right and bottom padding formatted as a single string (see PrimitiveThickness.fromString)
          */
         function Lines2D(points, settings) {
-            var _this = this;
+            var _this;
             if (!settings) {
                 settings = {};
             }
@@ -17891,7 +17891,7 @@ var BABYLON;
          * - padding: top, left, right and bottom padding formatted as a single string (see PrimitiveThickness.fromString)
          */
         function WorldSpaceCanvas2D(scene, size, settings) {
-            var _this = this;
+            var _this;
             BABYLON.Prim2DBase._isCanvasInit = true;
             var s = settings;
             s.isScreenSpace = false;
@@ -18053,7 +18053,7 @@ var BABYLON;
          * - padding: top, left, right and bottom padding formatted as a single string (see BABYLON.PrimitiveThickness.fromString)
          */
         function ScreenSpaceCanvas2D(scene, settings) {
-            var _this = this;
+            var _this;
             BABYLON.Prim2DBase._isCanvasInit = true;
             _this = _super.call(this, scene, settings) || this;
             return _this;
@@ -19037,7 +19037,7 @@ var BABYLON;
     var StackPanel = StackPanel_1 = (function (_super) {
         __extends(StackPanel, _super);
         function StackPanel(settings) {
-            var _this = this;
+            var _this;
             if (!settings) {
                 settings = {};
             }
@@ -19100,7 +19100,7 @@ var BABYLON;
     var DefaultStackPanelRenderingTemplate = DefaultStackPanelRenderingTemplate_1 = (function (_super) {
         __extends(DefaultStackPanelRenderingTemplate, _super);
         function DefaultStackPanelRenderingTemplate() {
-            return _super !== null && _super.apply(this, arguments) || this;
+            return _super.apply(this, arguments) || this;
         }
         DefaultStackPanelRenderingTemplate.prototype.createVisualTree = function (owner, visualPlaceholder) {
             return { root: visualPlaceholder, contentPlaceholder: visualPlaceholder };
@@ -19229,7 +19229,7 @@ var BABYLON;
     var ContentControl = ContentControl_1 = (function (_super) {
         __extends(ContentControl, _super);
         function ContentControl(settings) {
-            var _this = this;
+            var _this;
             if (!settings) {
                 settings = {};
             }
@@ -19384,7 +19384,7 @@ var BABYLON;
     var Window = Window_1 = (function (_super) {
         __extends(Window, _super);
         function Window(scene, settings) {
-            var _this = this;
+            var _this;
             if (!settings) {
                 settings = {};
             }
@@ -19569,7 +19569,7 @@ var BABYLON;
     var DefaultWindowRenderingTemplate = DefaultWindowRenderingTemplate_1 = (function (_super) {
         __extends(DefaultWindowRenderingTemplate, _super);
         function DefaultWindowRenderingTemplate() {
-            return _super !== null && _super.apply(this, arguments) || this;
+            return _super.apply(this, arguments) || this;
         }
         DefaultWindowRenderingTemplate.prototype.createVisualTree = function (owner, visualPlaceholder) {
             var r = new BABYLON.Rectangle2D({ parent: visualPlaceholder, fill: "#808080FF" });
@@ -19600,7 +19600,7 @@ var BABYLON;
     var Label = Label_1 = (function (_super) {
         __extends(Label, _super);
         function Label(settings) {
-            var _this = this;
+            var _this;
             if (!settings) {
                 settings = {};
             }
@@ -19647,7 +19647,7 @@ var BABYLON;
     var DefaultLabelRenderingTemplate = DefaultLabelRenderingTemplate_1 = (function (_super) {
         __extends(DefaultLabelRenderingTemplate, _super);
         function DefaultLabelRenderingTemplate() {
-            return _super !== null && _super.apply(this, arguments) || this;
+            return _super.apply(this, arguments) || this;
         }
         DefaultLabelRenderingTemplate.prototype.createVisualTree = function (owner, visualPlaceholder) {
             var r = new BABYLON.Text2D("", { parent: visualPlaceholder });
@@ -19680,7 +19680,7 @@ var BABYLON;
     var Button = Button_1 = (function (_super) {
         __extends(Button, _super);
         function Button(settings) {
-            var _this = this;
+            var _this;
             if (!settings) {
                 settings = {};
             }
@@ -19834,7 +19834,7 @@ var BABYLON;
     var DefaultButtonRenderingTemplate = DefaultButtonRenderingTemplate_1 = (function (_super) {
         __extends(DefaultButtonRenderingTemplate, _super);
         function DefaultButtonRenderingTemplate() {
-            return _super !== null && _super.apply(this, arguments) || this;
+            return _super.apply(this, arguments) || this;
         }
         DefaultButtonRenderingTemplate.prototype.createVisualTree = function (owner, visualPlaceholder) {
             this._rect = new BABYLON.Rectangle2D({ parent: visualPlaceholder, fill: "#FF8080FF", border: "#FF8080FF", roundRadius: 10, borderThickness: 2 });

File diff suppressed because it is too large
+ 9 - 9
dist/preview release/canvas2D/babylon.canvas2d.min.js


+ 248 - 248
dist/preview release/inspector/babylon.inspector.bundle.js

@@ -65,8 +65,8 @@ var INSPECTOR =
 	if(false) {
 		// When the styles change, update the <style> tags
 		if(!content.locals) {
-			module.hot.accept("!!../../../Tools/Gulp/node_modules/css-loader/index.js!./babylon.inspector.css", function() {
-				var newContent = require("!!../../../Tools/Gulp/node_modules/css-loader/index.js!./babylon.inspector.css");
+			module.hot.accept("!!./../../../Tools/Gulp/node_modules/css-loader/index.js!./babylon.inspector.css", function() {
+				var newContent = require("!!./../../../Tools/Gulp/node_modules/css-loader/index.js!./babylon.inspector.css");
 				if(typeof newContent === 'string') newContent = [[module.id, newContent, '']];
 				update(newContent);
 			});
@@ -150,252 +150,252 @@ var INSPECTOR =
 /* 4 */
 /***/ function(module, exports, __webpack_require__) {
 
-	/*
-		MIT License http://www.opensource.org/licenses/mit-license.php
-		Author Tobias Koppers @sokra
-	*/
-	var stylesInDom = {},
-		memoize = function(fn) {
-			var memo;
-			return function () {
-				if (typeof memo === "undefined") memo = fn.apply(this, arguments);
-				return memo;
-			};
-		},
-		isOldIE = memoize(function() {
-			return /msie [6-9]\b/.test(self.navigator.userAgent.toLowerCase());
-		}),
-		getHeadElement = memoize(function () {
-			return document.head || document.getElementsByTagName("head")[0];
-		}),
-		singletonElement = null,
-		singletonCounter = 0,
-		styleElementsInsertedAtTop = [];
-
-	module.exports = function(list, options) {
-		if(false) {
-			if(typeof document !== "object") throw new Error("The style-loader cannot be used in a non-browser environment");
-		}
-
-		options = options || {};
-		// Force single-tag solution on IE6-9, which has a hard limit on the # of <style>
-		// tags it will allow on a page
-		if (typeof options.singleton === "undefined") options.singleton = isOldIE();
-
-		// By default, add <style> tags to the bottom of <head>.
-		if (typeof options.insertAt === "undefined") options.insertAt = "bottom";
-
-		var styles = listToStyles(list);
-		addStylesToDom(styles, options);
-
-		return function update(newList) {
-			var mayRemove = [];
-			for(var i = 0; i < styles.length; i++) {
-				var item = styles[i];
-				var domStyle = stylesInDom[item.id];
-				domStyle.refs--;
-				mayRemove.push(domStyle);
-			}
-			if(newList) {
-				var newStyles = listToStyles(newList);
-				addStylesToDom(newStyles, options);
-			}
-			for(var i = 0; i < mayRemove.length; i++) {
-				var domStyle = mayRemove[i];
-				if(domStyle.refs === 0) {
-					for(var j = 0; j < domStyle.parts.length; j++)
-						domStyle.parts[j]();
-					delete stylesInDom[domStyle.id];
-				}
-			}
-		};
-	}
-
-	function addStylesToDom(styles, options) {
-		for(var i = 0; i < styles.length; i++) {
-			var item = styles[i];
-			var domStyle = stylesInDom[item.id];
-			if(domStyle) {
-				domStyle.refs++;
-				for(var j = 0; j < domStyle.parts.length; j++) {
-					domStyle.parts[j](item.parts[j]);
-				}
-				for(; j < item.parts.length; j++) {
-					domStyle.parts.push(addStyle(item.parts[j], options));
-				}
-			} else {
-				var parts = [];
-				for(var j = 0; j < item.parts.length; j++) {
-					parts.push(addStyle(item.parts[j], options));
-				}
-				stylesInDom[item.id] = {id: item.id, refs: 1, parts: parts};
-			}
-		}
-	}
-
-	function listToStyles(list) {
-		var styles = [];
-		var newStyles = {};
-		for(var i = 0; i < list.length; i++) {
-			var item = list[i];
-			var id = item[0];
-			var css = item[1];
-			var media = item[2];
-			var sourceMap = item[3];
-			var part = {css: css, media: media, sourceMap: sourceMap};
-			if(!newStyles[id])
-				styles.push(newStyles[id] = {id: id, parts: [part]});
-			else
-				newStyles[id].parts.push(part);
-		}
-		return styles;
-	}
-
-	function insertStyleElement(options, styleElement) {
-		var head = getHeadElement();
-		var lastStyleElementInsertedAtTop = styleElementsInsertedAtTop[styleElementsInsertedAtTop.length - 1];
-		if (options.insertAt === "top") {
-			if(!lastStyleElementInsertedAtTop) {
-				head.insertBefore(styleElement, head.firstChild);
-			} else if(lastStyleElementInsertedAtTop.nextSibling) {
-				head.insertBefore(styleElement, lastStyleElementInsertedAtTop.nextSibling);
-			} else {
-				head.appendChild(styleElement);
-			}
-			styleElementsInsertedAtTop.push(styleElement);
-		} else if (options.insertAt === "bottom") {
-			head.appendChild(styleElement);
-		} else {
-			throw new Error("Invalid value for parameter 'insertAt'. Must be 'top' or 'bottom'.");
-		}
-	}
-
-	function removeStyleElement(styleElement) {
-		styleElement.parentNode.removeChild(styleElement);
-		var idx = styleElementsInsertedAtTop.indexOf(styleElement);
-		if(idx >= 0) {
-			styleElementsInsertedAtTop.splice(idx, 1);
-		}
-	}
-
-	function createStyleElement(options) {
-		var styleElement = document.createElement("style");
-		styleElement.type = "text/css";
-		insertStyleElement(options, styleElement);
-		return styleElement;
-	}
-
-	function createLinkElement(options) {
-		var linkElement = document.createElement("link");
-		linkElement.rel = "stylesheet";
-		insertStyleElement(options, linkElement);
-		return linkElement;
-	}
-
-	function addStyle(obj, options) {
-		var styleElement, update, remove;
-
-		if (options.singleton) {
-			var styleIndex = singletonCounter++;
-			styleElement = singletonElement || (singletonElement = createStyleElement(options));
-			update = applyToSingletonTag.bind(null, styleElement, styleIndex, false);
-			remove = applyToSingletonTag.bind(null, styleElement, styleIndex, true);
-		} else if(obj.sourceMap &&
-			typeof URL === "function" &&
-			typeof URL.createObjectURL === "function" &&
-			typeof URL.revokeObjectURL === "function" &&
-			typeof Blob === "function" &&
-			typeof btoa === "function") {
-			styleElement = createLinkElement(options);
-			update = updateLink.bind(null, styleElement);
-			remove = function() {
-				removeStyleElement(styleElement);
-				if(styleElement.href)
-					URL.revokeObjectURL(styleElement.href);
-			};
-		} else {
-			styleElement = createStyleElement(options);
-			update = applyToTag.bind(null, styleElement);
-			remove = function() {
-				removeStyleElement(styleElement);
-			};
-		}
-
-		update(obj);
-
-		return function updateStyle(newObj) {
-			if(newObj) {
-				if(newObj.css === obj.css && newObj.media === obj.media && newObj.sourceMap === obj.sourceMap)
-					return;
-				update(obj = newObj);
-			} else {
-				remove();
-			}
-		};
-	}
-
-	var replaceText = (function () {
-		var textStore = [];
-
-		return function (index, replacement) {
-			textStore[index] = replacement;
-			return textStore.filter(Boolean).join('\n');
-		};
-	})();
-
-	function applyToSingletonTag(styleElement, index, remove, obj) {
-		var css = remove ? "" : obj.css;
-
-		if (styleElement.styleSheet) {
-			styleElement.styleSheet.cssText = replaceText(index, css);
-		} else {
-			var cssNode = document.createTextNode(css);
-			var childNodes = styleElement.childNodes;
-			if (childNodes[index]) styleElement.removeChild(childNodes[index]);
-			if (childNodes.length) {
-				styleElement.insertBefore(cssNode, childNodes[index]);
-			} else {
-				styleElement.appendChild(cssNode);
-			}
-		}
-	}
-
-	function applyToTag(styleElement, obj) {
-		var css = obj.css;
-		var media = obj.media;
-
-		if(media) {
-			styleElement.setAttribute("media", media)
-		}
-
-		if(styleElement.styleSheet) {
-			styleElement.styleSheet.cssText = css;
-		} else {
-			while(styleElement.firstChild) {
-				styleElement.removeChild(styleElement.firstChild);
-			}
-			styleElement.appendChild(document.createTextNode(css));
-		}
-	}
-
-	function updateLink(linkElement, obj) {
-		var css = obj.css;
-		var sourceMap = obj.sourceMap;
-
-		if(sourceMap) {
-			// http://stackoverflow.com/a/26603875
-			css += "\n/*# sourceMappingURL=data:application/json;base64," + btoa(unescape(encodeURIComponent(JSON.stringify(sourceMap)))) + " */";
-		}
-
-		var blob = new Blob([css], { type: "text/css" });
-
-		var oldSrc = linkElement.href;
-
-		linkElement.href = URL.createObjectURL(blob);
-
-		if(oldSrc)
-			URL.revokeObjectURL(oldSrc);
-	}
+	/*
+		MIT License http://www.opensource.org/licenses/mit-license.php
+		Author Tobias Koppers @sokra
+	*/
+	var stylesInDom = {},
+		memoize = function(fn) {
+			var memo;
+			return function () {
+				if (typeof memo === "undefined") memo = fn.apply(this, arguments);
+				return memo;
+			};
+		},
+		isOldIE = memoize(function() {
+			return /msie [6-9]\b/.test(window.navigator.userAgent.toLowerCase());
+		}),
+		getHeadElement = memoize(function () {
+			return document.head || document.getElementsByTagName("head")[0];
+		}),
+		singletonElement = null,
+		singletonCounter = 0,
+		styleElementsInsertedAtTop = [];
+
+	module.exports = function(list, options) {
+		if(false) {
+			if(typeof document !== "object") throw new Error("The style-loader cannot be used in a non-browser environment");
+		}
+
+		options = options || {};
+		// Force single-tag solution on IE6-9, which has a hard limit on the # of <style>
+		// tags it will allow on a page
+		if (typeof options.singleton === "undefined") options.singleton = isOldIE();
+
+		// By default, add <style> tags to the bottom of <head>.
+		if (typeof options.insertAt === "undefined") options.insertAt = "bottom";
+
+		var styles = listToStyles(list);
+		addStylesToDom(styles, options);
+
+		return function update(newList) {
+			var mayRemove = [];
+			for(var i = 0; i < styles.length; i++) {
+				var item = styles[i];
+				var domStyle = stylesInDom[item.id];
+				domStyle.refs--;
+				mayRemove.push(domStyle);
+			}
+			if(newList) {
+				var newStyles = listToStyles(newList);
+				addStylesToDom(newStyles, options);
+			}
+			for(var i = 0; i < mayRemove.length; i++) {
+				var domStyle = mayRemove[i];
+				if(domStyle.refs === 0) {
+					for(var j = 0; j < domStyle.parts.length; j++)
+						domStyle.parts[j]();
+					delete stylesInDom[domStyle.id];
+				}
+			}
+		};
+	}
+
+	function addStylesToDom(styles, options) {
+		for(var i = 0; i < styles.length; i++) {
+			var item = styles[i];
+			var domStyle = stylesInDom[item.id];
+			if(domStyle) {
+				domStyle.refs++;
+				for(var j = 0; j < domStyle.parts.length; j++) {
+					domStyle.parts[j](item.parts[j]);
+				}
+				for(; j < item.parts.length; j++) {
+					domStyle.parts.push(addStyle(item.parts[j], options));
+				}
+			} else {
+				var parts = [];
+				for(var j = 0; j < item.parts.length; j++) {
+					parts.push(addStyle(item.parts[j], options));
+				}
+				stylesInDom[item.id] = {id: item.id, refs: 1, parts: parts};
+			}
+		}
+	}
+
+	function listToStyles(list) {
+		var styles = [];
+		var newStyles = {};
+		for(var i = 0; i < list.length; i++) {
+			var item = list[i];
+			var id = item[0];
+			var css = item[1];
+			var media = item[2];
+			var sourceMap = item[3];
+			var part = {css: css, media: media, sourceMap: sourceMap};
+			if(!newStyles[id])
+				styles.push(newStyles[id] = {id: id, parts: [part]});
+			else
+				newStyles[id].parts.push(part);
+		}
+		return styles;
+	}
+
+	function insertStyleElement(options, styleElement) {
+		var head = getHeadElement();
+		var lastStyleElementInsertedAtTop = styleElementsInsertedAtTop[styleElementsInsertedAtTop.length - 1];
+		if (options.insertAt === "top") {
+			if(!lastStyleElementInsertedAtTop) {
+				head.insertBefore(styleElement, head.firstChild);
+			} else if(lastStyleElementInsertedAtTop.nextSibling) {
+				head.insertBefore(styleElement, lastStyleElementInsertedAtTop.nextSibling);
+			} else {
+				head.appendChild(styleElement);
+			}
+			styleElementsInsertedAtTop.push(styleElement);
+		} else if (options.insertAt === "bottom") {
+			head.appendChild(styleElement);
+		} else {
+			throw new Error("Invalid value for parameter 'insertAt'. Must be 'top' or 'bottom'.");
+		}
+	}
+
+	function removeStyleElement(styleElement) {
+		styleElement.parentNode.removeChild(styleElement);
+		var idx = styleElementsInsertedAtTop.indexOf(styleElement);
+		if(idx >= 0) {
+			styleElementsInsertedAtTop.splice(idx, 1);
+		}
+	}
+
+	function createStyleElement(options) {
+		var styleElement = document.createElement("style");
+		styleElement.type = "text/css";
+		insertStyleElement(options, styleElement);
+		return styleElement;
+	}
+
+	function createLinkElement(options) {
+		var linkElement = document.createElement("link");
+		linkElement.rel = "stylesheet";
+		insertStyleElement(options, linkElement);
+		return linkElement;
+	}
+
+	function addStyle(obj, options) {
+		var styleElement, update, remove;
+
+		if (options.singleton) {
+			var styleIndex = singletonCounter++;
+			styleElement = singletonElement || (singletonElement = createStyleElement(options));
+			update = applyToSingletonTag.bind(null, styleElement, styleIndex, false);
+			remove = applyToSingletonTag.bind(null, styleElement, styleIndex, true);
+		} else if(obj.sourceMap &&
+			typeof URL === "function" &&
+			typeof URL.createObjectURL === "function" &&
+			typeof URL.revokeObjectURL === "function" &&
+			typeof Blob === "function" &&
+			typeof btoa === "function") {
+			styleElement = createLinkElement(options);
+			update = updateLink.bind(null, styleElement);
+			remove = function() {
+				removeStyleElement(styleElement);
+				if(styleElement.href)
+					URL.revokeObjectURL(styleElement.href);
+			};
+		} else {
+			styleElement = createStyleElement(options);
+			update = applyToTag.bind(null, styleElement);
+			remove = function() {
+				removeStyleElement(styleElement);
+			};
+		}
+
+		update(obj);
+
+		return function updateStyle(newObj) {
+			if(newObj) {
+				if(newObj.css === obj.css && newObj.media === obj.media && newObj.sourceMap === obj.sourceMap)
+					return;
+				update(obj = newObj);
+			} else {
+				remove();
+			}
+		};
+	}
+
+	var replaceText = (function () {
+		var textStore = [];
+
+		return function (index, replacement) {
+			textStore[index] = replacement;
+			return textStore.filter(Boolean).join('\n');
+		};
+	})();
+
+	function applyToSingletonTag(styleElement, index, remove, obj) {
+		var css = remove ? "" : obj.css;
+
+		if (styleElement.styleSheet) {
+			styleElement.styleSheet.cssText = replaceText(index, css);
+		} else {
+			var cssNode = document.createTextNode(css);
+			var childNodes = styleElement.childNodes;
+			if (childNodes[index]) styleElement.removeChild(childNodes[index]);
+			if (childNodes.length) {
+				styleElement.insertBefore(cssNode, childNodes[index]);
+			} else {
+				styleElement.appendChild(cssNode);
+			}
+		}
+	}
+
+	function applyToTag(styleElement, obj) {
+		var css = obj.css;
+		var media = obj.media;
+
+		if(media) {
+			styleElement.setAttribute("media", media)
+		}
+
+		if(styleElement.styleSheet) {
+			styleElement.styleSheet.cssText = css;
+		} else {
+			while(styleElement.firstChild) {
+				styleElement.removeChild(styleElement.firstChild);
+			}
+			styleElement.appendChild(document.createTextNode(css));
+		}
+	}
+
+	function updateLink(linkElement, obj) {
+		var css = obj.css;
+		var sourceMap = obj.sourceMap;
+
+		if(sourceMap) {
+			// http://stackoverflow.com/a/26603875
+			css += "\n/*# sourceMappingURL=data:application/json;base64," + btoa(unescape(encodeURIComponent(JSON.stringify(sourceMap)))) + " */";
+		}
+
+		var blob = new Blob([css], { type: "text/css" });
+
+		var oldSrc = linkElement.href;
+
+		linkElement.href = URL.createObjectURL(blob);
+
+		if(oldSrc)
+			URL.revokeObjectURL(oldSrc);
+	}
 
 
 /***/ },

File diff suppressed because it is too large
+ 1 - 1
dist/preview release/materialsLibrary/babylon.furMaterial.js


File diff suppressed because it is too large
+ 1 - 1
dist/preview release/materialsLibrary/babylon.furMaterial.min.js


+ 11 - 0
dist/preview release/proceduralTexturesLibrary/babylon.normalMapProceduralTexture.d.ts

@@ -0,0 +1,11 @@
+/// <reference path="../../../dist/preview release/babylon.d.ts" />
+declare module BABYLON {
+    class NormalMapProceduralTexture extends ProceduralTexture {
+        private _baseTexture;
+        constructor(name: string, size: number, scene: Scene, fallbackTexture?: Texture, generateMipMaps?: boolean);
+        updateShaderUniforms(): void;
+        render(useCameraPostProcess?: boolean): void;
+        resize(size: any, generateMipMaps: any): void;
+        baseTexture: Texture;
+    }
+}

File diff suppressed because it is too large
+ 46 - 0
dist/preview release/proceduralTexturesLibrary/babylon.normalMapProceduralTexture.js


File diff suppressed because it is too large
+ 1 - 0
dist/preview release/proceduralTexturesLibrary/babylon.normalMapProceduralTexture.min.js


+ 8 - 0
dist/preview release/proceduralTexturesLibrary/babylon.waterProceduralTexture.d.ts

@@ -0,0 +1,8 @@
+/// <reference path="../../../dist/preview release/babylon.d.ts" />
+declare module BABYLON {
+    class WaterProceduralTexture extends ProceduralTexture {
+        private _time;
+        constructor(name: string, size: number, scene: Scene, fallbackTexture?: Texture, generateMipMaps?: boolean);
+        render(useCameraPostProcess?: boolean): void;
+    }
+}

File diff suppressed because it is too large
+ 28 - 0
dist/preview release/proceduralTexturesLibrary/babylon.waterProceduralTexture.js


File diff suppressed because it is too large
+ 1 - 0
dist/preview release/proceduralTexturesLibrary/babylon.waterProceduralTexture.min.js


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

@@ -15,6 +15,8 @@
  - Multi-platform Compressed Textures for Desktops & Mobile Devices with fall back.  Batch (dos) scripts to convert entire directories of .jpg's & .png's ([jcpalmer](https://github.com/Palmer-JC))
 
 ### Updates
+- Added `Light.customProjectionMatrixBuilder` to allow developers to define their own projection matrix for shadows ([deltakosh](https://github.com/deltakosh))
+- Added `set()` function to all basic types ([deltakosh](https://github.com/deltakosh))
 - Added `HDRCubeTextureAssetTask` to AssetManager ([deltakosh](https://github.com/deltakosh))
 - Engine now uses range based fog ([deltakosh](https://github.com/deltakosh))
 - `VertexBuffer.updatable` is now serialized ([deltakosh](https://github.com/deltakosh))

+ 9 - 1
proceduralTexturesLibrary/index.html

@@ -49,6 +49,7 @@
 	<script src="test/addBrickPT.js"></script>
 	<script src="test/addMarblePT.js"></script>
 	<script src="test/addStarfieldPT.js"></script>
+	<script src="test/addNormalMapPT.js"></script>
 	<script>
 		BABYLONDEVTOOLS.Loader.load(function() {
 		if (BABYLON.Engine.isSupported()) {
@@ -186,6 +187,10 @@
 				
 				// Starfield Procedural Texture
                 var starfieldPT = addStarfieldPT();
+
+				// Normal Map Procedural Texture
+				var normalMapPT = addNormalMapPT();
+				normalMapPT.baseTexture = diffuseTexture;
 								
 				// Default to std
 				var currentTexture = diffuseTexture;
@@ -302,7 +307,7 @@
 					}
 				}
 				
-				gui.add(options, 'texture', ['default', 'fire', 'wood', 'cloud', 'grass', 'road', 'brick', 'marble', 'starfield']).onFinishChange(function () {
+				gui.add(options, 'texture', ['default', 'fire', 'wood', 'cloud', 'grass', 'road', 'brick', 'marble', 'starfield', 'normalMap']).onFinishChange(function () {
 					resetPTOptions();
 					switch (options.texture) {
 						case "fire":
@@ -337,6 +342,9 @@
 							currentTexture = starfieldPT;
 							addPToptions(starfieldPT, ['saturation', 'distfading', 'darkmatter', 'alpha', 'time', 'beta', 'zoom', 'formuparam', 'stepsize', 'tile', 'brightness']);
 							break;
+						case "normalMap":
+							currentTexture = normalMapPT;
+							break;
 						case "none":
 						default:
 							currentTexture = diffuseTexture;

+ 37 - 0
proceduralTexturesLibrary/src/normalMap/babylon.normalMapProceduralTexture.ts

@@ -0,0 +1,37 @@
+/// <reference path="../../../dist/preview release/babylon.d.ts"/>
+
+module BABYLON {
+    export class NormalMapProceduralTexture extends ProceduralTexture {
+        private _baseTexture: Texture;
+
+        constructor(name: string, size: number, scene: Scene, fallbackTexture?: Texture, generateMipMaps?: boolean) {
+            super(name, size, "normalMapProceduralTexture", scene, fallbackTexture, generateMipMaps);
+            this.updateShaderUniforms();
+        }
+
+        public updateShaderUniforms() {
+            this.setTexture("baseSampler", this._baseTexture);
+            this.setFloat("size", this.getRenderSize());
+        }
+
+        public render(useCameraPostProcess?: boolean) {
+            super.render(useCameraPostProcess);
+        }
+
+        public resize(size: any, generateMipMaps: any): void {
+            super.resize(size, generateMipMaps);
+
+            // We need to update the "size" uniform
+            this.updateShaderUniforms();
+        }
+
+        public get baseTexture(): Texture {
+            return this._baseTexture;
+        }
+
+        public set baseTexture(texture: Texture) {
+            this._baseTexture = texture;
+            this.updateShaderUniforms();
+        }
+    }
+}

+ 30 - 0
proceduralTexturesLibrary/src/normalMap/normalMapProceduralTexture.fragment.fx

@@ -0,0 +1,30 @@
+precision highp float;
+
+// Uniforms
+uniform sampler2D baseSampler;
+uniform float size;
+
+// Varyings
+varying vec2 vUV;
+
+// Constants
+const vec3 LUMA_COEFFICIENT = vec3(0.2126, 0.7152, 0.0722);
+
+float lumaAtCoord(vec2 coord)
+{
+	vec3 pixel = texture2D(baseSampler, coord).rgb;
+	float luma = dot(pixel, LUMA_COEFFICIENT);
+	return luma;
+}
+
+void main()
+{
+	float lumaU0 = lumaAtCoord(vUV + vec2(-1.0,  0.0) / size);
+	float lumaU1 = lumaAtCoord(vUV + vec2( 1.0,  0.0) / size);
+	float lumaV0 = lumaAtCoord(vUV + vec2( 0.0, -1.0) / size);
+	float lumaV1 = lumaAtCoord(vUV + vec2( 0.0,  1.0) / size);
+
+	vec2 slope = (vec2(lumaU0 - lumaU1, lumaV0 - lumaV1) + 1.0) * 0.5;
+
+	gl_FragColor = vec4(slope, 1.0, 1.0);
+}

+ 6 - 0
proceduralTexturesLibrary/test/addNormalMapPT.js

@@ -0,0 +1,6 @@
+window.addNormalMapPT = function() {
+    // 128 = the size of the base texture which is "amiga" here
+    var nm = new BABYLON.NormalMapProceduralTexture("normalMapPT", 128, scene);
+
+    return nm;
+};

+ 3 - 9
readme.md

@@ -14,15 +14,9 @@ Getting started? Play directly with the Babylon.js API via our [playground](http
 - http://cdn.babylonjs.com/2-5/babylon.core.js 
 
 ## Preview release
-You can help by testing or contributing to the next version.
-- **3.0-alpha** can be found [here](https://github.com/BabylonJS/Babylon.js/tree/master/dist/preview%20release)
-- We are not complicated people, but we still have some [coding guidelines](http://doc.babylonjs.com/generals/Approved_Naming_Conventions)
-- Before submitting your PR, just check that everything goes well by [creating the minified version](http://doc.babylonjs.com/generals/Creating_the_Mini-fied_Version)
-- Need help contributing, here are some links:
-  - [Gulp](https://github.com/BabylonJS/Babylon.js/tree/master/Tools/Gulp) to build from command line.
-  - [VSCode Editor](https://code.visualstudio.com/), Microsoft Code editor, see [Julian Chenard's post](http://pixelcodr.com/tutos/contribute/contribute.html) a Microsoft code editor.
-  - [Visual Studio](http://doc.babylonjs.com/generals/setup_visualStudio), Microsoft's IDE.
-  - [Forum thread](http://www.html5gamedevs.com/topic/20456-contributing-on-babylonjs/) for assistance from our very helpful family.
+
+**3.0-alpha** can be found [here](https://github.com/BabylonJS/Babylon.js/tree/master/dist/preview%20release)
+If you want to contribute, please read our [contribution guidelines](https://github.com/BabylonJS/Babylon.js/blob/master/contributing.md) first.
 
 ## Documentation
 - [Documentation](http://doc.babylonjs.com)

+ 432 - 180
src/Bones/babylon.boneLookController.ts

@@ -3,114 +3,167 @@ module BABYLON {
 
         private static _tmpVecs: Vector3[] = [Vector3.Zero(), Vector3.Zero(), Vector3.Zero(),Vector3.Zero(), Vector3.Zero(), Vector3.Zero(), Vector3.Zero(), Vector3.Zero(), Vector3.Zero(), Vector3.Zero()];
         private static _tmpQuat = Quaternion.Identity();
-        private static _tmpMat1 = Matrix.Identity();
-        private static _tmpMat2 = Matrix.Identity();
-
+        private static _tmpMats: Matrix[] = [Matrix.Identity(), Matrix.Identity(), Matrix.Identity(), Matrix.Identity(), Matrix.Identity()];
+        
+        /**
+         * The target Vector3 that the bone will look at.
+         */
         public target: Vector3;
+
+        /**
+         * The mesh that the bone is attached to.
+         */
         public mesh: AbstractMesh;
+
+        /**
+         * The bone that will be looking to the target.
+         */
         public bone: Bone;
+
+        /**
+         * The up axis of the coordinate system that is used when the bone is rotated.
+         */
         public upAxis: Vector3 = Vector3.Up();
+
+        /**
+         * The space that the up axis is in - BABYLON.Space.BONE, BABYLON.Space.LOCAL (default), or BABYLON.Space.WORLD.
+         */
+        public upAxisSpace: Space = Space.LOCAL;
+
+        /**
+         * Used to make an adjustment to the yaw of the bone.
+         */
+        public adjustYaw = 0;
+
+        /**
+         * Used to make an adjustment to the pitch of the bone.
+         */
+        public adjustPitch = 0;
+
+        /**
+         * Used to make an adjustment to the roll of the bone.
+         */
+        public adjustRoll = 0;
+
+        /**
+         * The amount to slerp (spherical linear interpolation) to the target.  Set this to a value between 0 and 1 (a value of 1 disables slerp).
+         */
         public slerpAmount = 1;
 
-        private _adjustRotY = 0;
-        private _adjustRotX = 0;
-        private _adjustRotZ = 0;
-        private _minRotY:number;
-        private _maxRotY:number;
-        private _minRotX:number;
-        private _maxRotX:number;
-        private _minRotYSin:number;
-        private _minRotYCos:number;
-        private _maxRotYSin:number;
-        private _maxRotYCos:number;
-        private _minRotXTan:number;
-        private _maxRotXTan:number;
-        private _minRotZ:number;
-        private _maxRotZ:number;
-        private _minRotZSin:number;
-        private _minRotZCos:number;
-        private _maxRotZSin:number;
-        private _maxRotZCos:number;
+        private _minYaw:number;
+        private _maxYaw:number;
+        private _minPitch:number;
+        private _maxPitch:number;
+        private _minYawSin:number;
+        private _minYawCos:number;
+        private _maxYawSin:number;
+        private _maxYawCos:number;
+        private _midYawConstraint:number;
+        private _minPitchTan:number;
+        private _maxPitchTan:number;
+        
         private _boneQuat:Quaternion = Quaternion.Identity();
         private _slerping = false;
-
-        get minRotationY():number{
-            return this._minRotY - this._adjustRotY;
-        }
-
-        set minRotationY(value:number){
-            this._minRotY = value + this._adjustRotY;
-            this._minRotYSin = Math.sin(this._minRotY);
-            this._minRotYCos = Math.cos(this._minRotY);
-        }
-
-        get maxRoationY():number{
-            return this._maxRotY - this._adjustRotY;
-        }
-
-        set maxRotationY(value:number){
-            this._maxRotY = value + this._adjustRotY;
-            this._maxRotYSin = Math.sin(this._maxRotY);
-            this._maxRotYCos = Math.cos(this._maxRotY);
-        }
-
-        get minRotationX():number{
-            return this._minRotX - this._adjustRotX;
+        private _transformYawPitch:Matrix;
+        private _transformYawPitchInv:Matrix;
+        private _firstFrameSkipped = false;
+        private _yawRange:number;
+        private _fowardAxis: Vector3 = Vector3.Forward();
+
+        /**
+         * Get/set the minimum yaw angle that the bone can look to.
+         */
+        get minYaw():number{
+            return this._minYaw;
         }
 
-        set minRotationX(value:number){
-            this._minRotX = value + this._adjustRotX;
-            this._minRotXTan = Math.tan(this._minRotX);
+        set minYaw(value:number){
+            this._minYaw = value;
+            this._minYawSin = Math.sin(value);
+            this._minYawCos = Math.cos(value);
+            if(this._maxYaw != null){
+                this._midYawConstraint = this._getAngleDiff(this._minYaw, this._maxYaw)*.5 + this._minYaw;
+                this._yawRange = this._maxYaw - this._minYaw;
+            }
         }
 
-        get maxRotationX():number{
-            return this._maxRotX - this._adjustRotX;
+        /**
+         * Get/set the maximum yaw angle that the bone can look to.
+         */
+        get maxYaw():number{
+            return this._maxYaw;
         }
 
-        set maxRotationX(value:number){
-            this._maxRotX = value + this._adjustRotX;
-            this._maxRotXTan = Math.tan(this._maxRotX);
+        set maxYaw(value:number){
+            this._maxYaw = value;
+            this._maxYawSin = Math.sin(value);
+            this._maxYawCos = Math.cos(value);
+            if(this._minYaw != null){
+                this._midYawConstraint = this._getAngleDiff(this._minYaw, this._maxYaw)*.5 + this._minYaw;
+                this._yawRange = this._maxYaw - this._minYaw;
+            }
         }
 
-        get minRotationZ():number{
-            return this._minRotZ - this._adjustRotZ;
+        /**
+         * Get/set the minimum pitch angle that the bone can look to.
+         */
+        get minPitch():number{
+            return this._minPitch;
         }
 
-        set minRotationZ(value:number){
-            this._minRotZ = value + this._adjustRotZ;
-            this._minRotZSin = Math.sin(this._minRotZ);
-            this._minRotZCos = Math.cos(this._minRotZ);
+        set minPitch(value:number){
+            this._minPitch = value;
+            this._minPitchTan = Math.tan(value);
         }
 
-        get maxRotationZ():number{
-            return this._maxRotZ - this._adjustRotZ;
+        /**
+         * Get/set the maximum pitch angle that the bone can look to.
+         */
+        get maxPitch():number{
+            return this._maxPitch;
         }
 
-        set maxRotationZ(value:number){
-            this._maxRotZ = value + this._adjustRotZ;
-            this._maxRotZSin = Math.sin(this._maxRotZ);
-            this._maxRotZCos = Math.cos(this._maxRotZ);
+        set maxPitch(value:number){
+            this._maxPitch = value;
+            this._maxPitchTan = Math.tan(value);
         }
 
+        /**
+         * Create a BoneLookController
+         * @param mesh the mesh that the bone belongs to
+         * @param bone the bone that will be looking to the target
+         * @param target the target Vector3 to look at
+         * @param settings optional settings:
+         * - maxYaw: the maximum angle the bone will yaw to
+         * - minYaw: the minimum angle the bone will yaw to
+         * - maxPitch: the maximum angle the bone will pitch to
+         * - minPitch: the minimum angle the bone will yaw to
+         * - slerpAmount: set the between 0 and 1 to make the bone slerp to the target.
+         * - upAxis: the up axis of the coordinate system
+         * - upAxisSpace: the space that the up axis is in - BABYLON.Space.BONE, BABYLON.Space.LOCAL (default), or BABYLON.Space.WORLD.
+         * - yawAxis: set yawAxis if the bone does not yaw on the y axis
+         * - pitchAxis: set pitchAxis if the bone does not pitch on the x axis
+         * - adjustYaw: used to make an adjustment to the yaw of the bone
+         * - adjustPitch: used to make an adjustment to the pitch of the bone
+         * - adjustRoll: used to make an adjustment to the roll of the bone
+         **/
         constructor(mesh: AbstractMesh, 
                     bone: Bone, 
                     target: Vector3, 
-                    options?: { 
-                        adjustRotationX?: number, 
-                        adjustRotationY?: number, 
-                        adjustRotationZ?: number, 
-                        slerpAmount?: number, 
-                        maxRotationY?:number, 
-                        minRotationY?:number,
-                        maxRotationX?:number, 
-                        minRotationX?:number,
-                        maxRotationZ?:number, 
-                        minRotationZ?:number,
+                    options?: {
                         adjustYaw?: number, 
                         adjustPitch?: number, 
-                        adjustRoll?: number 
-                    } 
-                    ){
+                        adjustRoll?: number, 
+                        slerpAmount?: number, 
+                        maxYaw?:number, 
+                        minYaw?:number, 
+                        maxPitch?:number, 
+                        minPitch?:number,
+                        upAxis?:Vector3,
+                        upAxisSpace?:Space,
+                        yawAxis?:Vector3,
+                        pitchAxis?:Vector3
+                    }){
 
             this.mesh = mesh;
             this.bone = bone;
@@ -119,158 +172,292 @@ module BABYLON {
             if(options){
 
                 if(options.adjustYaw){
-                    this._adjustRotY = options.adjustYaw;
+                    this.adjustYaw = options.adjustYaw;
                 }
 
                 if(options.adjustPitch){
-                    this._adjustRotX = options.adjustPitch;
+                    this.adjustPitch = options.adjustPitch;
                 }
 
                 if(options.adjustRoll){
-                    this._adjustRotZ = options.adjustRoll;
+                    this.adjustRoll = options.adjustRoll;
                 }
 
-                if(options.adjustRotationY){
-                    this._adjustRotY = options.adjustRotationY;
+                if(options.maxYaw != null){
+                    this.maxYaw = options.maxYaw;
+                }else{
+                    this.maxYaw = Math.PI;
                 }
 
-                if(options.adjustRotationX){
-                    this._adjustRotX = options.adjustRotationX;
+                if(options.minYaw != null){
+                    this.minYaw = options.minYaw;
+                }else{
+                    this.minYaw = -Math.PI;
                 }
 
-                if(options.adjustRotationZ){
-                    this._adjustRotZ = options.adjustRotationZ;
+                if(options.maxPitch != null){
+                    this.maxPitch = options.maxPitch;
+                }else{
+                    this.maxPitch = Math.PI;
                 }
 
-                if(options.maxRotationY != undefined){
-                    this.maxRotationY = options.maxRotationY;
+                if(options.minPitch != null){
+                    this.minPitch = options.minPitch;
+                }else{
+                    this.minPitch = -Math.PI;
                 }
 
-                if(options.minRotationY != undefined){
-                    this.minRotationY = options.minRotationY;
+                if(options.slerpAmount != null){
+                    this.slerpAmount = options.slerpAmount;
                 }
 
-                if(options.maxRotationX != undefined){
-                    this.maxRotationX = options.maxRotationX;
+                if(options.upAxis != null){
+                    this.upAxis = options.upAxis;
                 }
 
-                if(options.minRotationX != undefined){
-                    this.minRotationX = options.minRotationX;
+                if(options.upAxisSpace != null){
+                    this.upAxisSpace = options.upAxisSpace;
                 }
 
-                if(options.maxRotationZ != undefined){
-                    this.maxRotationZ = options.maxRotationZ;
-                }
+                if(options.yawAxis != null || options.pitchAxis != null){
 
-                if(options.minRotationZ != undefined){
-                    this.minRotationZ = options.minRotationZ;
-                }
+                    var newYawAxis = Axis.Y;
+                    var newPitchAxis = Axis.X;
 
-                if(options.slerpAmount != undefined){
-                    this.slerpAmount = options.slerpAmount;
+                    if(options.yawAxis != null){
+                        newYawAxis = options.yawAxis.clone();
+                        newYawAxis.normalize();
+                    }
+
+                    if(options.pitchAxis != null){
+                        newPitchAxis = options.pitchAxis.clone();
+                        newPitchAxis.normalize();
+                    }
+
+                    var newRollAxis = Vector3.Cross(newPitchAxis, newYawAxis);
+
+                    this._transformYawPitch = Matrix.Identity();
+                    Matrix.FromXYZAxesToRef(newPitchAxis, newYawAxis, newRollAxis, this._transformYawPitch);
+
+                    this._transformYawPitchInv = this._transformYawPitch.clone();
+                    this._transformYawPitch.invert();
+                    
                 }
 
             }
 
+            if(!bone.getParent() && this.upAxisSpace == Space.BONE){
+                this.upAxisSpace = Space.LOCAL;
+            }
+
         }
 
+        /**
+         * Update the bone to look at the target.  This should be called before the scene is rendered (use scene.registerBeforeRender()).
+         */
         public update (): void {
-                
+
+            //skip the first frame when slerping so that the mesh rotation is correct
+            if(this.slerpAmount < 1 && !this._firstFrameSkipped){
+                this._firstFrameSkipped = true;
+                return;
+            }
+
             var bone = this.bone;
-            var target = this.target;
-            var mat1 = BoneLookController._tmpMat1;
-            var mat2 = BoneLookController._tmpMat2;
+            var bonePos = BoneLookController._tmpVecs[0];
+            bone.getAbsolutePositionToRef(this.mesh, bonePos);
 
+            var target = this.target;
+            var _tmpMat1 = BoneLookController._tmpMats[0];
+            var _tmpMat2 = BoneLookController._tmpMats[1];
+            
+            var mesh = this.mesh;
             var parentBone = bone.getParent();
 
-            if(parentBone){
-                if(this._maxRotX != undefined || this._minRotX != undefined){
-                    var localTarget = BoneLookController._tmpVecs[4];
-                    var _tmpVec5 = BoneLookController._tmpVecs[5];
-                    parentBone.getLocalPositionFromAbsoluteToRef(target, this.mesh, localTarget);
-                    bone.getPositionToRef(Space.LOCAL, null, _tmpVec5);
-                    localTarget.x -= _tmpVec5.x;
-                    localTarget.y -= _tmpVec5.y;
-                    localTarget.z -= _tmpVec5.z;
-                    var xzlen = Math.sqrt(localTarget.x*localTarget.x + localTarget.z*localTarget.z);
-                    var rotX = Math.atan2(localTarget.y, xzlen);
-
-                    if(rotX > this._maxRotX){
-                        localTarget.y = this._maxRotXTan*xzlen + _tmpVec5.y;
-                        parentBone.getAbsolutePositionFromLocalToRef(localTarget, this.mesh, localTarget);
-                        target = localTarget;
-                    }else if(rotX < this._minRotX){
-                        localTarget.y = this._minRotXTan*xzlen + _tmpVec5.y;
-                        parentBone.getAbsolutePositionFromLocalToRef(localTarget, this.mesh, localTarget);
-                        target = localTarget;
-                    }
+            var upAxis = BoneLookController._tmpVecs[1];
+            upAxis.copyFrom(this.upAxis);
+
+            if(this.upAxisSpace == Space.BONE){
+                if (this._transformYawPitch){
+                    Vector3.TransformCoordinatesToRef(upAxis, this._transformYawPitchInv, upAxis);
                 }
+                parentBone.getDirectionToRef(upAxis, this.mesh, upAxis);
+            }else if(this.upAxisSpace == Space.LOCAL){
+                mesh.getDirectionToRef(upAxis, upAxis);
+                if(mesh.scaling.x != 1 || mesh.scaling.y != 1 || mesh.scaling.z != 1){
+                    upAxis.normalize();
+                }
+            }
+
+            var checkYaw = false;
+            var checkPitch = false;
+
+            if(this._maxYaw != Math.PI || this._minYaw != -Math.PI){
+                checkYaw = true;
+            }
+            if(this._maxPitch != Math.PI || this._minPitch != -Math.PI){
+                checkPitch = true;
+            }
 
-                if(this._maxRotY != undefined || this._minRotY != undefined){
-                    var localTarget = BoneLookController._tmpVecs[6];
-                    var _tmpVec7 = BoneLookController._tmpVecs[7];
-                    parentBone.getLocalPositionFromAbsoluteToRef(target, this.mesh, localTarget);
-                    bone.getPositionToRef(Space.LOCAL, null, _tmpVec7);
-                    localTarget.x -= _tmpVec7.x;
-                    localTarget.z -= _tmpVec7.z;
-                    var rotY = Math.atan2(localTarget.x, localTarget.z);
+            if(checkYaw || checkPitch){
+
+                var _tmpMat3 = BoneLookController._tmpMats[2];
+                var _tmpMat3Inv = BoneLookController._tmpMats[3];
+
+                if(this.upAxisSpace == Space.BONE && upAxis.y == 1){
+
+                    parentBone.getRotationMatrixToRef(Space.WORLD, this.mesh, _tmpMat3);
                     
-                    if(rotY > this._maxRotY){
-                        var xzlen = Math.sqrt(localTarget.x*localTarget.x + localTarget.z*localTarget.z);
-                        localTarget.z = this._maxRotYCos*xzlen;
-                        localTarget.x = this._maxRotYSin*xzlen;
-                        parentBone.getAbsolutePositionFromLocalToRef(localTarget, this.mesh, localTarget);
-                        target = localTarget;
-                    }else if(rotY < this._minRotY){
-                        var xzlen = Math.sqrt(localTarget.x*localTarget.x + localTarget.z*localTarget.z);
-                        localTarget.z = this._minRotYCos*xzlen;
-                        localTarget.x = this._minRotYSin*xzlen;
-                        parentBone.getAbsolutePositionFromLocalToRef(localTarget, this.mesh, localTarget);
-                        target = localTarget;
+                }else if(this.upAxisSpace == Space.LOCAL && upAxis.y == 1 && !parentBone){
+
+                    _tmpMat3.copyFrom(mesh.getWorldMatrix());
+
+                }else{
+
+                    var forwardAxis = BoneLookController._tmpVecs[2];
+                    forwardAxis.copyFrom(this._fowardAxis);
+                    
+                    if (this._transformYawPitch) {
+                        Vector3.TransformCoordinatesToRef(forwardAxis, this._transformYawPitchInv, forwardAxis);
+                    }
+
+                    if(parentBone){
+                        parentBone.getDirectionToRef(forwardAxis, this.mesh, forwardAxis);
+                    }else{
+                        mesh.getDirectionToRef(forwardAxis, forwardAxis);
                     }
+
+                    var rightAxis = Vector3.Cross(upAxis, forwardAxis);
+                    rightAxis.normalize();
+                    var forwardAxis = Vector3.Cross(rightAxis, upAxis);
+
+                    Matrix.FromXYZAxesToRef(rightAxis, upAxis, forwardAxis, _tmpMat3);
+                    
                 }
 
-                if(this._maxRotZ != undefined || this._minRotZ != undefined){
-                    var localTarget = BoneLookController._tmpVecs[8];
-                    var _tmpVec9 = BoneLookController._tmpVecs[9];
-                    parentBone.getLocalPositionFromAbsoluteToRef(target, this.mesh, localTarget);
-                    bone.getPositionToRef(Space.LOCAL, null, _tmpVec9);
-                    localTarget.x -= _tmpVec9.x;
-                    localTarget.y -= _tmpVec9.y;
-                    var rotZ = Math.atan2(localTarget.y, localTarget.x);
+                _tmpMat3.invertToRef(_tmpMat3Inv);
+                
+                var xzlen:number;
+
+                if(checkPitch){
+                    var localTarget = BoneLookController._tmpVecs[3];
+                    Vector3.TransformCoordinatesToRef(target.subtract(bonePos), _tmpMat3Inv, localTarget);
+
+                    var xzlen = Math.sqrt(localTarget.x * localTarget.x + localTarget.z * localTarget.z);
+                    var pitch = Math.atan2(localTarget.y, xzlen);
+                    var newPitch = pitch;
+
+                    if(pitch > this._maxPitch){
+                        localTarget.y = this._maxPitchTan*xzlen;
+                        newPitch = this._maxPitch;
+                    }else if(pitch < this._minPitch){
+                        localTarget.y = this._minPitchTan*xzlen;
+                        newPitch = this._minPitch;
+                    }
                     
-                    if(rotZ > this._maxRotZ){
-                        var xylen = Math.sqrt(localTarget.x*localTarget.x + localTarget.y*localTarget.y);
-                        localTarget.x = this._maxRotZCos*xylen;
-                        localTarget.y = this._maxRotZSin*xylen;
-                        parentBone.getAbsolutePositionFromLocalToRef(localTarget, this.mesh, localTarget);
-                        target = localTarget;
-                    }else if(rotZ < this._minRotZ){
-                        var xylen = Math.sqrt(localTarget.x*localTarget.x + localTarget.y*localTarget.y);
-                        localTarget.x = this._minRotZCos*xylen;
-                        localTarget.y = this._minRotZSin*xylen;
-                        parentBone.getAbsolutePositionFromLocalToRef(localTarget, this.mesh, localTarget);
+                    if(pitch != newPitch){
+                        Vector3.TransformCoordinatesToRef(localTarget, _tmpMat3, localTarget);
+                        localTarget.addInPlace(bonePos);
                         target = localTarget;
                     }
                 }
 
+                if(checkYaw){
+                    var localTarget = BoneLookController._tmpVecs[4];
+                    Vector3.TransformCoordinatesToRef(target.subtract(bonePos), _tmpMat3Inv, localTarget);
+
+                    var yaw = Math.atan2(localTarget.x, localTarget.z);
+                    var newYaw = yaw;
+
+                    if(yaw > this._maxYaw || yaw < this._minYaw){
+                        
+                        if(xzlen == null){
+                            xzlen = Math.sqrt(localTarget.x * localTarget.x + localTarget.z * localTarget.z);
+                        }
+
+                        if(this._yawRange > Math.PI){
+                            if (this._isAngleBetween(yaw, this._maxYaw, this._midYawConstraint)) {
+                                localTarget.z = this._maxYawCos * xzlen;
+                                localTarget.x = this._maxYawSin * xzlen;
+                                newYaw = this._maxYaw;
+                            }else if (this._isAngleBetween(yaw, this._midYawConstraint, this._minYaw)) {
+                                localTarget.z = this._minYawCos * xzlen;
+                                localTarget.x = this._minYawSin * xzlen;
+                                newYaw = this._minYaw;
+                            }
+                        }else{
+                            if (yaw > this._maxYaw) {
+                                localTarget.z = this._maxYawCos * xzlen;
+                                localTarget.x = this._maxYawSin * xzlen;
+                                newYaw = this._maxYaw;
+                            }else if (yaw < this._minYaw) {
+                                localTarget.z = this._minYawCos * xzlen;
+                                localTarget.x = this._minYawSin * xzlen;
+                                newYaw = this._minYaw;
+                            }
+                        }
+                    }
+
+                    if(this._slerping && this._yawRange > Math.PI){
+                        //are we going to be crossing into the min/max region
+                        var _tmpVec8 = BoneLookController._tmpVecs[8];
+                        _tmpVec8.copyFrom(Axis.Z);
+                        if (this._transformYawPitch) {
+                            Vector3.TransformCoordinatesToRef(_tmpVec8, this._transformYawPitchInv, _tmpVec8);
+                        }
+
+                        var boneRotMat = BABYLON.BoneLookController._tmpMats[4];
+                        this._boneQuat.toRotationMatrix(boneRotMat);
+                        this.mesh.getWorldMatrix().multiplyToRef(boneRotMat, boneRotMat);
+                        BABYLON.Vector3.TransformCoordinatesToRef(_tmpVec8, boneRotMat, _tmpVec8);
+                        BABYLON.Vector3.TransformCoordinatesToRef(_tmpVec8, _tmpMat3Inv, _tmpVec8);
+
+                        var boneYaw = Math.atan2(_tmpVec8.x, _tmpVec8.z);
+                        var ang1 = this._getAngleBetween(boneYaw, yaw);
+                        var ang2 = this._getAngleBetween(boneYaw, this._midYawConstraint);
+
+                        if(ang1 > ang2){
+
+                            if (xzlen == null) {
+                                xzlen = Math.sqrt(localTarget.x * localTarget.x + localTarget.z * localTarget.z);
+                            }
+
+                            var ang3 = this._getAngleBetween(boneYaw, this._maxYaw);
+                            var ang4 = this._getAngleBetween(boneYaw, this._minYaw);
+
+                            if(ang4 < ang3){
+                                newYaw = boneYaw+Math.PI*.75;
+                                localTarget.z = Math.cos(newYaw) * xzlen;
+                                localTarget.x = Math.sin(newYaw) * xzlen;
+                            }else{
+                                newYaw = boneYaw-Math.PI*.75;
+                                localTarget.z = Math.cos(newYaw) * xzlen;
+                                localTarget.x = Math.sin(newYaw) * xzlen;
+                            }
+                        }
+                    }
+
+                    if(yaw != newYaw){
+                        Vector3.TransformCoordinatesToRef(localTarget, _tmpMat3, localTarget);
+                        localTarget.addInPlace(bonePos);
+                        target = localTarget;
+                    }
+                }
 
             }
 
-            var bonePos = BoneLookController._tmpVecs[0];
-            var zaxis = BoneLookController._tmpVecs[1];
-            var xaxis = BoneLookController._tmpVecs[2];
-            var yaxis = BoneLookController._tmpVecs[3];
+            var zaxis = BoneLookController._tmpVecs[5];
+            var xaxis = BoneLookController._tmpVecs[6];
+            var yaxis = BoneLookController._tmpVecs[7];
             var _tmpQuat = BoneLookController._tmpQuat;
 
-            bone.getAbsolutePositionToRef(this.mesh, bonePos);
             target.subtractToRef(bonePos, zaxis);
             zaxis.normalize();
-            Vector3.CrossToRef(this.upAxis, zaxis, xaxis);
+            Vector3.CrossToRef(upAxis, zaxis, xaxis);
             xaxis.normalize();
             Vector3.CrossToRef(zaxis, xaxis, yaxis);
             yaxis.normalize();
-            Matrix.FromXYZAxesToRef(xaxis, yaxis, zaxis, mat1);
+            Matrix.FromXYZAxesToRef(xaxis, yaxis, zaxis, _tmpMat1);
 
             if(xaxis.x === 0 && xaxis.y === 0 && xaxis.z === 0){
                 return;
@@ -284,25 +471,90 @@ module BABYLON {
                 return;
             }
 
-            if (this._adjustRotY || this._adjustRotX || this._adjustRotZ) {
-                Matrix.RotationYawPitchRollToRef(this._adjustRotY, this._adjustRotX, this._adjustRotZ, mat2);
-                mat2.multiplyToRef(mat1, mat1);
+            if (this.adjustYaw || this.adjustPitch || this.adjustRoll) {
+                Matrix.RotationYawPitchRollToRef(this.adjustYaw, this.adjustPitch, this.adjustRoll, _tmpMat2);
+                _tmpMat2.multiplyToRef(_tmpMat1, _tmpMat1);
             }
 
             if (this.slerpAmount < 1) {
                 if (!this._slerping) {
                     this.bone.getRotationQuaternionToRef(Space.WORLD, this.mesh, this._boneQuat);
                 }
-                Quaternion.FromRotationMatrixToRef(mat1, _tmpQuat);
+                if(this._transformYawPitch){
+                    this._transformYawPitch.multiplyToRef(_tmpMat1, _tmpMat1);
+                }
+                Quaternion.FromRotationMatrixToRef(_tmpMat1, _tmpQuat);
                 Quaternion.SlerpToRef(this._boneQuat, _tmpQuat, this.slerpAmount, this._boneQuat);
+                
                 this.bone.setRotationQuaternion(this._boneQuat, Space.WORLD, this.mesh);
                 this._slerping = true;
             } else {
-                this.bone.setRotationMatrix(mat1, Space.WORLD, this.mesh);
+                if(this._transformYawPitch){
+                    this._transformYawPitch.multiplyToRef(_tmpMat1, _tmpMat1);
+                }
+                this.bone.setRotationMatrix(_tmpMat1, Space.WORLD, this.mesh);
                 this._slerping = false;
             }
 
         }
 
+        private _getAngleDiff(ang1, ang2):number {
+
+            var angDiff = ang2 - ang1;
+            angDiff %= Math.PI*2;
+            
+            if(angDiff > Math.PI){
+                angDiff -= Math.PI*2;
+            }else if (angDiff < -Math.PI){
+                angDiff += Math.PI*2;
+            }
+            
+            return angDiff;
+        }
+
+        private _getAngleBetween(ang1, ang2):number {
+
+            ang1 %= (2 * Math.PI);
+            ang1 = (ang1 < 0) ? ang1 + (2 * Math.PI) : ang1;
+
+            ang2 %= (2 * Math.PI);
+            ang2 = (ang2 < 0) ? ang2 + (2 * Math.PI) : ang2;
+
+            var ab = 0;
+
+            if(ang1 < ang2){
+                ab = ang2 - ang1;
+            }else{
+                ab = ang1 - ang2;
+            }
+
+            if(ab > Math.PI){
+                ab = Math.PI*2 - ab;
+            }
+
+            return ab;
+        }
+
+        private _isAngleBetween(ang, ang1, ang2):boolean {
+
+            ang %= (2 * Math.PI);
+            ang = (ang < 0) ? ang + (2 * Math.PI) : ang;
+            ang1 %= (2 * Math.PI);
+            ang1 = (ang1 < 0) ? ang1 + (2 * Math.PI) : ang1;
+            ang2 %= (2 * Math.PI);
+            ang2 = (ang2 < 0) ? ang2 + (2 * Math.PI) : ang2;
+
+            if(ang1 < ang2){
+                if(ang > ang1 && ang < ang2){
+                    return true;
+                }
+            }else{
+                if(ang > ang2 && ang < ang1){
+                    return true;
+                }
+            }
+            return false;
+        }
+
     }
 }

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

@@ -361,7 +361,7 @@
                 var serializedBone: any = {
                     parentBoneIndex: bone.getParent() ? this.bones.indexOf(bone.getParent()) : -1,
                     name: bone.name,
-                    matrix: bone.getLocalMatrix().toArray(),
+                    matrix: bone.getBaseMatrix().toArray(),
                     rest: bone.getRestPose().toArray()
                 };
 

+ 31 - 18
src/Cameras/Inputs/babylon.freecamera.input.gamepad.ts

@@ -1,7 +1,7 @@
-module BABYLON {       
+module BABYLON {
     export class FreeCameraGamepadInput implements ICameraInput<FreeCamera> {
-        camera : FreeCamera;
-        
+        camera: FreeCamera;
+
         public gamepad: Gamepad;
         private _gamepads: Gamepads;
 
@@ -10,19 +10,25 @@ module BABYLON {
 
         @serialize()
         public gamepadMoveSensibility = 40;
-        
-        attachControl(element : HTMLElement, noPreventDefault?: boolean){
+
+        // private members
+        private _cameraTransform: Matrix = Matrix.Identity();
+        private _deltaTransform: Vector3 = Vector3.Zero();
+        private _vector3: Vector3 = Vector3.Zero();
+        private _vector2: Vector2 = Vector2.Zero();
+
+        attachControl(element: HTMLElement, noPreventDefault?: boolean) {
             this._gamepads = new Gamepads((gamepad: Gamepad) => { this._onNewGameConnected(gamepad); });
         }
-        
+
         detachControl(element: HTMLElement) {
             if (this._gamepads) {
                 this._gamepads.dispose();
             }
             this.gamepad = null;
         }
-        
-        checkInputs(){
+
+        checkInputs() {
             if (this.gamepad) {
                 var camera = this.camera;
                 var LSValues = this.gamepad.leftStick;
@@ -37,30 +43,37 @@ module BABYLON {
                 RSValues.x = Math.abs(normalizedRX) > 0.001 ? 0 + normalizedRX : 0;
                 RSValues.y = Math.abs(normalizedRY) > 0.001 ? 0 + normalizedRY : 0;
 
-                var cameraTransform = Matrix.RotationYawPitchRoll(camera.rotation.y, camera.rotation.x, 0);
+                if (!camera.rotationQuaternion) {
+                    Matrix.RotationYawPitchRollToRef(camera.rotation.y, camera.rotation.x, 0, this._cameraTransform);
+                } else {
+                    camera.rotationQuaternion.toRotationMatrix(this._cameraTransform);
+                }
 
                 var speed = camera._computeLocalCameraSpeed() * 50.0;
-                var deltaTransform = Vector3.TransformCoordinates(new Vector3(LSValues.x * speed, 0, -LSValues.y * speed), cameraTransform);
-                camera.cameraDirection = camera.cameraDirection.add(deltaTransform);
-                camera.cameraRotation = camera.cameraRotation.add(new Vector2(RSValues.y, RSValues.x));
+                this._vector3.copyFromFloats(LSValues.x * speed, 0, -LSValues.y * speed);
+
+                Vector3.TransformCoordinatesToRef(this._vector3, this._cameraTransform, this._deltaTransform);
+                camera.cameraDirection.addInPlace(this._deltaTransform);
+                this._vector2.copyFromFloats(RSValues.y, RSValues.x)
+                camera.cameraRotation.addInPlace(this._vector2);
             }
         }
-        
+
         private _onNewGameConnected(gamepad: Gamepad) {
             // Only the first gamepad can control the camera
             if (gamepad.index === 0) {
                 this.gamepad = gamepad;
             }
         }
-        
-        getTypeName(): string{
+
+        getTypeName(): string {
             return "FreeCameraGamepadInput";
         }
-        
-        getSimpleName(){
+
+        getSimpleName() {
             return "gamepad";
         }
     }
-    
+
     CameraInputTypes["FreeCameraGamepadInput"] = FreeCameraGamepadInput;
 }

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

@@ -445,7 +445,7 @@ module BABYLON {
                 this.position.copyFrom(this._newPosition);
 
                 var up = this.upVector;
-                if (this.allowUpsideDown && this.beta < 0) {
+                if (this.allowUpsideDown && sinb < 0) {
                     up = up.clone();
                     up = up.negate();
                 }

+ 8 - 0
src/Cameras/babylon.camera.ts

@@ -292,6 +292,14 @@
         public _checkInputs(): void {
         }
 
+        public get rigCameras(): Camera[] {
+            return this._rigCameras;
+        }
+
+        public get rigPostProcess(): PostProcess {
+            return this._rigPostProcess;
+        }
+
         private _cascadePostProcessesToRigCams(): void {
             // invalidate framebuffer
             if (this._postProcesses.length > 0) {

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

@@ -181,7 +181,7 @@
             if (this.checkCollisions && this.getScene().collisionsEnabled) {
                 this._collideWithWorld(this.cameraDirection);
             } else {
-                this.position.addInPlace(this.cameraDirection);
+                super._updatePosition();
             }
         }
 

+ 10 - 0
src/Cameras/babylon.targetCamera.ts

@@ -142,6 +142,10 @@ module BABYLON {
             }
         }
 
+
+        /**
+         * Return the current target position of the camera. This value is expressed in local space.
+         */
         public getTarget(): Vector3 {
             return this._currentTarget;
         }
@@ -151,6 +155,12 @@ module BABYLON {
         }
 
         public _updatePosition(): void {
+            if (this.parent) {
+                this.parent.getWorldMatrix().invertToRef(Tmp.Matrix[0]);
+                Vector3.TransformNormalToRef(this.cameraDirection, Tmp.Matrix[0], Tmp.Vector3[0]);
+                this.position.addInPlace(Tmp.Vector3[0]);
+                return;
+            }
             this.position.addInPlace(this.cameraDirection);
         }
         public _checkInputs(): void {

+ 4 - 1
src/Debug/babylon.debugLayer.ts

@@ -21,7 +21,10 @@ module BABYLON {
         }
         
         public isVisible(): boolean {
-            return false;
+            if (!this._inspector) {
+                return false;
+            }
+            return true;
         }
 
         public hide() {

+ 40 - 35
src/Lights/babylon.directionalLight.ts

@@ -17,6 +17,8 @@ module BABYLON {
 
         @serialize()
         public autoUpdateExtends = true;
+        
+        public customProjectionMatrixBuilder: (viewMatrix: Matrix, renderList: Array<AbstractMesh>, result: Matrix) => void;
 
         // Cache
         private _orthoLeft = Number.MAX_VALUE;
@@ -60,55 +62,58 @@ module BABYLON {
          * Returns the DirectionalLight.  
          */
         public setShadowProjectionMatrix(matrix: Matrix, viewMatrix: Matrix, renderList: Array<AbstractMesh>): DirectionalLight {
-            var activeCamera = this.getScene().activeCamera;
+            if (this.customProjectionMatrixBuilder) {
+                this.customProjectionMatrixBuilder(viewMatrix, renderList, matrix);
+            } else {
+                var activeCamera = this.getScene().activeCamera;
 
-            // Check extends
-            if (this.autoUpdateExtends || this._orthoLeft === Number.MAX_VALUE) {
-                var tempVector3 = Vector3.Zero();
+                // 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;
+                    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];
+                    for (var meshIndex = 0; meshIndex < renderList.length; meshIndex++) {
+                        var mesh = renderList[meshIndex];
 
-                    if (!mesh) {
-                        continue;
-                    }
+                        if (!mesh) {
+                            continue;
+                        }
 
-                    var boundingInfo = mesh.getBoundingInfo();
+                        var boundingInfo = mesh.getBoundingInfo();
 
-                    if (!boundingInfo) {
-                        continue;
-                    }
+                        if (!boundingInfo) {
+                            continue;
+                        }
 
-                    var boundingBox = boundingInfo.boundingBox;
+                        var boundingBox = boundingInfo.boundingBox;
 
-                    for (var index = 0; index < boundingBox.vectorsWorld.length; index++) {
-                        Vector3.TransformCoordinatesToRef(boundingBox.vectorsWorld[index], viewMatrix, tempVector3);
+                        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._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;
+                            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);
+                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);
+            }
             return this;
         }
 

+ 2 - 0
src/Lights/babylon.light.ts

@@ -9,6 +9,8 @@
         computeTransformedPosition(): boolean;
         getScene(): Scene;
 
+
+        customProjectionMatrixBuilder: (viewMatrix: Matrix, renderList: Array<AbstractMesh>, result: Matrix) => void;
         setShadowProjectionMatrix(matrix: Matrix, viewMatrix: Matrix, renderList: Array<AbstractMesh>): void;
 
         supportsVSM(): boolean;

+ 8 - 2
src/Lights/babylon.pointLight.ts

@@ -5,6 +5,8 @@
 
         @serializeAsVector3()
         public position: Vector3;
+        
+        public customProjectionMatrixBuilder: (viewMatrix: Matrix, renderList: Array<AbstractMesh>, result: Matrix) => void;
 
         /**
          * Creates a PointLight object from the passed name and position (Vector3) and adds it in the scene.  
@@ -117,8 +119,12 @@
          * Returns the PointLight.  
          */
         public setShadowProjectionMatrix(matrix: Matrix, viewMatrix: Matrix, renderList: Array<AbstractMesh>): PointLight {
-            var activeCamera = this.getScene().activeCamera;
-            Matrix.PerspectiveFovLHToRef(Math.PI / 2, 1.0, activeCamera.minZ, activeCamera.maxZ, matrix);
+            if (this.customProjectionMatrixBuilder) {
+                this.customProjectionMatrixBuilder(viewMatrix, renderList, matrix);
+            } else {
+                var activeCamera = this.getScene().activeCamera;
+                Matrix.PerspectiveFovLHToRef(Math.PI / 2, 1.0, activeCamera.minZ, activeCamera.maxZ, matrix);
+            }
             return this;
         }
 

+ 8 - 2
src/Lights/babylon.spotLight.ts

@@ -14,6 +14,8 @@
 
         public transformedPosition: Vector3;
 
+        public customProjectionMatrixBuilder: (viewMatrix: Matrix, renderList: Array<AbstractMesh>, result: Matrix) => void;
+
         private _transformedDirection: Vector3;
         private _worldMatrix: Matrix;
 
@@ -52,8 +54,12 @@
          * Returns the SpotLight.  
          */
         public setShadowProjectionMatrix(matrix: Matrix, viewMatrix: Matrix, renderList: Array<AbstractMesh>): SpotLight {
-            var activeCamera = this.getScene().activeCamera;
-            Matrix.PerspectiveFovLHToRef(this.angle, 1.0, activeCamera.minZ, activeCamera.maxZ, matrix);
+            if (this.customProjectionMatrixBuilder) {
+                this.customProjectionMatrixBuilder(viewMatrix, renderList, matrix);
+            } else {
+                var activeCamera = this.getScene().activeCamera;
+                Matrix.PerspectiveFovLHToRef(this.angle, 1.0, activeCamera.minZ, activeCamera.maxZ, matrix);
+            }
             return this;
         }
         /**

+ 8 - 3
src/Materials/babylon.effect.ts

@@ -28,6 +28,9 @@
             this._meshRank = rank;
             this._mesh = mesh;
 
+            if (rank < this._currentRank) {
+                this._currentRank = rank;
+            }
             if (rank > this._maxRank) {
                 this._maxRank = rank;
             }
@@ -40,9 +43,10 @@
         public reduce(currentDefines: string): string {
 
             var currentFallbacks = this._defines[this._currentRank];
-
-            for (var index = 0; index < currentFallbacks.length; index++) {
-                currentDefines = currentDefines.replace("#define " + currentFallbacks[index], "");
+            if (currentFallbacks) {
+                for (var index = 0; index < currentFallbacks.length; index++) {
+                    currentDefines = currentDefines.replace("#define " + currentFallbacks[index], "");
+                }
             }
 
             if (this._mesh && this._currentRank === this._meshRank) {
@@ -300,6 +304,7 @@
             result = result.replace(/[ \t]attribute/g, " in");
             
             if (isFragment) {
+                result = result.replace(/texture2DLodEXT\(/g, "textureLod(");
                 result = result.replace(/textureCubeLodEXT\(/g, "textureLod(");
                 result = result.replace(/texture2D\(/g, "texture(");
                 result = result.replace(/textureCube\(/g, "texture(");

+ 67 - 1
src/Math/babylon.math.ts

@@ -238,6 +238,15 @@
             this.b = b;
             return this;
         }
+
+        /**
+         * Updates the Color3 rgb values from the passed floats.  
+         * Returns the Color3.  
+         */
+        public set(r: number, g: number, b: number): Color3 {
+            return this.copyFromFloats(r, g, b);
+        }
+
         /**
          * Returns the Color3 hexadecimal code as a string.  
          */
@@ -489,6 +498,26 @@
             this.a = source.a;
             return this;
         }
+
+        /**
+         * Copies the passed float values into the current one.  
+         * Returns the updated Color4.  
+         */
+        public copyFromFloats(r: number, g: number, b: number, a: number): Color4 {
+            this.r = r;
+            this.g = g;
+            this.b = b;
+            this.a = a;
+            return this;
+        }
+
+        /**
+         * Copies the passed float values into the current one.  
+         * Returns the updated Color4.  
+         */
+        public set(r: number, g: number, b: number, a: number): Color4 {
+            return this.copyFromFloats(r, g, b,a);
+        }
         /**
          * Returns a string containing the hexadecimal Color4 code.  
          */
@@ -634,6 +663,13 @@
             return this;
         }
         /**
+         * Sets the Vector2 coordinates with the passed floats.  
+         * Returns the updated Vector2.  
+         */
+        public set(x: number, y: number): Vector2 {
+            return this.copyFromFloats(x, y);
+        }
+        /**
          * Returns a new Vector2 set with the addition of the current Vector2 and the passed one coordinates.  
          */
         public add(otherVector: Vector2): Vector2 {
@@ -1338,6 +1374,14 @@
             return this;
         }
 
+        /**
+         * Copies the passed floats to the current Vector3 coordinates.  
+         * Returns the updated Vector3.  
+         */
+        public set(x: number, y: number, z: number): Vector3 {
+            return this.copyFromFloats(x, y, z);
+        }
+
         // Statics
         /**
          * 
@@ -2088,6 +2132,13 @@
             this.w = w;
             return this;
         }
+        /**
+         * Updates the current Vector4 coordinates with the passed floats.  
+         * Returns the updated Vector4.  
+         */
+        public set(x: number, y: number, z: number, w: number): Vector4 {
+            return this.copyFromFloats(x, y, z, w);
+        }
 
         // Statics
         /**
@@ -2238,6 +2289,13 @@
             return this;
         }
         /**
+         * Updates in place the current Size from the passed floats.  
+         * Returns the updated Size.   
+         */
+        public set(width: number, height: number): Size {
+            return this.copyFromFloats(width, height);
+        }        
+        /**
          * Returns a new Size set with the multiplication result of the current Size and the passed floats.  
          */
         public multiplyByFloats(w: number, h: number): Size {
@@ -2368,6 +2426,13 @@
             return this;
         }
         /**
+         * Updates the current Quaternion from the passed float coordinates.  
+         * Returns the updated Quaterion.  
+         */
+        public set(x: number, y: number, z: number, w: number): Quaternion {
+            return this.copyFromFloats(x, y, z, w);
+        }        
+        /**
          * Returns a new Quaternion as the addition result of the passed one and the current Quaternion.  
          */
         public add(other: Quaternion): Quaternion {
@@ -4271,7 +4336,8 @@
 
     export enum Space {
         LOCAL = 0,
-        WORLD = 1
+        WORLD = 1,
+        BONE = 2
     }
 
     export class Axis {

+ 3 - 1
src/Mesh/babylon.geometry.ts

@@ -401,7 +401,9 @@
                 if (numOfMeshes === 1) {
                     this._vertexBuffers[kind].create();
                 }
-                this._vertexBuffers[kind].getBuffer().references = numOfMeshes;
+                var buffer = this._vertexBuffers[kind].getBuffer();
+                if (buffer)
+                    buffer.references = numOfMeshes;
 
                 if (kind === VertexBuffer.PositionKind) {
                     mesh._resetPointsArrayCache();

+ 8 - 0
src/PostProcess/babylon.postProcess.ts

@@ -14,6 +14,8 @@
         */ 
         public enablePixelPerfectMode = false;
 
+        public samples = 1;
+
         private _camera: Camera;
         private _scene: Scene;
         private _engine: Engine;
@@ -193,6 +195,12 @@
                 this.onSizeChangedObservable.notifyObservers(this);
             }
 
+            this._textures.forEach(texture => {
+                if (texture.samples !== this.samples) {
+                    this._engine.updateRenderTargetTextureSampleCount(texture, this.samples);
+                }
+            });
+
             if (this.enablePixelPerfectMode) {
                 this._scaleRatio.copyFromFloats(requiredWidth / desiredWidth, requiredHeight / desiredHeight);
                 this._engine.bindFramebuffer(this._textures.data[this._currentRenderTextureInd], 0, requiredWidth, requiredHeight);

+ 76 - 14
src/PostProcess/babylon.standardRenderingPipeline.ts

@@ -14,6 +14,7 @@ module BABYLON {
         public textureAdderPostProcess: PostProcess = null;
 
         public textureAdderFinalPostProcess: PostProcess = null;
+        public lensFlareFinalPostProcess: PostProcess = null;
 
         public lensFlarePostProcess: PostProcess = null;
         public lensFlareComposePostProcess: PostProcess = null;
@@ -21,26 +22,46 @@ module BABYLON {
         public depthOfFieldPostProcess: PostProcess = null;
 
         // Values
+        @serialize()
         public brightThreshold: number = 1.0;
 
+        @serialize()
         public blurWidth: number = 2.0;
+        @serialize()
+        public horizontalBlur: boolean = false;
+        @serialize()
         public gaussianCoefficient: number = 0.25;
+        @serialize()
         public gaussianMean: number = 1.0;
+        @serialize()
         public gaussianStandardDeviation: number = 1.0;
 
+        @serialize()
         public exposure: number = 1.0;
+        @serializeAsTexture("lensTexture")
         public lensTexture: Texture = null;
 
+        @serializeAsTexture("lensColorTexture")
         public lensColorTexture: Texture = null;
+        @serialize()
         public lensFlareStrength: number = 20.0;
+        @serialize()
         public lensFlareGhostDispersal: number = 1.4;
+        @serialize()
         public lensFlareHaloWidth: number = 0.7;
+        @serialize()
         public lensFlareDistortionStrength: number = 16.0;
+        @serializeAsTexture("lensStarTexture")
         public lensStarTexture: Texture = null;
+        @serializeAsTexture("lensFlareDirtTexture")
         public lensFlareDirtTexture: Texture = null;
 
+        @serialize()
         public depthOfFieldDistance: number = 10.0;
 
+        @serialize()
+        public depthOfFieldBlurWidth: number = 2.0;
+
         // IAnimatable
         public animations: Animation[] = [];
 
@@ -50,6 +71,7 @@ module BABYLON {
         private _scene: Scene;
 
         private _depthRenderer: DepthRenderer = null;
+        private _currentDepthOfFieldSource: PostProcess = null;
 
         // Getters and setters
         private _depthOfFieldEnabled: boolean = true;
@@ -73,6 +95,7 @@ module BABYLON {
             this._depthOfFieldEnabled = enabled;
         }
 
+        @serialize()
         public get DepthOfFieldEnabled(): boolean {
             return this._depthOfFieldEnabled;
         }
@@ -86,6 +109,8 @@ module BABYLON {
                 this._scene.postProcessRenderPipelineManager.enableEffectInPipeline(this._name, "HDRGaussianBlurH" + blurIndex, this._scene.cameras);
                 this._scene.postProcessRenderPipelineManager.enableEffectInPipeline(this._name, "HDRGaussianBlurV" + blurIndex, this._scene.cameras);
                 this._scene.postProcessRenderPipelineManager.enableEffectInPipeline(this._name, "HDRLensFlareCompose", this._scene.cameras);
+
+                this._setDepthOfFieldSavePostProcess("HDRPostLensFlareDepthOfFieldSource");
             }
             else if (!enabled && this._lensFlareEnabled) {
                 this._scene.postProcessRenderPipelineManager.disableEffectInPipeline(this._name, "HDRLensFlare", this._scene.cameras);
@@ -93,11 +118,14 @@ module BABYLON {
                 this._scene.postProcessRenderPipelineManager.disableEffectInPipeline(this._name, "HDRGaussianBlurH" + blurIndex, this._scene.cameras);
                 this._scene.postProcessRenderPipelineManager.disableEffectInPipeline(this._name, "HDRGaussianBlurV" + blurIndex, this._scene.cameras);
                 this._scene.postProcessRenderPipelineManager.disableEffectInPipeline(this._name, "HDRLensFlareCompose", this._scene.cameras);
+
+                this._setDepthOfFieldSavePostProcess("HDRBaseDepthOfFieldSource");
             }
 
             this._lensFlareEnabled = enabled;
         }
 
+        @serialize()
         public get LensFlareEnabled(): boolean {
             return this._lensFlareEnabled;
         }
@@ -118,7 +146,7 @@ module BABYLON {
 
             // Create pass post-processe
             if (!originalPostProcess) {
-                this.originalPostProcess = new PostProcess("HDRPass", "standard", [], [], ratio, null, Texture.BILINEAR_SAMPLINGMODE, scene.getEngine(), true, "#define PASS_POST_PROCESS", Engine.TEXTURETYPE_FLOAT);
+                this.originalPostProcess = new PostProcess("HDRPass", "standard", [], [], ratio, null, Texture.BILINEAR_SAMPLINGMODE, scene.getEngine(), false, "#define PASS_POST_PROCESS", Engine.TEXTURETYPE_FLOAT);
             }
             else {
                 this.originalPostProcess = originalPostProcess;
@@ -142,14 +170,18 @@ module BABYLON {
             this._createTextureAdderPostProcess(scene, ratio);
 
             // Create depth-of-field source post-process
-            this.textureAdderFinalPostProcess = new PostProcess("HDRDepthOfFieldSource", "standard", [], [], ratio, null, Texture.BILINEAR_SAMPLINGMODE, scene.getEngine(), true, "#define PASS_POST_PROCESS", Engine.TEXTURETYPE_UNSIGNED_INT);
-            this.addEffect(new PostProcessRenderEffect(scene.getEngine(), "HDRDepthOfFieldSource", () => { return this.textureAdderFinalPostProcess; }, true));
+            this.textureAdderFinalPostProcess = new PostProcess("HDRDepthOfFieldSource", "standard", [], [], ratio, null, Texture.BILINEAR_SAMPLINGMODE, scene.getEngine(), false, "#define PASS_POST_PROCESS", Engine.TEXTURETYPE_UNSIGNED_INT);
+            this.addEffect(new PostProcessRenderEffect(scene.getEngine(), "HDRBaseDepthOfFieldSource", () => { return this.textureAdderFinalPostProcess; }, true));
 
             // Create lens flare post-process
             this._createLensFlarePostProcess(scene, ratio);
 
+            // Create depth-of-field source post-process post lens-flare and disable it now
+            this.lensFlareFinalPostProcess = new PostProcess("HDRPostLensFlareDepthOfFieldSource", "standard", [], [], ratio, null, Texture.BILINEAR_SAMPLINGMODE, scene.getEngine(), false, "#define PASS_POST_PROCESS", Engine.TEXTURETYPE_UNSIGNED_INT);
+            this.addEffect(new PostProcessRenderEffect(scene.getEngine(), "HDRPostLensFlareDepthOfFieldSource", () => { return this.lensFlareFinalPostProcess; }, true));
+
             // Create gaussian blur used by depth-of-field
-            this._createGaussianBlurPostProcesses(scene, ratio / 2, 5);
+            this._createGaussianBlurPostProcesses(scene, ratio / 2, 5, "depthOfFieldBlurWidth");
 
             // Create depth-of-field post-process
             this._createDepthOfFieldPostProcess(scene, ratio);
@@ -166,6 +198,19 @@ module BABYLON {
             this.DepthOfFieldEnabled = false;
         }
 
+        // Sets depth-of-field save post-process
+        private _setDepthOfFieldSavePostProcess(name: string): void {
+            this._scene.postProcessRenderPipelineManager.disableEffectInPipeline(this._name, "HDRPostLensFlareDepthOfFieldSource", this._scene.cameras);
+
+            this._scene.postProcessRenderPipelineManager.enableEffectInPipeline(this._name, name, this._scene.cameras);
+
+            switch (name) {
+                case "HDRBaseDepthOfFieldSource": this._currentDepthOfFieldSource = this.textureAdderFinalPostProcess; break;
+                case "HDRPostLensFlareDepthOfFieldSource": this._currentDepthOfFieldSource = this.lensFlareFinalPostProcess; break;
+                default: break;
+            }
+        }
+
         // Down Sample X4 Post-Processs
         private _createDownSampleX4PostProcess(scene: Scene, ratio: number): void {
             var downSampleX4Offsets = new Array<number>(32);
@@ -215,7 +260,7 @@ module BABYLON {
         }
 
         // Create gaussian blur H&V post-processes
-        private _createGaussianBlurPostProcesses(scene: Scene, ratio: number, indice: number): void {
+        private _createGaussianBlurPostProcesses(scene: Scene, ratio: number, indice: number, blurWidthKey: string = "blurWidth"): void {
             var blurOffsets = new Array<number>(9);
             var blurWeights = new Array<number>(9);
             var uniforms: string[] = ["blurOffsets", "blurWeights", "blurWidth"];
@@ -245,16 +290,22 @@ module BABYLON {
 
                     effect.setArray("blurOffsets", blurOffsets);
                     effect.setArray("blurWeights", blurWeights);
-                    effect.setFloat("blurWidth", this.blurWidth);
+
+                    if (height) {
+                        effect.setFloat("blurWidth", this.horizontalBlur ? 1.0 : this[blurWidthKey]);
+                    }
+                    else {
+                        effect.setFloat("blurWidth", this[blurWidthKey]);
+                    }
                 };
             };
 
             // Create horizontal gaussian blur post-processes
-            var gaussianBlurHPostProcess = new PostProcess("HDRGaussianBlurH" + ratio, "standard", uniforms, [], ratio, null, Texture.BILINEAR_SAMPLINGMODE, scene.getEngine(), false, "#define GAUSSIAN_BLUR_H", Engine.TEXTURETYPE_UNSIGNED_INT);
+            var gaussianBlurHPostProcess = new PostProcess("HDRGaussianBlurH_" + ratio + "_" + indice, "standard", uniforms, [], ratio, null, Texture.BILINEAR_SAMPLINGMODE, scene.getEngine(), false, "#define GAUSSIAN_BLUR_H", Engine.TEXTURETYPE_UNSIGNED_INT);
             gaussianBlurHPostProcess.onApply = callback(false);
 
             // Create vertical gaussian blur post-process
-            var gaussianBlurVPostProcess = new PostProcess("HDRGaussianBlurV" + ratio, "standard", uniforms, [], ratio, null, Texture.BILINEAR_SAMPLINGMODE, scene.getEngine(), false, "#define GAUSSIAN_BLUR_V", Engine.TEXTURETYPE_UNSIGNED_INT);
+            var gaussianBlurVPostProcess = new PostProcess("HDRGaussianBlurV_" + ratio + "_" + indice, "standard", uniforms, [], ratio, null, Texture.BILINEAR_SAMPLINGMODE, scene.getEngine(), false, "#define GAUSSIAN_BLUR_V", Engine.TEXTURETYPE_UNSIGNED_INT);
             gaussianBlurVPostProcess.onApply = callback(true);
 
             // Add to pipeline
@@ -268,8 +319,6 @@ module BABYLON {
 
         // Create texture adder post-process
         private _createTextureAdderPostProcess(scene: Scene, ratio: number): void {
-            var lastGaussianBlurPostProcess = this.gaussianBlurVPostProcesses[3];
-
             this.textureAdderPostProcess = new PostProcess("HDRTextureAdder", "standard", ["exposure"], ["otherSampler", "lensSampler"], ratio, null, Texture.BILINEAR_SAMPLINGMODE, scene.getEngine(), false, "#define TEXTURE_ADDER", Engine.TEXTURETYPE_UNSIGNED_INT);
             this.textureAdderPostProcess.onApply = (effect: Effect) => {
                 effect.setTextureFromPostProcess("otherSampler", this.originalPostProcess);
@@ -284,13 +333,13 @@ module BABYLON {
 
         // Create lens flare post-process
         private _createLensFlarePostProcess(scene: Scene, ratio: number): void {
-            this.lensFlarePostProcess = new PostProcess("HDRLensFlare", "standard", ["strength", "ghostDispersal", "haloWidth", "resolution", "distortionStrength"], ["lensColorSampler"], ratio / 2, null, Texture.BILINEAR_SAMPLINGMODE, scene.getEngine(), true, "#define LENS_FLARE", Engine.TEXTURETYPE_UNSIGNED_INT);
-            this.addEffect(new PostProcessRenderEffect(scene.getEngine(), "HDRLensFlare", () => { return this.lensFlarePostProcess; }, false));
+            this.lensFlarePostProcess = new PostProcess("HDRLensFlare", "standard", ["strength", "ghostDispersal", "haloWidth", "resolution", "distortionStrength"], ["lensColorSampler"], ratio / 2, null, Texture.BILINEAR_SAMPLINGMODE, scene.getEngine(), false, "#define LENS_FLARE", Engine.TEXTURETYPE_UNSIGNED_INT);
+            this.addEffect(new PostProcessRenderEffect(scene.getEngine(), "HDRLensFlare", () => { return this.lensFlarePostProcess; }, true));
 
             this._createGaussianBlurPostProcesses(scene, ratio / 4, 4);
 
             this.lensFlareComposePostProcess = new PostProcess("HDRLensFlareCompose", "standard", ["lensStarMatrix"], ["otherSampler", "lensDirtSampler", "lensStarSampler"], ratio, null, Texture.BILINEAR_SAMPLINGMODE, scene.getEngine(), false, "#define LENS_FLARE_COMPOSE", Engine.TEXTURETYPE_UNSIGNED_INT);
-            this.addEffect(new PostProcessRenderEffect(scene.getEngine(), "HDRLensFlareCompose", () => { return this.lensFlareComposePostProcess; }, false));
+            this.addEffect(new PostProcessRenderEffect(scene.getEngine(), "HDRLensFlareCompose", () => { return this.lensFlareComposePostProcess; }, true));
 
             var resolution = new Vector2(0, 0);
 
@@ -353,7 +402,7 @@ module BABYLON {
         private _createDepthOfFieldPostProcess(scene: Scene, ratio: number): void {
             this.depthOfFieldPostProcess = new PostProcess("HDRDepthOfField", "standard", ["distance"], ["otherSampler", "depthSampler"], ratio, null, Texture.BILINEAR_SAMPLINGMODE, scene.getEngine(), false, "#define DEPTH_OF_FIELD", Engine.TEXTURETYPE_UNSIGNED_INT);
             this.depthOfFieldPostProcess.onApply = (effect: Effect) => {
-                effect.setTextureFromPostProcess("otherSampler", this.textureAdderFinalPostProcess);
+                effect.setTextureFromPostProcess("otherSampler", this._currentDepthOfFieldSource);
                 effect.setTexture("depthSampler", this._depthRenderer.getDepthMap());
 
                 effect.setFloat("distance", this.depthOfFieldDistance);
@@ -391,5 +440,18 @@ module BABYLON {
 
             super.dispose();
         }
+
+        // Serialize rendering pipeline
+        public serialize(): any {
+            var serializationObject = SerializationHelper.Serialize(this);
+            serializationObject.customType = "StandardRenderingPipeline";
+
+            return serializationObject;
+        }
+
+        // Parse serialized pipeline
+        public static Parse(source: any, scene: Scene, rootUrl: string): StandardRenderingPipeline {
+            return SerializationHelper.Parse(() => new StandardRenderingPipeline(source._name, scene, source._ratio), source, scene, rootUrl);
+        }
     }
 }

+ 2 - 2
src/Tools/babylon.database.ts

@@ -43,7 +43,7 @@ module BABYLON {
         }
 
         static ReturnFullUrlLocation = (url: string): string => {
-            if (url.indexOf("http:/") === -1) {
+            if (url.indexOf("http:/") === -1 && url.indexOf("https:/") === -1) {
                 return (Database.parseURL(window.location.href) + url);
             }
             else {
@@ -584,4 +584,4 @@ module BABYLON {
             }
         }
     }
-}
+}

+ 6 - 0
src/Tools/babylon.smartArray.ts

@@ -25,6 +25,12 @@
             value.__smartArrayFlags[this._id] = this._duplicateId;
         }
 
+        public forEach(func: (content: T) => void): void {
+            for (var index = 0; index < this.length; index++) {
+                func(this.data[index]);
+            }
+        }
+
         public pushNoDuplicate(value): boolean {
             if (value.__smartArrayFlags && value.__smartArrayFlags[this._id] === this._duplicateId) {
                 return false;

+ 2 - 2
src/Tools/babylon.tools.ts

@@ -298,13 +298,13 @@
             }
         }
 
-        public static SetCorsBehavior(url: string, img: HTMLImageElement): string {
+        public static SetCorsBehavior(url: string, img: HTMLImageElement): void {
             if (Tools.CorsBehavior) {
                 switch (typeof (Tools.CorsBehavior)) {
                     case "function":
                         var result = Tools.CorsBehavior(url);
                         if (result) {
-                            return result;
+                            img.crossOrigin = result;
                         }
                         break;
                     case "string":

+ 9 - 1
src/babylon.engine.ts

@@ -2005,7 +2005,7 @@
                     this._alphaState.alphaBlend = false;
                     break;
                 case Engine.ALPHA_PREMULTIPLIED:
-                    this._alphaState.setAlphaBlendFunctionParameters(this._gl.ONE, this._gl.ONE_MINUS_SRC_ALPHA, this._gl.ONE, this._gl.ONE_MINUS_SRC_ALPHA);
+                    this._alphaState.setAlphaBlendFunctionParameters(this._gl.ONE, this._gl.ONE_MINUS_SRC_ALPHA, this._gl.ONE, this._gl.ONE);
                     this._alphaState.alphaBlend = true;
                     break;
                 case Engine.ALPHA_COMBINE:
@@ -2499,6 +2499,7 @@
             texture._width = width;
             texture._height = height;
             texture.isReady = true;
+            texture.samples = 1;
             texture.generateMipMaps = generateMipMaps;
             texture.references = 1;
             texture.samplingMode = samplingMode;
@@ -2550,6 +2551,11 @@
             if (this.webGLVersion < 2) {
                 return 1;
             }
+
+            if (texture.samples === samples) {
+                return samples;
+            }
+
             var gl = this._gl;
 
             samples = Math.min(samples, gl.getParameter(gl.MAX_SAMPLES));
@@ -2582,6 +2588,7 @@
                 this.bindUnboundFramebuffer(texture._framebuffer);
             }
 
+            texture.samples = samples;
             texture._depthStencilBuffer = this._setupFramebufferDepthAttachments(texture._generateStencilBuffer, texture._generateDepthBuffer, texture._width, texture._height, samples);
 
             gl.bindRenderbuffer(gl.RENDERBUFFER, null);
@@ -2614,6 +2621,7 @@
             texture.references = 1;
             texture.generateMipMaps = generateMipMaps;
             texture.references = 1;
+            texture.samples = 1;
             texture.samplingMode = samplingMode;
 
             var filters = getSamplingParameters(samplingMode, generateMipMaps, gl);

+ 1 - 0
src/babylon.mixins.ts

@@ -89,6 +89,7 @@ interface WebGLTexture {
     samplingMode: number;
     references: number;
     generateMipMaps: boolean;
+    samples: number;
     type: number;
     onLoadedCallbacks: Array<Function>;
     _size: number;