using System; using System.IO; using System.Runtime.CompilerServices; using Dashboard.Pal; namespace Dashboard.Drawing { public class Image(ImageData data) : IDisposable { protected readonly ConditionalWeakTable Textures = new ConditionalWeakTable(); public virtual TextureType Type => data.Type; public PixelFormat Format { get; } = data.Format; public int Width { get; } = data.Width; public int Height { get; } = data.Height; public int Depth { get; } = data.Depth; public int Levels { get; } = data.Levels; public bool Premultiplied { get; } = data.Premultiplied; public bool IsDisposed { get; private set; } = false; ~Image() { InvokeDispose(false); } public virtual ITexture InternTexture(DeviceContext dc) { if (Textures.TryGetValue(dc, out ITexture? texture)) return texture; ITextureExtension ext = dc.ExtensionRequire(); texture = ext.CreateTexture(Type); texture.SetStorage(Format, Width, Height, Depth, Levels); for (int i = 0; i < Levels; i++) { texture.Write(Format, data.Bitmap.AsSpan()[(int)data.GetLevelOffset(i)..], level: i, align: data.Alignment); } texture.Premultiplied = Premultiplied; texture.GenerateMipmaps(); Textures.Add(dc, texture); return texture; } private void InvokeDispose(bool disposing) { if (IsDisposed) return; IsDisposed = true; Dispose(disposing); } protected virtual void Dispose(bool disposing) { foreach ((DeviceContext dc, ITexture texture) in Textures) { texture.Dispose(); } } public void Dispose() => InvokeDispose(true); public static Image Load(Stream stream) { IImageLoader imageLoader = Application.Current.ExtensionRequire(); return new Image(imageLoader.LoadImageData(stream)); } } }