mirror of
https://github.com/maxartz15/MoonWorksDearImGuiScaffold.git
synced 2025-06-26 21:46:06 +02:00
initial commit
This commit is contained in:
50
src/Clipboard.cs
Normal file
50
src/Clipboard.cs
Normal file
@ -0,0 +1,50 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
|
||||
namespace MoonWorksDearImGuiScaffold;
|
||||
|
||||
public static unsafe class Clipboard
|
||||
{
|
||||
private static IntPtr clipboard;
|
||||
private static readonly Dictionary<Delegate, IntPtr> pinned = new();
|
||||
|
||||
private static unsafe void Set(void* userdata, byte* text)
|
||||
{
|
||||
var len = 0; while (text[len] != 0) len++;
|
||||
var str = Encoding.UTF8.GetString(text, len);
|
||||
SDL2.SDL.SDL_SetClipboardText(str);
|
||||
}
|
||||
|
||||
private static unsafe byte* Get(void* userdata)
|
||||
{
|
||||
if (clipboard != IntPtr.Zero)
|
||||
{
|
||||
NativeMemory.Free((void*) clipboard);
|
||||
clipboard = IntPtr.Zero;
|
||||
}
|
||||
|
||||
var str = SDL2.SDL.SDL_GetClipboardText();
|
||||
var length = Encoding.UTF8.GetByteCount(str);
|
||||
var bytes = (byte*)(clipboard = (nint)NativeMemory.Alloc((nuint)(length + 1)));
|
||||
|
||||
Encoding.UTF8.GetBytes(str, new Span<byte>(bytes, length));
|
||||
bytes[length] = 0;
|
||||
return bytes;
|
||||
}
|
||||
|
||||
// Stops the delegate pointer from being collected
|
||||
private static IntPtr GetPointerTo<T>(T fn) where T : Delegate
|
||||
{
|
||||
if (pinned.TryGetValue(fn, out var ptr))
|
||||
return ptr;
|
||||
|
||||
ptr = Marshal.GetFunctionPointerForDelegate(fn);
|
||||
pinned.Add(fn, ptr);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
public static readonly IntPtr GetFnPtr = GetPointerTo(Get);
|
||||
public static readonly IntPtr SetFnPtr = GetPointerTo(Set);
|
||||
}
|
341
src/MoonWorksDearImGuiScaffoldGame.cs
Normal file
341
src/MoonWorksDearImGuiScaffoldGame.cs
Normal file
@ -0,0 +1,341 @@
|
||||
using MoonWorks.Graphics;
|
||||
using MoonWorks.Input;
|
||||
using MoonWorks;
|
||||
using ImGuiNET;
|
||||
using System.IO;
|
||||
using MoonWorks.Math.Float;
|
||||
using System;
|
||||
|
||||
namespace MoonWorksDearImGuiScaffold;
|
||||
|
||||
class MoonWorksDearImGuiScaffoldGame : Game
|
||||
{
|
||||
private string ShaderContentPath = Path.Combine(System.AppContext.BaseDirectory, "Content", "Shaders");
|
||||
|
||||
private GraphicsPipeline ImGuiPipeline;
|
||||
private ShaderModule ImGuiVertexShader;
|
||||
private ShaderModule ImGuiFragmentShader;
|
||||
private Sampler ImGuiSampler;
|
||||
|
||||
private uint VertexCount = 0;
|
||||
private uint IndexCount = 0;
|
||||
private MoonWorks.Graphics.Buffer ImGuiVertexBuffer = null;
|
||||
private MoonWorks.Graphics.Buffer ImGuiIndexBuffer = null;
|
||||
|
||||
private TextureStorage TextureStorage;
|
||||
|
||||
public MoonWorksDearImGuiScaffoldGame(
|
||||
WindowCreateInfo windowCreateInfo,
|
||||
FrameLimiterSettings frameLimiterSettings,
|
||||
bool debugMode
|
||||
) : base(windowCreateInfo, frameLimiterSettings, 60, debugMode)
|
||||
{
|
||||
TextureStorage = new TextureStorage();
|
||||
|
||||
ImGui.CreateContext();
|
||||
|
||||
var io = ImGui.GetIO();
|
||||
io.DisplaySize = new System.Numerics.Vector2(MainWindow.Width, MainWindow.Height);
|
||||
io.DisplayFramebufferScale = System.Numerics.Vector2.One;
|
||||
|
||||
ImGuiVertexShader =
|
||||
new ShaderModule(GraphicsDevice, Path.Combine(ShaderContentPath, "ImGui.vert.refresh"));
|
||||
ImGuiFragmentShader =
|
||||
new ShaderModule(GraphicsDevice, Path.Combine(ShaderContentPath, "ImGui.frag.refresh"));
|
||||
|
||||
|
||||
ImGuiSampler = new Sampler(GraphicsDevice, SamplerCreateInfo.LinearClamp);
|
||||
|
||||
ImGuiPipeline = new GraphicsPipeline(
|
||||
GraphicsDevice,
|
||||
new GraphicsPipelineCreateInfo
|
||||
{
|
||||
AttachmentInfo = new GraphicsPipelineAttachmentInfo(
|
||||
new ColorAttachmentDescription(
|
||||
MainWindow.SwapchainFormat,
|
||||
ColorAttachmentBlendState.NonPremultiplied
|
||||
)
|
||||
),
|
||||
DepthStencilState = DepthStencilState.Disable,
|
||||
VertexShaderInfo = GraphicsShaderInfo.Create<Matrix4x4>(ImGuiVertexShader, "main", 0),
|
||||
FragmentShaderInfo = GraphicsShaderInfo.Create(ImGuiFragmentShader, "main", 1),
|
||||
VertexInputState = VertexInputState.CreateSingleBinding<Position2DTextureColorVertex>(),
|
||||
PrimitiveType = PrimitiveType.TriangleList,
|
||||
RasterizerState = RasterizerState.CW_CullNone,
|
||||
MultisampleState = MultisampleState.None
|
||||
}
|
||||
);
|
||||
|
||||
BuildFontAtlas();
|
||||
|
||||
MainWindow.RegisterSizeChangeCallback(HandleSizeChange);
|
||||
|
||||
Inputs.TextInput += c =>
|
||||
{
|
||||
if (c == '\t') { return; }
|
||||
io.AddInputCharacter(c);
|
||||
};
|
||||
|
||||
io.ConfigFlags |= ImGuiConfigFlags.NavEnableKeyboard;
|
||||
|
||||
if (!OperatingSystem.IsWindows())
|
||||
{
|
||||
io.SetClipboardTextFn = Clipboard.SetFnPtr;
|
||||
io.GetClipboardTextFn = Clipboard.GetFnPtr;
|
||||
}
|
||||
}
|
||||
|
||||
protected void HandleSizeChange(uint width, uint height)
|
||||
{
|
||||
var io = ImGui.GetIO();
|
||||
io.DisplaySize = new System.Numerics.Vector2(width, height);
|
||||
}
|
||||
|
||||
protected override void Update(System.TimeSpan dt)
|
||||
{
|
||||
var io = ImGui.GetIO();
|
||||
|
||||
io.MousePos = new System.Numerics.Vector2(Inputs.Mouse.X, Inputs.Mouse.Y);
|
||||
io.MouseDown[0] = Inputs.Mouse.LeftButton.IsDown;
|
||||
io.MouseDown[1] = Inputs.Mouse.RightButton.IsDown;
|
||||
io.MouseDown[2] = Inputs.Mouse.MiddleButton.IsDown;
|
||||
io.MouseWheel = Inputs.Mouse.Wheel;
|
||||
|
||||
io.AddKeyEvent(ImGuiKey.A, Inputs.Keyboard.IsDown(KeyCode.A));
|
||||
io.AddKeyEvent(ImGuiKey.Z, Inputs.Keyboard.IsDown(KeyCode.Z));
|
||||
io.AddKeyEvent(ImGuiKey.Y, Inputs.Keyboard.IsDown(KeyCode.Y));
|
||||
io.AddKeyEvent(ImGuiKey.X, Inputs.Keyboard.IsDown(KeyCode.X));
|
||||
io.AddKeyEvent(ImGuiKey.C, Inputs.Keyboard.IsDown(KeyCode.C));
|
||||
io.AddKeyEvent(ImGuiKey.V, Inputs.Keyboard.IsDown(KeyCode.V));
|
||||
|
||||
io.AddKeyEvent(ImGuiKey.Tab, Inputs.Keyboard.IsDown(KeyCode.Tab));
|
||||
io.AddKeyEvent(ImGuiKey.LeftArrow, Inputs.Keyboard.IsDown(KeyCode.Left));
|
||||
io.AddKeyEvent(ImGuiKey.RightArrow, Inputs.Keyboard.IsDown(KeyCode.Right));
|
||||
io.AddKeyEvent(ImGuiKey.UpArrow, Inputs.Keyboard.IsDown(KeyCode.Up));
|
||||
io.AddKeyEvent(ImGuiKey.DownArrow, Inputs.Keyboard.IsDown(KeyCode.Down));
|
||||
io.AddKeyEvent(ImGuiKey.Enter, Inputs.Keyboard.IsDown(KeyCode.Return));
|
||||
io.AddKeyEvent(ImGuiKey.Escape, Inputs.Keyboard.IsDown(KeyCode.Escape));
|
||||
io.AddKeyEvent(ImGuiKey.Delete, Inputs.Keyboard.IsDown(KeyCode.Delete));
|
||||
io.AddKeyEvent(ImGuiKey.Backspace, Inputs.Keyboard.IsDown(KeyCode.Backspace));
|
||||
io.AddKeyEvent(ImGuiKey.Home, Inputs.Keyboard.IsDown(KeyCode.Home));
|
||||
io.AddKeyEvent(ImGuiKey.End, Inputs.Keyboard.IsDown(KeyCode.End));
|
||||
io.AddKeyEvent(ImGuiKey.PageDown, Inputs.Keyboard.IsDown(KeyCode.PageDown));
|
||||
io.AddKeyEvent(ImGuiKey.PageUp, Inputs.Keyboard.IsDown(KeyCode.PageUp));
|
||||
io.AddKeyEvent(ImGuiKey.Insert, Inputs.Keyboard.IsDown(KeyCode.Insert));
|
||||
|
||||
io.AddKeyEvent(ImGuiKey.ModCtrl, Inputs.Keyboard.IsDown(KeyCode.LeftControl) || Inputs.Keyboard.IsDown(KeyCode.RightControl));
|
||||
io.AddKeyEvent(ImGuiKey.ModShift, Inputs.Keyboard.IsDown(KeyCode.LeftShift) || Inputs.Keyboard.IsDown(KeyCode.RightShift));
|
||||
io.AddKeyEvent(ImGuiKey.ModAlt, Inputs.Keyboard.IsDown(KeyCode.LeftAlt) || Inputs.Keyboard.IsDown(KeyCode.RightAlt));
|
||||
io.AddKeyEvent(ImGuiKey.ModSuper, Inputs.Keyboard.IsDown(KeyCode.LeftMeta) || Inputs.Keyboard.IsDown(KeyCode.RightMeta));
|
||||
|
||||
ImGui.NewFrame();
|
||||
|
||||
ImGuiCommands();
|
||||
|
||||
ImGui.EndFrame();
|
||||
}
|
||||
|
||||
protected void ImGuiCommands()
|
||||
{
|
||||
// Do your ImGui commands here!
|
||||
ImGui.ShowDemoWindow();
|
||||
}
|
||||
|
||||
protected override void Draw(double alpha)
|
||||
{
|
||||
ImGui.Render();
|
||||
|
||||
var io = ImGui.GetIO();
|
||||
var drawDataPtr = ImGui.GetDrawData();
|
||||
|
||||
UpdateImGuiBuffers(drawDataPtr);
|
||||
|
||||
var commandBuffer = GraphicsDevice.AcquireCommandBuffer();
|
||||
var swapchainTexture = commandBuffer.AcquireSwapchainTexture(MainWindow);
|
||||
|
||||
if (swapchainTexture != null)
|
||||
{
|
||||
RenderCommandLists(commandBuffer, swapchainTexture, drawDataPtr, io);
|
||||
}
|
||||
|
||||
GraphicsDevice.Submit(commandBuffer);
|
||||
}
|
||||
|
||||
protected override void Destroy()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
private unsafe void UpdateImGuiBuffers(ImDrawDataPtr drawDataPtr)
|
||||
{
|
||||
if (drawDataPtr.TotalVtxCount == 0) { return; }
|
||||
|
||||
var commandBuffer = GraphicsDevice.AcquireCommandBuffer();
|
||||
|
||||
if (drawDataPtr.TotalVtxCount > VertexCount)
|
||||
{
|
||||
ImGuiVertexBuffer?.Dispose();
|
||||
|
||||
VertexCount = (uint)(drawDataPtr.TotalVtxCount * 1.5f);
|
||||
ImGuiVertexBuffer = MoonWorks.Graphics.Buffer.Create<Position2DTextureColorVertex>(
|
||||
GraphicsDevice,
|
||||
BufferUsageFlags.Vertex,
|
||||
VertexCount
|
||||
);
|
||||
}
|
||||
|
||||
if (drawDataPtr.TotalIdxCount > IndexCount)
|
||||
{
|
||||
ImGuiIndexBuffer?.Dispose();
|
||||
|
||||
IndexCount = (uint)(drawDataPtr.TotalIdxCount * 1.5f);
|
||||
ImGuiIndexBuffer = MoonWorks.Graphics.Buffer.Create<ushort>(
|
||||
GraphicsDevice,
|
||||
BufferUsageFlags.Index,
|
||||
IndexCount
|
||||
);
|
||||
}
|
||||
|
||||
uint vertexOffset = 0;
|
||||
uint indexOffset = 0;
|
||||
|
||||
for (var n = 0; n < drawDataPtr.CmdListsCount; n += 1)
|
||||
{
|
||||
var cmdList = drawDataPtr.CmdLists[n];
|
||||
|
||||
commandBuffer.SetBufferData<Position2DTextureColorVertex>(
|
||||
ImGuiVertexBuffer,
|
||||
cmdList.VtxBuffer.Data,
|
||||
vertexOffset,
|
||||
(uint)cmdList.VtxBuffer.Size
|
||||
);
|
||||
|
||||
commandBuffer.SetBufferData<ushort>(
|
||||
ImGuiIndexBuffer,
|
||||
cmdList.IdxBuffer.Data,
|
||||
indexOffset,
|
||||
(uint)cmdList.IdxBuffer.Size
|
||||
);
|
||||
|
||||
vertexOffset += (uint)cmdList.VtxBuffer.Size;
|
||||
indexOffset += (uint)cmdList.IdxBuffer.Size;
|
||||
}
|
||||
|
||||
GraphicsDevice.Submit(commandBuffer);
|
||||
}
|
||||
|
||||
private void RenderCommandLists(CommandBuffer commandBuffer, Texture renderTexture, ImDrawDataPtr drawDataPtr, ImGuiIOPtr ioPtr)
|
||||
{
|
||||
var view = Matrix4x4.CreateLookAt(
|
||||
new Vector3(0, 0, 1),
|
||||
Vector3.Zero,
|
||||
Vector3.Up
|
||||
);
|
||||
|
||||
var projection = Matrix4x4.CreateOrthographicOffCenter(
|
||||
0,
|
||||
480,
|
||||
270,
|
||||
0,
|
||||
0.01f,
|
||||
4000f
|
||||
);
|
||||
|
||||
var viewProjectionMatrix = view * projection;
|
||||
|
||||
commandBuffer.BeginRenderPass(
|
||||
new ColorAttachmentInfo(renderTexture, MoonWorks.Graphics.Color.CornflowerBlue)
|
||||
);
|
||||
|
||||
commandBuffer.BindGraphicsPipeline(ImGuiPipeline);
|
||||
|
||||
var vertexUniformOffset = commandBuffer.PushVertexShaderUniforms(
|
||||
Matrix4x4.CreateOrthographicOffCenter(0, ioPtr.DisplaySize.X, ioPtr.DisplaySize.Y, 0, -1, 1)
|
||||
);
|
||||
|
||||
commandBuffer.BindVertexBuffers(ImGuiVertexBuffer);
|
||||
commandBuffer.BindIndexBuffer(ImGuiIndexBuffer, IndexElementSize.Sixteen);
|
||||
|
||||
uint vertexOffset = 0;
|
||||
uint indexOffset = 0;
|
||||
|
||||
for (int n = 0; n < drawDataPtr.CmdListsCount; n += 1)
|
||||
{
|
||||
var cmdList = drawDataPtr.CmdLists[n];
|
||||
|
||||
for (int cmdIndex = 0; cmdIndex < cmdList.CmdBuffer.Size; cmdIndex += 1)
|
||||
{
|
||||
var drawCmd = cmdList.CmdBuffer[cmdIndex];
|
||||
|
||||
commandBuffer.BindFragmentSamplers(
|
||||
new TextureSamplerBinding(TextureStorage.GetTexture(drawCmd.TextureId), ImGuiSampler)
|
||||
);
|
||||
|
||||
var topLeft = Vector2.Transform(new Vector2(drawCmd.ClipRect.X, drawCmd.ClipRect.Y), viewProjectionMatrix);
|
||||
var bottomRight = Vector2.Transform(new Vector2(drawCmd.ClipRect.Z, drawCmd.ClipRect.W), viewProjectionMatrix);
|
||||
|
||||
var width = drawCmd.ClipRect.Z - (int)drawCmd.ClipRect.X;
|
||||
var height = drawCmd.ClipRect.W - (int)drawCmd.ClipRect.Y;
|
||||
|
||||
if (width <= 0 || height <= 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
commandBuffer.SetScissor(
|
||||
new Rect(
|
||||
(int)drawCmd.ClipRect.X,
|
||||
(int)drawCmd.ClipRect.Y,
|
||||
(int)width,
|
||||
(int)height
|
||||
)
|
||||
);
|
||||
|
||||
commandBuffer.DrawIndexedPrimitives(
|
||||
vertexOffset,
|
||||
indexOffset,
|
||||
drawCmd.ElemCount / 3,
|
||||
vertexUniformOffset,
|
||||
0
|
||||
);
|
||||
|
||||
indexOffset += drawCmd.ElemCount;
|
||||
}
|
||||
|
||||
vertexOffset += (uint)cmdList.VtxBuffer.Size;
|
||||
}
|
||||
|
||||
commandBuffer.EndRenderPass();
|
||||
}
|
||||
|
||||
private void BuildFontAtlas()
|
||||
{
|
||||
var commandBuffer = GraphicsDevice.AcquireCommandBuffer();
|
||||
|
||||
var io = ImGui.GetIO();
|
||||
|
||||
io.Fonts.GetTexDataAsRGBA32(
|
||||
out System.IntPtr pixelData,
|
||||
out int width,
|
||||
out int height,
|
||||
out int bytesPerPixel
|
||||
);
|
||||
|
||||
var fontTexture = Texture.CreateTexture2D(
|
||||
GraphicsDevice,
|
||||
(uint)width,
|
||||
(uint)height,
|
||||
TextureFormat.R8G8B8A8,
|
||||
TextureUsageFlags.Sampler
|
||||
);
|
||||
|
||||
commandBuffer.SetTextureData(fontTexture, pixelData, (uint)(width * height * bytesPerPixel));
|
||||
|
||||
GraphicsDevice.Submit(commandBuffer);
|
||||
|
||||
io.Fonts.SetTexID(fontTexture.Handle);
|
||||
io.Fonts.ClearTexData();
|
||||
|
||||
TextureStorage.Add(fontTexture);
|
||||
}
|
||||
}
|
33
src/Program.cs
Normal file
33
src/Program.cs
Normal file
@ -0,0 +1,33 @@
|
||||
using MoonWorks;
|
||||
|
||||
namespace MoonWorksDearImGuiScaffold;
|
||||
|
||||
class Program
|
||||
{
|
||||
static void Main(string[] args)
|
||||
{
|
||||
WindowCreateInfo windowCreateInfo = new WindowCreateInfo
|
||||
{
|
||||
WindowWidth = 1280,
|
||||
WindowHeight = 720,
|
||||
WindowTitle = "MoonWorksDearImGuiScaffold",
|
||||
ScreenMode = ScreenMode.Windowed,
|
||||
PresentMode = PresentMode.FIFORelaxed,
|
||||
SystemResizable = true
|
||||
};
|
||||
|
||||
FrameLimiterSettings frameLimiterSettings = new FrameLimiterSettings
|
||||
{
|
||||
Mode = FrameLimiterMode.Capped,
|
||||
Cap = 60
|
||||
};
|
||||
|
||||
MoonWorksDearImGuiScaffoldGame game = new MoonWorksDearImGuiScaffoldGame(
|
||||
windowCreateInfo,
|
||||
frameLimiterSettings,
|
||||
true
|
||||
);
|
||||
|
||||
game.Run();
|
||||
}
|
||||
}
|
13
src/Shaders/ImGui.frag
Normal file
13
src/Shaders/ImGui.frag
Normal file
@ -0,0 +1,13 @@
|
||||
#version 450
|
||||
|
||||
layout(set = 1, binding = 0) uniform sampler2D tex;
|
||||
|
||||
layout(location = 0) in vec2 inTexCoord;
|
||||
layout(location = 1) in vec4 inColor;
|
||||
|
||||
layout(location = 0) out vec4 outColor;
|
||||
|
||||
void main()
|
||||
{
|
||||
outColor = texture(tex, inTexCoord) * inColor;
|
||||
}
|
19
src/Shaders/ImGui.vert
Normal file
19
src/Shaders/ImGui.vert
Normal file
@ -0,0 +1,19 @@
|
||||
#version 450
|
||||
|
||||
layout(location = 0) in vec2 inPosition;
|
||||
layout(location = 1) in vec2 inTexCoord;
|
||||
layout(location = 2) in vec4 inColor;
|
||||
|
||||
layout (set = 2, binding = 0) uniform UniformBlock
|
||||
{
|
||||
mat4 projectionMatrix;
|
||||
} Uniforms;
|
||||
|
||||
layout(location = 0) out vec2 outTexCoord;
|
||||
layout(location = 1) out vec4 outColor;
|
||||
|
||||
void main() {
|
||||
gl_Position = Uniforms.projectionMatrix * vec4(inPosition, 0.0, 1.0);
|
||||
outTexCoord = inTexCoord;
|
||||
outColor = inColor;
|
||||
}
|
29
src/Structs.cs
Normal file
29
src/Structs.cs
Normal file
@ -0,0 +1,29 @@
|
||||
using MoonWorks.Graphics;
|
||||
using MoonWorks.Math.Float;
|
||||
|
||||
namespace MoonWorksDearImGuiScaffold;
|
||||
|
||||
public struct Position2DTextureColorVertex : IVertexType
|
||||
{
|
||||
public Vector2 Position;
|
||||
public Vector2 TexCoord;
|
||||
public Color Color;
|
||||
|
||||
public Position2DTextureColorVertex(
|
||||
Vector2 position,
|
||||
Vector2 texcoord,
|
||||
Color color
|
||||
)
|
||||
{
|
||||
Position = position;
|
||||
TexCoord = texcoord;
|
||||
Color = color;
|
||||
}
|
||||
|
||||
public static VertexElementFormat[] Formats { get; } = new VertexElementFormat[3]
|
||||
{
|
||||
VertexElementFormat.Vector2,
|
||||
VertexElementFormat.Vector2,
|
||||
VertexElementFormat.Color
|
||||
};
|
||||
}
|
37
src/TextureStorage.cs
Normal file
37
src/TextureStorage.cs
Normal file
@ -0,0 +1,37 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using MoonWorks.Graphics;
|
||||
|
||||
namespace MoonWorksDearImGuiScaffold;
|
||||
|
||||
public class TextureStorage
|
||||
{
|
||||
Dictionary<IntPtr, WeakReference<Texture>> PointerToTexture = new Dictionary<IntPtr, WeakReference<Texture>>();
|
||||
|
||||
public IntPtr Add(Texture texture)
|
||||
{
|
||||
if (!PointerToTexture.ContainsKey(texture.Handle))
|
||||
{
|
||||
PointerToTexture.Add(texture.Handle, new WeakReference<Texture>(texture));
|
||||
}
|
||||
return texture.Handle;
|
||||
}
|
||||
|
||||
public Texture GetTexture(IntPtr pointer)
|
||||
{
|
||||
if (!PointerToTexture.ContainsKey(pointer))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var result = PointerToTexture[pointer];
|
||||
|
||||
if (!result.TryGetTarget(out var texture))
|
||||
{
|
||||
PointerToTexture.Remove(pointer);
|
||||
return null;
|
||||
}
|
||||
|
||||
return texture;
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user