Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 | 2422x 2422x 2422x 2422x 671x 671x 671x 671x 1x 649x 649x 649x 649x 649x 163x 486x 486x 1x 2984x 38x 2946x 2186x 404x 1782x 1782x 1782x 1782x 1782x 1782x 393x 1389x 486x 903x 903x 450x 450x 450x 428x 450x 453x 453x 453x 420x 453x 760x | import BoundingRectangle from "./BoundingRectangle.js";
import Check from "./Check.js";
import defined from "./defined.js";
/**
* @typedef {object} TexturePacker.PackableObject
* Any object, such as an <code>Image</code> with the following properties:
* @private
* @property {number} width The width of the image, or other object, usually in pixels
* @property {number} height The height of the image, or other object, usually in pixels
*/
/**
* A texture atlas is recursively broken down into regions of space called nodes.
* Nodes contain either an image reference or child nodes.
* @private
* @constructor
* @param {object} options An options object with the following properties:
* @param {number} options.x The x-offset of the texture node
* @param {number} options.y The y-offset of the texture node
* @param {number} options.width The width of the texture node
* @param {number} options.height The width of the texture node
*/
function TextureNode({ x, y, width, height }) {
/**
* @type {BoundingRectangle}
*/
this.rectangle = new BoundingRectangle(x, y, width, height);
/**
* @type {TextureNode|undefined}
*/
this.childNode1 = undefined;
/**
* @type {TextureNode|undefined}
*/
this.childNode2 = undefined;
/**
* Identifier referencing an image or packed data
* @type {number|undefined}
*/
this.index = undefined;
}
/**
* Typically used with {@link TextureAtlas} to calculate efficient regions of the larger areas to store images or other data. Typically, all units are specified in pixels.
* @alias TexturePacker
* @constructor
* @private
* @param {options} options Object with the following properties:
* @param {number} options.width Width of the atlas, in pixels
* @param {number} options.height Height of atlas, in pixels
* @param {number} options.borderPadding Amount of border padding, in pixels
*/
function TexturePacker({ width, height, borderPadding }) {
this._width = width;
this._height = height;
this._borderPadding = borderPadding;
this._root = new TextureNode({
x: borderPadding,
y: borderPadding,
width: width - 2 * borderPadding,
height: height - 2 * borderPadding,
});
}
/**
* Inserts the given object into the next available region based on it's dimensions. Where convenient, it's most efficient to pack items largest to smallest.
* @private
* @param {number} index An identifier referencing the image or other stored data
* @param {TexturePacker.PackableObject} packableObject An object, such as an <code>Image</code>, with <code>width</code> and <code>height</code> properties in pixels.
* @returns {TextureNode|undefined} The created region, or <code>undefined</code> if there is no region large enough to accommodate the object's dimensions.
*/
TexturePacker.prototype.pack = function (index, { width, height }) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.number.greaterThanOrEquals("index", index, 0);
Check.typeOf.number.greaterThanOrEquals("image.width", width, 1);
Check.typeOf.number.greaterThanOrEquals("image.height", height, 1);
//>>includeEnd('debug');
const node = this._findNode(this._root, { width, height });
if (!defined(node)) {
return;
}
node.index = index;
return node;
};
// A recursive function that finds the best place to insert
// a new image based on existing image 'nodes'.
// Inspired by: http://blackpawn.com/texts/lightmaps/default.html
TexturePacker.prototype._findNode = function (node, { width, height }) {
if (!defined(node)) {
return undefined;
}
// Leaf node
if (!defined(node.childNode1) && !defined(node.childNode2)) {
if (defined(node.index)) {
// Node already contains an image: Skip it.
return undefined;
}
const { rectangle } = node;
const nodeWidth = rectangle.width;
const nodeHeight = rectangle.height;
const widthDifference = nodeWidth - width;
const heightDifference = nodeHeight - height;
// Node is smaller than the image.
if (widthDifference < 0 || heightDifference < 0) {
return undefined;
}
// If the node is the same size as the image, return the node
if (widthDifference === 0 && heightDifference === 0) {
return node;
}
const borderPadding = this._borderPadding;
// Vertical split (childNode1 = left half, childNode2 = right half).
if (widthDifference > heightDifference) {
node.childNode1 = new TextureNode({
x: rectangle.x,
y: rectangle.y,
width,
height: nodeHeight,
});
// Apply padding only along the vertical "cut".
const widthDifferencePadded = widthDifference - borderPadding;
if (widthDifferencePadded > 0) {
node.childNode2 = new TextureNode({
x: rectangle.x + width + borderPadding,
y: rectangle.y,
width: widthDifferencePadded,
height: nodeHeight,
});
}
return this._findNode(node.childNode1, { width, height });
}
// Horizontal split (childNode1 = bottom half, childNode2 = top half).
node.childNode1 = new TextureNode({
x: rectangle.x,
y: rectangle.y,
width: nodeWidth,
height,
});
// Apply padding only along the horizontal "cut".
const heightDifferencePadded = heightDifference - borderPadding;
if (heightDifferencePadded > 0) {
node.childNode2 = new TextureNode({
x: rectangle.x,
y: rectangle.y + height + borderPadding,
width: nodeWidth,
height: heightDifferencePadded,
});
}
return this._findNode(node.childNode1, { width, height });
}
// If not a leaf node
return (
this._findNode(node.childNode1, { width, height }) ||
this._findNode(node.childNode2, { width, height })
);
};
export default TexturePacker;
|