Files
2026-07-13 13:13:17 +08:00

158 lines
6.5 KiB
C#

using ImGuiNET;
using SharpDX;
using SharpDX.Direct3D11;
using SharpDX.DXGI;
using SharpDX.Mathematics.Interop;
using SharpDX.WIC;
using T3.Editor.Gui;
using T3.Editor.Gui.Styling;
using Device = SharpDX.Direct3D11.Device;
namespace T3.Editor.UiContentDrawing;
internal static class FontAtlasGenerator
{
private static string GetIconPathForScale(float scale, out float iconScaleFactor)
{
iconScaleFactor = float.NaN;
var bestDist = float.PositiveInfinity;
foreach (var x in Icons.IconFilePathForResolutions.Keys)
{
var dist = MathF.Abs(x - scale); // This should probably be logarithmic
if (!(dist < bestDist))
continue;
bestDist = dist;
iconScaleFactor = x;
}
return Icons.IconFilePathForResolutions[iconScaleFactor];
}
internal static unsafe void CreateFontAtlasWithIcons(Device device,
IntPtr imguiContext,
out ShaderResourceView fontTextureView,
out SamplerState fontSampler)
{
fontSampler = null;
fontTextureView = null;
var scaleFactor = T3Ui.UiScaleFactor;
var previousContext = ImGui.GetCurrentContext();
ImGui.SetCurrentContext(imguiContext);
ImGuiIOPtr io = ImGui.GetIO();
var iconFilePath = GetIconPathForScale(scaleFactor, out var iconScaleFactor);
Icons.IconFont = io.Fonts.AddFontDefault();
Icons.FontSize = 15 * iconScaleFactor;
var glyphIds
= Icons.CustomIcons
.Select(iconSource
=> io.Fonts.AddCustomRectFontGlyph(Icons.IconFont,
iconSource.Char,
(int)(iconSource.SourceArea.GetWidth() * iconScaleFactor),
(int)(iconSource.SourceArea.GetHeight() * iconScaleFactor),
iconSource.SourceArea.GetWidth() * iconScaleFactor)).ToArray();
io.Fonts.Build();
// Get pointer to texture data, must happen after font build
io.Fonts.GetTexDataAsRGBA32(out IntPtr atlasPixels, out var atlasWidth, out var atlasHeight, out _);
// Load the source image
ImagingFactory factory = new ImagingFactory();
//var iconFilePath = Icons.IconAtlasPath;
var bitmapDecoder = new BitmapDecoder(factory, iconFilePath, DecodeOptions.CacheOnDemand);
var formatConverter = new FormatConverter(factory);
var bitmapFrameDecode = bitmapDecoder.GetFrame(0);
formatConverter.Initialize(bitmapFrameDecode,
PixelFormat.Format32bppRGBA,
BitmapDitherType.None,
null,
0.0,
BitmapPaletteType.Custom);
// Copy the data into the font atlas texture
for (int i = 0; i < glyphIds.Length; i++)
{
var glyphId = glyphIds[i];
var icon = Icons.CustomIcons[i];
int sx = (int)(icon.SourceArea.GetWidth() * iconScaleFactor);
int sy = (int)(icon.SourceArea.GetHeight() * iconScaleFactor);
int px = (int)(icon.SourceArea.Min.X * iconScaleFactor);
int py = (int)(icon.SourceArea.Min.Y * iconScaleFactor);
uint[] iconContent = new uint[sx * sy];
formatConverter.CopyPixels(new RawBox(px, py, sx, sy), iconContent);
var rect = io.Fonts.GetCustomRectByIndex(glyphId);
for (int y = 0, s = 0; y < rect.Height; y++)
{
uint* p = (uint*)atlasPixels + (rect.Y + y) * atlasWidth + rect.X;
for (int x = rect.Width; x > 0; x--)
{
*p++ = iconContent[s];
s++;
}
}
}
// Upload texture
const IntPtr fontAtlasId = (IntPtr)1;
io.Fonts.SetTexID(fontAtlasId);
var box = new DataBox(atlasPixels, atlasWidth * 4, 0);
try
{
// Upload texture to graphics system
var textureDesc = new Texture2DDescription()
{
Width = atlasWidth,
Height = atlasHeight,
MipLevels = 1,
ArraySize = 1,
Format = Format.R8G8B8A8_UNorm,
SampleDescription = new SampleDescription() { Count = 1, Quality = 0 },
Usage = ResourceUsage.Default,
BindFlags = BindFlags.ShaderResource,
CpuAccessFlags = CpuAccessFlags.None
};
Texture2D texture = new Texture2D(device, textureDesc, [box]);
texture.DebugName = "FImgui Font Atlas";
fontTextureView = new ShaderResourceView(device, texture);
texture.Dispose();
// Store our identifier
io.Fonts.TexID = (IntPtr)fontTextureView;
var samplerDesc = new SamplerStateDescription()
{
Filter = Filter.MinMagMipLinear,
AddressU = TextureAddressMode.Wrap,
AddressV = TextureAddressMode.Wrap,
AddressW = TextureAddressMode.Wrap,
MipLodBias = 0.0f,
ComparisonFunction = Comparison.Always,
MinimumLod = 0.0f,
MaximumLod = 0.0f
};
fontSampler = new SamplerState(device, samplerDesc);
}
catch (Exception e)
{
Log.Error("Failed to create fonts texture: " + e.Message);
}
if (previousContext != IntPtr.Zero)
ImGui.SetCurrentContext(previousContext);
}
}