diff --git a/Dear ImGui Sample/ImGuiController.cs b/Dear ImGui Sample/ImGuiController.cs
index 36c2188..50f31af 100644
--- a/Dear ImGui Sample/ImGuiController.cs
+++ b/Dear ImGui Sample/ImGuiController.cs
@@ -7,6 +7,8 @@
using OpenTK.Windowing.Common.Input;
using OpenTK.Windowing.Desktop;
using OpenTK.Windowing.GraphicsLibraryFramework;
+using System.Diagnostics;
+using ErrorCode = OpenTK.Graphics.OpenGL4.ErrorCode;
namespace Dear_ImGui_Sample
{
@@ -20,14 +22,21 @@ public class ImGuiController : IDisposable
private int _indexBuffer;
private int _indexBufferSize;
- private Texture _fontTexture;
- private Shader _shader;
+ //private Texture _fontTexture;
+
+ private int _fontTexture;
+
+ private int _shader;
+ private int _shaderFontTextureLocation;
+ private int _shaderProjectionMatrixLocation;
private int _windowWidth;
private int _windowHeight;
private System.Numerics.Vector2 _scaleFactor = System.Numerics.Vector2.One;
+ private static bool KHRDebugAvailable = false;
+
///
/// Constructs a new ImGuiController.
///
@@ -36,6 +45,11 @@ public ImGuiController(int width, int height)
_windowWidth = width;
_windowHeight = height;
+ int major = GL.GetInteger(GetPName.MajorVersion);
+ int minor = GL.GetInteger(GetPName.MinorVersion);
+
+ KHRDebugAvailable = (major == 4 && minor >= 3) || IsExtensionSupported("KHR_debug");
+
IntPtr context = ImGui.CreateContext();
ImGui.SetCurrentContext(context);
var io = ImGui.GetIO();
@@ -65,15 +79,25 @@ public void DestroyDeviceObjects()
public void CreateDeviceResources()
{
- Util.CreateVertexArray("ImGui", out _vertexArray);
-
_vertexBufferSize = 10000;
_indexBufferSize = 2000;
- Util.CreateVertexBuffer("ImGui", out _vertexBuffer);
- Util.CreateElementBuffer("ImGui", out _indexBuffer);
- GL.NamedBufferData(_vertexBuffer, _vertexBufferSize, IntPtr.Zero, BufferUsageHint.DynamicDraw);
- GL.NamedBufferData(_indexBuffer, _indexBufferSize, IntPtr.Zero, BufferUsageHint.DynamicDraw);
+ int prevVAO = GL.GetInteger(GetPName.VertexArrayBinding);
+ int prevArrayBuffer = GL.GetInteger(GetPName.ArrayBufferBinding);
+
+ _vertexArray = GL.GenVertexArray();
+ GL.BindVertexArray(_vertexArray);
+ LabelObject(ObjectLabelIdentifier.VertexArray, _vertexArray, "ImGui");
+
+ _vertexBuffer = GL.GenBuffer();
+ GL.BindBuffer(BufferTarget.ArrayBuffer, _vertexBuffer);
+ LabelObject(ObjectLabelIdentifier.Buffer, _vertexBuffer, "VBO: ImGui");
+ GL.BufferData(BufferTarget.ArrayBuffer, _vertexBufferSize, IntPtr.Zero, BufferUsageHint.DynamicDraw);
+
+ _indexBuffer = GL.GenBuffer();
+ GL.BindBuffer(BufferTarget.ElementArrayBuffer, _indexBuffer);
+ LabelObject(ObjectLabelIdentifier.Buffer, _indexBuffer, "EBO: ImGui");
+ GL.BufferData(BufferTarget.ElementArrayBuffer, _indexBufferSize, IntPtr.Zero, BufferUsageHint.DynamicDraw);
RecreateFontDeviceTexture();
@@ -107,24 +131,24 @@ void main()
{
outputColor = color * texture(in_fontTexture, texCoord);
}";
- _shader = new Shader("ImGui", VertexSource, FragmentSource);
- GL.VertexArrayVertexBuffer(_vertexArray, 0, _vertexBuffer, IntPtr.Zero, Unsafe.SizeOf());
- GL.VertexArrayElementBuffer(_vertexArray, _indexBuffer);
+ _shader = CreateProgram("ImGui", VertexSource, FragmentSource);
+ _shaderProjectionMatrixLocation = GL.GetUniformLocation(_shader, "projection_matrix");
+ _shaderFontTextureLocation = GL.GetUniformLocation(_shader, "in_fontTexture");
- GL.EnableVertexArrayAttrib(_vertexArray, 0);
- GL.VertexArrayAttribBinding(_vertexArray, 0, 0);
- GL.VertexArrayAttribFormat(_vertexArray, 0, 2, VertexAttribType.Float, false, 0);
+ int stride = Unsafe.SizeOf();
+ GL.VertexAttribPointer(0, 2, VertexAttribPointerType.Float, false, stride, 0);
+ GL.VertexAttribPointer(1, 2, VertexAttribPointerType.Float, false, stride, 8);
+ GL.VertexAttribPointer(2, 4, VertexAttribPointerType.UnsignedByte, true, stride, 16);
- GL.EnableVertexArrayAttrib(_vertexArray, 1);
- GL.VertexArrayAttribBinding(_vertexArray, 1, 0);
- GL.VertexArrayAttribFormat(_vertexArray, 1, 2, VertexAttribType.Float, false, 8);
+ GL.EnableVertexAttribArray(0);
+ GL.EnableVertexAttribArray(1);
+ GL.EnableVertexAttribArray(2);
- GL.EnableVertexArrayAttrib(_vertexArray, 2);
- GL.VertexArrayAttribBinding(_vertexArray, 2, 0);
- GL.VertexArrayAttribFormat(_vertexArray, 2, 4, VertexAttribType.UnsignedByte, true, 16);
+ GL.BindVertexArray(prevVAO);
+ GL.BindBuffer(BufferTarget.ArrayBuffer, prevArrayBuffer);
- Util.CheckGLError("End of ImGui setup");
+ CheckGLError("End of ImGui setup");
}
///
@@ -135,11 +159,34 @@ public void RecreateFontDeviceTexture()
ImGuiIOPtr io = ImGui.GetIO();
io.Fonts.GetTexDataAsRGBA32(out IntPtr pixels, out int width, out int height, out int bytesPerPixel);
- _fontTexture = new Texture("ImGui Text Atlas", width, height, pixels);
- _fontTexture.SetMagFilter(TextureMagFilter.Linear);
- _fontTexture.SetMinFilter(TextureMinFilter.Linear);
-
- io.Fonts.SetTexID((IntPtr)_fontTexture.GLTexture);
+ int mips = (int)Math.Floor(Math.Log(Math.Max(width, height), 2));
+
+ int prevActiveTexture = GL.GetInteger(GetPName.ActiveTexture);
+ GL.ActiveTexture(0);
+ int prevTexture2D = GL.GetInteger(GetPName.Texture2D);
+
+ _fontTexture = GL.GenTexture();
+ GL.BindTexture(TextureTarget.Texture2D, _fontTexture);
+ GL.TexStorage2D(TextureTarget2d.Texture2D, mips, SizedInternalFormat.Rgba8, width, height);
+ LabelObject(ObjectLabelIdentifier.Texture, _fontTexture, "ImGui Text Atlas");
+
+ GL.TexSubImage2D(TextureTarget.Texture2D, 0, 0, 0, width, height, PixelFormat.Bgra, PixelType.UnsignedByte, pixels);
+
+ GL.GenerateMipmap(GenerateMipmapTarget.Texture2D);
+
+ GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (int)TextureWrapMode.Repeat);
+ GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int)TextureWrapMode.Repeat);
+
+ GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMaxLevel, mips - 1);
+
+ GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Linear);
+ GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Linear);
+
+ // Restore state
+ GL.BindTexture(TextureTarget.Texture2D, prevTexture2D);
+ GL.ActiveTexture((TextureUnit)prevActiveTexture);
+
+ io.Fonts.SetTexID((IntPtr)_fontTexture);
io.Fonts.ClearTexData();
}
@@ -270,6 +317,36 @@ private void RenderImDrawData(ImDrawDataPtr draw_data)
return;
}
+ // Get intial state.
+ int prevVAO = GL.GetInteger(GetPName.VertexArrayBinding);
+ int prevArrayBuffer = GL.GetInteger(GetPName.ArrayBufferBinding);
+ int prevProgram = GL.GetInteger(GetPName.CurrentProgram);
+ bool prevBlendEnabled = GL.GetBoolean(GetPName.Blend);
+ bool prevScissorTestEnabled = GL.GetBoolean(GetPName.ScissorTest);
+ int prevBlendEquationRgb = GL.GetInteger(GetPName.BlendEquationRgb);
+ int prevBlendEquationAlpha = GL.GetInteger(GetPName.BlendEquationAlpha);
+ int prevBlendFuncSrcRgb = GL.GetInteger(GetPName.BlendSrcRgb);
+ int prevBlendFuncSrcAlpha = GL.GetInteger(GetPName.BlendSrcAlpha);
+ int prevBlendFuncDstRgb = GL.GetInteger(GetPName.BlendDstRgb);
+ int prevBlendFuncDstAlpha = GL.GetInteger(GetPName.BlendDstAlpha);
+ bool prevCullFaceEnabled = GL.GetBoolean(GetPName.CullFace);
+ bool prevDepthTestEnabled = GL.GetBoolean(GetPName.DepthTest);
+ int prevActiveTexture = GL.GetInteger(GetPName.ActiveTexture);
+ GL.ActiveTexture(TextureUnit.Texture0);
+ int prevTexture2D = GL.GetInteger(GetPName.Texture2D);
+ Span prevScissorBox = stackalloc int[4];
+ unsafe
+ {
+ fixed (int* iptr = &prevScissorBox[0])
+ {
+ GL.GetInteger(GetPName.ScissorBox, iptr);
+ }
+ }
+
+ // Bind the element buffer (thru the VAO) so that we can resize it.
+ GL.BindVertexArray(_vertexArray);
+ // Bind the vertex buffer so that we can resize it.
+ GL.BindBuffer(BufferTarget.ArrayBuffer, _vertexBuffer);
for (int i = 0; i < draw_data.CmdListsCount; i++)
{
ImDrawListPtr cmd_list = draw_data.CmdListsRange[i];
@@ -278,7 +355,8 @@ private void RenderImDrawData(ImDrawDataPtr draw_data)
if (vertexSize > _vertexBufferSize)
{
int newSize = (int)Math.Max(_vertexBufferSize * 1.5f, vertexSize);
- GL.NamedBufferData(_vertexBuffer, newSize, IntPtr.Zero, BufferUsageHint.DynamicDraw);
+
+ GL.BufferData(BufferTarget.ArrayBuffer, newSize, IntPtr.Zero, BufferUsageHint.DynamicDraw);
_vertexBufferSize = newSize;
Console.WriteLine($"Resized dear imgui vertex buffer to new size {_vertexBufferSize}");
@@ -288,7 +366,7 @@ private void RenderImDrawData(ImDrawDataPtr draw_data)
if (indexSize > _indexBufferSize)
{
int newSize = (int)Math.Max(_indexBufferSize * 1.5f, indexSize);
- GL.NamedBufferData(_indexBuffer, newSize, IntPtr.Zero, BufferUsageHint.DynamicDraw);
+ GL.BufferData(BufferTarget.ElementArrayBuffer, newSize, IntPtr.Zero, BufferUsageHint.DynamicDraw);
_indexBufferSize = newSize;
Console.WriteLine($"Resized dear imgui index buffer to new size {_indexBufferSize}");
@@ -305,13 +383,13 @@ private void RenderImDrawData(ImDrawDataPtr draw_data)
-1.0f,
1.0f);
- _shader.UseShader();
- GL.UniformMatrix4(_shader.GetUniformLocation("projection_matrix"), false, ref mvp);
- GL.Uniform1(_shader.GetUniformLocation("in_fontTexture"), 0);
- Util.CheckGLError("Projection");
+ GL.UseProgram(_shader);
+ GL.UniformMatrix4(_shaderProjectionMatrixLocation, false, ref mvp);
+ GL.Uniform1(_shaderFontTextureLocation, 0);
+ CheckGLError("Projection");
GL.BindVertexArray(_vertexArray);
- Util.CheckGLError("VAO");
+ CheckGLError("VAO");
draw_data.ScaleClipRects(io.DisplayFramebufferScale);
@@ -327,11 +405,11 @@ private void RenderImDrawData(ImDrawDataPtr draw_data)
{
ImDrawListPtr cmd_list = draw_data.CmdListsRange[n];
- GL.NamedBufferSubData(_vertexBuffer, IntPtr.Zero, cmd_list.VtxBuffer.Size * Unsafe.SizeOf(), cmd_list.VtxBuffer.Data);
- Util.CheckGLError($"Data Vert {n}");
+ GL.BufferSubData(BufferTarget.ArrayBuffer, IntPtr.Zero, cmd_list.VtxBuffer.Size * Unsafe.SizeOf(), cmd_list.VtxBuffer.Data);
+ CheckGLError($"Data Vert {n}");
- GL.NamedBufferSubData(_indexBuffer, IntPtr.Zero, cmd_list.IdxBuffer.Size * sizeof(ushort), cmd_list.IdxBuffer.Data);
- Util.CheckGLError($"Data Idx {n}");
+ GL.BufferSubData(BufferTarget.ElementArrayBuffer, IntPtr.Zero, cmd_list.IdxBuffer.Size * sizeof(ushort), cmd_list.IdxBuffer.Data);
+ CheckGLError($"Data Idx {n}");
for (int cmd_i = 0; cmd_i < cmd_list.CmdBuffer.Size; cmd_i++)
{
@@ -344,28 +422,46 @@ private void RenderImDrawData(ImDrawDataPtr draw_data)
{
GL.ActiveTexture(TextureUnit.Texture0);
GL.BindTexture(TextureTarget.Texture2D, (int)pcmd.TextureId);
- Util.CheckGLError("Texture");
+ CheckGLError("Texture");
// We do _windowHeight - (int)clip.W instead of (int)clip.Y because gl has flipped Y when it comes to these coordinates
var clip = pcmd.ClipRect;
GL.Scissor((int)clip.X, _windowHeight - (int)clip.W, (int)(clip.Z - clip.X), (int)(clip.W - clip.Y));
- Util.CheckGLError("Scissor");
+ CheckGLError("Scissor");
if ((io.BackendFlags & ImGuiBackendFlags.RendererHasVtxOffset) != 0)
{
- GL.DrawElementsBaseVertex(PrimitiveType.Triangles, (int)pcmd.ElemCount, DrawElementsType.UnsignedShort, (IntPtr)(pcmd.IdxOffset * sizeof(ushort)), (int)pcmd.VtxOffset);
+ GL.DrawElementsBaseVertex(PrimitiveType.Triangles, (int)pcmd.ElemCount, DrawElementsType.UnsignedShort, (IntPtr)(pcmd.IdxOffset * sizeof(ushort)), unchecked((int)pcmd.VtxOffset));
}
else
{
GL.DrawElements(BeginMode.Triangles, (int)pcmd.ElemCount, DrawElementsType.UnsignedShort, (int)pcmd.IdxOffset * sizeof(ushort));
}
- Util.CheckGLError("Draw");
+ CheckGLError("Draw");
}
}
}
GL.Disable(EnableCap.Blend);
GL.Disable(EnableCap.ScissorTest);
+
+ // Reset state
+ GL.BindTexture(TextureTarget.Texture2D, prevTexture2D);
+ GL.ActiveTexture((TextureUnit)prevActiveTexture);
+ GL.UseProgram(prevProgram);
+ GL.BindVertexArray(prevVAO);
+ GL.Scissor(prevScissorBox[0], prevScissorBox[1], prevScissorBox[2], prevScissorBox[3]);
+ GL.BindBuffer(BufferTarget.ArrayBuffer, prevArrayBuffer);
+ GL.BlendEquationSeparate((BlendEquationMode)prevBlendEquationRgb, (BlendEquationMode)prevBlendEquationAlpha);
+ GL.BlendFuncSeparate(
+ (BlendingFactorSrc)prevBlendFuncSrcRgb,
+ (BlendingFactorDest)prevBlendFuncDstRgb,
+ (BlendingFactorSrc)prevBlendFuncSrcAlpha,
+ (BlendingFactorDest)prevBlendFuncDstAlpha);
+ if (prevBlendEnabled) GL.Enable(EnableCap.Blend); else GL.Disable(EnableCap.Blend);
+ if (prevDepthTestEnabled) GL.Enable(EnableCap.DepthTest); else GL.Disable(EnableCap.DepthTest);
+ if (prevCullFaceEnabled) GL.Enable(EnableCap.CullFace); else GL.Disable(EnableCap.CullFace);
+ if (prevScissorTestEnabled) GL.Enable(EnableCap.ScissorTest); else GL.Disable(EnableCap.ScissorTest);
}
///
@@ -377,8 +473,83 @@ public void Dispose()
GL.DeleteBuffer(_vertexBuffer);
GL.DeleteBuffer(_indexBuffer);
- _fontTexture.Dispose();
- _shader.Dispose();
+ GL.DeleteTexture(_fontTexture);
+ GL.DeleteProgram(_shader);
+ }
+
+ public static void LabelObject(ObjectLabelIdentifier objLabelIdent, int glObject, string name)
+ {
+ if (KHRDebugAvailable)
+ GL.ObjectLabel(objLabelIdent, glObject, name.Length, name);
+ }
+
+ static bool IsExtensionSupported(string name)
+ {
+ int n = GL.GetInteger(GetPName.NumExtensions);
+ for (int i = 0; i < n; i++)
+ {
+ string extension = GL.GetString(StringNameIndexed.Extensions, i);
+ if (extension == name) return true;
+ }
+
+ return false;
+ }
+
+ public static int CreateProgram(string name, string vertexSource, string fragmentSoruce)
+ {
+ int program = GL.CreateProgram();
+ LabelObject(ObjectLabelIdentifier.Program, program, $"Program: {name}");
+
+ int vertex = CompileShader(name, ShaderType.VertexShader, vertexSource);
+ int fragment = CompileShader(name, ShaderType.FragmentShader, fragmentSoruce);
+
+ GL.AttachShader(program, vertex);
+ GL.AttachShader(program, fragment);
+
+ GL.LinkProgram(program);
+
+ GL.GetProgram(program, GetProgramParameterName.LinkStatus, out int success);
+ if (success == 0)
+ {
+ string info = GL.GetProgramInfoLog(program);
+ Debug.WriteLine($"GL.LinkProgram had info log [{name}]:\n{info}");
+ }
+
+ GL.DetachShader(program, vertex);
+ GL.DetachShader(program, fragment);
+
+ GL.DeleteShader(vertex);
+ GL.DeleteShader(fragment);
+
+ return program;
+ }
+
+ private static int CompileShader(string name, ShaderType type, string source)
+ {
+ int shader = GL.CreateShader(type);
+ LabelObject(ObjectLabelIdentifier.Shader, shader, $"Shader: {name}");
+
+ GL.ShaderSource(shader, source);
+ GL.CompileShader(shader);
+
+ GL.GetShader(shader, ShaderParameter.CompileStatus, out int success);
+ if (success == 0)
+ {
+ string info = GL.GetShaderInfoLog(shader);
+ Debug.WriteLine($"GL.CompileShader for shader '{name}' [{type}] had info log:\n{info}");
+ }
+
+ return shader;
+ }
+
+ public static void CheckGLError(string title)
+ {
+ ErrorCode error;
+ int i = 1;
+ while ((error = GL.GetError()) != ErrorCode.NoError)
+ {
+ Debug.Print($"{title} ({i++}): {error}");
+ }
}
}
}
diff --git a/Dear ImGui Sample/Shader.cs b/Dear ImGui Sample/Shader.cs
deleted file mode 100644
index b381030..0000000
--- a/Dear ImGui Sample/Shader.cs
+++ /dev/null
@@ -1,142 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Diagnostics;
-using System.IO;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-using System.Runtime.CompilerServices;
-using System.Threading;
-using OpenTK.Graphics.OpenGL4;
-
-namespace Dear_ImGui_Sample
-{
- struct UniformFieldInfo
- {
- public int Location;
- public string Name;
- public int Size;
- public ActiveUniformType Type;
- }
-
- class Shader
- {
- public readonly string Name;
- public int Program { get; private set; }
- private readonly Dictionary UniformToLocation = new Dictionary();
- private bool Initialized = false;
-
- private readonly (ShaderType Type, string Path)[] Files;
-
- public Shader(string name, string vertexShader, string fragmentShader)
- {
- Name = name;
- Files = new[]{
- (ShaderType.VertexShader, vertexShader),
- (ShaderType.FragmentShader, fragmentShader),
- };
- Program = CreateProgram(name, Files);
- }
- public void UseShader()
- {
- GL.UseProgram(Program);
- }
-
- public void Dispose()
- {
- if (Initialized)
- {
- GL.DeleteProgram(Program);
- Initialized = false;
- }
- }
-
- public UniformFieldInfo[] GetUniforms()
- {
- GL.GetProgram(Program, GetProgramParameterName.ActiveUniforms, out int UnifromCount);
-
- UniformFieldInfo[] Uniforms = new UniformFieldInfo[UnifromCount];
-
- for (int i = 0; i < UnifromCount; i++)
- {
- string Name = GL.GetActiveUniform(Program, i, out int Size, out ActiveUniformType Type);
-
- UniformFieldInfo FieldInfo;
- FieldInfo.Location = GetUniformLocation(Name);
- FieldInfo.Name = Name;
- FieldInfo.Size = Size;
- FieldInfo.Type = Type;
-
- Uniforms[i] = FieldInfo;
- }
-
- return Uniforms;
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public int GetUniformLocation(string uniform)
- {
- if (UniformToLocation.TryGetValue(uniform, out int location) == false)
- {
- location = GL.GetUniformLocation(Program, uniform);
- UniformToLocation.Add(uniform, location);
-
- if (location == -1)
- {
- Debug.Print($"The uniform '{uniform}' does not exist in the shader '{Name}'!");
- }
- }
-
- return location;
- }
-
- private int CreateProgram(string name, params (ShaderType Type, string source)[] shaderPaths)
- {
- Util.CreateProgram(name, out int Program);
-
- int[] Shaders = new int[shaderPaths.Length];
- for (int i = 0; i < shaderPaths.Length; i++)
- {
- Shaders[i] = CompileShader(name, shaderPaths[i].Type, shaderPaths[i].source);
- }
-
- foreach (var shader in Shaders)
- GL.AttachShader(Program, shader);
-
- GL.LinkProgram(Program);
-
- GL.GetProgram(Program, GetProgramParameterName.LinkStatus, out int Success);
- if (Success == 0)
- {
- string Info = GL.GetProgramInfoLog(Program);
- Debug.WriteLine($"GL.LinkProgram had info log [{name}]:\n{Info}");
- }
-
- foreach (var Shader in Shaders)
- {
- GL.DetachShader(Program, Shader);
- GL.DeleteShader(Shader);
- }
-
- Initialized = true;
-
- return Program;
- }
-
- private int CompileShader(string name, ShaderType type, string source)
- {
- Util.CreateShader(type, name, out int Shader);
- GL.ShaderSource(Shader, source);
- GL.CompileShader(Shader);
-
- GL.GetShader(Shader, ShaderParameter.CompileStatus, out int success);
- if (success == 0)
- {
- string Info = GL.GetShaderInfoLog(Shader);
- Debug.WriteLine($"GL.CompileShader for shader '{Name}' [{type}] had info log:\n{Info}");
- }
-
- return Shader;
- }
- }
-}
diff --git a/Dear ImGui Sample/Texture.cs b/Dear ImGui Sample/Texture.cs
deleted file mode 100644
index cebf83a..0000000
--- a/Dear ImGui Sample/Texture.cs
+++ /dev/null
@@ -1,154 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Diagnostics;
-using System.Drawing;
-using System.Drawing.Imaging;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-using OpenTK.Graphics.OpenGL4;
-using PixelFormat = OpenTK.Graphics.OpenGL4.PixelFormat;
-
-namespace Dear_ImGui_Sample
-{
- public enum TextureCoordinate
- {
- S = TextureParameterName.TextureWrapS,
- T = TextureParameterName.TextureWrapT,
- R = TextureParameterName.TextureWrapR
- }
-
- class Texture : IDisposable
- {
- public const SizedInternalFormat Srgb8Alpha8 = (SizedInternalFormat)All.Srgb8Alpha8;
- public const SizedInternalFormat RGB32F = (SizedInternalFormat)All.Rgb32f;
-
- public const GetPName MAX_TEXTURE_MAX_ANISOTROPY = (GetPName)0x84FF;
-
- public static readonly float MaxAniso;
-
- static Texture()
- {
- MaxAniso = GL.GetFloat(MAX_TEXTURE_MAX_ANISOTROPY);
- }
-
- public readonly string Name;
- public readonly int GLTexture;
- public readonly int Width, Height;
- public readonly int MipmapLevels;
- public readonly SizedInternalFormat InternalFormat;
-
- public Texture(string name, Bitmap image, bool generateMipmaps, bool srgb)
- {
- Name = name;
- Width = image.Width;
- Height = image.Height;
- InternalFormat = srgb ? Srgb8Alpha8 : SizedInternalFormat.Rgba8;
-
- if (generateMipmaps)
- {
- // Calculate how many levels to generate for this texture
- MipmapLevels = (int)Math.Floor(Math.Log(Math.Max(Width, Height), 2));
- }
- else
- {
- // There is only one level
- MipmapLevels = 1;
- }
-
- Util.CheckGLError("Clear");
-
- Util.CreateTexture(TextureTarget.Texture2D, Name, out GLTexture);
- GL.TextureStorage2D(GLTexture, MipmapLevels, InternalFormat, Width, Height);
- Util.CheckGLError("Storage2d");
-
- BitmapData data = image.LockBits(new Rectangle(0, 0, Width, Height),
- ImageLockMode.ReadOnly, global::System.Drawing.Imaging.PixelFormat.Format32bppArgb);
-
- GL.TextureSubImage2D(GLTexture, 0, 0, 0, Width, Height, PixelFormat.Bgra, PixelType.UnsignedByte, data.Scan0);
- Util.CheckGLError("SubImage");
-
- image.UnlockBits(data);
-
- if (generateMipmaps) GL.GenerateTextureMipmap(GLTexture);
-
- GL.TextureParameter(GLTexture, TextureParameterName.TextureWrapS, (int)TextureWrapMode.Repeat);
- Util.CheckGLError("WrapS");
- GL.TextureParameter(GLTexture, TextureParameterName.TextureWrapT, (int)TextureWrapMode.Repeat);
- Util.CheckGLError("WrapT");
-
- GL.TextureParameter(GLTexture, TextureParameterName.TextureMinFilter, (int)(generateMipmaps ? TextureMinFilter.Linear : TextureMinFilter.LinearMipmapLinear));
- GL.TextureParameter(GLTexture, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Linear);
- Util.CheckGLError("Filtering");
-
- GL.TextureParameter(GLTexture, TextureParameterName.TextureMaxLevel, MipmapLevels - 1);
-
- // This is a bit weird to do here
- image.Dispose();
- }
-
- public Texture(string name, int GLTex, int width, int height, int mipmaplevels, SizedInternalFormat internalFormat)
- {
- Name = name;
- GLTexture = GLTex;
- Width = width;
- Height = height;
- MipmapLevels = mipmaplevels;
- InternalFormat = internalFormat;
- }
-
- public Texture(string name, int width, int height, IntPtr data, bool generateMipmaps = false, bool srgb = false)
- {
- Name = name;
- Width = width;
- Height = height;
- InternalFormat = srgb ? Srgb8Alpha8 : SizedInternalFormat.Rgba8;
- MipmapLevels = generateMipmaps == false ? 1 : (int)Math.Floor(Math.Log(Math.Max(Width, Height), 2));
-
- Util.CreateTexture(TextureTarget.Texture2D, Name, out GLTexture);
- GL.TextureStorage2D(GLTexture, MipmapLevels, InternalFormat, Width, Height);
-
- GL.TextureSubImage2D(GLTexture, 0, 0, 0, Width, Height, PixelFormat.Bgra, PixelType.UnsignedByte, data);
-
- if (generateMipmaps) GL.GenerateTextureMipmap(GLTexture);
-
- SetWrap(TextureCoordinate.S, TextureWrapMode.Repeat);
- SetWrap(TextureCoordinate.T, TextureWrapMode.Repeat);
-
- GL.TextureParameter(GLTexture, TextureParameterName.TextureMaxLevel, MipmapLevels - 1);
- }
-
- public void SetMinFilter(TextureMinFilter filter)
- {
- GL.TextureParameter(GLTexture, TextureParameterName.TextureMinFilter, (int)filter);
- }
-
- public void SetMagFilter(TextureMagFilter filter)
- {
- GL.TextureParameter(GLTexture, TextureParameterName.TextureMagFilter, (int)filter);
- }
-
- public void SetAnisotropy(float level)
- {
- const TextureParameterName TEXTURE_MAX_ANISOTROPY = (TextureParameterName)0x84FE;
- GL.TextureParameter(GLTexture, TEXTURE_MAX_ANISOTROPY, Util.Clamp(level, 1, MaxAniso));
- }
-
- public void SetLod(int @base, int min, int max)
- {
- GL.TextureParameter(GLTexture, TextureParameterName.TextureLodBias, @base);
- GL.TextureParameter(GLTexture, TextureParameterName.TextureMinLod, min);
- GL.TextureParameter(GLTexture, TextureParameterName.TextureMaxLod, max);
- }
-
- public void SetWrap(TextureCoordinate coord, TextureWrapMode mode)
- {
- GL.TextureParameter(GLTexture, (TextureParameterName)coord, (int)mode);
- }
-
- public void Dispose()
- {
- GL.DeleteTexture(GLTexture);
- }
- }
-}
diff --git a/Dear ImGui Sample/Util.cs b/Dear ImGui Sample/Util.cs
deleted file mode 100644
index f70865d..0000000
--- a/Dear ImGui Sample/Util.cs
+++ /dev/null
@@ -1,78 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Diagnostics;
-using System.Diagnostics.Contracts;
-using System.Linq;
-using System.Runtime.CompilerServices;
-using System.Text;
-using System.Threading.Tasks;
-using OpenTK.Graphics.OpenGL4;
-
-namespace Dear_ImGui_Sample
-{
- static class Util
- {
- [Pure]
- public static float Clamp(float value, float min, float max)
- {
- return value < min ? min : value > max ? max : value;
- }
-
- [Conditional("DEBUG")]
- public static void CheckGLError(string title)
- {
- var error = GL.GetError();
- if (error != ErrorCode.NoError)
- {
- Debug.Print($"{title}: {error}");
- }
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static void LabelObject(ObjectLabelIdentifier objLabelIdent, int glObject, string name)
- {
- GL.ObjectLabel(objLabelIdent, glObject, name.Length, name);
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static void CreateTexture(TextureTarget target, string Name, out int Texture)
- {
- GL.CreateTextures(target, 1, out Texture);
- LabelObject(ObjectLabelIdentifier.Texture, Texture, $"Texture: {Name}");
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static void CreateProgram(string Name, out int Program)
- {
- Program = GL.CreateProgram();
- LabelObject(ObjectLabelIdentifier.Program, Program, $"Program: {Name}");
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static void CreateShader(ShaderType type, string Name, out int Shader)
- {
- Shader = GL.CreateShader(type);
- LabelObject(ObjectLabelIdentifier.Shader, Shader, $"Shader: {type}: {Name}");
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static void CreateBuffer(string Name, out int Buffer)
- {
- GL.CreateBuffers(1, out Buffer);
- LabelObject(ObjectLabelIdentifier.Buffer, Buffer, $"Buffer: {Name}");
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static void CreateVertexBuffer(string Name, out int Buffer) => CreateBuffer($"VBO: {Name}", out Buffer);
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static void CreateElementBuffer(string Name, out int Buffer) => CreateBuffer($"EBO: {Name}", out Buffer);
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static void CreateVertexArray(string Name, out int VAO)
- {
- GL.CreateVertexArrays(1, out VAO);
- LabelObject(ObjectLabelIdentifier.VertexArray, VAO, $"VAO: {Name}");
- }
- }
-}
diff --git a/Dear ImGui Sample/Window.cs b/Dear ImGui Sample/Window.cs
index 652cf16..3413d9d 100644
--- a/Dear ImGui Sample/Window.cs
+++ b/Dear ImGui Sample/Window.cs
@@ -17,7 +17,7 @@ public class Window : GameWindow
{
ImGuiController _controller;
- public Window() : base(GameWindowSettings.Default, new NativeWindowSettings(){ Size = new Vector2i(1600, 900), APIVersion = new Version(4, 5) })
+ public Window() : base(GameWindowSettings.Default, new NativeWindowSettings(){ Size = new Vector2i(1600, 900), APIVersion = new Version(3, 3) })
{ }
protected override void OnLoad()
@@ -53,7 +53,7 @@ protected override void OnRenderFrame(FrameEventArgs e)
_controller.Render();
- Util.CheckGLError("End of frame");
+ ImGuiController.CheckGLError("End of frame");
SwapBuffers();
}
diff --git a/README.md b/README.md
index 9a9c0ef..be017e0 100644
--- a/README.md
+++ b/README.md
@@ -1,13 +1,17 @@
# Dear Imgui Sample using OpenTK
-## OpenGL 4.5
+## OpenTK 4
-This version of the repository uses a lot of opengl 4.5 features for convenience (not having to bind buffers and stuff).
+This version of the repo is targeting OpenTK 4.
+The minimum OpenGL version is 3.3.
+
+## Your OpenGL state will be untouched!
+
+Previous versions of this repo required users to manually reset the OpenGL state that the ImGui renderer changed.
+This is no longer needed!
+The renderer resets the OpenGL state itself.
-For a opengl 3.3 version of the repo using opentk 3.2 checkout the `opengl3.3` branch.
-The `opengl3.3` branch is written for OpenTK 3 so some changes will have to be made.
-There is no version of this sample that uses opentk 4 and opengl 3.3.
## BadImageFormatexception
@@ -21,18 +25,3 @@ To do that, right click your project (all projects referencing ImGui.NET), click
To see more info and a potential fix you can take a look at issue #2.
-## Remember to enable/disable OpenGL features after use!
-
-Note that `ImGuiController.Render()` enables and disables some OpenGL features. The following is a list of state that `ImGuiController.Render()` changes:
-
-- Disbles blending
-- Disables scissor test
-- Disables culling
-- Disables depth test
-- Changes blend function
-- Changes scissor rectangle
-- Changes the shader program in use
-- Sets texture unit `0`'s `Texture2D` to `zero`
-- Sets blend equation to `FuncAdd`
-- Sets blend func to `SrcAlpha`, `OneMinusSrcAlpha`
-- Unbinds any Vertex Array Object
\ No newline at end of file