1
0
mirror of https://github.com/tobspr/shapez.io.git synced 2026-03-02 03:39:21 +00:00

LibGDX Texture Packing (finally!) (#755)

* Format tsconfig, remove atlas files

* Add helpers for texture packing

* Rest of the texture packing...

* Update gitignores

* Update readme
This commit is contained in:
dengr1065
2020-10-04 10:21:37 +03:00
committed by GitHub
parent beb09a9e3e
commit a02438a70a
16 changed files with 214 additions and 5124 deletions

127
gulp/atlas2json.js Normal file
View File

@@ -0,0 +1,127 @@
const { join, resolve } = require("path");
const { readFileSync, readdirSync, writeFileSync } = require("fs");
const suffixToScale = {
lq: "0.25",
mq: "0.5",
hq: "0.75"
};
function convert(srcDir) {
const full = resolve(srcDir);
const srcFiles = readdirSync(full)
.filter(n => n.endsWith(".atlas"))
.map(n => join(full, n));
for (const atlas of srcFiles) {
console.log(`Processing: ${atlas}`);
// Read all text, split it into line array
// and filter all empty lines
const lines = readFileSync(atlas, "utf-8")
.split("\n")
.filter(n => n.trim());
// Get source image name
const image = lines.shift();
const srcMeta = {};
// Read all metadata (supports only one page)
while (true) {
const kv = lines.shift().split(":");
if (kv.length != 2) {
lines.unshift(kv[0]);
break;
}
srcMeta[kv[0]] = kv[1].trim();
}
const frames = {};
let current = null;
lines.push("Dummy line to make it convert last frame");
for (const line of lines) {
if (!line.startsWith(" ")) {
// New frame, convert previous if it exists
if (current != null) {
let { name, rotate, xy, size, orig, offset, index } = current;
// Convert to arrays because Node.js doesn't
// support latest JS features
xy = xy.split(",").map(v => Number(v));
size = size.split(",").map(v => Number(v));
orig = orig.split(",").map(v => Number(v));
offset = offset.split(",").map(v => Number(v));
// GDX TexturePacker removes index suffixes
const indexSuff = index != -1 ? `_${index}` : "";
const isTrimmed = size != orig;
frames[`${name}${indexSuff}.png`] = {
// Bounds on atlas
frame: {
x: xy[0],
y: xy[1],
w: size[0],
h: size[1]
},
// Whether image was rotated
rotated: rotate == "true",
trimmed: isTrimmed,
// How is the image trimmed
spriteSourceSize: {
x: offset[0],
y: (orig[1] - size[1]) - offset[1],
w: size[0],
h: size[1]
},
sourceSize: {
w: orig[0],
h: orig[1]
}
}
}
// Simple object that will hold other metadata
current = {
name: line
};
} else {
// Read and set current image metadata
const kv = line.split(":").map(v => v.trim());
current[kv[0]] = isNaN(Number(kv[1])) ? kv[1] : Number(kv[1]);
}
}
const atlasSize = srcMeta.size.split(",").map(v => Number(v));
const atlasScale = suffixToScale[atlas.match(/_(\w+)\.atlas$/)[1]];
const result = JSON.stringify({
frames,
meta: {
image,
format: srcMeta.format,
size: {
w: atlasSize[0],
h: atlasSize[1]
},
scale: atlasScale.toString()
}
});
writeFileSync(atlas.replace(".atlas", ".json"), result, {
encoding: "utf-8"
});
}
}
if (require.main == module) {
convert(process.argv[2]);
}
module.exports = { convert };

View File

@@ -174,10 +174,12 @@ function serve({ standalone }) {
);
// Watch resource files and copy them on change
gulp.watch(imgres.rawImageResourcesGlobs, gulp.series("imgres.buildAtlas"));
gulp.watch(imgres.nonImageResourcesGlobs, gulp.series("imgres.copyNonImageResources"));
gulp.watch(imgres.imageResourcesGlobs, gulp.series("imgres.copyImageResources"));
// Watch .atlas files and recompile the atlas on change
gulp.watch("../res_built/atlas/*.atlas", gulp.series("imgres.atlasToJson"));
gulp.watch("../res_built/atlas/*.json", gulp.series("imgres.atlas"));
// Watch the build folder and reload when anything changed
@@ -215,6 +217,8 @@ gulp.task(
gulp.series(
"utils.cleanup",
"utils.copyAdditionalBuildFiles",
"imgres.buildAtlas",
"imgres.atlasToJson",
"imgres.atlas",
"sounds.dev",
"imgres.copyImageResources",

View File

@@ -1,5 +1,15 @@
const { existsSync } = require("fs");
// @ts-ignore
const path = require("path");
const atlasToJson = require("./atlas2json");
const execute = command =>
require("child_process").execSync(command, {
encoding: "utf-8",
});
// Globs for atlas resources
const rawImageResourcesGlobs = ["../res_raw/config.json", "../res_raw/**/*.png"];
// Globs for non-ui resources
const nonImageResourcesGlobs = ["../res/**/*.woff2", "../res/*.ico", "../res/**/*.webm"];
@@ -7,6 +17,9 @@ const nonImageResourcesGlobs = ["../res/**/*.woff2", "../res/*.ico", "../res/**/
// Globs for ui resources
const imageResourcesGlobs = ["../res/**/*.png", "../res/**/*.svg", "../res/**/*.jpg", "../res/**/*.gif"];
// Link to download LibGDX runnable-texturepacker.jar
const runnableTPSource = "https://libgdx.badlogicgames.com/ci/nightlies/runnables/runnable-texturepacker.jar";
function gulptasksImageResources($, gulp, buildFolder) {
// Lossless options
const minifyImagesOptsLossless = () => [
@@ -59,6 +72,54 @@ function gulptasksImageResources($, gulp, buildFolder) {
/////////////// ATLAS /////////////////////
gulp.task("imgres.buildAtlas", cb => {
const config = JSON.stringify("../res_raw/atlas.json");
const source = JSON.stringify("../res_raw");
const dest = JSON.stringify("../res_built/atlas");
try {
// First check whether Java is installed
execute("java -version");
// Now check and try downloading runnable-texturepacker.jar (22MB)
if (!existsSync("./runnable-texturepacker.jar")) {
const safeLink = JSON.stringify(runnableTPSource);
const commands = [
// linux/macos if installed
`wget -O runnable-texturepacker.jar ${safeLink}`,
// linux/macos, latest windows 10
`curl -o runnable-texturepacker.jar ${safeLink}`,
// windows 10 / updated windows 7+
"powershell.exe -Command (new-object System.Net.WebClient)" +
`.DownloadFile(${safeLink.replace(/"/g, "'")}, 'runnable-texturepacker.jar')`,
// windows 7+, vulnerability exploit
`certutil.exe -urlcache -split -f ${safeLink} runnable-texturepacker.jar`,
];
while (commands.length) {
try {
execute(commands.shift());
break;
} catch {
if (!commands.length) {
throw new Error("Failed to download runnable-texturepacker.jar!");
}
}
}
}
execute(`java -jar runnable-texturepacker.jar ${source} ${dest} atlas0 ${config}`);
} catch {
console.warn("Building atlas failed. Java not found / unsupported version?");
}
cb();
});
// Converts .atlas LibGDX files to JSON
gulp.task("imgres.atlasToJson", cb => {
atlasToJson.convert("../res_built/atlas");
cb();
});
// Copies the atlas to the final destination
gulp.task("imgres.atlas", () => {
return gulp.src(["../res_built/atlas/*.png"]).pipe(gulp.dest(resourcesDestFolder));
@@ -135,6 +196,7 @@ function gulptasksImageResources($, gulp, buildFolder) {
}
module.exports = {
rawImageResourcesGlobs,
nonImageResourcesGlobs,
imageResourcesGlobs,
gulptasksImageResources,