// MIT License - Copyright (c) 2026 wallstop
// Full license text: https://github.com/wallstop/unity-helpers/blob/main/LICENSE
namespace WallstopStudios.UnityHelpers.Editor.Sprites
{
#if UNITY_EDITOR
using System;
using UnityEngine;
///
/// JSON-serializable configuration for sprite sheet extraction settings.
/// Stored alongside sprite sheet textures as {texturePath}.spritesheet.json.
///
[Serializable]
public sealed class SpriteSheetConfig
{
///
/// Configuration file extension (without the leading dot).
///
public const string FileExtension = "spritesheet.json";
///
/// Current configuration version for migration support.
///
public const int CurrentVersion = 3;
///
/// Configuration version number for future migration support.
///
public int version = CurrentVersion;
///
/// The pivot mode for extracted sprites.
///
public PivotMode pivotMode = PivotMode.Center;
///
/// Custom pivot point when pivotMode is set to Custom.
/// Values are normalized (0-1) where (0,0) is bottom-left and (1,1) is top-right.
///
public Vector2 customPivot = new(0.5f, 0.5f);
///
/// The auto-detection algorithm to use.
/// Stored as int for JSON serialization compatibility.
///
public int algorithm = (int)AutoDetectionAlgorithm.AutoBest;
///
/// Expected number of sprites in the sheet. -1 indicates not set.
/// Used for validation and uniform grid detection.
///
public int expectedSpriteCount = -1;
///
/// SHA256 hash of the texture file bytes for change detection.
/// When the texture content changes, this hash will no longer match,
/// indicating the configuration may be stale.
///
public string textureContentHash;
///
/// Cached algorithm results for this texture.
/// Invalidated when textureContentHash changes.
///
public CachedAlgorithmResult cachedAlgorithmResult;
///
/// Whether to snap detected cell sizes to exact divisors of texture dimensions
/// using transparency-aware analysis. When true, adjusts cell sizes to align
/// grid lines with transparent regions for cleaner sprite boundaries.
///
public bool snapToTextureDivisor = true;
///
/// Gets the config file path for a given texture path.
///
/// The path to the source texture.
/// The config file path with .spritesheet.json extension.
public static string GetConfigPath(string texturePath)
{
if (string.IsNullOrEmpty(texturePath))
{
return string.Empty;
}
return texturePath + "." + FileExtension;
}
///
/// Migrates a configuration from an older version to the current version.
/// Currently a no-op for version 1, but provides the hook for future migrations.
///
/// The configuration to migrate.
public static void MigrateConfig(SpriteSheetConfig config)
{
if (config == null || config.version >= CurrentVersion)
{
return;
}
// Migrate v1 -> v2: Add algorithm caching
if (config.version < 2)
{
config.algorithm = (int)AutoDetectionAlgorithm.AutoBest;
config.cachedAlgorithmResult = null;
config.version = 2;
}
// Migrate v2 -> v3: Add snapToTextureDivisor persistence
if (config.version < 3)
{
config.snapToTextureDivisor = true;
config.version = 3;
}
config.version = CurrentVersion;
}
}
///
/// Cached result from an auto-detection algorithm run.
/// Stored in the config file for cross-session persistence.
///
[Serializable]
public sealed class CachedAlgorithmResult
{
///
/// The algorithm that produced this result.
///
public int algorithm;
///
/// Detected cell width in pixels.
///
public int cellWidth;
///
/// Detected cell height in pixels.
///
public int cellHeight;
///
/// Confidence score in the range [0, 1].
///
public float confidence;
///
/// Creates a cached result from an algorithm result.
///
public static CachedAlgorithmResult FromResult(SpriteSheetAlgorithms.AlgorithmResult result)
{
return new CachedAlgorithmResult
{
algorithm = (int)result.Algorithm,
cellWidth = result.CellWidth,
cellHeight = result.CellHeight,
confidence = result.Confidence,
};
}
///
/// Converts this cached result to an algorithm result.
///
public SpriteSheetAlgorithms.AlgorithmResult ToResult()
{
return new SpriteSheetAlgorithms.AlgorithmResult(
cellWidth,
cellHeight,
confidence,
(AutoDetectionAlgorithm)algorithm
);
}
}
#endif
}