158 lines
6.5 KiB
C#
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);
|
|
}
|
|
} |