瀏覽代碼

update from upstream

nockawa 8 年之前
父節點
當前提交
f90aca6341

+ 206 - 0
canvas2D/src/Engine/babylon.prim2dBase.js

@@ -1299,6 +1299,8 @@ var BABYLON;
             this._firstZDirtyIndex = Prim2DBase._bigInt;
             this._actualOpacity = 0;
             this._actualScale = BABYLON.Vector2.Zero();
+            this._displayDebugAreas = false;
+            this._debugAreaGroup = null;
             var isPickable = true;
             var isContainer = true;
             if (settings.isPickable !== undefined) {
@@ -2374,6 +2376,207 @@ var BABYLON;
             enumerable: true,
             configurable: true
         });
+        Object.defineProperty(Prim2DBase.prototype, "displayDebugAreas", {
+            get: function () {
+                return this._displayDebugAreas;
+            },
+            set: function (value) {
+                if (this._displayDebugAreas === value) {
+                    return;
+                }
+                if (value === false) {
+                    this._debugAreaGroup.dispose();
+                    this._debugAreaGroup = null;
+                }
+                else {
+                    var layoutFill = "#F0808040"; // Red - Layout area
+                    var layoutBorder = "#F08080FF";
+                    var marginFill = "#F0F04040"; // Yellow - Margin area
+                    var marginBorder = "#F0F040FF";
+                    var paddingFill = "#F040F040"; // Magenta - Padding Area
+                    var paddingBorder = "#F040F0FF";
+                    var contentFill = "#40F0F040"; // Cyan - Content area
+                    var contentBorder = "#40F0F0FF";
+                    var s = new BABYLON.Size(10, 10);
+                    var p = BABYLON.Vector2.Zero();
+                    this._debugAreaGroup = new BABYLON.Group2D({
+                        parent: (this.parent != null) ? this.parent : this, id: "###DEBUG AREA GROUP###", children: [
+                            new BABYLON.Group2D({
+                                id: "###Layout Area###", position: p, size: s, children: [
+                                    new BABYLON.Rectangle2D({ id: "###Layout Frame###", position: BABYLON.Vector2.Zero(), size: s, fill: null, border: layoutBorder }),
+                                    new BABYLON.Rectangle2D({ id: "###Layout Top###", position: BABYLON.Vector2.Zero(), size: s, fill: layoutFill }),
+                                    new BABYLON.Rectangle2D({ id: "###Layout Left###", position: BABYLON.Vector2.Zero(), size: s, fill: layoutFill }),
+                                    new BABYLON.Rectangle2D({ id: "###Layout Right###", position: BABYLON.Vector2.Zero(), size: s, fill: layoutFill }),
+                                    new BABYLON.Rectangle2D({ id: "###Layout Bottom###", position: BABYLON.Vector2.Zero(), size: s, fill: layoutFill })
+                                ]
+                            }),
+                            new BABYLON.Group2D({
+                                id: "###Margin Area###", position: p, size: s, children: [
+                                    new BABYLON.Rectangle2D({ id: "###Margin Frame###", position: BABYLON.Vector2.Zero(), size: s, fill: null, border: marginBorder }),
+                                    new BABYLON.Rectangle2D({ id: "###Margin Top###", position: BABYLON.Vector2.Zero(), size: s, fill: marginFill }),
+                                    new BABYLON.Rectangle2D({ id: "###Margin Left###", position: BABYLON.Vector2.Zero(), size: s, fill: marginFill }),
+                                    new BABYLON.Rectangle2D({ id: "###Margin Right###", position: BABYLON.Vector2.Zero(), size: s, fill: marginFill }),
+                                    new BABYLON.Rectangle2D({ id: "###Margin Bottom###", position: BABYLON.Vector2.Zero(), size: s, fill: marginFill })
+                                ]
+                            }),
+                            new BABYLON.Group2D({
+                                id: "###Padding Area###", position: p, size: s, children: [
+                                    new BABYLON.Rectangle2D({ id: "###Padding Frame###", position: BABYLON.Vector2.Zero(), size: s, fill: null, border: paddingBorder }),
+                                    new BABYLON.Rectangle2D({ id: "###Padding Top###", position: BABYLON.Vector2.Zero(), size: s, fill: paddingFill }),
+                                    new BABYLON.Rectangle2D({ id: "###Padding Left###", position: BABYLON.Vector2.Zero(), size: s, fill: paddingFill }),
+                                    new BABYLON.Rectangle2D({ id: "###Padding Right###", position: BABYLON.Vector2.Zero(), size: s, fill: paddingFill }),
+                                    new BABYLON.Rectangle2D({ id: "###Padding Bottom###", position: BABYLON.Vector2.Zero(), size: s, fill: paddingFill })
+                                ]
+                            }),
+                            new BABYLON.Group2D({
+                                id: "###Content Area###", position: p, size: s, children: [
+                                    new BABYLON.Rectangle2D({ id: "###Content Frame###", position: BABYLON.Vector2.Zero(), size: s, fill: null, border: contentBorder }),
+                                    new BABYLON.Rectangle2D({ id: "###Content Top###", position: BABYLON.Vector2.Zero(), size: s, fill: contentFill }),
+                                    new BABYLON.Rectangle2D({ id: "###Content Left###", position: BABYLON.Vector2.Zero(), size: s, fill: contentFill }),
+                                    new BABYLON.Rectangle2D({ id: "###Content Right###", position: BABYLON.Vector2.Zero(), size: s, fill: contentFill }),
+                                    new BABYLON.Rectangle2D({ id: "###Content Bottom###", position: BABYLON.Vector2.Zero(), size: s, fill: contentFill })
+                                ]
+                            })
+                        ]
+                    });
+                    this._updateDebugArea();
+                }
+                this._displayDebugAreas = value;
+            },
+            enumerable: true,
+            configurable: true
+        });
+        Prim2DBase.prototype._updateDebugArea = function () {
+            var areaNames = ["Layout", "Margin", "Padding", "Content"];
+            var areaZones = ["Area", "Frame", "Top", "Left", "Right", "Bottom"];
+            var prims = new Array(4);
+            // Get all the primitives used to display the areas
+            for (var i = 0; i < 4; i++) {
+                prims[i] = new Array(6);
+                for (var j = 0; j < 6; j++) {
+                    prims[i][j] = this._debugAreaGroup.findById("###" + areaNames[i] + " " + areaZones[j] + "###");
+                    if (j > 1) {
+                        prims[i][j].levelVisible = false;
+                    }
+                }
+            }
+            // Update the visibility status of layout/margin/padding
+            var hasLayout = (this.layoutAreaPos.x !== 0) || (this.layoutAreaPos.y !== 0);
+            var hasMargin = this._hasMargin;
+            var hasPadding = this._hasPadding;
+            prims[0][0].levelVisible = hasLayout;
+            prims[1][0].levelVisible = hasMargin;
+            prims[2][0].levelVisible = hasPadding;
+            prims[3][0].levelVisible = true;
+            // Current offset
+            var curOffset = BABYLON.Vector2.Zero();
+            // Store the area info of the layout area
+            var curAreaIndex = 0;
+            // Store data about each area
+            var areaInfo = new Array(4);
+            var storeAreaInfo = function (pos, size) {
+                var min = pos.clone();
+                var max = pos.clone();
+                if (size.width > 0) {
+                    max.x += size.width;
+                }
+                if (size.height > 0) {
+                    max.y += size.height;
+                }
+                areaInfo[curAreaIndex++] = { off: pos, size: size, min: min, max: max };
+            };
+            {
+                var w = this.margin.leftPixels + this.margin.rightPixels + this.actualSize.width;
+                var h = this.margin.topPixels + this.margin.bottomPixels + this.actualSize.height;
+                storeAreaInfo(BABYLON.Vector2.Zero(), new BABYLON.Size(w, h));
+            }
+            // Compute the layout related data
+            if (hasLayout) {
+                var layoutOffset = this.layoutAreaPos;
+                var w = this.layoutArea.width - (layoutOffset.x + this.margin.leftPixels + this.margin.rightPixels + this.actualSize.width);
+                var h = this.layoutArea.height - (layoutOffset.y + this.margin.topPixels + this.margin.bottomPixels + this.actualSize.height);
+                var layoutArea = new BABYLON.Size(w, h);
+                storeAreaInfo(layoutOffset, layoutArea);
+                curOffset = this.layoutAreaPos;
+            }
+            // Compute margin data
+            if (hasMargin) {
+                var marginOffset = this._marginOffset.add(curOffset);
+                var marginArea = this.actualSize;
+                storeAreaInfo(marginOffset, marginArea);
+                curOffset.addInPlace(marginOffset);
+            }
+            if (hasPadding) {
+                var contentOffset = this._paddingOffset.add(curOffset);
+                var contentArea = this.contentArea;
+                storeAreaInfo(contentOffset, contentArea);
+                curOffset.addInPlace(contentOffset);
+            }
+            // Helper function that set the pos and size of a given prim
+            var setArea = function (i, j, pos, size) {
+                prims[i][j].position = pos;
+                prims[i][j].size = size;
+            };
+            var setFullRect = function (i, pos, size) {
+                var plist = prims[i];
+                plist[2].levelVisible = true;
+                plist[3].levelVisible = false;
+                plist[4].levelVisible = false;
+                plist[5].levelVisible = false;
+                setArea(i, 1, pos, size);
+                setArea(i, 2, pos, size);
+            };
+            var setQuadRect = function (i, areaIndex) {
+                var plist = prims[i];
+                plist[2].levelVisible = true;
+                plist[3].levelVisible = true;
+                plist[4].levelVisible = true;
+                plist[5].levelVisible = true;
+                var ca = areaInfo[areaIndex];
+                var na = areaInfo[areaIndex + 1];
+                var tp = new BABYLON.Vector2(ca.min.x, na.max.y);
+                var ts = new BABYLON.Size(ca.size.width, ca.max.y - tp.y);
+                var lp = new BABYLON.Vector2(ca.min.x, na.min.y);
+                var ls = new BABYLON.Size(na.min.x - ca.min.x, na.max.y - na.min.y);
+                var rp = new BABYLON.Vector2(na.max.x, na.min.y);
+                var rs = ls;
+                var bp = new BABYLON.Vector2(ca.min.x, ca.min.y);
+                var bs = ts;
+                // Frame
+                plist[1].position = ca.off;
+                plist[1].size = ca.size;
+                // Top rect
+                plist[2].position = tp;
+                plist[2].size = ts;
+                // Left rect
+                plist[3].position = lp;
+                plist[3].size = ls;
+                // Right rect
+                plist[4].position = rp;
+                plist[4].size = rs;
+                // Bottom rect
+                plist[5].position = bp;
+                plist[5].size = bs;
+            };
+            var areaCount = curAreaIndex;
+            curAreaIndex = 0;
+            // Available zones
+            var availableZones = [false, hasLayout, hasMargin, hasPadding, true];
+            for (var k = 1; k < 5; k++) {
+                if (availableZones[k]) {
+                    var ai = areaInfo[curAreaIndex];
+                    setArea(k - 1, 0, BABYLON.Vector2.Zero(), ai.size);
+                    //                    setArea(k-1, 1, Vector2.Zero(), ai.size);
+                    if (k === 4) {
+                        setFullRect(k - 1, ai.off, ai.size);
+                    }
+                    else {
+                        setQuadRect(k - 1, curAreaIndex);
+                    }
+                    ++curAreaIndex;
+                }
+            }
+        };
         Prim2DBase.prototype.findById = function (id) {
             if (this._id === id) {
                 return this;
@@ -2869,6 +3072,9 @@ var BABYLON;
             if (isSizeAuto) {
                 this._lastAutoSizeArea = this.actualSize;
             }
+            if (this.displayDebugAreas) {
+                this._updateDebugArea();
+            }
         };
         Object.defineProperty(Prim2DBase.prototype, "contentArea", {
             /**

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


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


+ 58 - 96
dist/preview release/babylon.canvas2d.max.js

@@ -10,8 +10,12 @@ function __() { this.constructor = d; }
 __.prototype = b.prototype;
 d.prototype = new __();
 };
+
 var BABYLON;
 (function (BABYLON) {
+    /**
+     * Custom type of the propertyChanged observable
+     */
     var PropertyChangedInfo = (function () {
         function PropertyChangedInfo() {
         }
@@ -68,11 +72,6 @@ var BABYLON;
         return PropertyChangedBase;
     }());
     BABYLON.PropertyChangedBase = PropertyChangedBase;
-})(BABYLON || (BABYLON = {}));
-
-
-var BABYLON;
-(function (BABYLON) {
     /**
      * Class for the ObservableArray.onArrayChanged observable
      */
@@ -621,7 +620,7 @@ var BABYLON;
             }
         };
         return ObservableArray;
-    }(BABYLON.PropertyChangedBase));
+    }(PropertyChangedBase));
     BABYLON.ObservableArray = ObservableArray;
 })(BABYLON || (BABYLON = {}));
 
@@ -1268,9 +1267,6 @@ var BABYLON;
                 var max = 0;
                 for (var _i = 0, _a = prim.children; _i < _a.length; _i++) {
                     var child = _a[_i];
-                    if (child._isFlagSet(BABYLON.SmartPropertyPrim.flagNoPartOfLayout)) {
-                        continue;
-                    }
                     var layoutArea = void 0;
                     if (child._hasMargin) {
                         child.margin.computeWithAlignment(prim.layoutArea, child.actualSize, child.marginAlignment, StackPanelLayoutEngine.dstOffset, StackPanelLayoutEngine.dstArea, true);
@@ -1285,9 +1281,6 @@ var BABYLON;
                 }
                 for (var _b = 0, _c = prim.children; _b < _c.length; _b++) {
                     var child = _c[_b];
-                    if (child._isFlagSet(BABYLON.SmartPropertyPrim.flagNoPartOfLayout)) {
-                        continue;
-                    }
                     child.layoutAreaPos = new BABYLON.Vector2(x, y);
                     var layoutArea = child.layoutArea;
                     if (h) {
@@ -1311,7 +1304,7 @@ var BABYLON;
         });
         StackPanelLayoutEngine._horizontal = null;
         StackPanelLayoutEngine._vertical = null;
-        StackPanelLayoutEngine.dstOffset = BABYLON.Vector4.Zero();
+        StackPanelLayoutEngine.dstOffset = BABYLON.Vector2.Zero();
         StackPanelLayoutEngine.dstArea = BABYLON.Size.Zero();
         StackPanelLayoutEngine = __decorate([
             BABYLON.className("StackPanelLayoutEngine", "BABYLON")
@@ -2614,7 +2607,7 @@ var BABYLON;
             }
         };
         SmartPropertyPrim.SMARTPROPERTYPRIM_PROPCOUNT = 0;
-        SmartPropertyPrim.flagNoPartOfLayout = 0x0000001; // set if the primitive's position/size must not be computed by Layout Engine
+        SmartPropertyPrim.flagFREE001 = 0x0000001; // set if the object is already disposed
         SmartPropertyPrim.flagLevelBoundingInfoDirty = 0x0000002; // set if the primitive's level bounding box (not including children) is dirty
         SmartPropertyPrim.flagModelDirty = 0x0000004; // set if the model must be changed
         SmartPropertyPrim.flagLayoutDirty = 0x0000008; // set if the layout must be computed
@@ -3672,7 +3665,7 @@ var BABYLON;
          * @param sourceArea the source area where the content must be sized/positioned
          * @param contentSize the content size to position/resize
          * @param alignment the alignment setting
-         * @param dstOffset the position of the content, x, y, z, w are left, bottom, right, top
+         * @param dstOffset the position of the content
          * @param dstArea the new size of the content
          */
         PrimitiveThickness.prototype.computeWithAlignment = function (sourceArea, contentSize, alignment, dstOffset, dstArea, computeLayoutArea) {
@@ -3704,7 +3697,6 @@ var BABYLON;
                         if (computeLayoutArea) {
                             dstArea.width += this.leftPixels;
                         }
-                        dstOffset.z = sourceArea.width - (dstOffset.x + width);
                         break;
                     }
                 case PrimitiveAlignment.AlignRight:
@@ -3720,7 +3712,6 @@ var BABYLON;
                         if (computeLayoutArea) {
                             dstArea.width += this.rightPixels;
                         }
-                        dstOffset.z = this.rightPixels;
                         break;
                     }
                 case PrimitiveAlignment.AlignStretch:
