75 lines
2.2 KiB
C#

using System;
using System.IO;
using System.Runtime.CompilerServices;
using Dashboard.Pal;
namespace Dashboard.Drawing
{
public class Image(ImageData data) : IDisposable
{
protected readonly ConditionalWeakTable<DeviceContext, ITexture> Textures =
new ConditionalWeakTable<DeviceContext, ITexture>();
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<ITextureExtension>();
texture = ext.CreateTexture(Type);
texture.SetStorage(Format, Width, Height, Depth, Levels);
for (int i = 0; i < Levels; i++)
{
texture.Write<byte>(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<IImageLoader>();
return new Image(imageLoader.LoadImageData(stream));
}
}
}