Skip to content

Commit

Permalink
small code refactoring to increase readability and "isolate" sprite s…
Browse files Browse the repository at this point in the history
…heet and/or packed texture parsing
  • Loading branch information
obiot committed Feb 14, 2024
1 parent 766a7ca commit 1d0fd5e
Show file tree
Hide file tree
Showing 3 changed files with 129 additions and 119 deletions.
125 changes: 6 additions & 119 deletions src/video/texture/atlas.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ import Sprite from "./../../renderable/sprite.js";
import { renderer } from "./../video.js";
import pool from "./../../system/pooling.js";
import { getImage } from "./../../loader/loader.js";
import { ETA } from "./../../math/math.js";
import { parseTexturePacker } from "./parser/texturepacker.js";
import { parseSpriteSheet } from "./parser/spritesheet.js";

/**
* create a simple 1 frame texture atlas based on the given parameters
Expand Down Expand Up @@ -107,9 +108,7 @@ export class TextureAtlas {
this.sources.set(atlas.meta.image || "default", typeof src === "string" ? getImage(src) : src);
}
this.repeat = "no-repeat";
}
// ShoeBox
else if (atlas.meta.app.includes("ShoeBox")) {
} else if (atlas.meta.app.includes("ShoeBox")) {
if (!atlas.meta.exporter || !atlas.meta.exporter.includes("melonJS")) {
throw new Error(
"ShoeBox requires the JSON exporter : " +
Expand All @@ -126,8 +125,9 @@ export class TextureAtlas {
this.repeat = atlas.meta.repeat || "no-repeat";
this.sources.set("default", typeof src === "string" ? getImage(src) : src);
}

// initialize the atlas
this.atlases.set(atlas.meta.image || "default", this.parse(atlas));
this.atlases.set(atlas.meta.image || "default", parseTexturePacker(atlas, this));

} else {
// a regular spritesheet
Expand All @@ -141,7 +141,7 @@ export class TextureAtlas {
atlas.image = typeof src === "string" ? getImage(src) : src;
}
// initialize the atlas
this.atlases.set("default", this.parseFromSpriteSheet(atlas));
this.atlases.set("default", parseSpriteSheet(atlas, this));
this.sources.set("default", atlas.image);

}
Expand All @@ -162,119 +162,6 @@ export class TextureAtlas {
}
}

/**
* build an atlas from the given data
* @ignore
*/
parse(data) {
let atlas = {};

data.frames.forEach((frame) => {
// fix wrongly formatted JSON (e.g. last dummy object in ShoeBox)
if (frame.hasOwnProperty("filename")) {
// Source coordinates
let s = frame.frame;
let trimmed = !!frame.trimmed;

let trim;

if (trimmed) {
trim = {
x : frame.spriteSourceSize.x,
y : frame.spriteSourceSize.y,
w : frame.spriteSourceSize.w,
h : frame.spriteSourceSize.h
};
}

let originX, originY;
// Pixel-based offset origin from the top-left of the source frame
let hasTextureAnchorPoint = (frame.sourceSize && frame.pivot);
if (hasTextureAnchorPoint) {
originX = (frame.sourceSize.w * frame.pivot.x) - ((trimmed) ? trim.x : 0);
originY = (frame.sourceSize.h * frame.pivot.y) - ((trimmed) ? trim.y : 0);
}

atlas[frame.filename] = {
name : frame.filename, // frame name
texture : data.meta.image || "default", // the source texture
offset : new Vector2d(s.x, s.y),
anchorPoint : (hasTextureAnchorPoint) ? new Vector2d(originX / s.w, originY / s.h) : null,
trimmed : trimmed,
trim : trim,
width : s.w,
height : s.h,
angle : (frame.rotated === true) ? -ETA : 0
};
this.addUVs(atlas, frame.filename, data.meta.size.w, data.meta.size.h);
}
});
return atlas;
}

/**
* build an atlas from the given spritesheet
* @ignore
*/
parseFromSpriteSheet(data) {
let atlas = {};
let image = data.image;
let spacing = data.spacing || 0;
let margin = data.margin || 0;

let width = image.width;
let height = image.height;

// calculate the sprite count (line, col)
let spritecount = pool.pull("Vector2d",
~~((width - margin + spacing) / (data.framewidth + spacing)),
~~((height - margin + spacing) / (data.frameheight + spacing))
);

// verifying the texture size
if ((width % (data.framewidth + spacing)) !== 0 ||
(height % (data.frameheight + spacing)) !== 0) {
let computed_width = spritecount.x * (data.framewidth + spacing);
let computed_height = spritecount.y * (data.frameheight + spacing);
if (computed_width - width !== spacing && computed_height - height !== spacing) {
// "truncate size" if delta is different from the spacing size
width = computed_width;
height = computed_height;
// warning message
console.warn(
"Spritesheet Texture for image: " + image.src +
" is not divisible by " + (data.framewidth + spacing) +
"x" + (data.frameheight + spacing) +
", truncating effective size to " + width + "x" + height
);
}
}

// build the local atlas
for (let frame = 0, count = spritecount.x * spritecount.y; frame < count; frame++) {
let name = "" + frame;
atlas[name] = {
name : name,
texture : "default", // the source texture
offset : new Vector2d(
margin + (spacing + data.framewidth) * (frame % spritecount.x),
margin + (spacing + data.frameheight) * ~~(frame / spritecount.x)
),
anchorPoint : (data.anchorPoint || null),
trimmed : false,
trim : undefined,
width : data.framewidth,
height : data.frameheight,
angle : 0
};
this.addUVs(atlas, name, width, height);
}

pool.push(spritecount);

return atlas;
}