@@ -3738,7 +3729,6 @@ var BABYLON;
                             right = this.rightPixels;
                         }
                         dstArea.width = sourceArea.width - (dstOffset.x + right);
-                        dstOffset.z = this.rightPixels;
                         break;
                     }
                 case PrimitiveAlignment.AlignCenter:
@@ -3752,7 +3742,6 @@ var BABYLON;
                         var offset = (isLeftAuto ? 0 : this.leftPixels) - (isRightAuto ? 0 : this.rightPixels);
                         dstOffset.x = Math.round(((sourceArea.width - width) / 2) + offset);
                         dstArea.width = width;
-                        dstOffset.z = sourceArea.width - (dstOffset.x + width);
                         break;
                     }
             }
@@ -3770,7 +3759,6 @@ var BABYLON;
                         if (computeLayoutArea) {
                             dstArea.height += this.topPixels;
                         }
-                        dstOffset.w = this.topPixels;
                         break;
                     }
                 case PrimitiveAlignment.AlignBottom:
@@ -3786,7 +3774,6 @@ var BABYLON;
                         if (computeLayoutArea) {
                             dstArea.height += this.bottomPixels;
                         }
-                        dstOffset.w = sourceArea.height - (dstOffset.y + height);
                         break;
                     }
                 case PrimitiveAlignment.AlignStretch:
@@ -3804,7 +3791,6 @@ var BABYLON;
                             top_1 = this.topPixels;
                         }
                         dstArea.height = sourceArea.height - (dstOffset.y + top_1);
-                        dstOffset.w = this.topPixels;
                         break;
                     }
                 case PrimitiveAlignment.AlignCenter:
@@ -3818,7 +3804,6 @@ var BABYLON;
                         var offset = (isBottomAuto ? 0 : this.bottomPixels) - (isTopAuto ? 0 : this.topPixels);
                         dstOffset.y = Math.round(((sourceArea.height - height) / 2) + offset);
                         dstArea.height = height;
-                        dstOffset.w = sourceArea.height - (dstOffset.y + height);
                         break;
                     }
             }
@@ -3947,8 +3932,8 @@ var BABYLON;
             this._layoutArea = BABYLON.Size.Zero();
             this._layoutAreaPos = null;
             this._layoutBoundingInfo = null;
-            this._marginOffset = BABYLON.Vector4.Zero();
-            this._paddingOffset = BABYLON.Vector4.Zero();
+            this._marginOffset = BABYLON.Vector2.Zero();
+            this._paddingOffset = BABYLON.Vector2.Zero();
             this._parentPaddingOffset = BABYLON.Vector2.Zero();
             this._parentContentArea = BABYLON.Size.Zero();
             this._lastAutoSizeArea = BABYLON.Size.Zero();
@@ -5115,7 +5100,6 @@ var BABYLON;
                             })
                         ]
                     });
-                    this._debugAreaGroup._setFlags(BABYLON.SmartPropertyPrim.flagNoPartOfLayout);
                     this._updateDebugArea();
                 }
                 this._displayDebugAreas = value;
@@ -5138,8 +5122,7 @@ var BABYLON;
                 }
             }
             // Update the visibility status of layout/margin/padding
-            var hasLayout = this._layoutAreaPos != null;
-            var hasPos = (this.actualPosition.x !== 0) || (this.actualPosition.y !== 0);
+            var hasLayout = (this.layoutAreaPos.x !== 0) || (this.layoutAreaPos.y !== 0);
             var hasMargin = this._hasMargin;
             var hasPadding = this._hasPadding;
             prims[0][0].levelVisible = hasLayout;
@@ -5163,34 +5146,32 @@ var BABYLON;
                 }
                 areaInfo[curAreaIndex++] = { off: pos, size: size, min: min, max: max };
             };
-            var marginH = this._marginOffset.x + this._marginOffset.z;
-            var marginV = this._marginOffset.y + this._marginOffset.w;
-            var w = hasLayout ? (this.layoutAreaPos.x + this.layoutArea.width) : (marginH + this.actualSize.width);
-            var h = hasLayout ? (this.layoutAreaPos.y + this.layoutArea.height) : (marginV + this.actualSize.height);
-            var pos = (!hasLayout && !hasMargin && !hasPadding && hasPos) ? this.actualPosition : BABYLON.Vector2.Zero();
-            storeAreaInfo(pos, new BABYLON.Size(w, h));
+            {
+                var w = this.margin.leftPixels + this.margin.rightPixels + this.actualSize.width;
+                var h = this.margin.topPixels + this.margin.bottomPixels + this.actualSize.height;
+                storeAreaInfo(BABYLON.Vector2.Zero(), new BABYLON.Size(w, h));
+            }
             // Compute the layout related data
             if (hasLayout) {
-                var layoutOffset = this.layoutAreaPos.clone();
-                storeAreaInfo(layoutOffset, (hasMargin || hasPadding) ? this.layoutArea.clone() : this.actualSize.clone());
-                curOffset = layoutOffset.clone();
+                var layoutOffset = this.layoutAreaPos;
+                var w = this.layoutArea.width - (layoutOffset.x + this.margin.leftPixels + this.margin.rightPixels + this.actualSize.width);
+                var h = this.layoutArea.height - (layoutOffset.y + this.margin.topPixels + this.margin.bottomPixels + this.actualSize.height);
+                var layoutArea = new BABYLON.Size(w, h);
+                storeAreaInfo(layoutOffset, layoutArea);
+                curOffset = this.layoutAreaPos;
             }
             // Compute margin data
             if (hasMargin) {
-                var marginOffset = curOffset.clone();
-                marginOffset.x += this._marginOffset.x;
-                marginOffset.y += this._marginOffset.y;
+                var marginOffset = this._marginOffset.add(curOffset);
                 var marginArea = this.actualSize;
                 storeAreaInfo(marginOffset, marginArea);
-                curOffset = marginOffset.clone();
+                curOffset.addInPlace(marginOffset);
             }
             if (hasPadding) {
-                var contentOffset = curOffset.clone();
-                contentOffset.x += this._paddingOffset.x;
-                contentOffset.y += this._paddingOffset.y;
+                var contentOffset = this._paddingOffset.add(curOffset);
                 var contentArea = this.contentArea;
                 storeAreaInfo(contentOffset, contentArea);
-                curOffset = curOffset.add(contentOffset);
+                curOffset.addInPlace(contentOffset);
             }
             // Helper function that set the pos and size of a given prim
             var setArea = function (i, j, pos, size) {
@@ -5219,9 +5200,9 @@ var BABYLON;
                 var lp = new BABYLON.Vector2(ca.min.x, na.min.y);
                 var ls = new BABYLON.Size(na.min.x - ca.min.x, na.max.y - na.min.y);
                 var rp = new BABYLON.Vector2(na.max.x, na.min.y);
-                var rs = new BABYLON.Size(ca.max.x - na.max.x, na.max.y - na.min.y);
+                var rs = ls;
                 var bp = new BABYLON.Vector2(ca.min.x, ca.min.y);
-                var bs = new BABYLON.Size(ca.size.width, na.min.y - ca.min.y);
+                var bs = ts;
                 // Frame
                 plist[1].position = ca.off;
                 plist[1].size = ca.size;
@@ -5663,7 +5644,7 @@ var BABYLON;
                 var parentPaddingChanged = false;
                 var parentPaddingOffset = Prim2DBase._v0;
                 if (this._parent) {
-                    parentPaddingOffset = new BABYLON.Vector2(this._parent._paddingOffset.x, this._parent._paddingOffset.y);
+                    parentPaddingOffset = this._parent._paddingOffset;
                     parentPaddingChanged = !parentPaddingOffset.equals(this._parentPaddingOffset);
                 }
                 // Check if there are changes in the parent that will force us to update the global matrix
@@ -5715,13 +5696,12 @@ var BABYLON;
                 this.margin.computeWithAlignment(this.layoutArea, this.size || this.actualSize, this.marginAlignment, this._marginOffset, Prim2DBase._size);
                 this.actualSize = Prim2DBase._size.clone();
             }
-            var po = new BABYLON.Vector2(this._paddingOffset.x, this._paddingOffset.y);
             if (this._hasPadding) {
                 // Two cases from here: the size of the Primitive is Auto, its content can't be shrink, so me resize the primitive itself
                 if (isSizeAuto) {
                     var content = this.size.clone();
                     this._getActualSizeFromContentToRef(content, Prim2DBase._icArea);
-                    this.padding.enlarge(Prim2DBase._icArea, po, Prim2DBase._size);
+                    this.padding.enlarge(Prim2DBase._icArea, this._paddingOffset, Prim2DBase._size);
                     this._contentArea.copyFrom(content);
                     this.actualSize = Prim2DBase._size.clone();
                     // Changing the padding has resize the prim, which forces us to recompute margin again
@@ -5730,27 +5710,20 @@ var BABYLON;
                     }
                 }
                 else {
-                    this._getInitialContentAreaToRef(this.actualSize, Prim2DBase._icZone, Prim2DBase._icArea);
+                    this._getInitialContentAreaToRef(this.actualSize, Prim2DBase._icPos, Prim2DBase._icArea);
                     Prim2DBase._icArea.width = Math.max(0, Prim2DBase._icArea.width);
                     Prim2DBase._icArea.height = Math.max(0, Prim2DBase._icArea.height);
-                    this.padding.compute(Prim2DBase._icArea, po, Prim2DBase._size);
-                    this._paddingOffset.x = po.x;
-                    this._paddingOffset.y = po.y;
-                    this._paddingOffset.x += Prim2DBase._icZone.x;
-                    this._paddingOffset.y += Prim2DBase._icZone.y;
-                    this._paddingOffset.z -= Prim2DBase._icZone.z;
-                    this._paddingOffset.w -= Prim2DBase._icZone.w;
+                    this.padding.compute(Prim2DBase._icArea, this._paddingOffset, Prim2DBase._size);
+                    this._paddingOffset.x += Prim2DBase._icPos.x;
+                    this._paddingOffset.y += Prim2DBase._icPos.y;
                     this._contentArea.copyFrom(Prim2DBase._size);
                 }
             }
             else {
-                this._getInitialContentAreaToRef(this.actualSize, Prim2DBase._icZone, Prim2DBase._icArea);
+                this._getInitialContentAreaToRef(this.actualSize, Prim2DBase._icPos, Prim2DBase._icArea);
                 Prim2DBase._icArea.width = Math.max(0, Prim2DBase._icArea.width);
                 Prim2DBase._icArea.height = Math.max(0, Prim2DBase._icArea.height);
-                this._paddingOffset.x = Prim2DBase._icZone.x;
-                this._paddingOffset.y = Prim2DBase._icZone.y;
-                this._paddingOffset.z = Prim2DBase._icZone.z;
-                this._paddingOffset.w = Prim2DBase._icZone.z;
+                this._paddingOffset.copyFrom(Prim2DBase._icPos);
                 this._contentArea.copyFrom(Prim2DBase._icArea);
             }
             if (!this._position) {
@@ -5953,12 +5926,12 @@ var BABYLON;
          * This method is used to alter the contentArea of the Primitive before margin is applied.
          * In most of the case you won't need to override this method, but it can prove some usefulness, check the Rectangle2D class for a concrete application.
          * @param primSize the current size of the primitive
-         * @param initialContentPosition the position of the initial content area to compute, a valid object is passed, you have to set its properties. PLEASE ROUND the values, we're talking about pixels and fraction of them is not a good thing! x, y, z, w area left, bottom, right, top
+         * @param initialContentPosition the position of the initial content area to compute, a valid object is passed, you have to set its properties. PLEASE ROUND the values, we're talking about pixels and fraction of them is not a good thing!
          * @param initialContentArea the size of the initial content area to compute, a valid object is passed, you have to set its properties. PLEASE ROUND the values, we're talking about pixels and fraction of them is not a good thing!
          */
         Prim2DBase.prototype._getInitialContentAreaToRef = function (primSize, initialContentPosition, initialContentArea) {
             initialContentArea.copyFrom(primSize);
-            initialContentPosition.x = initialContentPosition.y = initialContentPosition.z = initialContentPosition.w = 0;
+            initialContentPosition.x = initialContentPosition.y = 0;
         };
         /**
          * This method is used to calculate the new size of the primitive based on the content which must stay the same
@@ -5983,7 +5956,6 @@ var BABYLON;
         Prim2DBase._v0 = BABYLON.Vector2.Zero(); // Must stay with the value 0,0
         Prim2DBase._transMtx = BABYLON.Matrix.Zero();
         Prim2DBase._icPos = BABYLON.Vector2.Zero();
-        Prim2DBase._icZone = BABYLON.Vector4.Zero();
         Prim2DBase._icArea = BABYLON.Size.Zero();
         Prim2DBase._size = BABYLON.Size.Zero();
         Prim2DBase._zOrderChangedNotifList = new Array();
@@ -8910,8 +8882,6 @@ var BABYLON;
                 initialContentPosition.x = initialContentPosition.y = rr;
                 initialContentArea.width = Math.max(0, primSize.width - (rr * 2));
                 initialContentArea.height = Math.max(0, primSize.height - (rr * 2));
-                initialContentPosition.z = primSize.width - (initialContentPosition.x + initialContentArea.width);
-                initialContentPosition.w = primSize.height - (initialContentPosition.y + initialContentArea.height);
             }
         };
         Rectangle2D.prototype._getActualSizeFromContentToRef = function (primSize, newPrimSize) {
@@ -11927,25 +11897,19 @@ var BABYLON;
             ii.findFirstOnly = false;
             // Fast rejection: test if the mouse pointer is outside the canvas's bounding Info
             if (!isCapture && !this.levelBoundingInfo.doesIntersect(ii.pickPosition)) {
-                // Reset intersection info as we don't hit anything
-                ii.intersectedPrimitives = new Array();
-                ii.topMostIntersectedPrimitive = null;
-            }
-            else {
-                // The pointer is inside the Canvas, do an intersection test
-                this.intersect(ii);
-            }
-            {
-                // Update prev/actual intersection info, fire "overPrim" property change if needed
                 this._previousIntersectionList = this._actualIntersectionList;
-                this._actualIntersectionList = ii.intersectedPrimitives;
+                this._actualIntersectionList = null;
                 this._previousOverPrimitive = this._actualOverPrimitive;
-                this._actualOverPrimitive = ii.topMostIntersectedPrimitive;
-                var prev = (this._previousOverPrimitive != null) ? this._previousOverPrimitive.prim : null;
-                var actual = (this._actualOverPrimitive != null) ? this._actualOverPrimitive.prim : null;
-                if (prev !== actual) {
-                    this.onPropertyChanged("overPrim", this._previousOverPrimitive ? this._previousOverPrimitive.prim : null, this._actualOverPrimitive ? this._actualOverPrimitive.prim : null);
-                }
+                this._actualOverPrimitive = null;
+                return;
+            }
+            this.intersect(ii);
+            this._previousIntersectionList = this._actualIntersectionList;
+            this._actualIntersectionList = ii.intersectedPrimitives;
+            this._previousOverPrimitive = this._actualOverPrimitive;
+            this._actualOverPrimitive = ii.topMostIntersectedPrimitive;
+            if ((!this._actualOverPrimitive && !this._previousOverPrimitive) || !(this._actualOverPrimitive && this._previousOverPrimitive && this._actualOverPrimitive.prim === this._previousOverPrimitive.prim)) {
+                this.onPropertyChanged("overPrim", this._previousOverPrimitive ? this._previousOverPrimitive.prim : null, this._actualOverPrimitive ? this._actualOverPrimitive.prim : null);
             }
             this._intersectionRenderId = this.scene.getRenderId();
         };
@@ -12033,17 +11997,15 @@ var BABYLON;
                 if (bubbleCancelled) {
                     this._updatePrimPointerPos(cur);
                 }
-                // NOTE TO MYSELF, this is commented right now because it doesn't seemed needed but I can't figure out why I put this code in the first place
-                //// Trigger a PointerEnter corresponding to the PointerOver
-                //if (mask === PrimitivePointerInfo.PointerOver) {
-                //    this._debugExecObserver(cur, PrimitivePointerInfo.PointerEnter);
-                //    cur._pointerEventObservable.notifyObservers(ppi, PrimitivePointerInfo.PointerEnter);
-                //}
-                //// Trigger a PointerLeave corresponding to the PointerOut
-                //else if (mask === PrimitivePointerInfo.PointerOut) {
-                //    this._debugExecObserver(cur, PrimitivePointerInfo.PointerLeave);
-                //    cur._pointerEventObservable.notifyObservers(ppi, PrimitivePointerInfo.PointerLeave);
-                //}
+                // Trigger a PointerEnter corresponding to the PointerOver
+                if (mask === BABYLON.PrimitivePointerInfo.PointerOver) {
+                    this._debugExecObserver(cur, BABYLON.PrimitivePointerInfo.PointerEnter);
+                    cur._pointerEventObservable.notifyObservers(ppi, BABYLON.PrimitivePointerInfo.PointerEnter);
+                }
+                else if (mask === BABYLON.PrimitivePointerInfo.PointerOut) {
+                    this._debugExecObserver(cur, BABYLON.PrimitivePointerInfo.PointerLeave);
+                    cur._pointerEventObservable.notifyObservers(ppi, BABYLON.PrimitivePointerInfo.PointerLeave);
+                }
                 // Loop to the parent
                 cur = cur.parent;
             }

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


+ 320 - 298
dist/preview release/babylon.d.ts

@@ -3317,6 +3317,10 @@ declare module BABYLON {
          * Alpha blending mode used to apply the blur. Default is combine.
          */
         alphaBlendingMode?: number;
+        /**
+         * The camera attached to the layer.
+         */
+        camera?: Camera;
     }
     /**
      * The highlight layer Helps adding a glow effect around a mesh.
@@ -3358,6 +3362,7 @@ declare module BABYLON {
         private _maxSize;
         private _shouldRender;
         private _instanceGlowingMeshStencilReference;
+        private _excludedMeshes;
         /**
          * Specifies whether or not the inner glow is ACTIVE in the layer.
          */
