Fork of mellinoe/ImGui.NET, an ImGui wrapper for .NET, which includes access to internal functions.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

443 lines
17 KiB

using OpenTK;
using OpenTK.Graphics;
using OpenTK.Graphics.OpenGL;
using OpenTK.Input;
using System;
using System.Runtime.InteropServices;
using System.Threading;
#if NETFRAMEWORK
using System.Drawing;
#endif
namespace ImGuiNET
{
public class SampleWindow
{
private NativeWindow _nativeWindow;
private GraphicsContext _graphicsContext;
private int s_fontTexture;
private int _pressCount;
private IntPtr _textInputBuffer;
private int _textInputBufferLength;
private float _wheelPosition;
private float _sliderVal;
private System.Numerics.Vector4 _buttonColor = new System.Numerics.Vector4(55f / 255f, 155f / 255f, 1f, 1f);
private bool _mainWindowOpened;
private static double s_desiredFrameLength = 1f / 60.0f;
private DateTime _previousFrameStartTime;
private float _scaleFactor;
private System.Numerics.Vector3 _positionValue = new System.Numerics.Vector3(500);
private MemoryEditor _memoryEditor = new MemoryEditor();
private byte[] _memoryEditorData;
public unsafe SampleWindow()
{
int desiredWidth = 960, desiredHeight = 540;
_nativeWindow = new NativeWindow(desiredWidth, desiredHeight, "ImGui.NET", GameWindowFlags.Default, OpenTK.Graphics.GraphicsMode.Default, DisplayDevice.Default);
_scaleFactor = _nativeWindow.Width / desiredWidth;
GraphicsContextFlags flags = GraphicsContextFlags.Default;
_graphicsContext = new GraphicsContext(GraphicsMode.Default, _nativeWindow.WindowInfo, 3, 0, flags);
_graphicsContext.MakeCurrent(_nativeWindow.WindowInfo);
((IGraphicsContextInternal)_graphicsContext).LoadAll(); // wtf is this?
GL.ClearColor(Color.Black);
_nativeWindow.Visible = true;
_nativeWindow.X = _nativeWindow.X; // Work around OpenTK bug (?) on Ubuntu.
_nativeWindow.KeyDown += OnKeyDown;
_nativeWindow.KeyUp += OnKeyUp;
_nativeWindow.KeyPress += OnKeyPress;
ImGui.GetIO().FontAtlas.AddDefaultFont();
SetOpenTKKeyMappings();
_textInputBufferLength = 1024;
_textInputBuffer = Marshal.AllocHGlobal(_textInputBufferLength);
long* ptr = (long*)_textInputBuffer.ToPointer();
for (int i = 0; i < 1024 / sizeof(long); i++)
{
ptr[i] = 0;
}
_memoryEditorData = new byte[1024];
var rnd = new Random();
for (int i = 0; i < _memoryEditorData.Length; i++)
{
_memoryEditorData[i] = (byte) rnd.Next(255);
}
CreateDeviceObjects();
}
private void OnKeyPress(object sender, KeyPressEventArgs e)
{
Console.Write("Char typed: " + e.KeyChar);
ImGui.AddInputCharacter(e.KeyChar);
}
private static unsafe void SetOpenTKKeyMappings()
{
IO io = ImGui.GetIO();
io.KeyMap[GuiKey.Tab] = (int)Key.Tab;
io.KeyMap[GuiKey.LeftArrow] = (int)Key.Left;
io.KeyMap[GuiKey.RightArrow] = (int)Key.Right;
io.KeyMap[GuiKey.UpArrow] = (int)Key.Up;
io.KeyMap[GuiKey.DownArrow] = (int)Key.Down;
io.KeyMap[GuiKey.PageUp] = (int)Key.PageUp;
io.KeyMap[GuiKey.PageDown] = (int)Key.PageDown;
io.KeyMap[GuiKey.Home] = (int)Key.Home;
io.KeyMap[GuiKey.End] = (int)Key.End;
io.KeyMap[GuiKey.Delete] = (int)Key.Delete;
io.KeyMap[GuiKey.Backspace] = (int)Key.BackSpace;
io.KeyMap[GuiKey.Enter] = (int)Key.Enter;
io.KeyMap[GuiKey.Escape] = (int)Key.Escape;
io.KeyMap[GuiKey.A] = (int)Key.A;
io.KeyMap[GuiKey.C] = (int)Key.C;
io.KeyMap[GuiKey.V] = (int)Key.V;
io.KeyMap[GuiKey.X] = (int)Key.X;
io.KeyMap[GuiKey.Y] = (int)Key.Y;
io.KeyMap[GuiKey.Z] = (int)Key.Z;
}
private unsafe void OnKeyDown(object sender, KeyboardKeyEventArgs e)
{
ImGui.GetIO().KeysDown[(int)e.Key] = true;
UpdateModifiers(e);
}
private unsafe void OnKeyUp(object sender, KeyboardKeyEventArgs e)
{
ImGui.GetIO().KeysDown[(int)e.Key] = false;
UpdateModifiers(e);
}
private static unsafe void UpdateModifiers(KeyboardKeyEventArgs e)
{
IO io = ImGui.GetIO();
io.AltPressed = e.Alt;
io.CtrlPressed = e.Control;
io.ShiftPressed = e.Shift;
}
private unsafe void CreateDeviceObjects()
{
IO io = ImGui.GetIO();
// Build texture atlas
FontTextureData texData = io.FontAtlas.GetTexDataAsAlpha8();
// Create OpenGL texture
s_fontTexture = GL.GenTexture();
GL.BindTexture(TextureTarget.Texture2D, s_fontTexture);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)All.Linear);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)All.Linear);
GL.TexImage2D(
TextureTarget.Texture2D,
0,
PixelInternalFormat.Alpha,
texData.Width,
texData.Height,
0,
PixelFormat.Alpha,
PixelType.UnsignedByte,
new IntPtr(texData.Pixels));
// Store the texture identifier in the ImFontAtlas substructure.
io.FontAtlas.SetTexID(s_fontTexture);
// Cleanup (don't clear the input data if you want to append new fonts later)
//io.Fonts->ClearInputData();
io.FontAtlas.ClearTexData();
GL.BindTexture(TextureTarget.Texture2D, 0);
}
public void RunWindowLoop()
{
_nativeWindow.Visible = true;
while (_nativeWindow.Visible)
{
_previousFrameStartTime = DateTime.UtcNow;
RenderFrame();
_nativeWindow.ProcessEvents();
DateTime afterFrameTime = DateTime.UtcNow;
double elapsed = (afterFrameTime - _previousFrameStartTime).TotalSeconds;
double sleepTime = s_desiredFrameLength - elapsed;
if (sleepTime > 0.0)
{
DateTime finishTime = afterFrameTime + TimeSpan.FromSeconds(sleepTime);
while (DateTime.UtcNow < finishTime)
{
Thread.Sleep(0);
}
}
}
}
private unsafe void RenderFrame()
{
IO io = ImGui.GetIO();
io.DisplaySize = new System.Numerics.Vector2(_nativeWindow.Width, _nativeWindow.Height);
io.DisplayFramebufferScale = new System.Numerics.Vector2(_scaleFactor);
io.DeltaTime = (1f / 60f);
UpdateImGuiInput(io);
ImGui.NewFrame();
SubmitImGuiStuff();
ImGui.Render();
DrawData* data = ImGui.GetDrawData();
RenderImDrawData(data);
}
private unsafe void SubmitImGuiStuff()
{
ImGui.GetStyle().WindowRounding = 0;
ImGui.SetNextWindowSize(new System.Numerics.Vector2(_nativeWindow.Width - 10, _nativeWindow.Height - 20), SetCondition.Always);
ImGui.SetNextWindowPosCenter(SetCondition.Always);
ImGui.BeginWindow("ImGUI.NET Sample Program", ref _mainWindowOpened, WindowFlags.NoResize | WindowFlags.NoTitleBar | WindowFlags.NoMove);
ImGui.BeginMainMenuBar();
if (ImGui.BeginMenu("Help"))
{
if (ImGui.MenuItem("About", "Ctrl-Alt-A", false, true))
{
}
ImGui.EndMenu();
}
ImGui.EndMainMenuBar();
ImGui.Text("Hello,");
ImGui.Text("World!");
ImGui.Text("From ImGui.NET. ...Did that work?");
var pos = ImGui.GetIO().MousePosition;
bool leftPressed = ImGui.GetIO().MouseDown[0];
ImGui.Text("Current mouse position: " + pos + ". Pressed=" + leftPressed);
if (ImGui.Button("Increment the counter."))
{
_pressCount += 1;
}
ImGui.Text($"Button pressed {_pressCount} times.", new System.Numerics.Vector4(0, 1, 1, 1));
ImGui.InputTextMultiline("Input some text:",
_textInputBuffer, (uint)_textInputBufferLength,
new System.Numerics.Vector2(360, 240),
InputTextFlags.Default,
OnTextEdited);
ImGui.SliderFloat("SlidableValue", ref _sliderVal, -50f, 100f, $"{_sliderVal.ToString("##0.00")}", 1.0f);
ImGui.DragVector3("Vector3", ref _positionValue, -100, 100);
if (ImGui.TreeNode("First Item"))
{
ImGui.Text("Word!");
ImGui.TreePop();
}
if (ImGui.TreeNode("Second Item"))
{
ImGui.ColorButton(_buttonColor, false, true);
if (ImGui.Button("Push me to change color", new System.Numerics.Vector2(120, 30)))
{
_buttonColor = new System.Numerics.Vector4(_buttonColor.Y + .25f, _buttonColor.Z, _buttonColor.X, _buttonColor.W);
if (_buttonColor.X > 1.0f)
{
_buttonColor.X -= 1.0f;
}
}
ImGui.TreePop();
}
if (ImGui.Button("Press me!", new System.Numerics.Vector2(100, 30)))
{
ImGuiNative.igOpenPopup("SmallButtonPopup");
}
if (ImGui.BeginPopup("SmallButtonPopup"))
{
ImGui.Text("Here's a popup menu.");
ImGui.Text("With two lines.");
ImGui.EndPopup();
}
if (ImGui.Button("Open Modal window"))
{
ImGui.OpenPopup("ModalPopup");
}
if (ImGui.BeginPopupModal("ModalPopup"))
{
ImGui.Text("You can't press on anything else right now.");
ImGui.Text("You are stuck here.");
if (ImGui.Button("OK", new System.Numerics.Vector2(0, 0))) { }
ImGui.SameLine();
ImGui.Dummy(100f, 0f);
ImGui.SameLine();
if (ImGui.Button("Please go away", new System.Numerics.Vector2(0, 0))) { ImGui.CloseCurrentPopup(); }
ImGui.EndPopup();
}
ImGui.Text("I have a context menu.");
if (ImGui.BeginPopupContextItem("ItemContextMenu"))
{
if (ImGui.Selectable("How's this for a great menu?")) { }
ImGui.Selectable("Just click somewhere to get rid of me.");
ImGui.EndPopup();
}
ImGui.EndWindow();
_memoryEditor.Draw("Memory editor", _memoryEditorData, _memoryEditorData.Length);
if (ImGui.GetIO().AltPressed && ImGui.GetIO().KeysDown[(int)Key.F4])
{
_nativeWindow.Close();
}
}
private unsafe int OnTextEdited(TextEditCallbackData* data)
{
char currentEventChar = (char)data->EventChar;
return 0;
}
private unsafe void UpdateImGuiInput(IO io)
{
MouseState cursorState = Mouse.GetCursorState();
MouseState mouseState = Mouse.GetState();
if (_nativeWindow.Focused)
{
Point windowPoint = _nativeWindow.PointToClient(new Point(cursorState.X, cursorState.Y));
io.MousePosition = new System.Numerics.Vector2(windowPoint.X / io.DisplayFramebufferScale.X, windowPoint.Y / io.DisplayFramebufferScale.Y);
}
else
{
io.MousePosition = new System.Numerics.Vector2(-1f, -1f);
}
io.MouseDown[0] = mouseState.LeftButton == ButtonState.Pressed;
io.MouseDown[1] = mouseState.RightButton == ButtonState.Pressed;
io.MouseDown[2] = mouseState.MiddleButton == ButtonState.Pressed;
float newWheelPos = mouseState.WheelPrecise;
float delta = newWheelPos - _wheelPosition;
_wheelPosition = newWheelPos;
io.MouseWheel = delta;
}
private unsafe void RenderImDrawData(DrawData* draw_data)
{
// Rendering
int display_w, display_h;
display_w = _nativeWindow.Width;
display_h = _nativeWindow.Height;
Vector4 clear_color = new Vector4(114f / 255f, 144f / 255f, 154f / 255f, 1.0f);
GL.Viewport(0, 0, display_w, display_h);
GL.ClearColor(clear_color.X, clear_color.Y, clear_color.Z, clear_color.W);
GL.Clear(ClearBufferMask.ColorBufferBit);
// We are using the OpenGL fixed pipeline to make the example code simpler to read!
// Setup render state: alpha-blending enabled, no face culling, no depth testing, scissor enabled, vertex/texcoord/color pointers.
int last_texture;
GL.GetInteger(GetPName.TextureBinding2D, out last_texture);
GL.PushAttrib(AttribMask.EnableBit | AttribMask.ColorBufferBit | AttribMask.TransformBit);
GL.Enable(EnableCap.Blend);
GL.BlendFunc(BlendingFactorSrc.SrcAlpha, BlendingFactorDest.OneMinusSrcAlpha);
GL.Disable(EnableCap.CullFace);
GL.Disable(EnableCap.DepthTest);
GL.Enable(EnableCap.ScissorTest);
GL.EnableClientState(ArrayCap.VertexArray);
GL.EnableClientState(ArrayCap.TextureCoordArray);
GL.EnableClientState(ArrayCap.ColorArray);
GL.Enable(EnableCap.Texture2D);
GL.UseProgram(0);
// Handle cases of screen coordinates != from framebuffer coordinates (e.g. retina displays)
IO io = ImGui.GetIO();
ImGui.ScaleClipRects(draw_data, io.DisplayFramebufferScale);
// Setup orthographic projection matrix
GL.MatrixMode(MatrixMode.Projection);
GL.PushMatrix();
GL.LoadIdentity();
GL.Ortho(
0.0f,
io.DisplaySize.X / io.DisplayFramebufferScale.X,
io.DisplaySize.Y / io.DisplayFramebufferScale.Y,
0.0f,
-1.0f,
1.0f);
GL.MatrixMode(MatrixMode.Modelview);
GL.PushMatrix();
GL.LoadIdentity();
// Render command lists
for (int n = 0; n < draw_data->CmdListsCount; n++)
{
NativeDrawList* cmd_list = draw_data->CmdLists[n];
byte* vtx_buffer = (byte*)cmd_list->VtxBuffer.Data;
ushort* idx_buffer = (ushort*)cmd_list->IdxBuffer.Data;
DrawVert vert0 = *((DrawVert*)vtx_buffer);
DrawVert vert1 = *(((DrawVert*)vtx_buffer) + 1);
DrawVert vert2 = *(((DrawVert*)vtx_buffer) + 2);
GL.VertexPointer(2, VertexPointerType.Float, sizeof(DrawVert), new IntPtr(vtx_buffer + DrawVert.PosOffset));
GL.TexCoordPointer(2, TexCoordPointerType.Float, sizeof(DrawVert), new IntPtr(vtx_buffer + DrawVert.UVOffset));
GL.ColorPointer(4, ColorPointerType.UnsignedByte, sizeof(DrawVert), new IntPtr(vtx_buffer + DrawVert.ColOffset));
for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++)
{
DrawCmd* pcmd = &(((DrawCmd*)cmd_list->CmdBuffer.Data)[cmd_i]);
if (pcmd->UserCallback != IntPtr.Zero)
{
throw new NotImplementedException();
}
else
{
GL.BindTexture(TextureTarget.Texture2D, pcmd->TextureId.ToInt32());
GL.Scissor(
(int)pcmd->ClipRect.X,
(int)(io.DisplaySize.Y - pcmd->ClipRect.W),
(int)(pcmd->ClipRect.Z - pcmd->ClipRect.X),
(int)(pcmd->ClipRect.W - pcmd->ClipRect.Y));
ushort[] indices = new ushort[pcmd->ElemCount];
for (int i = 0; i < indices.Length; i++) { indices[i] = idx_buffer[i]; }
GL.DrawElements(PrimitiveType.Triangles, (int)pcmd->ElemCount, DrawElementsType.UnsignedShort, new IntPtr(idx_buffer));
}
idx_buffer += pcmd->ElemCount;
}
}
// Restore modified state
GL.DisableClientState(ArrayCap.ColorArray);
GL.DisableClientState(ArrayCap.TextureCoordArray);
GL.DisableClientState(ArrayCap.VertexArray);
GL.BindTexture(TextureTarget.Texture2D, last_texture);
GL.MatrixMode(MatrixMode.Modelview);
GL.PopMatrix();
GL.MatrixMode(MatrixMode.Projection);
GL.PopMatrix();
GL.PopAttrib();
_graphicsContext.SwapBuffers();
}
}
}