/**
* return the default or specified atlas dictionnary
* @param {string} [name] - atlas name in case of multipack textures
Expand Down
68 changes: 68 additions & 0 deletions src/video/texture/parser/spritesheet.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import pool from "./../../../system/pooling.js";
import Vector2d from "./../../../math/vector2.js";

/**
* parse the given data and return a corresponding atlas
* @param {Object} data - atlas data information. See {@link loader.getJSON}
* @param {TextureAtlas} textureAtlas - the texture atlas class calling the parser
* @returns {Object} the corresponding Atlas
* @ignore
*/
export function parseSpriteSheet(data, textureAtlas) {
let atlas = {};
let image = data.image;
let spacing = data.spacing || 0;
let margin = data.margin || 0;

let width = image.width;
let height = image.height;

// calculate the sprite count (line, col)
let spritecount = pool.pull("Vector2d",
~~((width - margin + spacing) / (data.framewidth + spacing)),
~~((height - margin + spacing) / (data.frameheight + spacing))
);

// verifying the texture size
if ((width % (data.framewidth + spacing)) !== 0 ||
(height % (data.frameheight + spacing)) !== 0) {
let computed_width = spritecount.x * (data.framewidth + spacing);
let computed_height = spritecount.y * (data.frameheight + spacing);
if (computed_width - width !== spacing && computed_height - height !== spacing) {
// "truncate size" if delta is different from the spacing size
width = computed_width;
height = computed_height;
// warning message
console.warn(
"Spritesheet Texture for image: " + image.src +
" is not divisible by " + (data.framewidth + spacing) +
"x" + (data.frameheight + spacing) +
", truncating effective size to " + width + "x" + height
);
}
}

// build the local atlas
for (let frame = 0, count = spritecount.x * spritecount.y; frame < count; frame++) {
let name = "" + frame;
atlas[name] = {
name : name,
texture : "default", // the source texture
offset : new Vector2d(
margin + (spacing + data.framewidth) * (frame % spritecount.x),
margin + (spacing + data.frameheight) * ~~(frame / spritecount.x)
),
anchorPoint : (data.anchorPoint || null),
trimmed : false,
trim : undefined,
width : data.framewidth,
height : data.frameheight,
angle : 0
};
textureAtlas.addUVs(atlas, name, width, height);
}

pool.push(spritecount);

return atlas;
}
55 changes: 55 additions & 0 deletions src/video/texture/parser/texturepacker.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import { ETA } from "./../../../math/math.js";
import Vector2d from "./../../../math/vector2.js";

/**
* parse the given data and return a corresponding atlas
* @param {Object} data - atlas data information. See {@link loader.getJSON}
* @param {TextureAtlas} textureAtlas - the texture atlas class calling the parser
* @returns {Object} the corresponding Atlas
* @ignore
*/
export function parseTexturePacker(data, textureAtlas) {
let atlas = {};

data.frames.forEach((frame) => {
// fix wrongly formatted JSON (e.g. last dummy object in ShoeBox)
if (frame.hasOwnProperty("filename")) {
// Source coordinates
let s = frame.frame;
let trimmed = !!frame.trimmed;

let trim;

if (trimmed) {
trim = {
x : frame.spriteSourceSize.x,
y : frame.spriteSourceSize.y,
w : frame.spriteSourceSize.w,
h : frame.spriteSourceSize.h
};
}

let originX, originY;
// Pixel-based offset origin from the top-left of the source frame
let hasTextureAnchorPoint = (frame.sourceSize && frame.pivot);
if (hasTextureAnchorPoint) {
originX = (frame.sourceSize.w * frame.pivot.x) - ((trimmed) ? trim.x : 0);
originY = (frame.sourceSize.h * frame.pivot.y) - ((trimmed) ? trim.y : 0);
}

atlas[frame.filename] = {
name : frame.filename, // frame name
texture : data.meta.image || "default", // the source texture
offset : new Vector2d(s.x, s.y),
anchorPoint : (hasTextureAnchorPoint) ? new Vector2d(originX / s.w, originY / s.h) : null,
trimmed : trimmed,
trim : trim,
width : s.w,
height : s.h,
angle : (frame.rotated === true) ? -ETA : 0
};
textureAtlas.addUVs(atlas, frame.filename, data.meta.size.w, data.meta.size.h);
}
});
return atlas;
}

0 comments on commit 1d0fd5e

Please sign in to comment.