File:TextureAtlas.js
/**
* @module EaselJS Display
* @namespace springroll.easeljs
* @requires Core
*/
(function(undefined)
{
/**
* Handles a spritesheet. File extensions and folder paths are dropped from frame names upon
* loading.
*
* @class TextureAtlas
* @constructor
* @param {Image|HTMLCanvasElement|Array} image The image that all textures pull from. This can
* also be an array of images, if the TextureAtlas
* should be built from several spritesheets.
* @param {Object|Array} spritesheetData The JSON object describing the frames in the atlas. This
* is expected to fit the JSON Hash format as exported from
* TexturePacker. This can also be an array of data
* objects, if the TextureAtlas should be built from
* several spritesheets.
*/
var TextureAtlas = function(image, spritesheetData)
{
/**
* The an array of image elements (Image|HTMLCanvasElement) that frames in texture atlas use.
* @property {Array} _image
* @private
*/
if (Array.isArray(image))
{
this._images = image;
}
else
{
this._images = [image];
spritesheetData = [spritesheetData];
}
/**
* The dictionary of Textures that this atlas consists of.
* @property {Object} frames
*/
this.frames = {};
/**
* The scale of the texture atlas, if available in spritesheet metadata. Defaults to 1,
* otherwise
* @property {Number} scale
*/
if (spritesheetData[0].meta && parseFloat(spritesheetData[0].meta.scale))
{
this.scale = parseFloat(spritesheetData[0].meta.scale);
}
else
this.scale = 1;
for (var i = 0; i < this._images.length; ++i)
{
image = this._images[i];
//TexturePacker outputs frames with (not) swapped width & height when rotated, so we need to
//swap them ourselves
var swapFrameSize = spritesheetData[i].meta &&
spritesheetData[i].meta.app == "http://www.codeandweb.com/texturepacker";
var dataFrames = spritesheetData[i].frames;
for (var name in dataFrames)
{
var data = dataFrames[name];
var index = name.lastIndexOf(".");
if (index > 0)
name = name.substring(0, index); //strip off any ".png" or ".jpg" at the end
index = name.lastIndexOf("/");
if (index >= 0)
name = name.substring(index + 1); //strip off any folder structure included in the name
this.frames[name] = new Texture(image, data, swapFrameSize);
}
}
};
// Extend Object
var p = extend(TextureAtlas);
/**
* Gets a frame by name.
* @method getFrame
* @param {String} name The frame name to get.
* @return {createjs.TextureAtlas.Texture} The texture by that name, or null if it doesn't exist.
*/
p.getFrame = function(name)
{
return this.frames[name] || null;
};
/**
* Get an array of Textures that match a specific name. If a frame in a sequence is not in the
* atlas, the previous frame in the sequence is used in place of it.
* @method getFrames
* @param {String} name The base name of all frames to look for, like "anim_#" to search for an
* animation exported as anim_0001.png (the ".png" is dropped when the
* TextureAtlas is loaded).
* @param {int} numberMin The number to start on while looking for frames. Flash PNG sequences
* generally start at 1.
* @param {int} numberMax The number to go until while looking for frames. If your animation runs
* from frame 0001 to frame 0014, numberMax would be 14.
* @param {int} [maxDigits=4] Maximum number of digits, like 4 for an animation exported as
* anim_0001.png
* @param {Array} [outArray] If already using an array, this can fill it instead of creating a
* new one.
* @return {Array} The collection of createjs.TextureAtlas.Textures.
*/
p.getFrames = function(name, numberMin, numberMax, maxDigits, outArray)
{
if (maxDigits === undefined)
maxDigits = 4;
if (maxDigits < 0)
maxDigits = 0;
if (!outArray)
outArray = [];
//set up strings to add the correct number of zeros ahead of time to avoid creating even more strings.
var zeros = []; //preceding zeroes array
var compares = []; //powers of 10 array for determining how many preceding zeroes to use
var i, c;
for (i = 1; i < maxDigits; ++i)
{
var s = "";
c = 1;
for (var j = 0; j < i; ++j)
{
s += "0";
c *= 10;
}
zeros.unshift(s);
compares.push(c);
}
var compareLength = compares.length; //the length of the compar
var prevTex; //the previous Texture, so we can place the same object in multiple times to control animation rate
var len;
for (i = numberMin, len = numberMax; i <= len; ++i)
{
var num = null;
//calculate the number of preceding zeroes needed, then create the full number string.
for (c = 0; c < compareLength; ++c)
{
if (i < compares[c])
{
num = zeros[c] + i;
break;
}
}
if (!num)
num = i.toString();
//If the texture doesn't exist, use the previous texture - this should allow us to use fewer textures
//that are in fact the same, if those textures were removed before making the spritesheet
var texName = name.replace("#", num);
var tex = this.frames[texName];
if (tex)
prevTex = tex;
if (prevTex)
outArray.push(prevTex);
}
return outArray;
};
/**
* Destroys the TextureAtlas by nulling the image and frame dictionary references.
* @method destroy
*/
p.destroy = function()
{
this.image = null;
this.frames = null;
};
namespace("createjs").TextureAtlas = TextureAtlas;
namespace("springroll.easeljs").TextureAtlas = TextureAtlas;
/**
* A Texture - a specific portion of an image that can then be drawn by a Bitmap.
* This class is hidden within TextureAtlas, and can't be manually created.
* @class Texture
*/
var Texture = function(image, data, swapRotatedSize)
{
/**
* The image element that this texture references.
* @property {Image|HTMLCanvasElement} image
*/
this.image = image;
/**
* If this texture has been rotated (90 degrees clockwise).
* @property {Boolean} rotated
*/
this.rotated = data.rotated;
var f = data.frame;
/**
* The frame rectangle within the image.
* @property {createjs.Rectangle} frame
*/
this.frame = new createjs.Rectangle(f.x, f.y, (data.rotated && swapRotatedSize) ? f.h : f.w, (data.rotated && swapRotatedSize) ? f.w : f.h);
/**
* If this texture has been trimmed.
* @property {Boolean} trimmed
*/
this.trimmed = data.trimmed;
/**
* The offset that the trimmed sprite should be placed at to restore it to the untrimmed position.
* @property {createjs.Point} offset
*/
this.offset = new createjs.Point(data.spriteSourceSize.x, data.spriteSourceSize.y);
/**
* The width of the untrimmed texture.
* @property {Number} width
*/
this.width = data.sourceSize.w;
/**
* The height of the untrimmed texture.
* @property {Number} height
*/
this.height = data.sourceSize.h;
};
}());