Add MrGameEng.Atlases: texture atlas builder, runtime loader and CLI tool
CI / build-test (push) Failing after 1m13s
CI / build-test (push) Failing after 1m13s
AtlasBuilder packs a directory tree of loose images into atlas pages plus JSON metadata (deterministic shelf packing, incremental rebuilds, orphan cleanup); TextureAtlas loads them back handing out Texture2DRegions, so sprites from one page batch into a single draw call. The asset handle generator maps .atlas files to TextureAtlas and skips page images. Demonstrated in the sample (Assets/Atlases + 'atlas' console command), wrapped as tools/MrGameEng.AtlasTool for build scripts. Documented dependency exception: Atlases depends on Graphics and Assets.
This commit is contained in:
@@ -0,0 +1,83 @@
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace MrGameEng.Atlases;
|
||||
|
||||
/// <summary>
|
||||
/// Serializable description of one packed atlas: its page image files and the source-relative
|
||||
/// region keys with their pixel rectangles. Stored as a JSON <c>.atlas</c> file next to the pages.
|
||||
/// </summary>
|
||||
public sealed class AtlasMetadata
|
||||
{
|
||||
private static readonly JsonSerializerOptions JsonOptions = new()
|
||||
{
|
||||
WriteIndented = true,
|
||||
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
|
||||
};
|
||||
|
||||
/// <summary>Format version, bumped on breaking metadata changes.</summary>
|
||||
public int Version { get; init; } = 1;
|
||||
|
||||
/// <summary>Atlas name (group key with '/' replaced by '.').</summary>
|
||||
public string Name { get; init; } = "";
|
||||
|
||||
/// <summary>Maximum page size the atlas was built with (staleness check input).</summary>
|
||||
public int PageSize { get; init; }
|
||||
|
||||
/// <summary>Padding in pixels the atlas was built with (staleness check input).</summary>
|
||||
public int Padding { get; init; }
|
||||
|
||||
/// <summary>Page image files (relative to the metadata file), in page-index order.</summary>
|
||||
public List<AtlasPage> Pages { get; init; } = [];
|
||||
|
||||
/// <summary>Packed regions, sorted by key.</summary>
|
||||
public List<AtlasRegion> Regions { get; init; } = [];
|
||||
|
||||
/// <summary>Serializes this metadata to indented JSON.</summary>
|
||||
public string ToJson() => JsonSerializer.Serialize(this, JsonOptions);
|
||||
|
||||
/// <summary>Parses metadata from JSON produced by <see cref="ToJson"/>.</summary>
|
||||
public static AtlasMetadata FromJson(string json) =>
|
||||
JsonSerializer.Deserialize<AtlasMetadata>(json, JsonOptions)
|
||||
?? throw new InvalidDataException("Atlas metadata JSON deserialized to null.");
|
||||
}
|
||||
|
||||
/// <summary>One page image of an atlas.</summary>
|
||||
public sealed class AtlasPage
|
||||
{
|
||||
/// <summary>Image file name, relative to the metadata file.</summary>
|
||||
public string File { get; init; } = "";
|
||||
|
||||
/// <summary>Page width in pixels.</summary>
|
||||
public int Width { get; init; }
|
||||
|
||||
/// <summary>Page height in pixels.</summary>
|
||||
public int Height { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>One packed source texture inside an atlas.</summary>
|
||||
public sealed class AtlasRegion
|
||||
{
|
||||
/// <summary>
|
||||
/// Region key: the source path relative to the build source root, forward slashes,
|
||||
/// without the file extension (e.g. <c>Things/Pawn/Animal/Fox</c>).
|
||||
/// </summary>
|
||||
public string Key { get; init; } = "";
|
||||
|
||||
/// <summary>Index of the page containing this region.</summary>
|
||||
public int Page { get; init; }
|
||||
|
||||
/// <summary>X of the region in page pixels.</summary>
|
||||
public int X { get; init; }
|
||||
|
||||
/// <summary>Y of the region in page pixels.</summary>
|
||||
public int Y { get; init; }
|
||||
|
||||
/// <summary>Region width in pixels.</summary>
|
||||
[JsonPropertyName("w")]
|
||||
public int Width { get; init; }
|
||||
|
||||
/// <summary>Region height in pixels.</summary>
|
||||
[JsonPropertyName("h")]
|
||||
public int Height { get; init; }
|
||||
}
|
||||
Reference in New Issue
Block a user