Compare commits
1 Commits
8bc4797145
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ddafcd6486 |
@@ -24,6 +24,8 @@ function parseArgs(argv) {
|
|||||||
case '--schema': opts.schema = next; i++; break;
|
case '--schema': opts.schema = next; i++; break;
|
||||||
case '--mode': opts.mode = next; i++; break;
|
case '--mode': opts.mode = next; i++; break;
|
||||||
case '--strip-prefix': opts.stripPrefix = next; i++; break;
|
case '--strip-prefix': opts.stripPrefix = next; i++; break;
|
||||||
|
case '--pixels-per-meter':
|
||||||
|
opts.pixelsPerMeter = parseInt(next, 10); i++; break;
|
||||||
case '--verbose': opts.verbose = true; break;
|
case '--verbose': opts.verbose = true; break;
|
||||||
default:
|
default:
|
||||||
console.error(`unknown arg: ${a}`);
|
console.error(`unknown arg: ${a}`);
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "sporel-tool-atlas-baker",
|
"name": "sporel-tool-atlas-baker",
|
||||||
"version": "0.3.0",
|
"version": "0.4.0",
|
||||||
"description": "Bake paired diffuse + height PNG atlases for the Sporel map-lib v0.3.0+ format. v0.2: edge-replicated padding (Rev 4 §13.3), --schema blob-14 E1 slot validation, collision.json sidecar E2 validation + pass-through, alpha-analysis opaque flag. Accepts PNG/WebP/JPG via jimp; v0.3 adds --mode sprite for diffuse-only atlases of irregularly-sized sprites with alias→UV-table sidecar",
|
"description": "Bake paired diffuse + height PNG atlases for the Sporel map-lib v0.3.0+ format. v0.2: edge-replicated padding (Rev 4 §13.3), --schema blob-14 E1 slot validation, collision.json sidecar E2 validation + pass-through, alpha-analysis opaque flag. Accepts PNG/WebP/JPG via jimp; v0.3 adds --mode sprite for diffuse-only atlases of irregularly-sized sprites with alias→UV-table sidecar; v0.4 adds --pixels-per-meter <N> to sprite-mode, embedded as atlas_meta.pixels_per_meter in sprites.uv.json (consumed by render-side scale-resolution per project canonical px/m).",
|
||||||
"bin": {
|
"bin": {
|
||||||
"sporel-atlas-baker": "bin/atlas-baker.js"
|
"sporel-atlas-baker": "bin/atlas-baker.js"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ async function bakeSprite(opts) {
|
|||||||
maxSize = 4096,
|
maxSize = 4096,
|
||||||
padPx = 1,
|
padPx = 1,
|
||||||
lockPath,
|
lockPath,
|
||||||
|
pixelsPerMeter,
|
||||||
verbose,
|
verbose,
|
||||||
} = opts;
|
} = opts;
|
||||||
|
|
||||||
@@ -26,6 +27,10 @@ async function bakeSprite(opts) {
|
|||||||
if (padPx < 0 || !Number.isInteger(padPx)) {
|
if (padPx < 0 || !Number.isInteger(padPx)) {
|
||||||
throw new Error(`bake-sprite: --pad-px must be non-negative integer, got ${padPx}`);
|
throw new Error(`bake-sprite: --pad-px must be non-negative integer, got ${padPx}`);
|
||||||
}
|
}
|
||||||
|
if (pixelsPerMeter !== undefined &&
|
||||||
|
(!Number.isFinite(pixelsPerMeter) || pixelsPerMeter <= 0)) {
|
||||||
|
throw new Error(`bake-sprite: --pixels-per-meter must be positive number, got ${pixelsPerMeter}`);
|
||||||
|
}
|
||||||
|
|
||||||
const scan = scanSpriteSourceDir(inDir, { stripPrefix });
|
const scan = scanSpriteSourceDir(inDir, { stripPrefix });
|
||||||
if (scan.errors.length > 0) {
|
if (scan.errors.length > 0) {
|
||||||
@@ -93,6 +98,7 @@ async function bakeSprite(opts) {
|
|||||||
boundsW: pack.boundsW,
|
boundsW: pack.boundsW,
|
||||||
boundsH: pack.boundsH,
|
boundsH: pack.boundsH,
|
||||||
lock,
|
lock,
|
||||||
|
pixelsPerMeter,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (verbose) {
|
if (verbose) {
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ async function composeSpriteAtlas(boundsW, boundsH, placed) {
|
|||||||
return atlas;
|
return atlas;
|
||||||
}
|
}
|
||||||
|
|
||||||
function buildUvJson(atlasId, boundsW, boundsH, placed) {
|
function buildUvJson(atlasId, boundsW, boundsH, placed, pixelsPerMeter) {
|
||||||
const sprites = {};
|
const sprites = {};
|
||||||
for (const p of placed) {
|
for (const p of placed) {
|
||||||
sprites[p.alias] = {
|
sprites[p.alias] = {
|
||||||
@@ -30,15 +30,22 @@ function buildUvJson(atlasId, boundsW, boundsH, placed) {
|
|||||||
source_file: p.sourceFile,
|
source_file: p.sourceFile,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
return JSON.stringify({
|
// Build payload with stable key order; only emit atlas_meta when at
|
||||||
|
// least one meta-field is set, so unannotated bakes stay byte-equal
|
||||||
|
// to the v0.3.0 output (no diff for unchanged callers).
|
||||||
|
const payload = {
|
||||||
atlas_id: atlasId,
|
atlas_id: atlasId,
|
||||||
atlas_size: [boundsW, boundsH],
|
atlas_size: [boundsW, boundsH],
|
||||||
sprites,
|
};
|
||||||
}, null, 2) + '\n';
|
if (pixelsPerMeter !== undefined && pixelsPerMeter !== null) {
|
||||||
|
payload.atlas_meta = { pixels_per_meter: pixelsPerMeter };
|
||||||
|
}
|
||||||
|
payload.sprites = sprites;
|
||||||
|
return JSON.stringify(payload, null, 2) + '\n';
|
||||||
}
|
}
|
||||||
|
|
||||||
async function writeSpriteOutputs(opts) {
|
async function writeSpriteOutputs(opts) {
|
||||||
const { atlasId, outDir, placed, boundsW, boundsH, lock } = opts;
|
const { atlasId, outDir, placed, boundsW, boundsH, lock, pixelsPerMeter } = opts;
|
||||||
const atlasDir = path.join(outDir, atlasId);
|
const atlasDir = path.join(outDir, atlasId);
|
||||||
fs.mkdirSync(atlasDir, { recursive: true });
|
fs.mkdirSync(atlasDir, { recursive: true });
|
||||||
|
|
||||||
@@ -47,7 +54,7 @@ async function writeSpriteOutputs(opts) {
|
|||||||
|
|
||||||
fs.writeFileSync(
|
fs.writeFileSync(
|
||||||
path.join(atlasDir, 'sprites.uv.json'),
|
path.join(atlasDir, 'sprites.uv.json'),
|
||||||
buildUvJson(atlasId, boundsW, boundsH, placed),
|
buildUvJson(atlasId, boundsW, boundsH, placed, pixelsPerMeter),
|
||||||
);
|
);
|
||||||
fs.writeFileSync(
|
fs.writeFileSync(
|
||||||
path.join(atlasDir, 'sprites.atlas.lock.json'),
|
path.join(atlasDir, 'sprites.atlas.lock.json'),
|
||||||
|
|||||||
Reference in New Issue
Block a user