123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208 |
- 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 = {}));
|