diff --git a/Dashboard.Common/Drawing/IImageLoader.cs b/Dashboard.Common/Drawing/IImageLoader.cs
new file mode 100644
index 0000000..d769594
--- /dev/null
+++ b/Dashboard.Common/Drawing/IImageLoader.cs
@@ -0,0 +1,61 @@
+using Dashboard.Pal;
+
+namespace Dashboard.Drawing
+{
+ public record ImageData(
+ TextureType Type,
+ PixelFormat Format,
+ int Width,
+ int Height,
+ byte[] Bitmap)
+ {
+ public int Depth { get; init; } = 1;
+ public int Levels { get; init; } = 1;
+ public bool Premultiplied { get; init; } = false;
+ public int Alignment { get; init; } = 4;
+
+ public long GetLevelOffset(int level)
+ {
+ ArgumentOutOfRangeException.ThrowIfLessThan(level, 0, nameof(level));
+ ArgumentOutOfRangeException.ThrowIfGreaterThan(level, Levels, nameof(level));
+ ArgumentOutOfRangeException.ThrowIfGreaterThan(level, Math.ILogB(Math.Max(Width, Height)));
+
+ long offset = 0;
+
+ long row = Width * Format switch
+ {
+ PixelFormat.R8I => 1,
+ PixelFormat.R16F => 2,
+ PixelFormat.Rg8I => 2,
+ PixelFormat.Rg16F => 4,
+ PixelFormat.Rgb8I => 3,
+ PixelFormat.Rgb16F => 6,
+ PixelFormat.Rgba8I => 4,
+ PixelFormat.Rgba16F => 8,
+ };
+
+ row += Alignment - (row % Alignment);
+ long plane = row * Height;
+ long volume = plane * Depth;
+
+ for (int i = 0; i < level; i++)
+ {
+ if (Depth == 1)
+ {
+ offset += plane / (1 << i) / (1 << i);
+ }
+ else
+ {
+ offset += volume / (1 << i) / (1 << i) / (1 << i);
+ }
+ }
+
+ return offset;
+ }
+ }
+
+ public interface IImageLoader : IApplicationExtension
+ {
+ public ImageData LoadImageData(Stream stream);
+ }
+}
diff --git a/Dashboard.StbImage/Dashboard.StbImage.csproj b/Dashboard.StbImage/Dashboard.StbImage.csproj
new file mode 100644
index 0000000..76eec2e
--- /dev/null
+++ b/Dashboard.StbImage/Dashboard.StbImage.csproj
@@ -0,0 +1,18 @@
+
+
+
+ net8.0
+ latest
+ enable
+ enable
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Dashboard.StbImage/StbImageLoader.cs b/Dashboard.StbImage/StbImageLoader.cs
new file mode 100644
index 0000000..fd573f6
--- /dev/null
+++ b/Dashboard.StbImage/StbImageLoader.cs
@@ -0,0 +1,47 @@
+using Dashboard.Drawing;
+using Dashboard.Pal;
+using ReFuel.Stb;
+
+namespace Dashboard.StbImage
+{
+ public class StbImageLoader : IImageLoader
+ {
+ public string DriverName { get; } = "Dashboard Stb Image Loader";
+ public string DriverVendor { get; } = "Dashboard";
+ public Version DriverVersion { get; } = new Version(1, 0);
+
+ public void Dispose()
+ {
+ }
+
+ IContextBase IContextExtensionBase.Context => Context;
+
+ public void Require(Application context)
+ {
+ Context = context;
+ }
+
+ public ImageData LoadImageData(Stream stream)
+ {
+ using ReFuel.Stb.StbImage image = ReFuel.Stb.StbImage.Load(stream, StbiImageFormat.Rgba);
+ ReadOnlySpan data = image.AsSpan();
+ return new ImageData(TextureType.Texture2D, image.Format switch
+ {
+ StbiImageFormat.GreyAlpha => PixelFormat.Rg8I,
+ StbiImageFormat.Rgb => PixelFormat.Rgb8I,
+ StbiImageFormat.Rgba => PixelFormat.Rgba8I,
+ _ => PixelFormat.R8I,
+ },
+ image.Width,
+ image.Height,
+ data.ToArray());
+ }
+
+ public Application Context { get; private set; } = null!;
+
+ void IContextExtensionBase.Require(IContextBase context)
+ {
+ Require((Application)context);
+ }
+ }
+}
diff --git a/Dashboard.sln b/Dashboard.sln
index 83febe3..ba0aedf 100644
--- a/Dashboard.sln
+++ b/Dashboard.sln
@@ -27,6 +27,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Dashboard.OpenTK", "Dashboa
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Dashboard.OpenGL", "Dashboard.OpenGL\Dashboard.OpenGL.csproj", "{33EB657C-B53A-41B4-BC3C-F38C09ABA577}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Dashboard.StbImage", "Dashboard.StbImage\Dashboard.StbImage.csproj", "{85BCEB9E-DEC2-4A53-B2DA-6BFC6F3EE4E7}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -65,6 +67,11 @@ Global
{33EB657C-B53A-41B4-BC3C-F38C09ABA577}.Debug|Any CPU.Build.0 = Debug|Any CPU
{33EB657C-B53A-41B4-BC3C-F38C09ABA577}.Release|Any CPU.ActiveCfg = Release|Any CPU
{33EB657C-B53A-41B4-BC3C-F38C09ABA577}.Release|Any CPU.Build.0 = Release|Any CPU
+ {85BCEB9E-DEC2-4A53-B2DA-6BFC6F3EE4E7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {85BCEB9E-DEC2-4A53-B2DA-6BFC6F3EE4E7}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {85BCEB9E-DEC2-4A53-B2DA-6BFC6F3EE4E7}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {85BCEB9E-DEC2-4A53-B2DA-6BFC6F3EE4E7}.Release|Any CPU.Build.0 = Release|Any CPU
+ {14616F42-663B-4673-8561-5637FAD1B22F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -72,5 +79,6 @@ Global
GlobalSection(NestedProjects) = preSolution
{7C90B90B-DF31-439B-9080-CD805383B014} = {9D6CCC74-4DF3-47CB-B9B2-6BB75DF2BC40}
{7B064228-2629-486E-95C6-BDDD4B4602C4} = {9B62A92D-ABF5-4704-B831-FD075515A82F}
+ {85BCEB9E-DEC2-4A53-B2DA-6BFC6F3EE4E7} = {9B62A92D-ABF5-4704-B831-FD075515A82F}
EndGlobalSection
EndGlobal
diff --git a/Dashboard/Controls/Form.cs b/Dashboard/Controls/Form.cs
index ff0e725..06c80ee 100644
--- a/Dashboard/Controls/Form.cs
+++ b/Dashboard/Controls/Form.cs
@@ -1,6 +1,5 @@
using System;
using Dashboard.Drawing;
-using Dashboard.Resources;
using Dashboard.Windowing;
namespace Dashboard.Controls
diff --git a/Dashboard/Dashboard.csproj b/Dashboard/Dashboard.csproj
index 66cde79..95aa9e2 100644
--- a/Dashboard/Dashboard.csproj
+++ b/Dashboard/Dashboard.csproj
@@ -12,8 +12,4 @@
-
-
-
-
diff --git a/tests/Dashboard.TestApplication/Program.cs b/tests/Dashboard.TestApplication/Program.cs
index 630285b..2dba001 100644
--- a/tests/Dashboard.TestApplication/Program.cs
+++ b/tests/Dashboard.TestApplication/Program.cs
@@ -1,22 +1,16 @@
-using Dashboard.Drawing;
-using System.Drawing;
+using System.Drawing;
using System.Text;
-using Dashboard.Drawing.OpenGL;
-using Dashboard.ImmediateUI;
+using Dashboard.Controls;
+using Dashboard.Drawing;
+using Dashboard.Drawing.OpenGL.Pal;
using Dashboard.OpenTK.PAL2;
-using OpenTK.Platform;
+using Dashboard.Pal;
+using Dashboard.StbImage;
using OpenTK.Graphics.OpenGL;
using OpenTK.Mathematics;
-using Box2d = Dashboard.Box2d;
+using OpenTK.Platform;
+using Image = Dashboard.Drawing.Image;
using TK = OpenTK.Platform.Toolkit;
-using Dashboard;
-using Dashboard.Controls;
-using Dashboard.Drawing.OpenGL.Pal;
-using Dashboard.Pal;
-using Dashboard.Windowing;
-using OpenTK.Windowing.GraphicsLibraryFramework;
-using ReFuel.Stb;
-using Image = Dashboard.Resources.Image;
using Vector4 = System.Numerics.Vector4;
TK.Init(new ToolkitOptions()
@@ -66,6 +60,7 @@ List points = new List();
StringBuilder builder = new StringBuilder();
app.Initialize();
+app.ExtensionRequire();
window = (PhysicalWindow)app.CreatePhysicalWindow();