Этап 2
This commit is contained in:
35
Minint.Core/Models/MinintContainer.cs
Normal file
35
Minint.Core/Models/MinintContainer.cs
Normal file
@@ -0,0 +1,35 @@
|
||||
namespace Minint.Core.Models;
|
||||
|
||||
/// <summary>
|
||||
/// Top-level container: holds dimensions shared by all documents/layers,
|
||||
/// and a list of documents (frames).
|
||||
/// </summary>
|
||||
public sealed class MinintContainer
|
||||
{
|
||||
public int Width { get; set; }
|
||||
public int Height { get; set; }
|
||||
public List<MinintDocument> Documents { get; }
|
||||
|
||||
public int PixelCount => Width * Height;
|
||||
|
||||
public MinintContainer(int width, int height)
|
||||
{
|
||||
ArgumentOutOfRangeException.ThrowIfLessThan(width, 1);
|
||||
ArgumentOutOfRangeException.ThrowIfLessThan(height, 1);
|
||||
|
||||
Width = width;
|
||||
Height = height;
|
||||
Documents = [];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new document with a single transparent layer and adds it to the container.
|
||||
/// </summary>
|
||||
public MinintDocument AddNewDocument(string name)
|
||||
{
|
||||
var doc = new MinintDocument(name);
|
||||
doc.Layers.Add(new MinintLayer("Layer 1", PixelCount));
|
||||
Documents.Add(doc);
|
||||
return doc;
|
||||
}
|
||||
}
|
||||
53
Minint.Core/Models/MinintDocument.cs
Normal file
53
Minint.Core/Models/MinintDocument.cs
Normal file
@@ -0,0 +1,53 @@
|
||||
namespace Minint.Core.Models;
|
||||
|
||||
/// <summary>
|
||||
/// A single document (frame) within a container.
|
||||
/// Has its own palette shared by all layers, plus a list of layers.
|
||||
/// </summary>
|
||||
public sealed class MinintDocument
|
||||
{
|
||||
public string Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Delay before showing the next frame during animation playback (ms).
|
||||
/// </summary>
|
||||
public uint FrameDelayMs { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Document palette. Index 0 is always <see cref="RgbaColor.Transparent"/>.
|
||||
/// All layers reference colors by index into this list.
|
||||
/// </summary>
|
||||
public List<RgbaColor> Palette { get; }
|
||||
|
||||
public List<MinintLayer> Layers { get; }
|
||||
|
||||
public MinintDocument(string name)
|
||||
{
|
||||
Name = name;
|
||||
FrameDelayMs = 100;
|
||||
Palette = [RgbaColor.Transparent];
|
||||
Layers = [];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor for deserialization — accepts pre-built palette and layers.
|
||||
/// </summary>
|
||||
public MinintDocument(string name, uint frameDelayMs, List<RgbaColor> palette, List<MinintLayer> layers)
|
||||
{
|
||||
Name = name;
|
||||
FrameDelayMs = frameDelayMs;
|
||||
Palette = palette;
|
||||
Layers = layers;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the number of bytes needed to store a single palette index on disk.
|
||||
/// </summary>
|
||||
public int IndexByteWidth => Palette.Count switch
|
||||
{
|
||||
<= 255 => 1,
|
||||
<= 65_535 => 2,
|
||||
<= 16_777_215 => 3,
|
||||
_ => 4
|
||||
};
|
||||
}
|
||||
42
Minint.Core/Models/MinintLayer.cs
Normal file
42
Minint.Core/Models/MinintLayer.cs
Normal file
@@ -0,0 +1,42 @@
|
||||
namespace Minint.Core.Models;
|
||||
|
||||
/// <summary>
|
||||
/// A single raster layer. Pixels are indices into the parent document's palette.
|
||||
/// Array layout is row-major: Pixels[y * width + x].
|
||||
/// </summary>
|
||||
public sealed class MinintLayer
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public bool IsVisible { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Per-layer opacity (0 = fully transparent, 255 = fully opaque).
|
||||
/// Used during compositing: effective alpha = paletteColor.A * Opacity / 255.
|
||||
/// </summary>
|
||||
public byte Opacity { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Palette indices, length must equal container Width * Height.
|
||||
/// Index 0 = transparent by convention.
|
||||
/// </summary>
|
||||
public int[] Pixels { get; }
|
||||
|
||||
public MinintLayer(string name, int pixelCount)
|
||||
{
|
||||
Name = name;
|
||||
IsVisible = true;
|
||||
Opacity = 255;
|
||||
Pixels = new int[pixelCount];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor for deserialization — accepts a pre-filled pixel buffer.
|
||||
/// </summary>
|
||||
public MinintLayer(string name, bool isVisible, byte opacity, int[] pixels)
|
||||
{
|
||||
Name = name;
|
||||
IsVisible = isVisible;
|
||||
Opacity = opacity;
|
||||
Pixels = pixels;
|
||||
}
|
||||
}
|
||||
37
Minint.Core/Models/RgbaColor.cs
Normal file
37
Minint.Core/Models/RgbaColor.cs
Normal file
@@ -0,0 +1,37 @@
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Minint.Core.Models;
|
||||
|
||||
/// <summary>
|
||||
/// 4-byte RGBA color value. Equality is component-wise.
|
||||
/// </summary>
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
public readonly record struct RgbaColor(byte R, byte G, byte B, byte A)
|
||||
{
|
||||
public static readonly RgbaColor Transparent = new(0, 0, 0, 0);
|
||||
public static readonly RgbaColor Black = new(0, 0, 0, 255);
|
||||
public static readonly RgbaColor White = new(255, 255, 255, 255);
|
||||
|
||||
/// <summary>
|
||||
/// Packs color into a single uint as 0xAABBGGRR (little-endian RGBA).
|
||||
/// Suitable for writing directly into BGRA bitmap buffers after byte-swap,
|
||||
/// or for use as a dictionary key.
|
||||
/// </summary>
|
||||
public uint ToPackedRgba() =>
|
||||
(uint)(R | (G << 8) | (B << 16) | (A << 24));
|
||||
|
||||
public static RgbaColor FromPackedRgba(uint packed) =>
|
||||
new(
|
||||
(byte)(packed & 0xFF),
|
||||
(byte)((packed >> 8) & 0xFF),
|
||||
(byte)((packed >> 16) & 0xFF),
|
||||
(byte)((packed >> 24) & 0xFF));
|
||||
|
||||
/// <summary>
|
||||
/// Packs as 0xAARRGGBB — used for Avalonia/SkiaSharp pixel buffers.
|
||||
/// </summary>
|
||||
public uint ToPackedArgb() =>
|
||||
(uint)(B | (G << 8) | (R << 16) | (A << 24));
|
||||
|
||||
public override string ToString() => $"#{R:X2}{G:X2}{B:X2}{A:X2}";
|
||||
}
|
||||
Reference in New Issue
Block a user