浏览代码

Fixing issue with bakeCurrentTransformIntoVertices
Fixing issue with Billboard and parenting

David Catuhe 9 年之前
父节点
当前提交
ef4ba244a0

+ 6 - 6
Tools/Gulp/config.json

@@ -22,9 +22,7 @@
       "../../src/Tools/babylon.tools.tga.js",
       "../../src/Tools/babylon.smartArray.js",
       "../../src/Tools/babylon.stringDictionary.js",
-	  "../../src/Tools/babylon.rectPackingMap.js",
-	  "../../src/Tools/babylon.dynamicFloatArray.js",
-      "../../src/Tools/babylon.tools.js",      
+      "../../src/Tools/babylon.tools.js",
       "../../src/States/babylon.alphaCullingState.js",
       "../../src/States/babylon.depthCullingState.js",
       "../../src/babylon.engine.js",
@@ -84,7 +82,7 @@
       "../../src/Materials/Textures/babylon.videoTexture.js",
       "../../src/Materials/Textures/Procedurals/babylon.customProceduralTexture.js",
       "../../src/Materials/babylon.effect.js",
-      "../../src/Materials/babylon.materialHelper.js",      
+      "../../src/Materials/babylon.materialHelper.js",
       "../../src/Materials/babylon.fresnelParameters.js",
       "../../src/Materials/babylon.material.js",
       "../../src/Materials/babylon.standardMaterial.js",
@@ -155,8 +153,10 @@
     }
   ],
   "extras": {
-    "files": [      
+    "files": [
       "../../src/Math/babylon.math.SIMD.js",
+      "../../src/Tools/babylon.rectPackingMap.js",
+      "../../src/Tools/babylon.dynamicFloatArray.js",
       "../../src/Materials/babylon.shaderMaterial.js",
       "../../src/Tools/babylon.tools.dds.js",
       "../../src/Physics/Plugins/babylon.cannonJSPlugin.js",
@@ -212,7 +212,7 @@
       "../../src/tools/hdr/babylon.tools.pmremGenerator.js",
       "../../src/materials/textures/babylon.hdrcubetexture.js",
       "../../src/debug/babylon.skeletonViewer.js",
-      "../../src/materials/babylon.pbrmaterial.js"      
+      "../../src/materials/babylon.pbrmaterial.js"
     ]
   }
 }

文件差异内容过多而无法显示
+ 22 - 22
dist/preview release/babylon.core.js


+ 184 - 51
dist/preview release/babylon.d.ts