@@ -3367,10 +3372,6 @@ declare module BABYLON {
          */
         outerGlow: boolean;
         /**
-         * Specifies the listof mesh excluded during the generation of the highlight layer.
-         */
-        excludedMeshes: Mesh[];
-        /**
          * Gets the horizontal size of the blur.
          */
         /**
@@ -3385,6 +3386,10 @@ declare module BABYLON {
          */
         blurVerticalSize: number;
         /**
+         * Gets the camera attached to the layer.
+         */
+        camera: Camera;
+        /**
          * An event triggered when the highlight layer has been disposed.
          * @type {BABYLON.Observable}
          */
@@ -3443,6 +3448,16 @@ declare module BABYLON {
          */
         render(): void;
         /**
+         * Add a mesh in the exclusion list to prevent it to impact or being impacted by the highlight layer.
+         * @param mesh The mesh to exclude from the highlight layer
+         */
+        addExcludedMesh(mesh: Mesh): void;
+        /**
+          * Remove a mesh from the exclusion list to let it impact or being impacted by the highlight layer.
+          * @param mesh The mesh to highlight
+          */
+        removeExcludedMesh(mesh: Mesh): void;
+        /**
          * Add a mesh in the highlight layer in order to make it glow with the chosen color.
          * @param mesh The mesh to highlight
          * @param color The color of the highlight
@@ -4660,7 +4675,7 @@ declare module BABYLON {
         setMatrix(name: string, value: Matrix): ShaderMaterial;
         setMatrix3x3(name: string, value: Float32Array): ShaderMaterial;
         setMatrix2x2(name: string, value: Float32Array): ShaderMaterial;
-        setVector3Array(name: string, value: number[]): ShaderMaterial;
+        setArray3(name: string, value: number[]): ShaderMaterial;
         isReady(mesh?: AbstractMesh, useInstances?: boolean): boolean;
         bindOnlyWorldMatrix(world: Matrix): void;
         bind(world: Matrix, mesh?: Mesh): void;
@@ -5639,7 +5654,7 @@ declare module BABYLON {
         detachFromBone(): void;
         isInFrustum(frustumPlanes: Plane[]): boolean;
         isCompletelyInFrustum(frustumPlanes: Plane[]): boolean;
-        intersectsMesh(mesh: AbstractMesh, precise?: boolean): boolean;
+        intersectsMesh(mesh: AbstractMesh | SolidParticle, precise?: boolean): boolean;
         intersectsPoint(point: Vector3): boolean;
         /**
          *  @Deprecated. Use new PhysicsImpostor instead.
@@ -8343,9 +8358,12 @@ declare module BABYLON {
         _model: ModelShape;
         shapeId: number;
         idxInShape: number;
-        constructor(particleIndex: number, positionIndex: number, model: ModelShape, shapeId: number, idxInShape: number);
+        _modelBoundingInfo: BoundingInfo;
+        _boundingInfo: BoundingInfo;
+        constructor(particleIndex: number, positionIndex: number, model: ModelShape, shapeId: number, idxInShape: number, modelBoundingInfo?: BoundingInfo);
         scale: Vector3;
         quaternion: Quaternion;
+        intersectsMesh(target: Mesh | SolidParticle): boolean;
     }
     class ModelShape {
         shapeID: number;
@@ -8466,16 +8484,20 @@ declare module BABYLON {
         private _maximum;
         private _scale;
         private _translation;
+        private _particlesIntersect;
+        private _wm;
         /**
         * Creates a SPS (Solid Particle System) object.
         * `name` (String) is the SPS name, this will be the underlying mesh name.
         * `scene` (Scene) is the scene in which the SPS is added.
         * `updatable` (default true) : if the SPS must be updatable or immutable.
         * `isPickable` (default false) : if the solid particles must be pickable.
+        * `particleIntersection` (default false) : if the solid particle intersections must be computed
         */
         constructor(name: string, scene: Scene, options?: {
             updatable?: boolean;
             isPickable?: boolean;
+            particleIntersection?: boolean;
         });
         /**
         * Builds the SPS underlying mesh. Returns a standard Mesh.
@@ -8500,7 +8522,7 @@ declare module BABYLON {
         private _meshBuilder(p, shape, positions, meshInd, indices, meshUV, uvs, meshCol, colors, meshNor, normals, idx, idxInShape, options);
         private _posToShape(positions);
         private _uvsToShapeUV(uvs);
-        private _addParticle(idx, idxpos, model, shapeId, idxInShape);
+        private _addParticle(idx, idxpos, model, shapeId, idxInShape, bInfo?);
         /**
         * Adds some particles to the SPS from the model shape. Returns the shape id.
         * Please read the doc : http://doc.babylonjs.com/overviews/Solid_Particle_System#create-an-immutable-sps
@@ -8655,6 +8677,237 @@ declare module BABYLON {
 }
 
 declare module BABYLON {
+    class BoundingBoxRenderer {
+        frontColor: Color3;
+        backColor: Color3;
+        showBackLines: boolean;
+        renderList: SmartArray<BoundingBox>;
+        private _scene;
+        private _colorShader;
+        private _vertexBuffers;
+        private _indexBuffer;
+        constructor(scene: Scene);
+        private _prepareRessources();
+        reset(): void;
+        render(): void;
+        dispose(): void;
+    }
+}
+
+declare module BABYLON {
+    class DepthRenderer {
+        private _scene;
+        private _depthMap;
+        private _effect;
+        private _viewMatrix;
+        private _projectionMatrix;
+        private _transformMatrix;
+        private _worldViewProjection;
+        private _cachedDefines;
+        constructor(scene: Scene, type?: number);
+        isReady(subMesh: SubMesh, useInstances: boolean): boolean;
+        getDepthMap(): RenderTargetTexture;
+        dispose(): void;
+    }
+}
+
+declare module BABYLON {
+    class EdgesRenderer {
+        edgesWidthScalerForOrthographic: number;
+        edgesWidthScalerForPerspective: number;
+        private _source;
+        private _linesPositions;
+        private _linesNormals;
+        private _linesIndices;
+        private _epsilon;
+        private _indicesCount;
+        private _lineShader;
+        private _ib;
+        private _buffers;
+        private _checkVerticesInsteadOfIndices;
+        constructor(source: AbstractMesh, epsilon?: number, checkVerticesInsteadOfIndices?: boolean);
+        private _prepareRessources();
+        dispose(): void;
+        private _processEdgeForAdjacencies(pa, pb, p0, p1, p2);
+        private _processEdgeForAdjacenciesWithVertices(pa, pb, p0, p1, p2);
+        private _checkEdge(faceIndex, edge, faceNormals, p0, p1);
+        _generateEdgesLines(): void;
+        render(): void;
+    }
+}
+
+declare module BABYLON {
+    class OutlineRenderer {
+        private _scene;
+        private _effect;
+        private _cachedDefines;
+        constructor(scene: Scene);
+        render(subMesh: SubMesh, batch: _InstancesBatch, useOverlay?: boolean): void;
+        isReady(subMesh: SubMesh, useInstances: boolean): boolean;
+    }
+}
+
+declare module BABYLON {
+    class RenderingGroup {
+        index: number;
+        private _scene;
+        private _opaqueSubMeshes;
+        private _transparentSubMeshes;
+        private _alphaTestSubMeshes;
+        private _activeVertices;
+        private _opaqueSortCompareFn;
+        private _alphaTestSortCompareFn;
+        private _transparentSortCompareFn;
+        private _renderOpaque;
+        private _renderAlphaTest;
+        private _renderTransparent;
+        onBeforeTransparentRendering: () => void;
+        /**
+         * Set the opaque sort comparison function.
+         * If null the sub meshes will be render in the order they were created
+         */
+        opaqueSortCompareFn: (a: SubMesh, b: SubMesh) => number;
+        /**
+         * Set the alpha test sort comparison function.
+         * If null the sub meshes will be render in the order they were created
+         */
+        alphaTestSortCompareFn: (a: SubMesh, b: SubMesh) => number;
+        /**
+         * Set the transparent sort comparison function.
+         * If null the sub meshes will be render in the order they were created
+         */
+        transparentSortCompareFn: (a: SubMesh, b: SubMesh) => number;
+        /**
+         * Creates a new rendering group.
+         * @param index The rendering group index
+         * @param opaqueSortCompareFn The opaque sort comparison function. If null no order is applied
+         * @param alphaTestSortCompareFn The alpha test sort comparison function. If null no order is applied
+         * @param transparentSortCompareFn The transparent sort comparison function. If null back to front + alpha index sort is applied
+         */
+        constructor(index: number, scene: Scene, opaqueSortCompareFn?: (a: SubMesh, b: SubMesh) => number, alphaTestSortCompareFn?: (a: SubMesh, b: SubMesh) => number, transparentSortCompareFn?: (a: SubMesh, b: SubMesh) => number);
+        /**
+         * Render all the sub meshes contained in the group.
+         * @param customRenderFunction Used to override the default render behaviour of the group.
+         * @returns true if rendered some submeshes.
+         */
+        render(customRenderFunction: (opaqueSubMeshes: SmartArray<SubMesh>, transparentSubMeshes: SmartArray<SubMesh>, alphaTestSubMeshes: SmartArray<SubMesh>) => void): boolean;
+        /**
+         * Renders the opaque submeshes in the order from the opaqueSortCompareFn.
+         * @param subMeshes The submeshes to render
+         */
+        private renderOpaqueSorted(subMeshes);
+        /**
+         * Renders the opaque submeshes in the order from the alphatestSortCompareFn.
+         * @param subMeshes The submeshes to render
+         */
+        private renderAlphaTestSorted(subMeshes);
+        /**
+         * Renders the opaque submeshes in the order from the transparentSortCompareFn.
+         * @param subMeshes The submeshes to render
+         */
+        private renderTransparentSorted(subMeshes);
+        /**
+         * Renders the submeshes in a specified order.
+         * @param subMeshes The submeshes to sort before render
+         * @param sortCompareFn The comparison function use to sort
+         * @param cameraPosition The camera position use to preprocess the submeshes to help sorting
+         * @param transparent Specifies to activate blending if true
+         */
+        private static renderSorted(subMeshes, sortCompareFn, cameraPosition, transparent);
+        /**
+         * Renders the submeshes in the order they were dispatched (no sort applied).
+         * @param subMeshes The submeshes to render
+         */
+        private static renderUnsorted(subMeshes);
+        /**
+         * Build in function which can be applied to ensure meshes of a special queue (opaque, alpha test, transparent)
+         * are rendered back to front if in the same alpha index.
+         *
+         * @param a The first submesh
+         * @param b The second submesh
+         * @returns The result of the comparison
+         */
+        static defaultTransparentSortCompare(a: SubMesh, b: SubMesh): number;
+        /**
+         * Build in function which can be applied to ensure meshes of a special queue (opaque, alpha test, transparent)
+         * are rendered back to front.
+         *
+         * @param a The first submesh
+         * @param b The second submesh
+         * @returns The result of the comparison
+         */
+        static backToFrontSortCompare(a: SubMesh, b: SubMesh): number;
+        /**
+         * Build in function which can be applied to ensure meshes of a special queue (opaque, alpha test, transparent)
+         * are rendered front to back (prevent overdraw).
+         *
+         * @param a The first submesh
+         * @param b The second submesh
+         * @returns The result of the comparison
+         */
+        static frontToBackSortCompare(a: SubMesh, b: SubMesh): number;
+        /**
+         * Resets the different lists of submeshes to prepare a new frame.
+         */
+        prepare(): void;
+        /**
+         * Inserts the submesh in its correct queue depending on its material.
+         * @param subMesh The submesh to dispatch
+         */
+        dispatch(subMesh: SubMesh): void;
+    }
+}
+
+declare module BABYLON {
+    class RenderingManager {
+        /**
+         * The max id used for rendering groups (not included)
+         */
+        static MAX_RENDERINGGROUPS: number;
+        /**
+         * The min id used for rendering groups (included)
+         */
+        static MIN_RENDERINGGROUPS: number;
+        private _scene;
+        private _renderingGroups;
+        private _depthStencilBufferAlreadyCleaned;
+        private _currentIndex;
+        private _currentActiveMeshes;
+        private _currentRenderParticles;
+        private _currentRenderSprites;
+        private _autoClearDepthStencil;
+        private _customOpaqueSortCompareFn;
+        private _customAlphaTestSortCompareFn;
+        private _customTransparentSortCompareFn;
+        constructor(scene: Scene);
+        private _renderParticles(index, activeMeshes);
+        private _renderSprites(index);
+        private _clearDepthStencilBuffer();
+        private _renderSpritesAndParticles();
+        render(customRenderFunction: (opaqueSubMeshes: SmartArray<SubMesh>, transparentSubMeshes: SmartArray<SubMesh>, alphaTestSubMeshes: SmartArray<SubMesh>) => void, activeMeshes: AbstractMesh[], renderParticles: boolean, renderSprites: boolean): void;
+        reset(): void;
+        dispatch(subMesh: SubMesh): void;
+        /**
+         * Overrides the default sort function applied in the renderging group to prepare the meshes.
+         * This allowed control for front to back rendering or reversly depending of the special needs.
+         *
+         * @param renderingGroupId The rendering group id corresponding to its index
+         * @param opaqueSortCompareFn The opaque queue comparison function use to sort.
+         * @param alphaTestSortCompareFn The alpha test queue comparison function use to sort.
+         * @param transparentSortCompareFn The transparent queue comparison function use to sort.
+         */
+        setRenderingOrder(renderingGroupId: number, opaqueSortCompareFn?: (a: SubMesh, b: SubMesh) => number, alphaTestSortCompareFn?: (a: SubMesh, b: SubMesh) => number, transparentSortCompareFn?: (a: SubMesh, b: SubMesh) => number): void;
+        /**
+         * Specifies whether or not the stencil and depth buffer are cleared between two rendering groups.
+         *
+         * @param renderingGroupId The rendering group id corresponding to its index
+         * @param autoClearDepthStencil Automatically clears depth and stencil between groups if true.
+         */
+        setRenderingAutoClearDepthStencil(renderingGroupId: number, autoClearDepthStencil: boolean): void;
+    }
+}
+
+declare module BABYLON {
     class AnaglyphPostProcess extends PostProcess {
         private _passedProcess;
         constructor(name: string, options: number | PostProcessOptions, rigCameras: Camera[], samplingMode?: number, engine?: Engine, reusable?: boolean);
@@ -9329,233 +9582,72 @@ declare module BABYLON {
 }
 
 declare module BABYLON {
-    class BoundingBoxRenderer {
-        frontColor: Color3;
-        backColor: Color3;
-        showBackLines: boolean;
-        renderList: SmartArray<BoundingBox>;
-        private _scene;
-        private _colorShader;
-        private _vertexBuffers;
-        private _indexBuffer;
-        constructor(scene: Scene);
-        private _prepareRessources();
-        reset(): void;
-        render(): void;
-        dispose(): void;
-    }
-}
-
-declare module BABYLON {
-    class DepthRenderer {
-        private _scene;
-        private _depthMap;
-        private _effect;
-        private _viewMatrix;
-        private _projectionMatrix;
-        private _transformMatrix;
-        private _worldViewProjection;
-        private _cachedDefines;
-        constructor(scene: Scene, type?: number);
-        isReady(subMesh: SubMesh, useInstances: boolean): boolean;
-        getDepthMap(): RenderTargetTexture;
-        dispose(): void;
-    }
-}
-
-declare module BABYLON {
-    class EdgesRenderer {
-        edgesWidthScalerForOrthographic: number;
-        edgesWidthScalerForPerspective: number;
-        private _source;
-        private _linesPositions;
-        private _linesNormals;
-        private _linesIndices;
-        private _epsilon;
-        private _indicesCount;
-        private _lineShader;
-        private _ib;
-        private _buffers;
-        private _checkVerticesInsteadOfIndices;
-        constructor(source: AbstractMesh, epsilon?: number, checkVerticesInsteadOfIndices?: boolean);
-        private _prepareRessources();
+    class Sprite {
+        name: string;
+        position: Vector3;
+        color: Color4;
+        width: number;
+        height: number;
+        angle: number;
+        cellIndex: number;
+        invertU: number;
+        invertV: number;
+        disposeWhenFinishedAnimating: boolean;
+        animations: Animation[];
+        isPickable: boolean;
+        actionManager: ActionManager;
+        private _animationStarted;
+        private _loopAnimation;
+        private _fromIndex;
+        private _toIndex;
+        private _delay;
+        private _direction;
+        private _frameCount;
+        private _manager;
+        private _time;
+        private _onAnimationEnd;
+        size: number;
+        constructor(name: string, manager: SpriteManager);
+        playAnimation(from: number, to: number, loop: boolean, delay: number, onAnimationEnd: () => void): void;
+        stopAnimation(): void;
+        _animate(deltaTime: number): void;
         dispose(): void;
-        private _processEdgeForAdjacencies(pa, pb, p0, p1, p2);
-        private _processEdgeForAdjacenciesWithVertices(pa, pb, p0, p1, p2);
-        private _checkEdge(faceIndex, edge, faceNormals, p0, p1);
-        _generateEdgesLines(): void;
-        render(): void;
     }
 }
 
 declare module BABYLON {
-    class OutlineRenderer {
-        private _scene;
-        private _effect;
-        private _cachedDefines;
-        constructor(scene: Scene);
-        render(subMesh: SubMesh, batch: _InstancesBatch, useOverlay?: boolean): void;
-        isReady(subMesh: SubMesh, useInstances: boolean): boolean;
-    }
-}
-
-declare module BABYLON {
-    class RenderingGroup {
-        index: number;
-        private _scene;
-        private _opaqueSubMeshes;
-        private _transparentSubMeshes;
-        private _alphaTestSubMeshes;
-        private _activeVertices;
-        private _opaqueSortCompareFn;
-        private _alphaTestSortCompareFn;
-        private _transparentSortCompareFn;
-        private _renderOpaque;
-        private _renderAlphaTest;
-        private _renderTransparent;
-        onBeforeTransparentRendering: () => void;
-        /**
-         * Set the opaque sort comparison function.
-         * If null the sub meshes will be render in the order they were created
-         */
-        opaqueSortCompareFn: (a: SubMesh, b: SubMesh) => number;
-        /**
-         * Set the alpha test sort comparison function.
-         * If null the sub meshes will be render in the order they were created
-         */
-        alphaTestSortCompareFn: (a: SubMesh, b: SubMesh) => number;
-        /**
-         * Set the transparent sort comparison function.
-         * If null the sub meshes will be render in the order they were created
-         */
-        transparentSortCompareFn: (a: SubMesh, b: SubMesh) => number;
-        /**
-         * Creates a new rendering group.
-         * @param index The rendering group index
-         * @param opaqueSortCompareFn The opaque sort comparison function. If null no order is applied
-         * @param alphaTestSortCompareFn The alpha test sort comparison function. If null no order is applied
-         * @param transparentSortCompareFn The transparent sort comparison function. If null back to front + alpha index sort is applied
-         */
-        constructor(index: number, scene: Scene, opaqueSortCompareFn?: (a: SubMesh, b: SubMesh) => number, alphaTestSortCompareFn?: (a: SubMesh, b: SubMesh) => number, transparentSortCompareFn?: (a: SubMesh, b: SubMesh) => number);
-        /**
-         * Render all the sub meshes contained in the group.
-         * @param customRenderFunction Used to override the default render behaviour of the group.
-         * @returns true if rendered some submeshes.
-         */
-        render(customRenderFunction: (opaqueSubMeshes: SmartArray<SubMesh>, transparentSubMeshes: SmartArray<SubMesh>, alphaTestSubMeshes: SmartArray<SubMesh>) => void): boolean;
-        /**
-         * Renders the opaque submeshes in the order from the opaqueSortCompareFn.
-         * @param subMeshes The submeshes to render
-         */
-        private renderOpaqueSorted(subMeshes);
-        /**
-         * Renders the opaque submeshes in the order from the alphatestSortCompareFn.
-         * @param subMeshes The submeshes to render
-         */
-        private renderAlphaTestSorted(subMeshes);
-        /**
-         * Renders the opaque submeshes in the order from the transparentSortCompareFn.
-         * @param subMeshes The submeshes to render
-         */
-        private renderTransparentSorted(subMeshes);
-        /**
-         * Renders the submeshes in a specified order.
-         * @param subMeshes The submeshes to sort before render
-         * @param sortCompareFn The comparison function use to sort
-         * @param cameraPosition The camera position use to preprocess the submeshes to help sorting
-         * @param transparent Specifies to activate blending if true
-         */
-        private static renderSorted(subMeshes, sortCompareFn, cameraPosition, transparent);
-        /**
-         * Renders the submeshes in the order they were dispatched (no sort applied).
-         * @param subMeshes The submeshes to render
-         */
-        private static renderUnsorted(subMeshes);
-        /**
-         * Build in function which can be applied to ensure meshes of a special queue (opaque, alpha test, transparent)
-         * are rendered back to front if in the same alpha index.
-         *
-         * @param a The first submesh
-         * @param b The second submesh
-         * @returns The result of the comparison
-         */
-        static defaultTransparentSortCompare(a: SubMesh, b: SubMesh): number;
-        /**
-         * Build in function which can be applied to ensure meshes of a special queue (opaque, alpha test, transparent)
-         * are rendered back to front.
-         *
-         * @param a The first submesh
-         * @param b The second submesh
-         * @returns The result of the comparison
-         */
-        static backToFrontSortCompare(a: SubMesh, b: SubMesh): number;
-        /**
-         * Build in function which can be applied to ensure meshes of a special queue (opaque, alpha test, transparent)
-         * are rendered front to back (prevent overdraw).
-         *
-         * @param a The first submesh
-         * @param b The second submesh
-         * @returns The result of the comparison
-         */
-        static frontToBackSortCompare(a: SubMesh, b: SubMesh): number;
-        /**
-         * Resets the different lists of submeshes to prepare a new frame.
-         */
-        prepare(): void;
-        /**
-         * Inserts the submesh in its correct queue depending on its material.
-         * @param subMesh The submesh to dispatch
-         */
-        dispatch(subMesh: SubMesh): void;
-    }
-}
-
-declare module BABYLON {
-    class RenderingManager {
-        /**
-         * The max id used for rendering groups (not included)
-         */
-        static MAX_RENDERINGGROUPS: number;
+    class SpriteManager {
+        name: string;
+        sprites: Sprite[];
+        renderingGroupId: number;
+        layerMask: number;
+        fogEnabled: boolean;
+        isPickable: boolean;
+        cellWidth: number;
+        cellHeight: number;
         /**
-         * The min id used for rendering groups (included)
-         */
-        static MIN_RENDERINGGROUPS: number;
+        * An event triggered when the manager is disposed.
+        * @type {BABYLON.Observable}
+        */
+        onDisposeObservable: Observable<SpriteManager>;
+        private _onDisposeObserver;
+        onDispose: () => void;
+        private _capacity;
+        private _spriteTexture;
+        private _epsilon;
         private _scene;
-        private _renderingGroups;
-        private _depthStencilBufferAlreadyCleaned;
-        private _currentIndex;
-        private _currentActiveMeshes;
-        private _currentRenderParticles;
-        private _currentRenderSprites;
-        private _autoClearDepthStencil;
-        private _customOpaqueSortCompareFn;
-        private _customAlphaTestSortCompareFn;
-        private _customTransparentSortCompareFn;
-        constructor(scene: Scene);
-        private _renderParticles(index, activeMeshes);
-        private _renderSprites(index);
-        private _clearDepthStencilBuffer();
-        private _renderSpritesAndParticles();
-        render(customRenderFunction: (opaqueSubMeshes: SmartArray<SubMesh>, transparentSubMeshes: SmartArray<SubMesh>, alphaTestSubMeshes: SmartArray<SubMesh>) => void, activeMeshes: AbstractMesh[], renderParticles: boolean, renderSprites: boolean): void;
-        reset(): void;
-        dispatch(subMesh: SubMesh): void;
-        /**
-         * Overrides the default sort function applied in the renderging group to prepare the meshes.
-         * This allowed control for front to back rendering or reversly depending of the special needs.
-         *
-         * @param renderingGroupId The rendering group id corresponding to its index
-         * @param opaqueSortCompareFn The opaque queue comparison function use to sort.
-         * @param alphaTestSortCompareFn The alpha test queue comparison function use to sort.
-         * @param transparentSortCompareFn The transparent queue comparison function use to sort.
-         */
-        setRenderingOrder(renderingGroupId: number, opaqueSortCompareFn?: (a: SubMesh, b: SubMesh) => number, alphaTestSortCompareFn?: (a: SubMesh, b: SubMesh) => number, transparentSortCompareFn?: (a: SubMesh, b: SubMesh) => number): void;
-        /**
-         * Specifies whether or not the stencil and depth buffer are cleared between two rendering groups.
-         *
-         * @param renderingGroupId The rendering group id corresponding to its index
-         * @param autoClearDepthStencil Automatically clears depth and stencil between groups if true.
-         */
-        setRenderingAutoClearDepthStencil(renderingGroupId: number, autoClearDepthStencil: boolean): void;
+        private _vertexData;
+        private _buffer;
+        private _vertexBuffers;
+        private _indexBuffer;
+        private _effectBase;
+        private _effectFog;
+        texture: Texture;
+        constructor(name: string, imgUrl: string, capacity: number, cellSize: any, scene: Scene, epsilon?: number, samplingMode?: number);
+        private _appendSpriteVertex(index, sprite, offsetX, offsetY, rowSize);
+        intersects(ray: Ray, camera: Camera, predicate?: (sprite: Sprite) => boolean, fastCheck?: boolean): PickingInfo;
+        render(): void;
+        dispose(): void;
     }
 }
 
@@ -9628,76 +9720,6 @@ declare module BABYLON.Internals {
     }
 }
 
-declare module BABYLON {
-    class Sprite {
-        name: string;
-        position: Vector3;
-        color: Color4;
-        width: number;
-        height: number;
-        angle: number;
-        cellIndex: number;
-        invertU: number;
-        invertV: number;
-        disposeWhenFinishedAnimating: boolean;
-        animations: Animation[];
-        isPickable: boolean;
-        actionManager: ActionManager;
-        private _animationStarted;
-        private _loopAnimation;
-        private _fromIndex;
-        private _toIndex;
-        private _delay;
-        private _direction;
-        private _frameCount;
-        private _manager;
-        private _time;
-        private _onAnimationEnd;
-        size: number;
-        constructor(name: string, manager: SpriteManager);
-        playAnimation(from: number, to: number, loop: boolean, delay: number, onAnimationEnd: () => void): void;
-        stopAnimation(): void;
-        _animate(deltaTime: number): void;
-        dispose(): void;
-    }
-}
-
-declare module BABYLON {
-    class SpriteManager {
-        name: string;
-        sprites: Sprite[];
-        renderingGroupId: number;
-        layerMask: number;
-        fogEnabled: boolean;
-        isPickable: boolean;
-        cellWidth: number;
-        cellHeight: number;
-        /**
-        * An event triggered when the manager is disposed.
-        * @type {BABYLON.Observable}
-        */
-        onDisposeObservable: Observable<SpriteManager>;
-        private _onDisposeObserver;
-        onDispose: () => void;
-        private _capacity;
-        private _spriteTexture;
-        private _epsilon;
-        private _scene;
-        private _vertexData;
-        private _buffer;
-        private _vertexBuffers;
-        private _indexBuffer;
-        private _effectBase;
-        private _effectFog;
-        texture: Texture;
-        constructor(name: string, imgUrl: string, capacity: number, cellSize: any, scene: Scene, epsilon?: number, samplingMode?: number);
-        private _appendSpriteVertex(index, sprite, offsetX, offsetY, rowSize);
-        intersects(ray: Ray, camera: Camera, predicate?: (sprite: Sprite) => boolean, fastCheck?: boolean): PickingInfo;
-        render(): void;
-        dispose(): void;
-    }
-}
-
 declare module BABYLON.Internals {
     class AndOrNotEvaluator {
         static Eval(query: string, evaluateCallback: (val: any) => boolean): boolean;

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


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


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


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

@@ -17,6 +17,7 @@
 - Several memory allocation reduction ([benaadams](https://github.com/benaadams))
 - Several GPU state change reduction ([benaadams](https://github.com/benaadams)) 
 - MapTexture: add `supersample` mode to double font quality. ([nockawa](https://github.com/nockawa))
+- New SPS feature : solid particle intersection with other solid particle or with any mesh `particle.intersectsMesh()` ([jerome](https://github.com/jbousquie))
 - New `invertUV` parameter an all ribbon based shapes : ribbon, tube, lathe, basic and custom extrusion ([jerome](https://github.com/jbousquie))
 - Text2D: new `fontSuperSample` setting to use high quality font ([nockawa](https://github.com/nockawa))
 - PerfCounter class added to monitor time/counter and expose min/max/average/lastSecondAverage/current metrics. Updated engine/scene current counter to use this class, exposing new properties as well to access the PerfCounter object ([nockawa](https://github.com/nockawa))

+ 57 - 6
src/Layer/babylon.highlightlayer.js

@@ -47,6 +47,7 @@ var BABYLON;
             this._maxSize = 0;
             this._shouldRender = false;
             this._instanceGlowingMeshStencilReference = HighlightLayer.glowingMeshStencilReference++;
+            this._excludedMeshes = {};
             /**
              * Specifies whether or not the inner glow is ACTIVE in the layer.
              */
@@ -56,10 +57,6 @@ var BABYLON;
              */
             this.outerGlow = true;
             /**
-             * Specifies the listof mesh excluded during the generation of the highlight layer.
-             */
-            this.excludedMeshes = [];
-            /**
              * An event triggered when the highlight layer has been disposed.
              * @type {BABYLON.Observable}
              */
@@ -172,6 +169,16 @@ var BABYLON;
             enumerable: true,
             configurable: true
         });
+        Object.defineProperty(HighlightLayer.prototype, "camera", {
+            /**
+             * Gets the camera attached to the layer.
+             */
+            get: function () {
+                return this._options.camera;
+            },
+            enumerable: true,
+            configurable: true
+        });
         /**
          * Creates the render target textures and post processes used in the highlight layer.
          */
@@ -185,6 +192,7 @@ var BABYLON;
                 width: this._mainTextureDesiredSize.width,
                 height: this._mainTextureDesiredSize.height
             }, this._scene, false, true, BABYLON.Engine.TEXTURETYPE_UNSIGNED_INT);
+            this._mainTexture.activeCamera = this._options.camera;
             this._mainTexture.wrapU = BABYLON.Texture.CLAMP_ADDRESSMODE;
             this._mainTexture.wrapV = BABYLON.Texture.CLAMP_ADDRESSMODE;
             this._mainTexture.anisotropicFilteringLevel = 1;
@@ -230,7 +238,7 @@ var BABYLON;
                     return;
                 }
                 // Excluded Mesh
-                if (_this.excludedMeshes.indexOf(mesh) > -1) {
+                if (_this._excludedMeshes[mesh.id]) {
                     return;
                 }
                 ;
@@ -429,6 +437,36 @@ var BABYLON;
             }
         };
         /**
+         * Add a mesh in the exclusion list to prevent it to impact or being impacted by the highlight layer.
+         * @param mesh The mesh to exclude from the highlight layer
+         */
+        HighlightLayer.prototype.addExcludedMesh = function (mesh) {
+            var meshExcluded = this._excludedMeshes[mesh.id];
+            if (!meshExcluded) {
+                this._excludedMeshes[mesh.id] = {
+                    mesh: mesh,
+                    beforeRender: mesh.onBeforeRenderObservable.add(function (mesh) {
+                        mesh.getEngine().setStencilBuffer(false);
+                    }),
+                    afterRender: mesh.onAfterRenderObservable.add(function (mesh) {
+                        mesh.getEngine().setStencilBuffer(true);
+                    }),
+                };
+            }
+        };
+        /**
+          * Remove a mesh from the exclusion list to let it impact or being impacted by the highlight layer.
+          * @param mesh The mesh to highlight
+          */
+        HighlightLayer.prototype.removeExcludedMesh = function (mesh) {
+            var meshExcluded = this._excludedMeshes[mesh.id];
+            if (meshExcluded) {
+                mesh.onBeforeRenderObservable.remove(meshExcluded.beforeRender);
+                mesh.onAfterRenderObservable.remove(meshExcluded.afterRender);
+            }
+            this._excludedMeshes[mesh.id] = undefined;
+        };
+        /**
          * Add a mesh in the highlight layer in order to make it glow with the chosen color.
          * @param mesh The mesh to highlight
          * @param color The color of the highlight
@@ -447,7 +485,12 @@ var BABYLON;
                     color: color,
                     // Lambda required for capture due to Observable this context
                     observerHighlight: mesh.onBeforeRenderObservable.add(function (mesh) {
-                        mesh.getScene().getEngine().setStencilFunctionReference(_this._instanceGlowingMeshStencilReference);
+                        if (_this._excludedMeshes[mesh.id]) {
+                            _this.defaultStencilReference(mesh);
+                        }
+                        else {
+                            mesh.getScene().getEngine().setStencilFunctionReference(_this._instanceGlowingMeshStencilReference);
+                        }
                     }),
                     observerDefault: mesh.onAfterRenderObservable.add(this.defaultStencilReference),
                     glowEmissiveOnly: glowEmissiveOnly
@@ -530,6 +573,14 @@ var BABYLON;
                 }
             }
             this._meshes = null;
+            for (var id in this._excludedMeshes) {
+                var meshHighlight = this._excludedMeshes[id];
+                if (meshHighlight) {
+                    meshHighlight.mesh.onBeforeRenderObservable.remove(meshHighlight.beforeRender);
+                    meshHighlight.mesh.onAfterRenderObservable.remove(meshHighlight.afterRender);
+                }
+            }
+            this._excludedMeshes = null;
             // Remove from scene
             var index = this._scene.highlightLayers.indexOf(this, 0);
             if (index > -1) {

+ 82 - 9
src/Layer/babylon.highlightlayer.ts

@@ -45,6 +45,11 @@
          * Alpha blending mode used to apply the blur. Default is combine.
          */
         alphaBlendingMode?: number
+
+        /**
+         * The camera attached to the layer.
+         */
+        camera?: Camera;
     }
 
     /**
@@ -75,6 +80,24 @@
     }
 
     /**
+     * Storage interface grouping all the information required for an excluded mesh.
+     */
+    interface IHighlightLayerExcludedMesh {
+        /** 
+         * The glowy mesh
+         */
+        mesh: Mesh;
+        /**
+         * The mesh render callback use to prevent stencil use
+         */
+        beforeRender: Observer<Mesh>;
+        /**
+         * The mesh render callback use to restore previous stencil use
+         */
+        afterRender: Observer<Mesh>;
+    }
+
+    /**
      * The highlight layer Helps adding a glow effect around a mesh.
      * 
      * Once instantiated in a scene, simply use the pushMesh or removeMesh method to add or remove
@@ -117,6 +140,7 @@
         private _maxSize: number = 0;
         private _shouldRender = false;
         private _instanceGlowingMeshStencilReference = HighlightLayer.glowingMeshStencilReference++;
+        private _excludedMeshes: { [id: string]: IHighlightLayerExcludedMesh } = {};
 
         /**
          * Specifies whether or not the inner glow is ACTIVE in the layer.
@@ -129,11 +153,6 @@
         public outerGlow: boolean = true;
 
         /**
-         * Specifies the listof mesh excluded during the generation of the highlight layer.
-         */
-        public excludedMeshes: Mesh[] = [];
-
-        /**
          * Specifies the horizontal size of the blur.
          */
         public set blurHorizontalSize(value: number) {
@@ -162,6 +181,13 @@
         }
 
         /**
+         * Gets the camera attached to the layer.
+         */
+        public get camera(): Camera {
+            return this._options.camera;
+        }
+
+        /**
          * An event triggered when the highlight layer has been disposed.
          * @type {BABYLON.Observable}
          */
@@ -287,6 +313,7 @@
                 false,
                 true,
                 Engine.TEXTURETYPE_UNSIGNED_INT);
+            this._mainTexture.activeCamera = this._options.camera;
             this._mainTexture.wrapU = Texture.CLAMP_ADDRESSMODE;
             this._mainTexture.wrapV = Texture.CLAMP_ADDRESSMODE;
             this._mainTexture.anisotropicFilteringLevel = 1;
@@ -353,7 +380,7 @@
                 }
 
                 // Excluded Mesh
-                if (this.excludedMeshes.indexOf(mesh) > -1) {
+                if (this._excludedMeshes[mesh.id]) {
                     return;
                 };
 
@@ -600,6 +627,39 @@
         }
 
         /**
+         * Add a mesh in the exclusion list to prevent it to impact or being impacted by the highlight layer.
+         * @param mesh The mesh to exclude from the highlight layer
+         */
+        public addExcludedMesh(mesh: Mesh) {
+            var meshExcluded = this._excludedMeshes[mesh.id];
+            if (!meshExcluded) {
+                this._excludedMeshes[mesh.id] = {
+                    mesh: mesh,
+                    beforeRender: mesh.onBeforeRenderObservable.add((mesh: Mesh) => {
+                        mesh.getEngine().setStencilBuffer(false);
+                    }),
+                    afterRender: mesh.onAfterRenderObservable.add((mesh: Mesh) => {
+                        mesh.getEngine().setStencilBuffer(true);
+                    }),
+                }
+            }
+        }
+
+        /**
+          * Remove a mesh from the exclusion list to let it impact or being impacted by the highlight layer.
+          * @param mesh The mesh to highlight
+          */
+        public removeExcludedMesh(mesh: Mesh) {
+            var meshExcluded = this._excludedMeshes[mesh.id];
+            if (meshExcluded) {
+                mesh.onBeforeRenderObservable.remove(meshExcluded.beforeRender);
+                mesh.onAfterRenderObservable.remove(meshExcluded.afterRender);
+            }
+
+            this._excludedMeshes[mesh.id] = undefined;
+        }
+
+        /**
          * Add a mesh in the highlight layer in order to make it glow with the chosen color.
          * @param mesh The mesh to highlight
          * @param color The color of the highlight
@@ -616,7 +676,12 @@
                     color: color,
                     // Lambda required for capture due to Observable this context
                     observerHighlight: mesh.onBeforeRenderObservable.add((mesh: Mesh) => {
-                        mesh.getScene().getEngine().setStencilFunctionReference(this._instanceGlowingMeshStencilReference);
+                        if (this._excludedMeshes[mesh.id]) {
+                            this.defaultStencilReference(mesh);
+                        }
+                        else {
+                            mesh.getScene().getEngine().setStencilFunctionReference(this._instanceGlowingMeshStencilReference);
+                        }
                     }),
                     observerDefault: mesh.onAfterRenderObservable.add(this.defaultStencilReference),
                     glowEmissiveOnly: glowEmissiveOnly
@@ -705,14 +770,22 @@
             this.disposeTextureAndPostProcesses();
 
             // Clean mesh references 
-            for (var id in this._meshes) {
-                var meshHighlight = this._meshes[id];
+            for (let id in this._meshes) {
+                let meshHighlight = this._meshes[id];
                 if (meshHighlight && meshHighlight.mesh) {
                     meshHighlight.mesh.onBeforeRenderObservable.remove(meshHighlight.observerHighlight);
                     meshHighlight.mesh.onAfterRenderObservable.remove(meshHighlight.observerDefault);
                 }
             }
             this._meshes = null;
+            for (let id in this._excludedMeshes) {
+                let meshHighlight = this._excludedMeshes[id];
+                if (meshHighlight) {
+                    meshHighlight.mesh.onBeforeRenderObservable.remove(meshHighlight.beforeRender);
+                    meshHighlight.mesh.onAfterRenderObservable.remove(meshHighlight.afterRender);
+                }
+            }
+            this._excludedMeshes = null;
 
             // Remove from scene
             var index = this._scene.highlightLayers.indexOf(this, 0);

+ 3 - 5
src/Materials/babylon.shaderMaterial.js

@@ -108,7 +108,7 @@ var BABYLON;
             this._matrices2x2[name] = value;
             return this;
         };
-        ShaderMaterial.prototype.setVector3Array = function (name, value) {
+        ShaderMaterial.prototype.setArray3 = function (name, value) {
             this._checkUniform(name);
             this._vectors3Arrays[name] = value;
             return this;
@@ -179,9 +179,7 @@ var BABYLON;
                     this._effect.setMatrix("viewProjection", this.getScene().getTransformMatrix());
                 }
                 // Bones
-                if (mesh && mesh.useBones && mesh.computeBonesUsingShaders) {
-                    this._effect.setMatrices("mBones", mesh.skeleton.getTransformMatrices(mesh));
-                }
+                BABYLON.MaterialHelper.BindBonesParameters(mesh, this._effect);
                 var name;
                 // Texture
                 for (name in this._textures) {
@@ -394,7 +392,7 @@ var BABYLON;
             }
             // Vector3Array
             for (name in source.vectors3Arrays) {
-                material.setVector3Array(name, source.vectors3Arrays[name]);
+                material.setArray3(name, source.vectors3Arrays[name]);
             }
             return material;
         };

+ 3 - 5
src/Materials/babylon.shaderMaterial.ts

@@ -137,7 +137,7 @@
             return this;
         }
 
-        public setVector3Array(name: string, value: number[]): ShaderMaterial {
+        public setArray3(name: string, value: number[]): ShaderMaterial {
             this._checkUniform(name);
             this._vectors3Arrays[name] = value;
 
@@ -234,9 +234,7 @@
                 }
 
                 // Bones
-                if (mesh && mesh.useBones && mesh.computeBonesUsingShaders) {
-                    this._effect.setMatrices("mBones", mesh.skeleton.getTransformMatrices(mesh));
-                }
+                MaterialHelper.BindBonesParameters(mesh, this._effect);
 
                 var name: string;
                 // Texture
@@ -503,7 +501,7 @@
 
             // Vector3Array
             for (name in source.vectors3Arrays) {
-                material.setVector3Array(name, source.vectors3Arrays[name]);
+                material.setArray3(name, source.vectors3Arrays[name]);
             }
             
             return material;

+ 15 - 30
src/Math/babylon.math.js

@@ -1542,36 +1542,21 @@ var BABYLON;
         };
         Quaternion.prototype.toEulerAnglesToRef = function (result, order) {
             if (order === void 0) { order = "YZX"; }
-            var heading, attitude, bank;
-            var x = this.x, y = this.y, z = this.z, w = this.w;
-            switch (order) {
-                case "YZX":
-                    var test = x * y + z * w;
-                    if (test > 0.499) {
-                        heading = 2 * Math.atan2(x, w);
-                        attitude = Math.PI / 2;
-                        bank = 0;
-                    }
-                    if (test < -0.499) {
-                        heading = -2 * Math.atan2(x, w);
-                        attitude = -Math.PI / 2;
-                        bank = 0;
-                    }
-                    if (isNaN(heading)) {
-                        var sqx = x * x;
-                        var sqy = y * y;
-                        var sqz = z * z;
-                        heading = Math.atan2(2 * y * w - 2 * x * z, 1 - 2 * sqy - 2 * sqz); // Heading
-                        attitude = Math.asin(2 * test); // attitude
-                        bank = Math.atan2(2 * x * w - 2 * y * z, 1 - 2 * sqx - 2 * sqz); // bank
-                    }
-                    break;
-                default:
-                    throw new Error("Euler order " + order + " not supported yet.");
-            }
-            result.y = heading;
-            result.z = attitude;
-            result.x = bank;
+            var qx = this.x;
+            var qy = this.y;
+            var qz = this.z;
+            var qw = this.w;
+            var xsqr = qx * qx;
+            var t0 = -2.0 * (xsqr + qy * qy) + 1.0;
+            var t1 = 2.0 * (qz * qx + qw * qy);
+            var t2 = -2.0 * (qz * qy - qw * qx);
+            var t3 = 2.0 * (qx * qy + qw * qz);
+            var t4 = -2.0 * (qz * qz + xsqr) + 1.0;
+            t2 = t2 > 1.0 ? 1.0 : t2;
+            t2 = t2 < -1.0 ? -1.0 : t2;
+            result.x = Math.asin(t2);
+            result.z = Math.atan2(t3, t4);
+            result.y = Math.atan2(t1, t0);
             return this;
         };
         ;

+ 20 - 32
src/Math/babylon.math.ts

@@ -1909,40 +1909,28 @@
         }
 
         public toEulerAnglesToRef(result: Vector3, order = "YZX"): Quaternion {
-            var heading: number, attitude: number, bank: number;
-            var x = this.x, y = this.y, z = this.z, w = this.w;
-
-            switch (order) {
-                case "YZX":
-                    var test = x * y + z * w;
-                    if (test > 0.499) { // singularity at north pole
-                        heading = 2 * Math.atan2(x, w);
-                        attitude = Math.PI / 2;
-                        bank = 0;
-                    }
-                    if (test < -0.499) { // singularity at south pole
-                        heading = -2 * Math.atan2(x, w);
-                        attitude = - Math.PI / 2;
-                        bank = 0;
-                    }
-                    if (isNaN(heading)) {
-                        var sqx = x * x;
-                        var sqy = y * y;
-                        var sqz = z * z;
-                        heading = Math.atan2(2 * y * w - 2 * x * z, 1 - 2 * sqy - 2 * sqz); // Heading
-                        attitude = Math.asin(2 * test); // attitude
-                        bank = Math.atan2(2 * x * w - 2 * y * z, 1 - 2 * sqx - 2 * sqz); // bank
-                    }
-                    break;
-                default:
-                    throw new Error("Euler order " + order + " not supported yet.");
-            }
-
-            result.y = heading;
-            result.z = attitude;
-            result.x = bank;
+            
+            var qx = this.x;
+            var qy = this.y;
+            var qz = this.z;
+            var qw = this.w;
+            var xsqr = qx * qx;
+
+            var t0 = -2.0 * (xsqr + qy * qy) + 1.0;
+            var t1 = 2.0 * (qz * qx + qw * qy);
+            var t2 = -2.0 * (qz * qy - qw * qx);
+            var t3 = 2.0 * (qx * qy + qw * qz);
+            var t4 = -2.0 * (qz * qz + xsqr) + 1.0;
+
+            t2 = t2 > 1.0 ? 1.0 : t2;
+            t2 = t2 < -1.0 ? -1.0 : t2;
+
+            result.x = Math.asin(t2);
+            result.z = Math.atan2(t3, t4);
+            result.y = Math.atan2(t1, t0);
 
             return this;
+            
         };
 
         public toRotationMatrix(result: Matrix): Quaternion {

+ 1 - 1
src/Mesh/babylon.abstractMesh.ts

@@ -794,7 +794,7 @@
             return this._boundingInfo.isCompletelyInFrustum(frustumPlanes);;
         }
 
-        public intersectsMesh(mesh: AbstractMesh, precise?: boolean): boolean {
+        public intersectsMesh(mesh: AbstractMesh | SolidParticle, precise?: boolean): boolean {
             if (!this._boundingInfo || !mesh._boundingInfo) {
                 return false;
             }

+ 1 - 0
src/Mesh/babylon.mesh.js

@@ -1202,6 +1202,7 @@ var BABYLON;
                 var highlightLayer = highlightLayers[i];
                 if (highlightLayer) {
                     highlightLayer.removeMesh(this);
+                    highlightLayer.removeExcludedMesh(this);
                 }
             }
             _super.prototype.dispose.call(this, doNotRecurse);

+ 4 - 3
src/Mesh/babylon.mesh.ts

@@ -439,7 +439,7 @@
             if (!this._geometry) {
                 var result = [];
                 if (this._delayInfo) {
-                    this._delayInfo.forEach( function(kind, index, array) {
+                    this._delayInfo.forEach(function (kind, index, array) {
                         result.push(kind);
                     });
                 }
@@ -759,7 +759,7 @@
 
             var geometry = this._geometry.copy(Geometry.RandomId());
 
-			oldGeometry.releaseForMesh(this, true);
+            oldGeometry.releaseForMesh(this, true);
             geometry.applyToMesh(this);
         }
 
@@ -1346,6 +1346,7 @@
                 let highlightLayer = highlightLayers[i];
                 if (highlightLayer) {
                     highlightLayer.removeMesh(this);
+                    highlightLayer.removeExcludedMesh(this);
                 }
             }
 
@@ -2582,7 +2583,7 @@
         public static MinMax(meshes: AbstractMesh[]): { min: Vector3; max: Vector3 } {
             var minVector: Vector3 = null;
             var maxVector: Vector3 = null;
-            meshes.forEach( function(mesh, index, array) {
+            meshes.forEach(function (mesh, index, array) {
                 var boundingBox = mesh.getBoundingInfo().boundingBox;
                 if (!minVector) {
                     minVector = boundingBox.minimumWorld;

+ 21 - 4
src/Particles/babylon.solidParticle.js

@@ -1,20 +1,28 @@
 var BABYLON;
 (function (BABYLON) {
     var SolidParticle = (function () {
-        function SolidParticle(particleIndex, positionIndex, model, shapeId, idxInShape) {
-            this.color = new BABYLON.Color4(1, 1, 1, 1); // color
+        function SolidParticle(particleIndex, positionIndex, model, shapeId, idxInShape, modelBoundingInfo) {
+            this.idx = 0; // particle global index
+            this.color = new BABYLON.Color4(1.0, 1.0, 1.0, 1.0); // color
             this.position = BABYLON.Vector3.Zero(); // position
             this.rotation = BABYLON.Vector3.Zero(); // rotation
-            this.scaling = new BABYLON.Vector3(1, 1, 1); // scaling
-            this.uvs = new BABYLON.Vector4(0, 0, 1, 1); // uvs
+            this.scaling = new BABYLON.Vector3(1.0, 1.0, 1.0); // scaling
+            this.uvs = new BABYLON.Vector4(0.0, 0.0, 1.0, 1.0); // uvs
             this.velocity = BABYLON.Vector3.Zero(); // velocity
             this.alive = true; // alive
             this.isVisible = true; // visibility
+            this._pos = 0; // index of this particle in the global "positions" array
+            this.shapeId = 0; // model shape id
+            this.idxInShape = 0; // index of the particle in its shape id
             this.idx = particleIndex;
             this._pos = positionIndex;
             this._model = model;
             this.shapeId = shapeId;
             this.idxInShape = idxInShape;
+            if (modelBoundingInfo) {
+                this._modelBoundingInfo = modelBoundingInfo;
+                this._boundingInfo = new BABYLON.BoundingInfo(modelBoundingInfo.minimum, modelBoundingInfo.maximum);
+            }
         }
         Object.defineProperty(SolidParticle.prototype, "scale", {
             //legacy support, changed scale to scaling
@@ -38,6 +46,15 @@ var BABYLON;
             enumerable: true,
             configurable: true
         });
+        SolidParticle.prototype.intersectsMesh = function (target) {
+            if (!(this.isVisible && target.isVisible)) {
+                return false; // only visible particle and target can intersect
+            }
+            if (!this._boundingInfo || !target._boundingInfo) {
+                return false;
+            }
+            return this._boundingInfo.intersects(target._boundingInfo, false);
+        };
         return SolidParticle;
     }());
     BABYLON.SolidParticle = SolidParticle;

+ 32 - 16
src/Particles/babylon.solidParticle.ts

@@ -1,27 +1,33 @@
 module BABYLON {
 
     export class SolidParticle {
-        public idx: number;                     // particle global index
-        public color = new Color4(1, 1, 1, 1);  // color
-        public position = Vector3.Zero();       // position
-        public rotation = Vector3.Zero();       // rotation
-        public rotationQuaternion: Quaternion;    // quaternion, will overwrite rotation
-        public scaling = new Vector3(1, 1, 1);  // scaling
-        public uvs = new Vector4(0, 0, 1, 1);   // uvs
-        public velocity = Vector3.Zero();       // velocity
-        public alive = true;                    // alive
-        public isVisible = true;                // visibility
-        public _pos: number;                    // index of this particle in the global "positions" array
-        public _model: ModelShape;              // model shape reference
-        public shapeId: number;                 // model shape id
-        public idxInShape: number;              // index of the particle in its shape id
-
-        constructor(particleIndex: number, positionIndex: number, model: ModelShape, shapeId: number, idxInShape: number) {
+        public idx: number = 0;                         // particle global index
+        public color = new Color4(1.0, 1.0, 1.0, 1.0);  // color
+        public position = Vector3.Zero();               // position
+        public rotation = Vector3.Zero();               // rotation
+        public rotationQuaternion: Quaternion;          // quaternion, will overwrite rotation
+        public scaling = new Vector3(1.0, 1.0, 1.0);    // scaling
+        public uvs = new Vector4(0.0, 0.0, 1.0, 1.0);   // uvs
+        public velocity = Vector3.Zero();               // velocity
+        public alive = true;                            // alive
+        public isVisible = true;                        // visibility
+        public _pos: number = 0;                        // index of this particle in the global "positions" array
+        public _model: ModelShape;                      // model shape reference
+        public shapeId: number = 0;                     // model shape id
+        public idxInShape: number = 0;                  // index of the particle in its shape id
+        public _modelBoundingInfo: BoundingInfo;        // reference to the shape model BoundingInfo object
+        public _boundingInfo: BoundingInfo;             // particle BoundingInfo
+
+        constructor(particleIndex: number, positionIndex: number, model: ModelShape, shapeId: number, idxInShape: number, modelBoundingInfo?: BoundingInfo) {
             this.idx = particleIndex;
             this._pos = positionIndex;
             this._model = model;
             this.shapeId = shapeId;
             this.idxInShape = idxInShape;
+            if (modelBoundingInfo) {
+                this._modelBoundingInfo = modelBoundingInfo;
+                this._boundingInfo = new BoundingInfo(modelBoundingInfo.minimum, modelBoundingInfo.maximum);
+            }
         }
 
         //legacy support, changed scale to scaling
@@ -41,6 +47,16 @@ module BABYLON {
         public set quaternion(q: Quaternion) {
             this.rotationQuaternion = q;
         }
+
+        public intersectsMesh(target: Mesh | SolidParticle): boolean {
+            if (!(this.isVisible && target.isVisible)) {
+                return false;       // only visible particle and target can intersect
+            }
+            if (!this._boundingInfo || !target._boundingInfo) {
+                return false;
+            }
+            return this._boundingInfo.intersects(target._boundingInfo, false);
+        }
     }
 
     export class ModelShape {

+ 74 - 14
src/Particles/babylon.solidParticleSystem.js

@@ -10,6 +10,7 @@ var BABYLON;
         * `scene` (Scene) is the scene in which the SPS is added.
         * `updatable` (default true) : if the SPS must be updatable or immutable.
         * `isPickable` (default false) : if the solid particles must be pickable.
+        * `particleIntersection` (default false) : if the solid particle intersections must be computed
         */
         function SolidParticleSystem(name, scene, options) {
             // public members
@@ -87,10 +88,12 @@ var BABYLON;
             this._maximum = BABYLON.Tmp.Vector3[1];
             this._scale = BABYLON.Tmp.Vector3[2];
             this._translation = BABYLON.Tmp.Vector3[3];
+            this._particlesIntersect = false;
             this.name = name;
             this._scene = scene;
             this._camera = scene.activeCamera;
             this._pickable = options ? options.isPickable : false;
+            this._particlesIntersect = options ? options.particleIntersection : false;
             if (options && options.updatable) {
                 this._updatable = options.updatable;
             }
@@ -134,6 +137,7 @@ var BABYLON;
             vertexData.applyToMesh(mesh, this._updatable);
             this.mesh = mesh;
             this.mesh.isPickable = this._pickable;
+            this._wm = this.mesh.getWorldMatrix();
             // free memory
             this._positions = null;
             this._normals = null;
@@ -218,10 +222,14 @@ var BABYLON;
                 for (v = 0; v < shape.length; v++) {
                     shape[v].subtractInPlace(barycenter);
                 }
+                var bInfo;
+                if (this._particlesIntersect) {
+                    bInfo = new BABYLON.BoundingInfo(barycenter, barycenter);
+                }
                 var modelShape = new BABYLON.ModelShape(this._shapeCounter, shape, shapeUV, null, null);
                 // add the particle in the SPS
                 this._meshBuilder(this._index, shape, this._positions, facetInd, this._indices, facetUV, this._uvs, facetCol, this._colors, meshNor, this._normals, idx, 0, null);
-                this._addParticle(idx, this._positions.length, modelShape, this._shapeCounter, 0);
+                this._addParticle(idx, this._positions.length, modelShape, this._shapeCounter, 0, bInfo);
                 // initialize the particle position
                 this.particles[this.nbParticles].position.addInPlace(barycenter);
                 this._index += shape.length;
@@ -340,8 +348,8 @@ var BABYLON;
             return shapeUV;
         };
         // adds a new particle object in the particles array
-        SolidParticleSystem.prototype._addParticle = function (idx, idxpos, model, shapeId, idxInShape) {
-            this.particles.push(new BABYLON.SolidParticle(idx, idxpos, model, shapeId, idxInShape));
+        SolidParticleSystem.prototype._addParticle = function (idx, idxpos, model, shapeId, idxInShape, bInfo) {
+            this.particles.push(new BABYLON.SolidParticle(idx, idxpos, model, shapeId, idxInShape, bInfo));
         };
         /**
         * Adds some particles to the SPS from the model shape. Returns the shape id.
@@ -357,6 +365,10 @@ var BABYLON;
             var meshUV = mesh.getVerticesData(BABYLON.VertexBuffer.UVKind);
             var meshCol = mesh.getVerticesData(BABYLON.VertexBuffer.ColorKind);
             var meshNor = mesh.getVerticesData(BABYLON.VertexBuffer.NormalKind);
+            var bbInfo;
+            if (this._particlesIntersect) {
+                bbInfo = mesh.getBoundingInfo();
+            }
             var shape = this._posToShape(meshPos);
             var shapeUV = this._uvsToShapeUV(meshUV);
             var posfunc = options ? options.positionFunction : null;
@@ -367,7 +379,7 @@ var BABYLON;
             for (var i = 0; i < nb; i++) {
                 this._meshBuilder(this._index, shape, this._positions, meshInd, this._indices, meshUV, this._uvs, meshCol, this._colors, meshNor, this._normals, idx, i, options);
                 if (this._updatable) {
-                    this._addParticle(idx, this._positions.length, modelShape, this._shapeCounter, i);
+                    this._addParticle(idx, this._positions.length, modelShape, this._shapeCounter, i, bbInfo);
                 }
                 this._index += shape.length;
                 idx++;
@@ -408,16 +420,16 @@ var BABYLON;
                 this._positions32[particle._pos + pt * 3 + 1] = this._copy.position.y + this._rotated.y;
                 this._positions32[particle._pos + pt * 3 + 2] = this._copy.position.z + this._rotated.z;
             }
-            particle.position.x = 0;
-            particle.position.y = 0;
-            particle.position.z = 0;
-            particle.rotation.x = 0;
-            particle.rotation.y = 0;
-            particle.rotation.z = 0;
+            particle.position.x = 0.0;
+            particle.position.y = 0.0;
+            particle.position.z = 0.0;
+            particle.rotation.x = 0.0;
+            particle.rotation.y = 0.0;
+            particle.rotation.z = 0.0;
             particle.rotationQuaternion = null;
-            particle.scaling.x = 1;
-            particle.scaling.y = 1;
-            particle.scaling.z = 1;
+            particle.scaling.x = 1.0;
+            particle.scaling.y = 1.0;
+            particle.scaling.z = 1.0;
         };
         /**
         * Rebuilds the whole mesh and updates the VBO : custom positions and vertices are recomputed if needed.
@@ -457,7 +469,7 @@ var BABYLON;
             // if the particles will always face the camera
             if (this.billboard) {
                 // compute the camera position and un-rotate it by the current mesh rotation
-                if (this.mesh._worldMatrix.decompose(this._scale, this._quaternion, this._translation)) {
+                if (this._wm.decompose(this._scale, this._quaternion, this._translation)) {
                     this._quaternionToRotationMatrix();
                     this._rotMatrix.invertToRef(this._invertMatrix);
                     this._camera._currentTarget.subtractToRef(this._camera.globalPosition, this._camDir);
@@ -598,6 +610,54 @@ var BABYLON;
                         }
                     }
                 }
+                // if the particle intersections must be computed : update the bbInfo
+                if (this._particlesIntersect) {
+                    var bInfo = this._particle._boundingInfo;
+                    var bBox = bInfo.boundingBox;
+                    var bSphere = bInfo.boundingSphere;
+                    // place, scale and rotate the particle bbox within the SPS local system
+                    for (var b = 0; b < bBox.vectors.length; b++) {
+                        if (this._particle.isVisible) {
+                            this._vertex.x = this._particle._modelBoundingInfo.boundingBox.vectors[b].x * this._particle.scaling.x;
+                            this._vertex.y = this._particle._modelBoundingInfo.boundingBox.vectors[b].y * this._particle.scaling.y;
+                            this._vertex.z = this._particle._modelBoundingInfo.boundingBox.vectors[b].z * this._particle.scaling.z;
+                            this._w = (this._vertex.x * this._rotMatrix.m[3]) + (this._vertex.y * this._rotMatrix.m[7]) + (this._vertex.z * this._rotMatrix.m[11]) + this._rotMatrix.m[15];
+                            this._rotated.x = ((this._vertex.x * this._rotMatrix.m[0]) + (this._vertex.y * this._rotMatrix.m[4]) + (this._vertex.z * this._rotMatrix.m[8]) + this._rotMatrix.m[12]) / this._w;
+                            this._rotated.y = ((this._vertex.x * this._rotMatrix.m[1]) + (this._vertex.y * this._rotMatrix.m[5]) + (this._vertex.z * this._rotMatrix.m[9]) + this._rotMatrix.m[13]) / this._w;
+                            this._rotated.z = ((this._vertex.x * this._rotMatrix.m[2]) + (this._vertex.y * this._rotMatrix.m[6]) + (this._vertex.z * this._rotMatrix.m[10]) + this._rotMatrix.m[14]) / this._w;
+                            bBox.vectors[b].x = this._particle.position.x + this._cam_axisX.x * this._rotated.x + this._cam_axisY.x * this._rotated.y + this._cam_axisZ.x * this._rotated.z;
+                            bBox.vectors[b].y = this._particle.position.y + this._cam_axisX.y * this._rotated.x + this._cam_axisY.y * this._rotated.y + this._cam_axisZ.y * this._rotated.z;
+                            bBox.vectors[b].z = this._particle.position.z + this._cam_axisX.z * this._rotated.x + this._cam_axisY.z * this._rotated.y + this._cam_axisZ.z * this._rotated.z;
+                        }
+                        else {
+                            bBox.vectors[b].x = this._camera.position.x;
+                            bBox.vectors[b].y = this._camera.position.y;
+                            bBox.vectors[b].z = this._camera.position.z;
+                        }
+                    }
+                    // place and scale the particle bouding sphere in the SPS local system
+                    if (this._particle.isVisible) {
+                        this._minimum.x = this._particle._modelBoundingInfo.minimum.x * this._particle.scaling.x;
+                        this._minimum.y = this._particle._modelBoundingInfo.minimum.y * this._particle.scaling.y;
+                        this._minimum.z = this._particle._modelBoundingInfo.minimum.z * this._particle.scaling.z;
+                        this._maximum.x = this._particle._modelBoundingInfo.maximum.x * this._particle.scaling.x;
+                        this._maximum.y = this._particle._modelBoundingInfo.maximum.y * this._particle.scaling.y;
+                        this._maximum.z = this._particle._modelBoundingInfo.maximum.z * this._particle.scaling.z;
+                        bSphere.center.x = this._particle.position.x + (this._minimum.x + this._maximum.x) * 0.5;
+                        bSphere.center.y = this._particle.position.y + (this._minimum.y + this._maximum.y) * 0.5;
+                        bSphere.center.z = this._particle.position.z + (this._minimum.z + this._maximum.z) * 0.5;
+                        bSphere.radius = BABYLON.Vector3.Distance(this._minimum, this._maximum) * 0.5;
+                    }
+                    else {
+                        bSphere.center.x = this._camera.position.x;
+                        bSphere.center.y = this._camera.position.x;
+                        bSphere.center.z = this._camera.position.x;
+                        bSphere.radius = 0.0;
+                    }
+                    // then update the bbox and the bsphere into the world system
+                    bBox._update(this._wm);
+                    bSphere._update(this._wm);
+                }
                 // increment indexes for the next particle
                 index = idx + 3;
                 colorIndex = colidx + 4;

+ 79 - 17
src/Particles/babylon.solidParticleSystem.ts

@@ -108,6 +108,8 @@
         private _maximum: Vector3 = Tmp.Vector3[1];
         private _scale: Vector3 = Tmp.Vector3[2];
         private _translation: Vector3 = Tmp.Vector3[3];
+        private _particlesIntersect: boolean = false;
+        private _wm: Matrix;
 
 
         /**
@@ -116,12 +118,14 @@
         * `scene` (Scene) is the scene in which the SPS is added.  
         * `updatable` (default true) : if the SPS must be updatable or immutable.  
         * `isPickable` (default false) : if the solid particles must be pickable.  
+        * `particleIntersection` (default false) : if the solid particle intersections must be computed
         */
-        constructor(name: string, scene: Scene, options?: { updatable?: boolean; isPickable?: boolean }) {
+        constructor(name: string, scene: Scene, options?: { updatable?: boolean; isPickable?: boolean; particleIntersection?: boolean }) {
             this.name = name;
             this._scene = scene;
             this._camera = <TargetCamera>scene.activeCamera;
             this._pickable = options ? options.isPickable : false;
+            this._particlesIntersect = options ? options.particleIntersection : false;
             if (options && options.updatable) {
                 this._updatable = options.updatable;
             } else {
@@ -164,6 +168,7 @@
             vertexData.applyToMesh(mesh, this._updatable);
             this.mesh = mesh;
             this.mesh.isPickable = this._pickable;
+            this._wm = this.mesh.getWorldMatrix();
 
             // free memory
             this._positions = null;
@@ -258,11 +263,15 @@
                 for (v = 0; v < shape.length; v++) {
                     shape[v].subtractInPlace(barycenter);
                 }
+                var bInfo;
+                if (this._particlesIntersect) {
+                    bInfo = new BoundingInfo(barycenter, barycenter);
+                }
                 var modelShape = new ModelShape(this._shapeCounter, shape, shapeUV, null, null);
 
                 // add the particle in the SPS
                 this._meshBuilder(this._index, shape, this._positions, facetInd, this._indices, facetUV, this._uvs, facetCol, this._colors, meshNor, this._normals, idx, 0, null);
-                this._addParticle(idx, this._positions.length, modelShape, this._shapeCounter, 0);
+                this._addParticle(idx, this._positions.length, modelShape, this._shapeCounter, 0, bInfo);
                 // initialize the particle position
                 this.particles[this.nbParticles].position.addInPlace(barycenter);
 
@@ -395,8 +404,8 @@
         }
 
         // adds a new particle object in the particles array
-        private _addParticle(idx: number, idxpos: number, model: ModelShape, shapeId: number, idxInShape: number): void {
-            this.particles.push(new SolidParticle(idx, idxpos, model, shapeId, idxInShape));
+        private _addParticle(idx: number, idxpos: number, model: ModelShape, shapeId: number, idxInShape: number, bInfo?: BoundingInfo): void {
+            this.particles.push(new SolidParticle(idx, idxpos, model, shapeId, idxInShape, bInfo));
         }
 
         /**
@@ -413,6 +422,10 @@
             var meshUV = mesh.getVerticesData(VertexBuffer.UVKind);
             var meshCol = mesh.getVerticesData(VertexBuffer.ColorKind);
             var meshNor = mesh.getVerticesData(VertexBuffer.NormalKind);
+            var bbInfo;
+            if (this._particlesIntersect) {
+                bbInfo = mesh.getBoundingInfo();
+            }
 
             var shape = this._posToShape(meshPos);
             var shapeUV = this._uvsToShapeUV(meshUV);
@@ -427,7 +440,7 @@
             for (var i = 0; i < nb; i++) {
                 this._meshBuilder(this._index, shape, this._positions, meshInd, this._indices, meshUV, this._uvs, meshCol, this._colors, meshNor, this._normals, idx, i, options);
                 if (this._updatable) {
-                    this._addParticle(idx, this._positions.length, modelShape, this._shapeCounter, i);
+                    this._addParticle(idx, this._positions.length, modelShape, this._shapeCounter, i, bbInfo);
                 }
                 this._index += shape.length;
                 idx++;
@@ -474,16 +487,16 @@
                 this._positions32[particle._pos + pt * 3 + 1] = this._copy.position.y + this._rotated.y;
                 this._positions32[particle._pos + pt * 3 + 2] = this._copy.position.z + this._rotated.z;
             }
-            particle.position.x = 0;
-            particle.position.y = 0;
-            particle.position.z = 0;
-            particle.rotation.x = 0;
-            particle.rotation.y = 0;
-            particle.rotation.z = 0;
+            particle.position.x = 0.0;
+            particle.position.y = 0.0;
+            particle.position.z = 0.0;
+            particle.rotation.x = 0.0;
+            particle.rotation.y = 0.0;
+            particle.rotation.z = 0.0;
             particle.rotationQuaternion = null;
-            particle.scaling.x = 1;
-            particle.scaling.y = 1;
-            particle.scaling.z = 1;
+            particle.scaling.x = 1.0;
+            particle.scaling.y = 1.0;
+            particle.scaling.z = 1.0;
         }
 
         /**
@@ -528,7 +541,7 @@
             // if the particles will always face the camera
             if (this.billboard) {
                 // compute the camera position and un-rotate it by the current mesh rotation
-                if (this.mesh._worldMatrix.decompose(this._scale, this._quaternion, this._translation)) {
+                if (this._wm.decompose(this._scale, this._quaternion, this._translation)) {
                     this._quaternionToRotationMatrix();
                     this._rotMatrix.invertToRef(this._invertMatrix);
                     this._camera._currentTarget.subtractToRef(this._camera.globalPosition, this._camDir);
@@ -661,8 +674,7 @@
                             this._uvs32[uvidx] = this._shapeUV[pt * 2] * (this._particle.uvs.z - this._particle.uvs.x) + this._particle.uvs.x;
                             this._uvs32[uvidx + 1] = this._shapeUV[pt * 2 + 1] * (this._particle.uvs.w - this._particle.uvs.y) + this._particle.uvs.y;
                         }
-                    }
-
+                    } 
                 } 
                 // particle not visible : scaled to zero and positioned to the camera position
                 else {
@@ -689,6 +701,56 @@
                     }
                 }
                 
+                // if the particle intersections must be computed : update the bbInfo
+                if (this._particlesIntersect) {
+                    var bInfo = this._particle._boundingInfo;
+                    var bBox = bInfo.boundingBox;
+                    var bSphere = bInfo.boundingSphere;
+                    
+                    // place, scale and rotate the particle bbox within the SPS local system
+                    for (var b = 0; b < bBox.vectors.length; b++) {
+                        if (this._particle.isVisible) {
+                            this._vertex.x = this._particle._modelBoundingInfo.boundingBox.vectors[b].x * this._particle.scaling.x;
+                            this._vertex.y = this._particle._modelBoundingInfo.boundingBox.vectors[b].y * this._particle.scaling.y;
+                            this._vertex.z = this._particle._modelBoundingInfo.boundingBox.vectors[b].z * this._particle.scaling.z;
+                            this._w = (this._vertex.x * this._rotMatrix.m[3]) + (this._vertex.y * this._rotMatrix.m[7]) + (this._vertex.z * this._rotMatrix.m[11]) + this._rotMatrix.m[15];
+                            this._rotated.x = ((this._vertex.x * this._rotMatrix.m[0]) + (this._vertex.y * this._rotMatrix.m[4]) + (this._vertex.z * this._rotMatrix.m[8]) + this._rotMatrix.m[12]) / this._w;
+                            this._rotated.y = ((this._vertex.x * this._rotMatrix.m[1]) + (this._vertex.y * this._rotMatrix.m[5]) + (this._vertex.z * this._rotMatrix.m[9]) + this._rotMatrix.m[13]) / this._w;
+                            this._rotated.z = ((this._vertex.x * this._rotMatrix.m[2]) + (this._vertex.y * this._rotMatrix.m[6]) + (this._vertex.z * this._rotMatrix.m[10]) + this._rotMatrix.m[14]) / this._w;
+                            bBox.vectors[b].x = this._particle.position.x + this._cam_axisX.x * this._rotated.x + this._cam_axisY.x * this._rotated.y + this._cam_axisZ.x * this._rotated.z;
+                            bBox.vectors[b].y = this._particle.position.y + this._cam_axisX.y * this._rotated.x + this._cam_axisY.y * this._rotated.y + this._cam_axisZ.y * this._rotated.z;
+                            bBox.vectors[b].z = this._particle.position.z + this._cam_axisX.z * this._rotated.x + this._cam_axisY.z * this._rotated.y + this._cam_axisZ.z * this._rotated.z;
+                        }
+                        else {
+                            bBox.vectors[b].x = this._camera.position.x;
+                            bBox.vectors[b].y = this._camera.position.y;
+                            bBox.vectors[b].z = this._camera.position.z;
+                        }
+                    }
+                    // place and scale the particle bouding sphere in the SPS local system
+                    if (this._particle.isVisible) {
+                        this._minimum.x = this._particle._modelBoundingInfo.minimum.x * this._particle.scaling.x;
+                        this._minimum.y = this._particle._modelBoundingInfo.minimum.y * this._particle.scaling.y;
+                        this._minimum.z = this._particle._modelBoundingInfo.minimum.z * this._particle.scaling.z;
+                        this._maximum.x = this._particle._modelBoundingInfo.maximum.x * this._particle.scaling.x;
+                        this._maximum.y = this._particle._modelBoundingInfo.maximum.y * this._particle.scaling.y;
+                        this._maximum.z = this._particle._modelBoundingInfo.maximum.z * this._particle.scaling.z;
+                        bSphere.center.x = this._particle.position.x + (this._minimum.x + this._maximum.x) * 0.5;
+                        bSphere.center.y = this._particle.position.y + (this._minimum.y + this._maximum.y) * 0.5;
+                        bSphere.center.z = this._particle.position.z + (this._minimum.z + this._maximum.z) * 0.5;
+                        bSphere.radius = Vector3.Distance(this._minimum, this._maximum) * 0.5;
+                    } else {
+                        bSphere.center.x = this._camera.position.x;
+                        bSphere.center.y = this._camera.position.x;
+                        bSphere.center.z = this._camera.position.x;
+                        bSphere.radius = 0.0;                       
+                    }
+
+                    // then update the bbox and the bsphere into the world system
+                    bBox._update(this._wm);
+                    bSphere._update(this._wm);
+                }
+
                 // increment indexes for the next particle
                 index = idx + 3;
                 colorIndex = colidx + 4;

+ 30 - 30
src/babylon.engine.js

@@ -1159,40 +1159,40 @@ var BABYLON;
             }
         };
         Engine.prototype.bindBuffers = function (vertexBuffers, indexBuffer, effect) {
-            //   if (this._cachedVertexBuffers !== vertexBuffers || this._cachedEffectForVertexBuffers !== effect) {
-            this._cachedVertexBuffers = vertexBuffers;
-            this._cachedEffectForVertexBuffers = effect;
-            var attributes = effect.getAttributesNames();
-            for (var index = 0; index < attributes.length; index++) {
-                var order = effect.getAttributeLocation(index);
-                if (order >= 0) {
-                    var vertexBuffer = vertexBuffers[attributes[index]];
-                    if (!vertexBuffer) {
-                        if (this._vertexAttribArraysEnabled[order]) {
-                            this._gl.disableVertexAttribArray(order);
-                            this._vertexAttribArraysEnabled[order] = false;
+            if (this._cachedVertexBuffers !== vertexBuffers || this._cachedEffectForVertexBuffers !== effect) {
+                this._cachedVertexBuffers = vertexBuffers;
+                this._cachedEffectForVertexBuffers = effect;
+                var attributes = effect.getAttributesNames();
+                for (var index = 0; index < attributes.length; index++) {
+                    var order = effect.getAttributeLocation(index);
+                    if (order >= 0) {
+                        var vertexBuffer = vertexBuffers[attributes[index]];
+                        if (!vertexBuffer) {
+                            if (this._vertexAttribArraysEnabled[order]) {
+                                this._gl.disableVertexAttribArray(order);
+                                this._vertexAttribArraysEnabled[order] = false;
+                            }
+                            continue;
+                        }
+                        if (!this._vertexAttribArraysEnabled[order]) {
+                            this._gl.enableVertexAttribArray(order);
+                            this._vertexAttribArraysEnabled[order] = true;
+                        }
+                        var buffer = vertexBuffer.getBuffer();
+                        this.vertexAttribPointer(buffer, order, vertexBuffer.getSize(), this._gl.FLOAT, false, vertexBuffer.getStrideSize() * 4, vertexBuffer.getOffset() * 4);
+                        if (vertexBuffer.getIsInstanced()) {
+                            this._caps.instancedArrays.vertexAttribDivisorANGLE(order, 1);
+                            this._currentInstanceLocations.push(order);
+                            this._currentInstanceBuffers.push(buffer);
                         }
-                        continue;
-                    }
-                    if (!this._vertexAttribArraysEnabled[order]) {
-                        this._gl.enableVertexAttribArray(order);
-                        this._vertexAttribArraysEnabled[order] = true;
-                    }
-                    var buffer = vertexBuffer.getBuffer();
-                    this.vertexAttribPointer(buffer, order, vertexBuffer.getSize(), this._gl.FLOAT, false, vertexBuffer.getStrideSize() * 4, vertexBuffer.getOffset() * 4);
-                    if (vertexBuffer.getIsInstanced()) {
-                        this._caps.instancedArrays.vertexAttribDivisorANGLE(order, 1);
-                        this._currentInstanceLocations.push(order);
-                        this._currentInstanceBuffers.push(buffer);
                     }
                 }
             }
-            //   }
-            // if (indexBuffer != null && this._cachedIndexBuffer !== indexBuffer) {
-            this._cachedIndexBuffer = indexBuffer;
-            this.bindIndexBuffer(indexBuffer);
-            this._uintIndicesCurrentlySet = indexBuffer.is32Bits;
-            //}
+            if (indexBuffer != null && this._cachedIndexBuffer !== indexBuffer) {
+                this._cachedIndexBuffer = indexBuffer;
+                this.bindIndexBuffer(indexBuffer);
+                this._uintIndicesCurrentlySet = indexBuffer.is32Bits;
+            }
         };
         Engine.prototype.unbindInstanceAttributes = function () {
             var boundBuffer;

+ 4 - 4
src/babylon.engine.ts

@@ -1349,7 +1349,7 @@
         }
 
         public bindBuffers(vertexBuffers: { [key: string]: VertexBuffer; }, indexBuffer: WebGLBuffer, effect: Effect): void {
-         //   if (this._cachedVertexBuffers !== vertexBuffers || this._cachedEffectForVertexBuffers !== effect) {
+            if (this._cachedVertexBuffers !== vertexBuffers || this._cachedEffectForVertexBuffers !== effect) {
                 this._cachedVertexBuffers = vertexBuffers;
                 this._cachedEffectForVertexBuffers = effect;
 
@@ -1384,13 +1384,13 @@
                         }
                     }
                 }
-         //   }
+            }
 
-           // if (indexBuffer != null && this._cachedIndexBuffer !== indexBuffer) {
+            if (indexBuffer != null && this._cachedIndexBuffer !== indexBuffer) {
                 this._cachedIndexBuffer = indexBuffer;
                 this.bindIndexBuffer(indexBuffer);
                 this._uintIndicesCurrentlySet = indexBuffer.is32Bits;
-            //}
+            }
         }
 
         public unbindInstanceAttributes() {

+ 4 - 0
src/babylon.node.js

@@ -17,6 +17,7 @@ var BABYLON;
          */
         function Node(name, scene) {
             this.state = "";
+            this.metadata = null;
             this.animations = new Array();
             this._ranges = {};
             this._childrenFlag = -1;
@@ -292,6 +293,9 @@ var BABYLON;
         __decorate([
             BABYLON.serialize()
         ], Node.prototype, "state", void 0);
+        __decorate([
+            BABYLON.serialize()
+        ], Node.prototype, "metadata", void 0);
         return Node;
     }());
     BABYLON.Node = Node;

+ 3 - 0
src/babylon.node.ts

@@ -16,6 +16,9 @@
         @serialize()
         public state = "";
 
+        @serialize()
+        public metadata:any = null;
+
         public animations = new Array<Animation>();
         private _ranges: { [name: string]: AnimationRange; } = {};
 

+ 2 - 1
src/babylon.scene.js

@@ -1734,7 +1734,8 @@ var BABYLON;
             var renderhighlights = false;
             if (this.highlightLayers && this.highlightLayers.length > 0) {
                 for (var i = 0; i < this.highlightLayers.length; i++) {
-                    if (this.highlightLayers[i].shouldRender()) {
+                    var highlightLayer = this.highlightLayers[i];
+                    if ((!highlightLayer.camera || camera == highlightLayer.camera) && highlightLayer.shouldRender()) {
                         renderhighlights = true;
                         this._engine.setStencilBuffer(true);
                         break;

+ 22 - 21
src/babylon.scene.ts

@@ -34,7 +34,7 @@
     export class PointerInfoBase {
         constructor(public type: number, public event: PointerEvent | MouseWheelEvent) {
         }
-        
+
     }
 
     /**
@@ -104,7 +104,7 @@
         public animationsEnabled = true;
         public constantlyUpdateMeshUnderPointer = false;
         public useRightHandedSystem = false;
-        
+
         public hoverCursor = "pointer";
 
         // Events
@@ -412,7 +412,7 @@
          * @type {BABYLON.ActionManager}
         */
         public actionManager: ActionManager;
-     
+
         public _actionManagers = new Array<ActionManager>();
         private _meshesForIntersections = new SmartArray<AbstractMesh>(256);
 
@@ -433,20 +433,20 @@
         private _engine: Engine;
 
         // Performance counters
-        private _totalMeshesCounter           = new PerfCounter();
-        private _totalLightsCounter           = new PerfCounter();
-        private _totalMaterialsCounter        = new PerfCounter();
-        private _totalTexturesCounter         = new PerfCounter();
-        private _totalVertices                = new PerfCounter();
-        public  _activeIndices                = new PerfCounter();
-        public  _activeParticles              = new PerfCounter();
-        private _lastFrameDuration            = new PerfCounter();
+        private _totalMeshesCounter = new PerfCounter();
+        private _totalLightsCounter = new PerfCounter();
+        private _totalMaterialsCounter = new PerfCounter();
+        private _totalTexturesCounter = new PerfCounter();
+        private _totalVertices = new PerfCounter();
+        public _activeIndices = new PerfCounter();
+        public _activeParticles = new PerfCounter();
+        private _lastFrameDuration = new PerfCounter();
         private _evaluateActiveMeshesDuration = new PerfCounter();
-        private _renderTargetsDuration        = new PerfCounter();
-        public  _particlesDuration            = new PerfCounter();
-        private _renderDuration               = new PerfCounter();
-        public  _spritesDuration              = new PerfCounter();
-        public  _activeBones                  = new PerfCounter();
+        private _renderTargetsDuration = new PerfCounter();
+        public _particlesDuration = new PerfCounter();
+        private _renderDuration = new PerfCounter();
+        public _spritesDuration = new PerfCounter();
+        public _activeBones = new PerfCounter();
 
         private _animationRatio: number;
 
@@ -1925,7 +1925,7 @@
             this._particlesDuration.endMonitoring(false);
         }
 
-        private _activeMesh(sourceMesh:AbstractMesh, mesh: AbstractMesh): void {
+        private _activeMesh(sourceMesh: AbstractMesh, mesh: AbstractMesh): void {
             if (mesh.skeleton && this.skeletonsEnabled) {
                 if (this._activeSkeletons.pushNoDuplicate(mesh.skeleton)) {
                     mesh.skeleton.prepare();
@@ -2054,7 +2054,8 @@
             var renderhighlights = false;
             if (this.highlightLayers && this.highlightLayers.length > 0) {
                 for (let i = 0; i < this.highlightLayers.length; i++) {
-                    if (this.highlightLayers[i].shouldRender()) {
+                    let highlightLayer = this.highlightLayers[i];
+                    if ((!highlightLayer.camera || camera == highlightLayer.camera) && highlightLayer.shouldRender()) {
                         renderhighlights = true;
                         this._engine.setStencilBuffer(true);
                         break;
@@ -2229,7 +2230,7 @@
 
             // Before render
             this.onBeforeRenderObservable.notifyObservers(this);
-            
+
             // Customs render targets
             this._renderTargetsDuration.beginMonitoring();
             var beforeRenderTargetDate = Tools.Now;
@@ -2989,7 +2990,7 @@
             opaqueSortCompareFn: (a: SubMesh, b: SubMesh) => number = null,
             alphaTestSortCompareFn: (a: SubMesh, b: SubMesh) => number = null,
             transparentSortCompareFn: (a: SubMesh, b: SubMesh) => number = null): void {
-            
+
             this._renderingManager.setRenderingOrder(renderingGroupId,
                 opaqueSortCompareFn,
                 alphaTestSortCompareFn,
@@ -3002,7 +3003,7 @@
          * @param renderingGroupId The rendering group id corresponding to its index
          * @param autoClearDepthStencil Automatically clears depth and stencil between groups if true.
          */
-        public setRenderingAutoClearDepthStencil(renderingGroupId: number, autoClearDepthStencil: boolean): void {            
+        public setRenderingAutoClearDepthStencil(renderingGroupId: number, autoClearDepthStencil: boolean): void {
             this._renderingManager.setRenderingAutoClearDepthStencil(renderingGroupId, autoClearDepthStencil);
         }
     }