Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: multi-pack spritesheets #35

Merged
merged 12 commits into from
Jun 25, 2024
10 changes: 6 additions & 4 deletions .eslintrc.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,17 @@ module.exports = {
ecmaVersion: 2020,
sourceType: "module",
},
plugins: ['import'],
rules: {
"spaced-comment": [1, "always", { markers: ["/"] }],
"@typescript-eslint/triple-slash-reference": [1, { path: "always" }],
"@typescript-eslint/consistent-type-imports": [
1,
{ disallowTypeAnnotations: false },
],
"@typescript-eslint/type-annotation-spacing": 1,
"@typescript-eslint/no-non-null-assertion": 0,
"@typescript-eslint/consistent-type-imports":
["error", { disallowTypeAnnotations: false }],
"import/consistent-type-specifier-style": ["error", "prefer-top-level"],
"import/no-duplicates": ["error"],
"camelcase": 0,
},
overrides: [
{
Expand Down
10 changes: 10 additions & 0 deletions src/core/pipes/PipeSystem.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { finalCopyPipe } from './finalCopyPipe.js';
import { mergePipeOptions } from './mergePipeOptions.js';
import { multiPipe } from './multiPipe.js';

Expand Down Expand Up @@ -72,6 +73,15 @@ export class PipeSystem

pipeIndex++;

// if the asset has the copy tag on it, then the only pipe that should be run is the final copy pipe
// this is to ensure that the asset is copied to the output directory without any other processing
if (asset.allMetaData.copy && pipe !== finalCopyPipe)
{
await this._transform(asset, pipeIndex);

return;
}

const options = mergePipeOptions(pipe, asset);

if (options !== false && pipe.transform && pipe.test?.(asset, options))
Expand Down
35 changes: 21 additions & 14 deletions src/manifest/pixiManifest.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import fs from 'fs-extra';
import {
type Asset,
type AssetPipe,
path,
type PipeSystem,
stripTags
import { path, stripTags } from '../core/index.js';

import type {
Asset,
AssetPipe,
PipeSystem, PluginOptions
} from '../core/index.js';

export interface PixiBundle
Expand All @@ -28,7 +28,7 @@ export interface PixiManifestEntry
};
}

export interface PixiManifestOptions
export interface PixiManifestOptions extends PluginOptions<'mIgnore' | 'manifest'>
{
output?: string;
createShortcuts?: boolean;
Expand All @@ -38,12 +38,16 @@ export interface PixiManifestOptions

export function pixiManifest(_options: PixiManifestOptions = {}): AssetPipe<PixiManifestOptions>
{
const defaultOptions = {
const defaultOptions: PixiManifestOptions = {
output: 'manifest.json',
createShortcuts: false,
trimExtensions: false,
includeMetaData: true,
..._options
..._options,
tags: {
manifest: 'm',
mIgnore: 'mIgnore'
}
};

return {
Expand Down Expand Up @@ -98,7 +102,7 @@ function collectAssets(
outputPath = '',
entryPath = '',
bundles: PixiBundle[],
bundle: PixiBundle,
bundle: PixiBundle
)
{
if (asset.skip) return;
Expand All @@ -107,7 +111,7 @@ function collectAssets(

let localBundle = bundle;

if (asset.metaData.m || asset.metaData.manifest)
if (asset.metaData[options.tags!.manifest!])
{
localBundle = {
name: stripTags(asset.filename),
Expand All @@ -118,14 +122,17 @@ function collectAssets(
}

const bundleAssets = localBundle.assets;

const finalAssets = asset.getFinalTransformedChildren();

if (asset.transformChildren.length > 0)
if (asset.transformChildren.length > 0 && !asset.inheritedMetaData[options.tags!.mIgnore!])
{
const nonIgnored = finalAssets.filter((finalAsset) => !finalAsset.inheritedMetaData[options.tags!.mIgnore!]);

if (nonIgnored.length === 0) return;

bundleAssets.push({
alias: getShortNames(stripTags(path.relative(entryPath, asset.path)), options),
src: finalAssets
src: nonIgnored
.map((finalAsset) => path.relative(outputPath, finalAsset.path))
.sort((a, b) => b.localeCompare(a)),
data: options.includeMetaData ? {
Expand Down
2 changes: 0 additions & 2 deletions src/pixi/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import { spineAtlasMipmap } from '../spine/spineAtlasMipmap.js';
import { texturePacker } from '../texture-packer/texturePacker.js';
import { texturePackerCacheBuster } from '../texture-packer/texturePackerCacheBuster.js';
import { texturePackerCompress } from '../texture-packer/texturePackerCompress.js';
import { texturePackerManifestMod } from '../texture-packer/texturePackerManifestMod.js';
import { webfont } from '../webfont/webfont.js';

import type { FfmpegOptions } from '../ffmpeg/ffmpeg.js';
Expand Down Expand Up @@ -109,7 +108,6 @@ export function pixiAssetPackPipes(config: PixiAssetPack)

pipes.push(
pixiManifest(manifestOptions),
texturePackerManifestMod(manifestOptions),
spineAtlasManifestMod(manifestOptions),
);

Expand Down
4 changes: 3 additions & 1 deletion src/spine/spineAtlasCacheBuster.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import fs from 'fs-extra';
import { type Asset, type AssetPipe, checkExt, findAssets } from '../core/index.js';
import { checkExt, findAssets } from '../core/index.js';
import { AtlasView } from './AtlasView.js';

import type { Asset, AssetPipe } from '../core/index.js';

/**
* This should be used after the cache buster plugin in the pipes.
* As it relies on the cache buster plugin to have already cache busted all files.
Expand Down
4 changes: 3 additions & 1 deletion src/spine/spineAtlasManifestMod.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import fs from 'fs-extra';
import { type Asset, type AssetPipe, findAssets, path } from '../core/index.js';
import { findAssets, path } from '../core/index.js';
import { AtlasView } from './AtlasView.js';

import type { Asset, AssetPipe } from '../core/index.js';

export interface SpineManifestOptions
{
output?: string;
Expand Down
1 change: 0 additions & 1 deletion src/texture-packer/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
export * from './texturePacker.js';
export * from './texturePackerCacheBuster.js';
export * from './texturePackerCompress.js';
export * from './texturePackerManifestMod.js';
56 changes: 28 additions & 28 deletions src/texture-packer/packer/createJsons.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,12 @@ export function createJsons(
width: number,
height: number,
options: {
textureName: string,
resolution: number,
textureFormat: 'png' | 'jpg',
nameStyle: 'short' | 'relative',
removeFileExtension: boolean
}
textureName: string;
resolution: number;
textureFormat: 'png' | 'jpg';
nameStyle: 'short' | 'relative';
removeFileExtension: boolean;
},
)
{
const bins = packer.bins;
Expand All @@ -32,7 +32,7 @@ export function createJsons(
const bin = bins[i];

const json: any = {
frames: {}
frames: {},
};

for (let j = 0; j < bin.rects.length; j++)
Expand All @@ -44,52 +44,52 @@ export function createJsons(
x: rect.x,
y: rect.y,
w: rect.width,
h: rect.height
h: rect.height,
},
rotated: rect.rot,
trimmed: rect.textureData.trimmed,
spriteSourceSize: {
x: rect.textureData.trimOffsetLeft,
y: rect.textureData.trimOffsetTop,
w: rect.width,
h: rect.height
h: rect.height,
},
sourceSize: {
w: rect.textureData.originalWidth,
h: rect.textureData.originalHeight
}
h: rect.textureData.originalHeight,
},
};
}

json.meta = {
app: 'http://github.com/pixijs/assetpack',
version: '1.0',
image: createName(
options.textureName,
i,
bins.length !== 1,
options.resolution,
options.textureFormat
),
image: createName(options.textureName, i, bins.length !== 1, options.resolution, options.textureFormat),
format: 'RGBA8888',
size: {
w: width,
h: height
h: height,
},
scale: options.resolution
scale: options.resolution,
related_multi_packs: null,
};

jsons.push({
name: createName(
options.textureName,
i,
bins.length !== 1,
options.resolution,
'json'
),
json
name: createName(options.textureName, i, bins.length !== 1, options.resolution, 'json'),
json,
});
}

// before we leave, lets connect all the jsons to the first json..

const firstJsonMeta = jsons[0].json.meta;

firstJsonMeta.related_multi_packs = [];

for (let i = 1; i < jsons.length; i++)
{
firstJsonMeta.related_multi_packs.push(jsons[i].name);
}

return jsons;
}
1 change: 1 addition & 0 deletions src/texture-packer/texturePacker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,7 @@ export function texturePacker(_options: TexturePackerOptions = {}): AssetPipe<Te
const textureAsset = createNewAssetAt(asset, name);

textureAsset.buffer = buffer;
textureAsset.metaData.mIgnore = true;

const { json, name: jsonName } = out.jsons[i];

Expand Down
20 changes: 15 additions & 5 deletions src/texture-packer/texturePackerCacheBuster.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,12 +54,13 @@ export function texturePackerCacheBuster(
// to the output folder.
const jsonAssets = textureJsonFilesToFix.map((asset) => asset.getFinalTransformedChildren()[0]);

jsonAssets.forEach((jsonAsset) =>
// loop through all the json files back to front
for (let i = jsonAssets.length - 1; i >= 0; i--)
{
// we are going to replace the textures in the atlas file with the new cache busted textures
// as we do this, the hash of the atlas file will change, so we need to update the path
// and also remove the original file.

const jsonAsset = jsonAssets[i];
const originalHash = jsonAsset.hash;
const originalPath = jsonAsset.path;

Expand All @@ -75,15 +76,24 @@ export function texturePackerCacheBuster(

json.meta.image = cacheBustedTexture.filename;

jsonAsset.buffer = Buffer.from(JSON.stringify(json));
if (json.meta.related_multi_packs)
{
json.meta.related_multi_packs = (json.meta.related_multi_packs as string[]).map((pack) =>
{
const foundAssets = findAssets((asset) =>
asset.filename === pack, asset, true);

jsonAsset.path = jsonAsset.path.replace(originalHash, jsonAsset.hash);
return foundAssets[0].getFinalTransformedChildren()[0].filename;
});
}

jsonAsset.buffer = Buffer.from(JSON.stringify(json));
jsonAsset.path = jsonAsset.path.replace(originalHash, jsonAsset.hash);
fs.removeSync(originalPath);

// rewrite..
fs.writeFileSync(jsonAsset.path, jsonAsset.buffer);
});
}

textureJsonFilesToFix.length = 0;
}
Expand Down
35 changes: 26 additions & 9 deletions src/texture-packer/texturePackerCompress.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@ import type { CompressOptions } from '../image/compress.js';

export type TexturePackerCompressOptions = PluginOptions<'tps' | 'nc'> & Omit<CompressOptions, 'jpg'>;

export function texturePackerCompress(_options?: TexturePackerCompressOptions): AssetPipe<TexturePackerCompressOptions>
export function texturePackerCompress(
_options?: TexturePackerCompressOptions,
): AssetPipe<TexturePackerCompressOptions>
{
const defaultOptions = {
...{
Expand All @@ -17,26 +19,28 @@ export function texturePackerCompress(_options?: TexturePackerCompressOptions):
tags: {
tps: 'tps',
nc: 'nc',
..._options?.tags
}
..._options?.tags,
},
};

return {
name: 'texture-packer-compress',
defaultOptions,
test(asset: Asset, options)
{
return (asset.allMetaData[options.tags.tps]
return (
asset.allMetaData[options.tags.tps]
&& !asset.allMetaData[options.tags.nc]
&& checkExt(asset.path, '.json'));
&& checkExt(asset.path, '.json')
);
},
async transform(asset: Asset, options)
{
const formats = [];

if (options.avif)formats.push('avif');
if (options.png)formats.push('png');
if (options.webp)formats.push('webp');
if (options.avif) formats.push('avif');
if (options.png) formats.push('png');
if (options.webp) formats.push('webp');

const json = JSON.parse(asset.buffer.toString());

Expand All @@ -49,8 +53,21 @@ export function texturePackerCompress(_options?: TexturePackerCompressOptions):
json.meta.image = swapExt(json.meta.image, extension);

const newAsset = createNewAssetAt(asset, newFileName);
const newJson = JSON.parse(JSON.stringify(json));

if (newJson.meta.related_multi_packs)
{
newJson.meta.related_multi_packs = (newJson.meta.related_multi_packs as string[]).map((pack) =>
swapExt(pack, `${extension}.json`),
);
}

newAsset.buffer = Buffer.from(JSON.stringify(newJson, null, 2));

newAsset.buffer = Buffer.from(JSON.stringify(json, null, 2));
if (!newJson.meta.related_multi_packs)
{
newAsset.metaData.mIgnore = true;
}

return newAsset;
});
Expand Down
Loading