@@ -2923,50 +2923,6 @@ declare module BABYLON {
 }
 
 declare module BABYLON {
-    interface ISceneLoaderPlugin {
-        extensions: string;
-        importMesh: (meshesNames: any, scene: Scene, data: any, rootUrl: string, meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => boolean;
-        load: (scene: Scene, data: string, rootUrl: string) => boolean;
-    }
-    interface ISceneLoaderPluginAsync {
-        extensions: string;
-        importMeshAsync: (meshesNames: any, scene: Scene, data: any, rootUrl: string, onsuccess?: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onerror?: () => void) => void;
-        loadAsync: (scene: Scene, data: string, rootUrl: string, onsuccess: () => void, onerror: () => void) => boolean;
-    }
-    class SceneLoader {
-        private static _ForceFullSceneLoadingForIncremental;
-        private static _ShowLoadingScreen;
-        static NO_LOGGING: number;
-        static MINIMAL_LOGGING: number;
-        static SUMMARY_LOGGING: number;
-        static DETAILED_LOGGING: number;
-        private static _loggingLevel;
-        static ForceFullSceneLoadingForIncremental: boolean;
-        static ShowLoadingScreen: boolean;
-        static loggingLevel: number;
-        private static _registeredPlugins;
-        private static _getPluginForFilename(sceneFilename);
-        static GetPluginForExtension(extension: string): ISceneLoaderPlugin | ISceneLoaderPluginAsync;
-        static RegisterPlugin(plugin: ISceneLoaderPlugin): void;
-        static ImportMesh(meshesNames: any, rootUrl: string, sceneFilename: string, scene: Scene, onsuccess?: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, progressCallBack?: () => void, onerror?: (scene: Scene, message: string, exception?: any) => void): void;
-        /**
-        * Load a scene
-        * @param rootUrl a string that defines the root url for scene and resources
-        * @param sceneFilename a string that defines the name of the scene file. can start with "data:" following by the stringified version of the scene
-        * @param engine is the instance of BABYLON.Engine to use to create the scene
-        */
-        static Load(rootUrl: string, sceneFilename: any, engine: Engine, onsuccess?: (scene: Scene) => void, progressCallBack?: any, onerror?: (scene: Scene) => void): void;
-        /**
-        * Append a scene
-        * @param rootUrl a string that defines the root url for scene and resources
-        * @param sceneFilename a string that defines the name of the scene file. can start with "data:" following by the stringified version of the scene
-        * @param scene is the instance of BABYLON.Scene to append to
-        */
-        static Append(rootUrl: string, sceneFilename: any, scene: Scene, onsuccess?: (scene: Scene) => void, progressCallBack?: any, onerror?: (scene: Scene) => void): void;
-    }
-}
-
-declare module BABYLON {
     class EffectFallbacks {
         private _defines;
         private _currentRank;
@@ -3536,6 +3492,50 @@ declare module BABYLON {
 }
 
 declare module BABYLON {
+    interface ISceneLoaderPlugin {
+        extensions: string;
+        importMesh: (meshesNames: any, scene: Scene, data: any, rootUrl: string, meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => boolean;
+        load: (scene: Scene, data: string, rootUrl: string) => boolean;
+    }
+    interface ISceneLoaderPluginAsync {
+        extensions: string;
+        importMeshAsync: (meshesNames: any, scene: Scene, data: any, rootUrl: string, onsuccess?: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onerror?: () => void) => void;
+        loadAsync: (scene: Scene, data: string, rootUrl: string, onsuccess: () => void, onerror: () => void) => boolean;
+    }
+    class SceneLoader {
+        private static _ForceFullSceneLoadingForIncremental;
+        private static _ShowLoadingScreen;
+        static NO_LOGGING: number;
+        static MINIMAL_LOGGING: number;
+        static SUMMARY_LOGGING: number;
+        static DETAILED_LOGGING: number;
+        private static _loggingLevel;
+        static ForceFullSceneLoadingForIncremental: boolean;
+        static ShowLoadingScreen: boolean;
+        static loggingLevel: number;
+        private static _registeredPlugins;
+        private static _getPluginForFilename(sceneFilename);
+        static GetPluginForExtension(extension: string): ISceneLoaderPlugin | ISceneLoaderPluginAsync;
+        static RegisterPlugin(plugin: ISceneLoaderPlugin): void;
+        static ImportMesh(meshesNames: any, rootUrl: string, sceneFilename: string, scene: Scene, onsuccess?: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, progressCallBack?: () => void, onerror?: (scene: Scene, message: string, exception?: any) => void): void;
+        /**
+        * Load a scene
+        * @param rootUrl a string that defines the root url for scene and resources
+        * @param sceneFilename a string that defines the name of the scene file. can start with "data:" following by the stringified version of the scene
+        * @param engine is the instance of BABYLON.Engine to use to create the scene
+        */
+        static Load(rootUrl: string, sceneFilename: any, engine: Engine, onsuccess?: (scene: Scene) => void, progressCallBack?: any, onerror?: (scene: Scene) => void): void;
+        /**
+        * Append a scene
+        * @param rootUrl a string that defines the root url for scene and resources
+        * @param sceneFilename a string that defines the name of the scene file. can start with "data:" following by the stringified version of the scene
+        * @param scene is the instance of BABYLON.Scene to append to
+        */
+        static Append(rootUrl: string, sceneFilename: any, scene: Scene, onsuccess?: (scene: Scene) => void, progressCallBack?: any, onerror?: (scene: Scene) => void): void;
+    }
+}
+
+declare module BABYLON {
     class SIMDVector3 {
         static TransformCoordinatesToRefSIMD(vector: Vector3, transformation: Matrix, result: Vector3): void;
         static TransformCoordinatesFromFloatsToRefSIMD(x: number, y: number, z: number, transformation: Matrix, result: Vector3): void;
@@ -3805,6 +3805,19 @@ declare module BABYLON {
         static DistanceSquared(value1: Vector4, value2: Vector4): number;
         static Center(value1: Vector4, value2: Vector4): Vector4;
     }
+    interface ISize {
+        width: number;
+        height: number;
+    }
+    class Size implements ISize {
+        width: number;
+        height: number;
+        constructor(width: number, height: number);
+        clone(): Size;
+        equals(other: Size): boolean;
+        surface: number;
+        static Zero(): Size;
+    }
     class Quaternion {
         x: number;
         y: number;
@@ -8180,6 +8193,42 @@ declare module BABYLON {
 }
 
 declare module BABYLON {
+    /**
+    * The purpose of this class is to store float32 based elements of a given size (defined by the stride argument) in a dynamic fashion, that is, you can add/free elements. You can then access to a defragmented/packed version of the underlying Float32Array by calling the pack() method.
+    * The intent is to maintain through time data that will be bound to a WebGlBuffer with the ability to change add/remove elements.
+    * It was first built to effiently maintain the WebGlBuffer that contain instancing based data.
+    * Allocating an Element will return a instance of DynamicFloatArrayEntry which contains the offset into the Float32Array of where the element starts, you are then responsible to copy your data using this offset.
+    * Beware, calling pack() may change the offset of some Entries because this method will defrag the Float32Array to replace empty elements by moving allocated ones at their location.
+     * This method will retrun an ArrayBufferView on the existing Float32Array that describes the occupied elements. Use this View to update the WebGLBuffer and NOT the "buffer" field of the class. The pack() method won't shrink/reallocate the buffer to keep it GC friendly, all the empty space will be put at the end of the buffer, the method just ensure there're no "free holes".
+    */
+    class DynamicFloatArray {
+        /**
+         * Construct an instance of the dynamic float array
+         * @param stride size of one entry in float (i.e. not bytes!)
+         * @param initialEntryCount the number of available entries at construction
+         */
+        constructor(stride: number, initialEntryCount: number);
+        allocElement(): DynamicFloatArrayEntry;
+        freeElement(entry: DynamicFloatArrayEntry): void;
+        /**
+         * This method will pack all the occupied elements into a linear sequence and free the rest.
+         * Instances of DynamicFloatArrayEntry may have their 'offset' member changed as data could be copied from one location to another, so be sure to read/write your data based on the value inside this member after you called pack().
+         */
+        pack(): Float32Array;
+        private _moveEntry(entry, destOffset);
+        private _growBuffer();
+        buffer: Float32Array;
+        entryCount: number;
+        stride: number;
+        allEntries: Array<DynamicFloatArrayEntry>;
+        freeEntries: Array<DynamicFloatArrayEntry>;
+    }
+    class DynamicFloatArrayEntry {
+        offset: number;
+    }
+}
+
+declare module BABYLON {
     class FilesInput {
         private _engine;
         private _currentScene;
@@ -8412,6 +8461,74 @@ declare module BABYLON {
 }
 
 declare module BABYLON {
+    /**
+     * The purpose of this class is to pack several Rectangles into a big map, while trying to fit everything as optimaly as possible.
+     * This class is typically used to build lightmaps, sprite map or to pack several little textures into a big one.
+     * Note that this class allows allocated Rectangles to be freed: that is the map is dynamically maintained so you can add/remove rectangle based on their lifecycle.
+     */
+    class RectPackingMap extends PackedRect {
+        /**
+         * Create an instance of the object with a dimension using the given size
+         * @param size The dimension of the rectangle that will contain all the sub ones.
+         */
+        constructor(size: Size);
+        /**
+         * Add a rectangle, finding the best location to store it into the map
+         * @param size the dimension of the rectangle to store
+         * @return the Node containing the rectangle information, or null if we couldn't find a free spot
+         */
+        addRect(size: Size): PackedRect;
+        /**
+         * Return the current space free normalized between [0;1]
+         * @returns {}
+         */
+        freeSpace: number;
+    }
+    /**
+     * This class describe a rectangle that were added to the map.
+     * You have access to its coordinates either in pixel or normalized (UV)
+     */
+    class PackedRect {
+        constructor(root: PackedRect, parent: PackedRect, pos: Vector2, size: Size);
+        /**
+         * @returns the position of this node into the map
+         */
+        pos: Vector2;
+        /**
+         * @returns the size of the rectangle this node handles
+         */
+        contentSize: Size;
+        /**
+         * Compute the UV of the top/left, top/right, bottom/right, bottom/left points of the rectangle this node handles into the map
+         * @returns And array of 4 Vector2, containing UV coordinates for the four corners of the Rectangle into the map
+         */
+        UVs: Vector2[];
+        /**
+         * Free this rectangle from the map.
+         * Call this method when you no longer need the rectangle to be in the map.
+         */
+        freeContent(): void;
+        protected isUsed: boolean;
+        protected findAndSplitNode(contentSize: Size): PackedRect;
+        private findNode(size);
+        private splitNode(contentSize);
+        private attemptDefrag();
+        private clearNode();
+        private isRecursiveFree;
+        protected evalFreeSize(size: number): number;
+        protected _root: PackedRect;
+        protected _parent: PackedRect;
+        private _contentSize;
+        private _initialSize;
+        private _leftNode;
+        private _rightNode;
+        private _bottomNode;
+        private _pos;
+        protected _size: Size;
+    }
+}
+
+declare module BABYLON {
     class SceneOptimization {
         priority: number;
         apply: (scene: Scene) => boolean;
@@ -8493,6 +8610,26 @@ declare module BABYLON {
 }
 
 declare module BABYLON {
+    class SmartCollection {
+        count: number;
+        items: any;
+        private _keys;
+        private _initialCapacity;
+        constructor(capacity?: number);
+        add(key: any, item: any): number;
+        remove(key: any): number;
+        removeItemOfIndex(index: number): number;
+        indexOf(key: any): number;
+        item(key: any): any;
+        getAllKeys(): any[];
+        getKeyByIndex(index: number): any;
+        getItemByIndex(index: number): any;
+        empty(): void;
+        forEach(block: (item: any) => void): void;
+    }
+}
+
+declare module BABYLON {
     /**
      * This class implement a typical dictionary using a string as key and the generic type T as value.
      * The underlying implemetation relies on an associative array to ensure the best performances.
@@ -8626,10 +8763,6 @@ declare module BABYLON {
     interface IAnimatable {
         animations: Array<Animation>;
     }
-    interface ISize {
-        width: number;
-        height: number;
-    }
     class Tools {
         static BaseUrl: string;
         static CorsBehavior: any;
@@ -9213,9 +9346,6 @@ declare module BABYLON {
     }
 }
 
-declare module BABYLON.Internals {
-}
-
 declare module BABYLON {
     class BaseTexture {
         name: string;
@@ -9538,6 +9668,9 @@ declare module BABYLON {
     }
 }
 
+declare module BABYLON.Internals {
+}
+
 declare module BABYLON {
     class CannonJSPlugin implements IPhysicsEnginePlugin {
         private _useDeltaForWorldStep;

文件差异内容过多而无法显示
+ 33 - 33
dist/preview release/babylon.js


文件差异内容过多而无法显示
+ 387 - 3
dist/preview release/babylon.max.js


文件差异内容过多而无法显示
+ 33 - 33
dist/preview release/babylon.noworker.js


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

@@ -86,7 +86,7 @@ var BABYLON;
                         cacheSoloPointer.y = evt.clientY;
                     }
                     else if (pointA && pointB) {
-                        //if (noPreventDefault) { evt.preventDefault(); } //if pinch gesture, could be usefull to force preventDefault to avoid html page scroll/zoom in some mobile browsers
+                        //if (noPreventDefault) { evt.preventDefault(); } //if pinch gesture, could be useful to force preventDefault to avoid html page scroll/zoom in some mobile browsers
                         var ed = (pointA.pointerId === evt.pointerId) ? pointA : pointB;
                         ed.x = evt.clientX;
                         ed.y = evt.clientY;

+ 6 - 6
src/Cameras/Inputs/babylon.arcrotatecamera.input.pointers.ts

@@ -67,7 +67,7 @@ module BABYLON {
                     } catch (e) {
                         //Nothing to do with the error.
                     }
-                    
+
                     cacheSoloPointer = null;
                     previousPinchDistance = 0;
 
@@ -88,8 +88,8 @@ module BABYLON {
                     // One button down
                     if (pointA && pointB === undefined) {
                         if (this.panningSensibility !== 0 &&
-                        ((this._isCtrlPushed && this.camera._useCtrlForPanning) ||
-                        (!this.camera._useCtrlForPanning && this._isRightClick))) {
+                            ((this._isCtrlPushed && this.camera._useCtrlForPanning) ||
+                                (!this.camera._useCtrlForPanning && this._isRightClick))) {
                             this.camera
                                 .inertialPanningX += -(evt.clientX - cacheSoloPointer.x) / this.panningSensibility;
                             this.camera
@@ -104,10 +104,10 @@ module BABYLON {
                         cacheSoloPointer.y = evt.clientY;
                     }
 
-                   // Two buttons down: pinch
+                    // Two buttons down: pinch
                     else if (pointA && pointB) {
-                        //if (noPreventDefault) { evt.preventDefault(); } //if pinch gesture, could be usefull to force preventDefault to avoid html page scroll/zoom in some mobile browsers
-                        var ed = (pointA.pointerId===evt.pointerId) ? pointA : pointB;
+                        //if (noPreventDefault) { evt.preventDefault(); } //if pinch gesture, could be useful to force preventDefault to avoid html page scroll/zoom in some mobile browsers
+                        var ed = (pointA.pointerId === evt.pointerId) ? pointA : pointB;
                         ed.x = evt.clientX;
                         ed.y = evt.clientY;
                         var direction = this.pinchInwards ? 1 : -1;

文件差异内容过多而无法显示
+ 2964 - 2965
src/Math/babylon.math.js


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

@@ -580,7 +580,7 @@ var BABYLON;
                     else {
                         parentMatrix = this.parent.getWorldMatrix();
                     }
-                    BABYLON.Vector3.TransformCoordinatesToRef(localPosition, parentMatrix, BABYLON.Tmp.Vector3[1]);
+                    BABYLON.Vector3.TransformNormalToRef(localPosition, parentMatrix, BABYLON.Tmp.Vector3[1]);
                     localPosition = BABYLON.Tmp.Vector3[1];
                 }
                 var zero = this.getScene().activeCamera.globalPosition.clone();

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

@@ -632,7 +632,7 @@
                         parentMatrix = this.parent.getWorldMatrix();
                     }
 
-                    Vector3.TransformCoordinatesToRef(localPosition, parentMatrix, Tmp.Vector3[1]);
+                    Vector3.TransformNormalToRef(localPosition, parentMatrix, Tmp.Vector3[1]);
                     localPosition = Tmp.Vector3[1];
                 }
 

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

@@ -1068,6 +1068,7 @@ var BABYLON;
             if (!this.isVerticesDataPresent(BABYLON.VertexBuffer.PositionKind)) {
                 return;
             }
+            var submeshes = this.subMeshes.splice(0);
             this._resetPointsArrayCache();
             var data = this.getVerticesData(BABYLON.VertexBuffer.PositionKind);
             var temp = [];
@@ -1090,6 +1091,9 @@ var BABYLON;
             if (transform.m[0] * transform.m[5] * transform.m[10] < 0) {
                 this.flipFaces();
             }
+            // Restore submeshes
+            this.releaseSubMeshes();
+            this.subMeshes = submeshes;
         };
         /**
          * Modifies the mesh geometry according to its own current World Matrix.

+ 6 - 0
src/Mesh/babylon.mesh.ts

@@ -1190,6 +1190,8 @@
                 return;
             }
 
+            var submeshes = this.subMeshes.splice(0);
+
             this._resetPointsArrayCache();
 
             var data = this.getVerticesData(VertexBuffer.PositionKind);
@@ -1214,6 +1216,10 @@
 
             // flip faces?
             if (transform.m[0] * transform.m[5] * transform.m[10] < 0) { this.flipFaces(); }
+
+            // Restore submeshes
+            this.releaseSubMeshes();
+            this.subMeshes = submeshes;
         }
 
         /**

+ 142 - 143
src/Tools/babylon.dynamicFloatArray.js

@@ -1,143 +1,142 @@
-var BABYLON;
-(function (BABYLON) {
-    /**
-    * The purpose of this class is to store float32 based elements of a given size (defined by the stride argument) in a dynamic fashion, that is, you can add/free elements. You can then access to a defragmented/packed version of the underlying Float32Array by calling the pack() method.
-    * The intent is to maintain through time data that will be bound to a WebGlBuffer with the ability to change add/remove elements.
-    * It was first built to effiently maintain the WebGlBuffer that contain instancing based data.
-    * Allocating an Element will return a instance of DynamicFloatArrayEntry which contains the offset into the Float32Array of where the element starts, you are then responsible to copy your data using this offset.
-    * Beware, calling pack() may change the offset of some Entries because this method will defrag the Float32Array to replace empty elements by moving allocated ones at their location.
-     * This method will retrun an ArrayBufferView on the existing Float32Array that describes the occupied elements. Use this View to update the WebGLBuffer and NOT the "buffer" field of the class. The pack() method won't shrink/reallocate the buffer to keep it GC friendly, all the empty space will be put at the end of the buffer, the method just ensure there're no "free holes".
-    */
-    var DynamicFloatArray = (function () {
-        /**
-         * Construct an instance of the dynamic float array
-         * @param stride size of one entry in float (i.e. not bytes!)
-         * @param initialEntryCount the number of available entries at construction
-         */
-        function DynamicFloatArray(stride, initialEntryCount) {
-            this.stride = stride;
-            this.entryCount = initialEntryCount;
-            this.buffer = new Float32Array(stride * initialEntryCount);
-            this.allEntries = new Array(initialEntryCount);
-            this.freeEntries = new Array(initialEntryCount);
-            for (var i = 0; i < initialEntryCount; i++) {
-                var entry = new DynamicFloatArrayEntry();
-                entry.offset = i * stride;
-                this.allEntries[i] = entry;
-                this.freeEntries[initialEntryCount - i - 1] = entry;
-            }
-        }
-        DynamicFloatArray.prototype.allocElement = function () {
-            if (this.freeEntries.length === 0) {
-                this._growBuffer();
-            }
-            var entry = this.freeEntries.pop();
-            return entry;
-        };
-        DynamicFloatArray.prototype.freeElement = function (entry) {
-            this.freeEntries.push(entry);
-        };
-        /**
-         * This method will pack all the occupied elements into a linear sequence and free the rest.
-         * Instances of DynamicFloatArrayEntry may have their 'offset' member changed as data could be copied from one location to another, so be sure to read/write your data based on the value inside this member after you called pack().
-         */
-        DynamicFloatArray.prototype.pack = function () {
-            // no free slot? no need to pack
-            if (this.freeEntries.length === 0) {
-                return this.buffer;
-            }
-            var s = this.stride;
-            var sortedFree = this.freeEntries.sort(function (a, b) { return a.offset - b.offset; });
-            var sortedAll = this.allEntries.sort(function (a, b) { return a.offset - b.offset; });
-            // Make sure there's a free element at the very end, we need it to create a range where we'll move the occupied elements that may appear before
-            var lastFree = new DynamicFloatArrayEntry();
-            lastFree.offset = this.entryCount * s;
-            sortedFree.push(lastFree);
-            var firstFreeSlotOffset = sortedFree[0].offset;
-            var freeZoneSize = 1;
-            var prevOffset = sortedFree[0].offset;
-            for (var i = 1; i < sortedFree.length; i++) {
-                var curFree = sortedFree[i];
-                var curOffset = curFree.offset;
-                // Compute the distance between this offset and the previous
-                var distance = curOffset - prevOffset;
-                // If the distance is the stride size, they are adjacents, it good, move to the next
-                if (distance === s) {
-                    // Free zone is one element bigger
-                    ++freeZoneSize;
-                    // as we're about to iterate to the next, the cur becomes the prev...
-                    prevOffset = curOffset;
-                    continue;
-                }
-                // Distance is bigger, which means there's x element between the previous free and this one
-                var occupiedRange = (distance / s) - 1;
-                // Two cases the free zone is smaller than the data to move or bigger
-                // Copy what can fit in the free zone
-                var curMoveOffset = curOffset - s;
-                var copyCount = Math.min(freeZoneSize, occupiedRange);
-                for (var j = 0; j < copyCount; j++) {
-                    var freeI = firstFreeSlotOffset / s;
-                    var curI = curMoveOffset / s;
-                    var moveEntry = sortedAll[curI];
-                    this._moveEntry(moveEntry, firstFreeSlotOffset);
-                    var replacedEntry = sortedAll[freeI];
-                    // set the offset of the element entry we replace with a value that will make it discard at the end of the method
-                    replacedEntry.offset = curMoveOffset;
-                    // Swap the entry we moved and the one it replaced in the sorted array to reflect the action we've made
-                    sortedAll[freeI] = moveEntry;
-                    sortedAll[curI] = replacedEntry;
-                    curMoveOffset -= s;
-                    firstFreeSlotOffset += s;
-                }
-                // Free Zone is smaller or equal so it's no longer a free zone, set the new one to the current location
-                if (freeZoneSize <= occupiedRange) {
-                    firstFreeSlotOffset = curOffset;
-                    freeZoneSize = 1;
-                }
-                else {
-                    freeZoneSize = ((curOffset - firstFreeSlotOffset) / s) + 1;
-                }
-                // as we're about to iterate to the next, the cur becomes the prev...
-                prevOffset = curOffset;
-            }
-            // Allocate a new buffer with the perfect size, copy the content, update free data
-            this.entryCount = firstFreeSlotOffset / s;
-            var optimizedBuffer = this.buffer.subarray(0, firstFreeSlotOffset);
-            this.freeEntries.splice(0);
-            this.allEntries = sortedAll.slice(0, this.entryCount);
-            return optimizedBuffer;
-        };
-        DynamicFloatArray.prototype._moveEntry = function (entry, destOffset) {
-            for (var i = 0; i < this.stride; i++) {
-                this.buffer[destOffset + i] = this.buffer[entry.offset + i];
-            }
-            entry.offset = destOffset;
-        };
-        DynamicFloatArray.prototype._growBuffer = function () {
-            // Allocate the new buffer with 50% more entries, copy the content of the current one
-            var newEntryCount = this.entryCount * 1.5;
-            var newBuffer = new Float32Array(newEntryCount * this.stride);
-            newBuffer.set(this.buffer);
-            var addedCount = newEntryCount - this.entryCount;
-            this.allEntries.length += addedCount;
-            this.freeEntries.length += addedCount;
-            for (var i = this.entryCount; i < newEntryCount; i++) {
-                var entry = new DynamicFloatArrayEntry();
-                entry.offset = i * this.stride;
-                this.allEntries[i] = entry;
-                this.freeEntries[i] = entry;
-            }
-            this.buffer = newBuffer;
-            this.entryCount = newEntryCount;
-        };
-        return DynamicFloatArray;
-    }());
-    BABYLON.DynamicFloatArray = DynamicFloatArray;
-    var DynamicFloatArrayEntry = (function () {
-        function DynamicFloatArrayEntry() {
-        }
-        return DynamicFloatArrayEntry;
-    }());
-    BABYLON.DynamicFloatArrayEntry = DynamicFloatArrayEntry;
-})(BABYLON || (BABYLON = {}));
-//# sourceMappingURL=babylon.dynamicFloatArray.js.map
+var BABYLON;
+(function (BABYLON) {
+    /**
+    * The purpose of this class is to store float32 based elements of a given size (defined by the stride argument) in a dynamic fashion, that is, you can add/free elements. You can then access to a defragmented/packed version of the underlying Float32Array by calling the pack() method.
+    * The intent is to maintain through time data that will be bound to a WebGlBuffer with the ability to change add/remove elements.
+    * It was first built to effiently maintain the WebGlBuffer that contain instancing based data.
+    * Allocating an Element will return a instance of DynamicFloatArrayEntry which contains the offset into the Float32Array of where the element starts, you are then responsible to copy your data using this offset.
+    * Beware, calling pack() may change the offset of some Entries because this method will defrag the Float32Array to replace empty elements by moving allocated ones at their location.
+     * This method will retrun an ArrayBufferView on the existing Float32Array that describes the occupied elements. Use this View to update the WebGLBuffer and NOT the "buffer" field of the class. The pack() method won't shrink/reallocate the buffer to keep it GC friendly, all the empty space will be put at the end of the buffer, the method just ensure there're no "free holes".
+    */
+    var DynamicFloatArray = (function () {
+        /**
+         * Construct an instance of the dynamic float array
+         * @param stride size of one entry in float (i.e. not bytes!)
+         * @param initialEntryCount the number of available entries at construction
+         */
+        function DynamicFloatArray(stride, initialEntryCount) {
+            this.stride = stride;
+            this.entryCount = initialEntryCount;
+            this.buffer = new Float32Array(stride * initialEntryCount);
+            this.allEntries = new Array(initialEntryCount);
+            this.freeEntries = new Array(initialEntryCount);
+            for (var i = 0; i < initialEntryCount; i++) {
+                var entry = new DynamicFloatArrayEntry();
+                entry.offset = i * stride;
+                this.allEntries[i] = entry;
+                this.freeEntries[initialEntryCount - i - 1] = entry;
+            }
+        }
+        DynamicFloatArray.prototype.allocElement = function () {
+            if (this.freeEntries.length === 0) {
+                this._growBuffer();
+            }
+            var entry = this.freeEntries.pop();
+            return entry;
+        };
+        DynamicFloatArray.prototype.freeElement = function (entry) {
+            this.freeEntries.push(entry);
+        };
+        /**
+         * This method will pack all the occupied elements into a linear sequence and free the rest.
+         * Instances of DynamicFloatArrayEntry may have their 'offset' member changed as data could be copied from one location to another, so be sure to read/write your data based on the value inside this member after you called pack().
+         */
+        DynamicFloatArray.prototype.pack = function () {
+            // no free slot? no need to pack
+            if (this.freeEntries.length === 0) {
+                return this.buffer;
+            }
+            var s = this.stride;
+            var sortedFree = this.freeEntries.sort(function (a, b) { return a.offset - b.offset; });
+            var sortedAll = this.allEntries.sort(function (a, b) { return a.offset - b.offset; });
+            // Make sure there's a free element at the very end, we need it to create a range where we'll move the occupied elements that may appear before
+            var lastFree = new DynamicFloatArrayEntry();
+            lastFree.offset = this.entryCount * s;
+            sortedFree.push(lastFree);
+            var firstFreeSlotOffset = sortedFree[0].offset;
+            var freeZoneSize = 1;
+            var prevOffset = sortedFree[0].offset;
+            for (var i = 1; i < sortedFree.length; i++) {
+                var curFree = sortedFree[i];
+                var curOffset = curFree.offset;
+                // Compute the distance between this offset and the previous
+                var distance = curOffset - prevOffset;
+                // If the distance is the stride size, they are adjacents, it good, move to the next
+                if (distance === s) {
+                    // Free zone is one element bigger
+                    ++freeZoneSize;
+                    // as we're about to iterate to the next, the cur becomes the prev...
+                    prevOffset = curOffset;
+                    continue;
+                }
+                // Distance is bigger, which means there's x element between the previous free and this one
+                var occupiedRange = (distance / s) - 1;
+                // Two cases the free zone is smaller than the data to move or bigger
+                // Copy what can fit in the free zone
+                var curMoveOffset = curOffset - s;
+                var copyCount = Math.min(freeZoneSize, occupiedRange);
+                for (var j = 0; j < copyCount; j++) {
+                    var freeI = firstFreeSlotOffset / s;
+                    var curI = curMoveOffset / s;
+                    var moveEntry = sortedAll[curI];
+                    this._moveEntry(moveEntry, firstFreeSlotOffset);
+                    var replacedEntry = sortedAll[freeI];
+                    // set the offset of the element entry we replace with a value that will make it discard at the end of the method
+                    replacedEntry.offset = curMoveOffset;
+                    // Swap the entry we moved and the one it replaced in the sorted array to reflect the action we've made
+                    sortedAll[freeI] = moveEntry;
+                    sortedAll[curI] = replacedEntry;
+                    curMoveOffset -= s;
+                    firstFreeSlotOffset += s;
+                }
+                // Free Zone is smaller or equal so it's no longer a free zone, set the new one to the current location
+                if (freeZoneSize <= occupiedRange) {
+                    firstFreeSlotOffset = curOffset;
+                    freeZoneSize = 1;
+                }
+                else {
+                    freeZoneSize = ((curOffset - firstFreeSlotOffset) / s) + 1;
+                }
+                // as we're about to iterate to the next, the cur becomes the prev...
+                prevOffset = curOffset;
+            }
+            // Allocate a new buffer with the perfect size, copy the content, update free data
+            this.entryCount = firstFreeSlotOffset / s;
+            var optimizedBuffer = this.buffer.subarray(0, firstFreeSlotOffset);
+            this.freeEntries.splice(0);
+            this.allEntries = sortedAll.slice(0, this.entryCount);
+            return optimizedBuffer;
+        };
+        DynamicFloatArray.prototype._moveEntry = function (entry, destOffset) {
+            for (var i = 0; i < this.stride; i++) {
+                this.buffer[destOffset + i] = this.buffer[entry.offset + i];
+            }
+            entry.offset = destOffset;
+        };
+        DynamicFloatArray.prototype._growBuffer = function () {
+            // Allocate the new buffer with 50% more entries, copy the content of the current one
+            var newEntryCount = this.entryCount * 1.5;
+            var newBuffer = new Float32Array(newEntryCount * this.stride);
+            newBuffer.set(this.buffer);
+            var addedCount = newEntryCount - this.entryCount;
+            this.allEntries.length += addedCount;
+            this.freeEntries.length += addedCount;
+            for (var i = this.entryCount; i < newEntryCount; i++) {
+                var entry = new DynamicFloatArrayEntry();
+                entry.offset = i * this.stride;
+                this.allEntries[i] = entry;
+                this.freeEntries[i] = entry;
+            }
+            this.buffer = newBuffer;
+            this.entryCount = newEntryCount;
+        };
+        return DynamicFloatArray;
+    })();
+    BABYLON.DynamicFloatArray = DynamicFloatArray;
+    var DynamicFloatArrayEntry = (function () {
+        function DynamicFloatArrayEntry() {
+        }
+        return DynamicFloatArrayEntry;
+    })();
+    BABYLON.DynamicFloatArrayEntry = DynamicFloatArrayEntry;
+})(BABYLON || (BABYLON = {}));

+ 208 - 209
src/Tools/babylon.rectPackingMap.js

@@ -1,209 +1,208 @@
-var __extends = (this && this.__extends) || function (d, b) {
-    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
-    function __() { this.constructor = d; }
-    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
-};
-var BABYLON;
-(function (BABYLON) {
-    /**
-     * The purpose of this class is to pack several Rectangles into a big map, while trying to fit everything as optimaly as possible.
-     * This class is typically used to build lightmaps, sprite map or to pack several little textures into a big one.
-     * Note that this class allows allocated Rectangles to be freed: that is the map is dynamically maintained so you can add/remove rectangle based on their lifecycle.
-     */
-    var RectPackingMap = (function (_super) {
-        __extends(RectPackingMap, _super);
-        /**
-         * Create an instance of the object with a dimension using the given size
-         * @param size The dimension of the rectangle that will contain all the sub ones.
-         */
-        function RectPackingMap(size) {
-            _super.call(this, null, null, BABYLON.Vector2.Zero(), size);
-            this._root = this;
-        }
-        /**
-         * Add a rectangle, finding the best location to store it into the map
-         * @param size the dimension of the rectangle to store
-         * @return the Node containing the rectangle information, or null if we couldn't find a free spot
-         */
-        RectPackingMap.prototype.addRect = function (size) {
-            var node = this.findAndSplitNode(size);
-            return node;
-        };
-        Object.defineProperty(RectPackingMap.prototype, "freeSpace", {
-            /**
-             * Return the current space free normalized between [0;1]
-             * @returns {}
-             */
-            get: function () {
-                var freeSize = 0;
-                freeSize = this.evalFreeSize(freeSize);
-                return freeSize / (this._size.width * this._size.height);
-            },
-            enumerable: true,
-            configurable: true
-        });
-        return RectPackingMap;
-    }(PackedRect));
-    BABYLON.RectPackingMap = RectPackingMap;
-    /**
-     * This class describe a rectangle that were added to the map.
-     * You have access to its coordinates either in pixel or normalized (UV)
-     */
-    var PackedRect = (function () {
-        function PackedRect(root, parent, pos, size) {
-            this._pos = pos;
-            this._size = size;
-            this._root = root;
-            this._parent = parent;
-        }
-        Object.defineProperty(PackedRect.prototype, "pos", {
-            /**
-             * @returns the position of this node into the map
-             */
-            get: function () {
-                return this._pos;
-            },
-            enumerable: true,
-            configurable: true
-        });
-        Object.defineProperty(PackedRect.prototype, "contentSize", {
-            /**
-             * @returns the size of the rectangle this node handles
-             */
-            get: function () {
-                return this._contentSize;
-            },
-            enumerable: true,
-            configurable: true
-        });
-        Object.defineProperty(PackedRect.prototype, "UVs", {
-            /**
-             * Compute the UV of the top/left, top/right, bottom/right, bottom/left points of the rectangle this node handles into the map
-             * @returns And array of 4 Vector2, containing UV coordinates for the four corners of the Rectangle into the map
-             */
-            get: function () {
-                var mainWidth = this._root._size.width;
-                var mainHeight = this._root._size.height;
-                var topLeft = new BABYLON.Vector2(this._pos.x / mainWidth, this._pos.y / mainHeight);
-                var rightBottom = new BABYLON.Vector2((this._pos.x + this._contentSize.width - 1) / mainWidth, (this._pos.y + this._contentSize.height - 1) / mainHeight);
-                var uvs = new Array();
-                uvs.push(topLeft);
-                uvs.push(new BABYLON.Vector2(rightBottom.x, topLeft.y));
-                uvs.push(rightBottom);
-                uvs.push(new BABYLON.Vector2(topLeft.x, rightBottom.y));
-                return uvs;
-            },
-            enumerable: true,
-            configurable: true
-        });
-        /**
-         * Free this rectangle from the map.
-         * Call this method when you no longer need the rectangle to be in the map.
-         */
-        PackedRect.prototype.freeContent = function () {
-            if (!this.contentSize) {
-                return;
-            }
-            this._contentSize = null;
-            // If everything below is also free, reset the whole node, and attempt to reset parents if they also become free
-            this.attemptDefrag();
-        };
-        Object.defineProperty(PackedRect.prototype, "isUsed", {
-            get: function () {
-                return this._contentSize != null || this._leftNode != null;
-            },
-            enumerable: true,
-            configurable: true
-        });
-        PackedRect.prototype.findAndSplitNode = function (contentSize) {
-            var node = this.findNode(contentSize);
-            // Not enought space...
-            if (!node) {
-                return null;
-            }
-            node.splitNode(contentSize);
-            return node;
-        };
-        PackedRect.prototype.findNode = function (size) {
-            var resNode = null;
-            // If this node is used, recurse to each of his subNodes to find an available one in its branch
-            if (this.isUsed) {
-                if (this._leftNode) {
-                    resNode = this._leftNode.findNode(size);
-                }
-                if (!resNode && this._rightNode) {
-                    resNode = this._rightNode.findNode(size);
-                }
-                if (!resNode && this._bottomNode) {
-                    resNode = this._bottomNode.findNode(size);
-                }
-            }
-            else if (this._initialSize && (size.width <= this._initialSize.width) && (size.height <= this._initialSize.height)) {
-                resNode = this;
-            }
-            else if ((size.width <= this._size.width) && (size.height <= this._size.height)) {
-                resNode = this;
-            }
-            return resNode;
-        };
-        PackedRect.prototype.splitNode = function (contentSize) {
-            // If there's no contentSize but an initialSize it means this node were previously allocated, but freed, we need to create a _leftNode as subNode and use to allocate the space we need (and this node will have a right/bottom subNode for the space left as this._initialSize may be greater than contentSize)
-            if (!this._contentSize && this._initialSize) {
-                this._leftNode = new PackedRect(this._root, this, new BABYLON.Vector2(this._pos.x, this._pos.y), new BABYLON.Size(this._initialSize.width, this._initialSize.height));
-                return this._leftNode.splitNode(contentSize);
-            }
-            else {
-                this._contentSize = contentSize.clone();
-                this._initialSize = contentSize.clone();
-                if (contentSize.width !== this._size.width) {
-                    this._rightNode = new PackedRect(this._root, this, new BABYLON.Vector2(this._pos.x + contentSize.width, this._pos.y), new BABYLON.Size(this._size.width - contentSize.width, contentSize.height));
-                }
-                if (contentSize.height !== this._size.height) {
-                    this._bottomNode = new PackedRect(this._root, this, new BABYLON.Vector2(this._pos.x, this._pos.y + contentSize.height), new BABYLON.Size(this._size.width, this._size.height - contentSize.height));
-                }
-                return this;
-            }
-        };
-        PackedRect.prototype.attemptDefrag = function () {
-            if (!this.isUsed && this.isRecursiveFree) {
-                this.clearNode();
-                if (this._parent) {
-                    this._parent.attemptDefrag();
-                }
-            }
-        };
-        PackedRect.prototype.clearNode = function () {
-            this._initialSize = null;
-            this._rightNode = null;
-            this._bottomNode = null;
-        };
-        Object.defineProperty(PackedRect.prototype, "isRecursiveFree", {
-            get: function () {
-                return !this.contentSize && (!this._leftNode || this._leftNode.isRecursiveFree) && (!this._rightNode || this._rightNode.isRecursiveFree) && (!this._bottomNode || this._bottomNode.isRecursiveFree);
-            },
-            enumerable: true,
-            configurable: true
-        });
-        PackedRect.prototype.evalFreeSize = function (size) {
-            var levelSize = 0;
-            if (!this.isUsed) {
-                if (this._initialSize) {
-                    levelSize = this._initialSize.surface;
-                }
-                else {
-                    levelSize = this._size.surface;
-                }
-            }
-            if (this._rightNode) {
-                levelSize += this._rightNode.evalFreeSize(0);
-            }
-            if (this._bottomNode) {
-                levelSize += this._bottomNode.evalFreeSize(0);
-            }
-            return levelSize + size;
-        };
-        return PackedRect;
-    }());
-    BABYLON.PackedRect = PackedRect;
-})(BABYLON || (BABYLON = {}));
-//# sourceMappingURL=babylon.rectPackingMap.js.map
+var __extends = (this && this.__extends) || function (d, b) {
+    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
+    function __() { this.constructor = d; }
+    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
+};
+var BABYLON;
+(function (BABYLON) {
+    /**
+     * The purpose of this class is to pack several Rectangles into a big map, while trying to fit everything as optimaly as possible.
+     * This class is typically used to build lightmaps, sprite map or to pack several little textures into a big one.
+     * Note that this class allows allocated Rectangles to be freed: that is the map is dynamically maintained so you can add/remove rectangle based on their lifecycle.
+     */
+    var RectPackingMap = (function (_super) {
+        __extends(RectPackingMap, _super);
+        /**
+         * Create an instance of the object with a dimension using the given size
+         * @param size The dimension of the rectangle that will contain all the sub ones.
+         */
+        function RectPackingMap(size) {
+            _super.call(this, null, null, BABYLON.Vector2.Zero(), size);
+            this._root = this;
+        }
+        /**
+         * Add a rectangle, finding the best location to store it into the map
+         * @param size the dimension of the rectangle to store
+         * @return the Node containing the rectangle information, or null if we couldn't find a free spot
+         */
+        RectPackingMap.prototype.addRect = function (size) {
+            var node = this.findAndSplitNode(size);
+            return node;
+        };
+        Object.defineProperty(RectPackingMap.prototype, "freeSpace", {
+            /**
+             * Return the current space free normalized between [0;1]
+             * @returns {}
+             */
+            get: function () {
+                var freeSize = 0;
+                freeSize = this.evalFreeSize(freeSize);
+                return freeSize / (this._size.width * this._size.height);
+            },
+            enumerable: true,
+            configurable: true
+        });
+        return RectPackingMap;
+    })(PackedRect);
+    BABYLON.RectPackingMap = RectPackingMap;
+    /**
+     * This class describe a rectangle that were added to the map.
+     * You have access to its coordinates either in pixel or normalized (UV)
+     */
+    var PackedRect = (function () {
+        function PackedRect(root, parent, pos, size) {
+            this._pos = pos;
+            this._size = size;
+            this._root = root;
+            this._parent = parent;
+        }
+        Object.defineProperty(PackedRect.prototype, "pos", {
+            /**
+             * @returns the position of this node into the map
+             */
+            get: function () {
+                return this._pos;
+            },
+            enumerable: true,
+            configurable: true
+        });
+        Object.defineProperty(PackedRect.prototype, "contentSize", {
+            /**
+             * @returns the size of the rectangle this node handles
+             */
+            get: function () {
+                return this._contentSize;
+            },
+            enumerable: true,
+            configurable: true
+        });
+        Object.defineProperty(PackedRect.prototype, "UVs", {
+            /**
+             * Compute the UV of the top/left, top/right, bottom/right, bottom/left points of the rectangle this node handles into the map
+             * @returns And array of 4 Vector2, containing UV coordinates for the four corners of the Rectangle into the map
+             */
+            get: function () {
+                var mainWidth = this._root._size.width;
+                var mainHeight = this._root._size.height;
+                var topLeft = new BABYLON.Vector2(this._pos.x / mainWidth, this._pos.y / mainHeight);
+                var rightBottom = new BABYLON.Vector2((this._pos.x + this._contentSize.width - 1) / mainWidth, (this._pos.y + this._contentSize.height - 1) / mainHeight);
+                var uvs = new Array();
+                uvs.push(topLeft);
+                uvs.push(new BABYLON.Vector2(rightBottom.x, topLeft.y));
+                uvs.push(rightBottom);
+                uvs.push(new BABYLON.Vector2(topLeft.x, rightBottom.y));
+                return uvs;
+            },
+            enumerable: true,
+            configurable: true
+        });
+        /**
+         * Free this rectangle from the map.
+         * Call this method when you no longer need the rectangle to be in the map.
+         */
+        PackedRect.prototype.freeContent = function () {
+            if (!this.contentSize) {
+                return;
+            }
+            this._contentSize = null;
+            // If everything below is also free, reset the whole node, and attempt to reset parents if they also become free
+            this.attemptDefrag();
+        };
+        Object.defineProperty(PackedRect.prototype, "isUsed", {
+            get: function () {
+                return this._contentSize != null || this._leftNode != null;
+            },
+            enumerable: true,
+            configurable: true
+        });
+        PackedRect.prototype.findAndSplitNode = function (contentSize) {
+            var node = this.findNode(contentSize);
+            // Not enought space...
+            if (!node) {
+                return null;
+            }
+            node.splitNode(contentSize);
+            return node;
+        };
+        PackedRect.prototype.findNode = function (size) {
+            var resNode = null;
+            // If this node is used, recurse to each of his subNodes to find an available one in its branch
+            if (this.isUsed) {
+                if (this._leftNode) {
+                    resNode = this._leftNode.findNode(size);
+                }
+                if (!resNode && this._rightNode) {
+                    resNode = this._rightNode.findNode(size);
+                }
+                if (!resNode && this._bottomNode) {
+                    resNode = this._bottomNode.findNode(size);
+                }
+            }
+            else if (this._initialSize && (size.width <= this._initialSize.width) && (size.height <= this._initialSize.height)) {
+                resNode = this;
+            }
+            else if ((size.width <= this._size.width) && (size.height <= this._size.height)) {
+                resNode = this;
+            }
+            return resNode;
+        };
+        PackedRect.prototype.splitNode = function (contentSize) {
+            // If there's no contentSize but an initialSize it means this node were previously allocated, but freed, we need to create a _leftNode as subNode and use to allocate the space we need (and this node will have a right/bottom subNode for the space left as this._initialSize may be greater than contentSize)
+            if (!this._contentSize && this._initialSize) {
+                this._leftNode = new PackedRect(this._root, this, new BABYLON.Vector2(this._pos.x, this._pos.y), new BABYLON.Size(this._initialSize.width, this._initialSize.height));
+                return this._leftNode.splitNode(contentSize);
+            }
+            else {
+                this._contentSize = contentSize.clone();
+                this._initialSize = contentSize.clone();
+                if (contentSize.width !== this._size.width) {
+                    this._rightNode = new PackedRect(this._root, this, new BABYLON.Vector2(this._pos.x + contentSize.width, this._pos.y), new BABYLON.Size(this._size.width - contentSize.width, contentSize.height));
+                }
+                if (contentSize.height !== this._size.height) {
+                    this._bottomNode = new PackedRect(this._root, this, new BABYLON.Vector2(this._pos.x, this._pos.y + contentSize.height), new BABYLON.Size(this._size.width, this._size.height - contentSize.height));
+                }
+                return this;
+            }
+        };
+        PackedRect.prototype.attemptDefrag = function () {
+            if (!this.isUsed && this.isRecursiveFree) {
+                this.clearNode();
+                if (this._parent) {
+                    this._parent.attemptDefrag();
+                }
+            }
+        };
+        PackedRect.prototype.clearNode = function () {
+            this._initialSize = null;
+            this._rightNode = null;
+            this._bottomNode = null;
+        };
+        Object.defineProperty(PackedRect.prototype, "isRecursiveFree", {
+            get: function () {
+                return !this.contentSize && (!this._leftNode || this._leftNode.isRecursiveFree) && (!this._rightNode || this._rightNode.isRecursiveFree) && (!this._bottomNode || this._bottomNode.isRecursiveFree);
+            },
+            enumerable: true,
+            configurable: true
+        });
+        PackedRect.prototype.evalFreeSize = function (size) {
+            var levelSize = 0;
+            if (!this.isUsed) {
+                if (this._initialSize) {
+                    levelSize = this._initialSize.surface;
+                }
+                else {
+                    levelSize = this._size.surface;
+                }
+            }
+            if (this._rightNode) {
+                levelSize += this._rightNode.evalFreeSize(0);
+            }
+            if (this._bottomNode) {
+                levelSize += this._bottomNode.evalFreeSize(0);
+            }
+            return levelSize + size;
+        };
+        return PackedRect;
+    })();
+    BABYLON.PackedRect = PackedRect;
+})(BABYLON || (BABYLON = {}));

+ 0 - 100
src/Tools/babylon.smartCollection.js

@@ -1,100 +0,0 @@
-var BABYLON;
-(function (BABYLON) {
-    var SmartCollection = (function () {
-        function SmartCollection(capacity) {
-            if (capacity === void 0) { capacity = 10; }
-            this.count = 0;
-            this._initialCapacity = capacity;
-            this.items = {};
-            this._keys = new Array(this._initialCapacity);
-        }
-        SmartCollection.prototype.add = function (key, item) {
-            if (this.items[key] != undefined) {
-                return -1;
-            }
-            this.items[key] = item;
-            //literal keys are always strings, but we keep source type of key in _keys array
-            this._keys[this.count++] = key;
-            if (this.count > this._keys.length) {
-                this._keys.length *= 2;
-            }
-            return this.count;
-        };
-        SmartCollection.prototype.remove = function (key) {
-            if (this.items[key] == undefined) {
-                return -1;
-            }
-            return this.removeItemOfIndex(this.indexOf(key));
-        };
-        SmartCollection.prototype.removeItemOfIndex = function (index) {
-            if (index < this.count && index > -1) {
-                delete this.items[this._keys[index]];
-                //here, shifting by hand is better optimised than .splice
-                while (index < this.count) {
-                    this._keys[index] = this._keys[index + 1];
-                    index++;
-                }
-            }
-            else {
-                return -1;
-            }
-            return --this.count;
-        };
-        SmartCollection.prototype.indexOf = function (key) {
-            for (var i = 0; i !== this.count; i++) {
-                if (this._keys[i] === key) {
-                    return i;
-                }
-            }
-            return -1;
-        };
-        SmartCollection.prototype.item = function (key) {
-            return this.items[key];
-        };
-        SmartCollection.prototype.getAllKeys = function () {
-            if (this.count > 0) {
-                var keys = new Array(this.count);
-                for (var i = 0; i < this.count; i++) {
-                    keys[i] = this._keys[i];
-                }
-                return keys;
-            }
-            else {
-                return undefined;
-            }
-        };
-        SmartCollection.prototype.getKeyByIndex = function (index) {
-            if (index < this.count && index > -1) {
-                return this._keys[index];
-            }
-            else {
-                return undefined;
-            }
-        };
-        SmartCollection.prototype.getItemByIndex = function (index) {
-            if (index < this.count && index > -1) {
-                return this.items[this._keys[index]];
-            }
-            else {
-                return undefined;
-            }
-        };
-        SmartCollection.prototype.empty = function () {
-            if (this.count > 0) {
-                this.count = 0;
-                this.items = {};
-                this._keys = new Array(this._initialCapacity);
-            }
-        };
-        SmartCollection.prototype.forEach = function (block) {
-            var key;
-            for (key in this.items) {
-                if (this.items.hasOwnProperty(key)) {
-                    block(this.items[key]);
-                }
-            }
-        };
-        return SmartCollection;
-    })();
-    BABYLON.SmartCollection = SmartCollection;
-})(BABYLON || (BABYLON = {}));

文件差异内容过多而无法显示
+ 900 - 901
src/Tools/babylon.tools.js