perf: 优化合图功能

This commit is contained in:
richarjiang
2026-01-27 09:58:11 +08:00
parent c26d6eaada
commit b29de1dd80
15 changed files with 1117 additions and 493 deletions

View File

@@ -15,14 +15,41 @@ export interface BrowserSprite {
}
/**
* Complete atlas result
* Single atlas result
*/
export interface AtlasResult {
export interface SingleAtlasResult {
index: number;
width: number;
height: number;
placements: PackerPlacement[];
frames: AtlasFrame[];
imageDataUrl: string | null;
/** Sprite IDs in this atlas */
spriteIds: string[];
}
/**
* Complete atlas result (supports multiple atlases)
*/
export interface AtlasResult {
/** All atlases */
atlases: SingleAtlasResult[];
/** Total number of packed sprites */
packedCount: number;
/** Sprites that couldn't fit in any atlas (only when multi-atlas is disabled) */
unpackedSpriteIds: string[];
}
/**
* Legacy single result format for backward compatibility
*/
export interface LegacyAtlasResult {
width: number;
height: number;
placements: PackerPlacement[];
frames: AtlasFrame[];
imageDataUrl: string | null;
unpackedSpriteIds: string[];
}
/**
@@ -41,14 +68,23 @@ interface AtlasState {
// Configuration
config: TextureAtlasConfig;
// Multi-atlas mode
enableMultiAtlas: boolean;
// Compression mode (PNG quantization)
enableCompression: boolean;
// Processing state
status: AtlasProcessStatus;
progress: number;
errorMessage: string | null;
// Result
// Result (supports multiple atlases)
result: AtlasResult | null;
// Current preview atlas index
currentAtlasIndex: number;
// Preview state
previewScale: number;
previewOffset: { x: number; y: number };
@@ -67,11 +103,15 @@ interface AtlasState {
updateConfig: (config: Partial<TextureAtlasConfig>) => void;
resetConfig: () => void;
setEnableMultiAtlas: (enable: boolean) => void;
setEnableCompression: (enable: boolean) => void;
setStatus: (status: AtlasProcessStatus) => void;
setProgress: (progress: number) => void;
setError: (message: string | null) => void;
setResult: (result: AtlasResult | null) => void;
setCurrentAtlasIndex: (index: number) => void;
setPreviewScale: (scale: number) => void;
setPreviewOffset: (offset: { x: number; y: number }) => void;
@@ -81,6 +121,9 @@ interface AtlasState {
openAnimationDialog: () => void;
closeAnimationDialog: () => void;
setAnimationFps: (fps: number) => void;
// Computed helpers
getCurrentAtlas: () => SingleAtlasResult | null;
}
/**
@@ -91,7 +134,7 @@ const defaultConfig: TextureAtlasConfig = {
maxHeight: 1024,
padding: 2,
allowRotation: false,
pot: true,
pot: false,
format: "png",
quality: 90,
outputFormat: "cocos2d",
@@ -106,10 +149,13 @@ export const useAtlasStore = create<AtlasState>((set, get) => ({
sprites: [],
folderName: "",
config: { ...defaultConfig },
enableMultiAtlas: false,
enableCompression: false,
status: "idle",
progress: 0,
errorMessage: null,
result: null,
currentAtlasIndex: 0,
previewScale: 1,
previewOffset: { x: 0, y: 0 },
selectedSpriteIds: [],
@@ -128,7 +174,7 @@ export const useAtlasStore = create<AtlasState>((set, get) => ({
a.name.localeCompare(b.name, undefined, { numeric: true, sensitivity: "base" })
);
return { sprites: allSprites, result: null };
return { sprites: allSprites, result: null, currentAtlasIndex: 0 };
});
},
@@ -137,6 +183,7 @@ export const useAtlasStore = create<AtlasState>((set, get) => ({
sprites: state.sprites.filter((s) => s.id !== id),
selectedSpriteIds: state.selectedSpriteIds.filter((sid) => sid !== id),
result: null,
currentAtlasIndex: 0,
}));
},
@@ -149,6 +196,7 @@ export const useAtlasStore = create<AtlasState>((set, get) => ({
sprites: [],
folderName: "",
result: null,
currentAtlasIndex: 0,
selectedSpriteIds: [],
status: "idle",
progress: 0,
@@ -163,10 +211,17 @@ export const useAtlasStore = create<AtlasState>((set, get) => ({
set((state) => ({
config: { ...state.config, ...partialConfig },
result: null, // Clear result when config changes
currentAtlasIndex: 0,
}));
},
resetConfig: () => set({ config: { ...defaultConfig }, result: null }),
resetConfig: () => set({ config: { ...defaultConfig }, result: null, currentAtlasIndex: 0 }),
// Multi-atlas mode
setEnableMultiAtlas: (enable) => set({ enableMultiAtlas: enable, result: null, currentAtlasIndex: 0 }),
// Compression mode (only affects download, not preview)
setEnableCompression: (enable) => set({ enableCompression: enable }),
// Status actions
setStatus: (status) => set({ status }),
@@ -174,7 +229,14 @@ export const useAtlasStore = create<AtlasState>((set, get) => ({
setError: (message) => set({ errorMessage: message, status: message ? "error" : "idle" }),
// Result actions
setResult: (result) => set({ result, status: result ? "completed" : "idle" }),
setResult: (result) => set({ result, status: result ? "completed" : "idle", currentAtlasIndex: 0 }),
setCurrentAtlasIndex: (index) => {
const { result } = get();
if (result && index >= 0 && index < result.atlases.length) {
set({ currentAtlasIndex: index, previewOffset: { x: 0, y: 0 } });
}
},
// Preview actions
setPreviewScale: (scale) => set({ previewScale: Math.max(0.1, Math.min(4, scale)) }),
@@ -191,7 +253,7 @@ export const useAtlasStore = create<AtlasState>((set, get) => ({
: [...state.selectedSpriteIds, id],
};
}
return { selectedSpriteIds: [id] };
return { selectedSpriteIds: id ? [id] : [] };
});
},
@@ -201,6 +263,13 @@ export const useAtlasStore = create<AtlasState>((set, get) => ({
openAnimationDialog: () => set({ isAnimationDialogOpen: true }),
closeAnimationDialog: () => set({ isAnimationDialogOpen: false }),
setAnimationFps: (fps) => set({ animationFps: Math.max(1, Math.min(60, fps)) }),
// Computed helpers
getCurrentAtlas: () => {
const { result, currentAtlasIndex } = get();
if (!result || result.atlases.length === 0) return null;
return result.atlases[currentAtlasIndex] || null;
},
}));
/**
@@ -218,3 +287,7 @@ export const useAtlasPreview = () => useAtlasStore((state) => ({
scale: state.previewScale,
offset: state.previewOffset,
}));
export const useCurrentAtlas = () => useAtlasStore((state) => {
if (!state.result || state.result.atlases.length === 0) return null;
return state.result.atlases[state.currentAtlasIndex] || null;
});