mirror of
https://github.com/ishanjitchattaraj/simple-sober-external.git
synced 2026-10-27 12:44:36 +00:00
634 lines
26 KiB
C#
634 lines
26 KiB
C#
using ImGuiNET;
|
|
using OpenTK.Graphics.OpenGL4;
|
|
using OpenTK.Mathematics;
|
|
using System;
|
|
using System.Runtime.CompilerServices;
|
|
using System.Runtime.InteropServices;
|
|
|
|
namespace Dear_ImGui_Sample.Backends
|
|
{
|
|
public unsafe static class ImguiImplOpenGL3
|
|
{
|
|
// See: https://github.com/ImGuiNET/ImGui.NET/issues/527
|
|
internal struct ImDrawCmd_fixed
|
|
{
|
|
public Vector4 ClipRect;
|
|
public ulong TextureId;
|
|
public uint VtxOffset;
|
|
public uint IdxOffset;
|
|
public uint ElemCount;
|
|
public nint UserCallback;
|
|
public unsafe void* UserCallbackData;
|
|
public int UserCallbackDataSize;
|
|
public int UserCallbackDataOffset;
|
|
}
|
|
internal struct ImDrawCmdPtr_fixed
|
|
{
|
|
public unsafe ImDrawCmd_fixed* NativePtr { get; }
|
|
|
|
public unsafe nint GetTexID()
|
|
{
|
|
return ImGuiNative.ImDrawCmd_GetTexID((ImDrawCmd*)NativePtr);
|
|
}
|
|
}
|
|
|
|
struct RendererData {
|
|
public int FontTexture;
|
|
public int ShaderHandle;
|
|
public int UniformLocationTex;
|
|
public int UniformLocationProjMtx;
|
|
public int AttribLocationVtxPos;
|
|
public int AttribLocationVtxUV;
|
|
public int AttribLocationVtxColor;
|
|
public int VboHandle;
|
|
public int EboHandle;
|
|
// FIXME: ??
|
|
public bool HasPolygonMode;
|
|
public bool HasClipOrigin;
|
|
|
|
public int GlslVersion;
|
|
public bool KHRDebugAvailable;
|
|
}
|
|
|
|
static RendererData* GetBackendData()
|
|
{
|
|
return ImGui.GetCurrentContext() == 0 ? null : (RendererData*)ImGui.GetIO().BackendRendererUserData;
|
|
}
|
|
|
|
public static bool Init(bool useKHRDebugIfAvailable = true)
|
|
{
|
|
var io = ImGui.GetIO();
|
|
|
|
RendererData* bd = (RendererData*)NativeMemory.AllocZeroed((uint)sizeof(RendererData));
|
|
|
|
int major = GL.GetInteger(GetPName.MajorVersion);
|
|
int minor = GL.GetInteger(GetPName.MinorVersion);
|
|
bd->HasPolygonMode = true;
|
|
bd->HasClipOrigin = major > 4 || (major == 4 && minor >= 5);
|
|
|
|
bd->GlslVersion = (major, minor) switch
|
|
{
|
|
(4, 6) => 460,
|
|
(4, 5) => 450,
|
|
(4, 4) => 440,
|
|
(4, 3) => 430,
|
|
(4, 2) => 420,
|
|
(4, 1) => 410,
|
|
(4, 0) => 400,
|
|
(3, 3) => 330,
|
|
(3, 2) => 150,
|
|
(3, 1) => 140,
|
|
(3, 0) => 130,
|
|
(2, 1) => 120,
|
|
(2, 0) => 110,
|
|
_ => 110,
|
|
};
|
|
|
|
if (useKHRDebugIfAvailable)
|
|
bd->KHRDebugAvailable = (major == 4 && minor >= 3) || IsExtensionSupported("KHR_debug");
|
|
else
|
|
bd->KHRDebugAvailable = false;
|
|
|
|
io.BackendRendererUserData = (IntPtr)bd;
|
|
io.NativePtr->BackendRendererName = (byte*)Unsafe.AsPointer(ref MemoryMarshal.GetReference("opentk_impl_opengl3"u8));
|
|
|
|
io.BackendFlags |= ImGuiBackendFlags.RendererHasVtxOffset;
|
|
io.BackendFlags |= ImGuiBackendFlags.RendererHasViewports;
|
|
|
|
InitMultiViewportSupport();
|
|
|
|
return true;
|
|
|
|
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 void Shutdown()
|
|
{
|
|
var io = ImGui.GetIO();
|
|
|
|
RendererData* bd = (RendererData*)io.NativePtr->BackendRendererUserData;
|
|
|
|
ShutdownMultiViewportSupport();
|
|
|
|
io.NativePtr->BackendRendererName = null;
|
|
io.NativePtr->BackendRendererUserData = null;
|
|
|
|
io.BackendFlags &= ~(ImGuiBackendFlags.RendererHasVtxOffset);
|
|
|
|
NativeMemory.Free(bd);
|
|
}
|
|
|
|
public static void NewFrame()
|
|
{
|
|
RendererData* bd = GetBackendData();
|
|
|
|
if (bd->ShaderHandle == 0)
|
|
{
|
|
CreateDeviceObjects();
|
|
}
|
|
if (bd->FontTexture == 0)
|
|
{
|
|
CreateFontsTexture();
|
|
}
|
|
}
|
|
|
|
public static void SetupRenderState(ImDrawDataPtr drawData, int fbWidth, int fbHeight, int vao)
|
|
{
|
|
RendererData* bd = GetBackendData();
|
|
|
|
GL.Enable(EnableCap.Blend);
|
|
GL.BlendEquation(BlendEquationMode.FuncAdd);
|
|
GL.BlendFuncSeparate(BlendingFactorSrc.SrcAlpha, BlendingFactorDest.OneMinusSrcAlpha, BlendingFactorSrc.One, BlendingFactorDest.OneMinusSrcAlpha);
|
|
GL.Disable(EnableCap.CullFace);
|
|
GL.Disable(EnableCap.DepthTest);
|
|
GL.Disable(EnableCap.StencilTest);
|
|
GL.Enable(EnableCap.ScissorTest);
|
|
// FIXME: check for 3.1
|
|
GL.Disable(EnableCap.PrimitiveRestart);
|
|
|
|
GL.PolygonMode(TriangleFace.FrontAndBack, PolygonMode.Fill);
|
|
|
|
bool clip_origin_lower_left = true;
|
|
ClipOrigin clip_origin = (ClipOrigin)GL.GetInteger(GetPName.ClipOrigin);
|
|
if (clip_origin == ClipOrigin.UpperLeft)
|
|
clip_origin_lower_left = false;
|
|
|
|
GL.Viewport(0, 0, fbWidth, fbHeight);
|
|
float L = drawData.DisplayPos.X;
|
|
float R = drawData.DisplayPos.X + drawData.DisplaySize.X;
|
|
float T = drawData.DisplayPos.Y;
|
|
float B = drawData.DisplayPos.Y + drawData.DisplaySize.Y;
|
|
if (clip_origin_lower_left == false)
|
|
(T, B) = (B, T); // Swap top and bottom if origin is upper left.
|
|
Matrix4 mvp = Matrix4.CreateOrthographicOffCenter(L, R, B, T, -1, 1);
|
|
GL.UseProgram(bd->ShaderHandle);
|
|
GL.Uniform1(bd->UniformLocationTex, 0);
|
|
GL.UniformMatrix4(bd->UniformLocationProjMtx, true, ref mvp);
|
|
|
|
GL.BindSampler(0, 0);
|
|
|
|
GL.BindVertexArray(vao);
|
|
GL.BindBuffer(BufferTarget.ArrayBuffer, bd->VboHandle);
|
|
GL.BindBuffer(BufferTarget.ElementArrayBuffer, bd->EboHandle);
|
|
GL.EnableVertexAttribArray(bd->AttribLocationVtxPos);
|
|
GL.EnableVertexAttribArray(bd->AttribLocationVtxUV);
|
|
GL.EnableVertexAttribArray(bd->AttribLocationVtxColor);
|
|
GL.VertexAttribPointer(bd->AttribLocationVtxPos, 2, VertexAttribPointerType.Float, false, sizeof(ImDrawVert), 0);
|
|
GL.VertexAttribPointer(bd->AttribLocationVtxUV, 2, VertexAttribPointerType.Float, false, sizeof(ImDrawVert), 8);
|
|
GL.VertexAttribPointer(bd->AttribLocationVtxColor, 4, VertexAttribPointerType.UnsignedByte, true, sizeof(ImDrawVert), 16);
|
|
|
|
if (bd->KHRDebugAvailable)
|
|
{
|
|
GL.ObjectLabel(ObjectLabelIdentifier.VertexArray, vao, -1, "OpenTK_ImGui: VAO");
|
|
}
|
|
}
|
|
|
|
public static void RenderDrawData(ImDrawDataPtr drawData)
|
|
{
|
|
int fbWidth = (int)(drawData.DisplaySize.X * drawData.FramebufferScale.X);
|
|
int fbHeight = (int)(drawData.DisplaySize.Y * drawData.FramebufferScale.Y);
|
|
if (fbWidth <= 0 || fbHeight <= 0)
|
|
return;
|
|
|
|
int last_active_texture = GL.GetInteger(GetPName.ActiveTexture);
|
|
GL.ActiveTexture(TextureUnit.Texture0);
|
|
int last_program = GL.GetInteger(GetPName.CurrentProgram);
|
|
int last_texture = GL.GetInteger(GetPName.TextureBinding2D);
|
|
int last_sampler = GL.GetInteger(GetPName.SamplerBinding);
|
|
int last_array_buffer = GL.GetInteger(GetPName.ArrayBufferBinding);
|
|
int last_vao = GL.GetInteger(GetPName.VertexArrayBinding);
|
|
// OpenGL 3.0 & 3.1 have separate polygon modes for front and back.
|
|
Span<int> last_polygon_mode = stackalloc int[2];
|
|
GL.GetInteger(GetPName.PolygonMode, out last_polygon_mode[0]);
|
|
Span<int> last_viewport = stackalloc int[4];
|
|
GL.GetInteger(GetPName.Viewport, out last_viewport[0]);
|
|
Span<int> last_scissor_box = stackalloc int[4];
|
|
GL.GetInteger(GetPName.ScissorBox, out last_scissor_box[0]);
|
|
int last_blend_src_rgb = GL.GetInteger(GetPName.BlendSrcRgb);
|
|
int last_blend_dst_rgb = GL.GetInteger(GetPName.BlendDstRgb);
|
|
int last_blend_src_alpha = GL.GetInteger(GetPName.BlendSrcAlpha);
|
|
int last_blend_dst_alpha = GL.GetInteger(GetPName.BlendDstAlpha);
|
|
int last_blend_equation_rgb = GL.GetInteger(GetPName.BlendEquationRgb);
|
|
int last_blend_equation_alpha = GL.GetInteger(GetPName.BlendEquationAlpha);
|
|
bool last_enable_blend = GL.IsEnabled(EnableCap.Blend);
|
|
bool last_enable_cull_face = GL.IsEnabled(EnableCap.CullFace);
|
|
bool last_enable_depth_test = GL.IsEnabled(EnableCap.DepthTest);
|
|
bool last_enable_stencil_test = GL.IsEnabled(EnableCap.StencilTest);
|
|
bool last_enable_scissor_test = GL.IsEnabled(EnableCap.ScissorTest);
|
|
// FIXME: Check for >= 3.1
|
|
bool last_enable_primitive_restart = GL.IsEnabled(EnableCap.PrimitiveRestart);
|
|
|
|
int vao = GL.GenVertexArray();
|
|
SetupRenderState(drawData, fbWidth, fbHeight, vao);
|
|
|
|
var clipOff = drawData.DisplayPos;
|
|
var clipScale = drawData.FramebufferScale;
|
|
for (int n = 0; n < drawData.CmdListsCount; n++)
|
|
{
|
|
ImDrawListPtr drawList = drawData.CmdLists[n];
|
|
|
|
nint vtx_buffer_size = drawList.VtxBuffer.Size * (int)sizeof(ImDrawVert);
|
|
nint idx_buffer_size = drawList.IdxBuffer.Size * (int)sizeof(ushort);
|
|
GL.BufferData(BufferTarget.ArrayBuffer, vtx_buffer_size, drawList.VtxBuffer.Data, BufferUsageHint.StreamDraw);
|
|
GL.BufferData(BufferTarget.ElementArrayBuffer, idx_buffer_size, drawList.IdxBuffer.Data, BufferUsageHint.StreamDraw);
|
|
|
|
for (int cmd_i = 0; cmd_i < drawList.CmdBuffer.Size; cmd_i++)
|
|
{
|
|
// FIXME: This is a hack to make 32-bit builds work. See: https://github.com/ImGuiNET/ImGui.NET/issues/527
|
|
ImDrawCmdPtr_fixed cmdPtr = new ImPtrVector<ImDrawCmdPtr_fixed>(drawList.NativePtr->CmdBuffer, sizeof(ImDrawCmd_fixed))[cmd_i];
|
|
ref ImDrawCmd_fixed cmd = ref Unsafe.AsRef<ImDrawCmd_fixed>(cmdPtr.NativePtr);
|
|
if (cmd.UserCallback != 0)
|
|
{
|
|
// FIXME: ...
|
|
nint ImDrawCallback_ResetRenderState = -8;
|
|
if (cmd.UserCallback == ImDrawCallback_ResetRenderState)
|
|
{
|
|
SetupRenderState(drawData, fbWidth, fbHeight, vao);
|
|
}
|
|
else
|
|
{
|
|
throw new NotImplementedException("User callbacks are not implemented yet...");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Vector2 clip_min = new((cmd.ClipRect.X -clipOff.X) *clipScale.X, (cmd.ClipRect.Y - clipOff.Y) * clipScale.Y);
|
|
Vector2 clip_max = new((cmd.ClipRect.Z -clipOff.X) *clipScale.X, (cmd.ClipRect.W - clipOff.Y) * clipScale.Y);
|
|
if (clip_max.X <= clip_min.X || clip_max.Y <= clip_min.Y)
|
|
continue;
|
|
|
|
GL.Scissor((int)clip_min.X, (int)((float)fbHeight - clip_max.Y), (int)(clip_max.X - clip_min.X), (int)(clip_max.Y - clip_min.Y));
|
|
|
|
GL.BindTexture(TextureTarget.Texture2D, (int)cmdPtr.GetTexID());
|
|
|
|
GL.DrawElementsBaseVertex(PrimitiveType.Triangles, (int)cmd.ElemCount, DrawElementsType.UnsignedShort, (int)(cmd.IdxOffset * sizeof(ushort)), (int)cmd.VtxOffset);
|
|
}
|
|
}
|
|
}
|
|
|
|
GL.DeleteVertexArray(vao);
|
|
|
|
if (last_program == 0 || GL.IsProgram(last_program)) GL.UseProgram(last_program);
|
|
GL.BindTexture(TextureTarget.Texture2D, last_texture);
|
|
GL.BindSampler(0, last_sampler);
|
|
GL.ActiveTexture((TextureUnit)last_active_texture);
|
|
GL.BindVertexArray(last_vao);
|
|
GL.BindBuffer(BufferTarget.ArrayBuffer, last_array_buffer);
|
|
GL.BlendEquationSeparate((BlendEquationMode)last_blend_equation_rgb, (BlendEquationMode)last_blend_equation_alpha);
|
|
GL.BlendFuncSeparate((BlendingFactorSrc)last_blend_src_rgb, (BlendingFactorDest)last_blend_dst_rgb, (BlendingFactorSrc)last_blend_src_alpha, (BlendingFactorDest)last_blend_dst_alpha);
|
|
if (last_enable_blend) GL.Enable(EnableCap.Blend); else GL.Disable(EnableCap.Blend);
|
|
if (last_enable_cull_face) GL.Enable(EnableCap.CullFace); else GL.Disable(EnableCap.CullFace);
|
|
if (last_enable_depth_test) GL.Enable(EnableCap.DepthTest); else GL.Disable(EnableCap.DepthTest);
|
|
if (last_enable_stencil_test) GL.Enable(EnableCap.StencilTest); else GL.Disable(EnableCap.StencilTest);
|
|
if (last_enable_scissor_test) GL.Enable(EnableCap.ScissorTest); else GL.Disable(EnableCap.ScissorTest);
|
|
if (last_enable_primitive_restart) GL.Enable(EnableCap.PrimitiveRestart); else GL.Disable(EnableCap.PrimitiveRestart);
|
|
|
|
if (true)
|
|
{
|
|
// FIXME:
|
|
// if (bd->HasPolygonMode) {
|
|
// if (bd->GlVersion <= 310 || bd->GlProfileIsCompat) {
|
|
// glPolygonMode(GL_FRONT, (GLenum)last_polygon_mode[0]);
|
|
// glPolygonMode(GL_BACK, (GLenum)last_polygon_mode[1]);
|
|
// } else {
|
|
// glPolygonMode(GL_FRONT_AND_BACK, (GLenum)last_polygon_mode[0]);
|
|
// }
|
|
// }
|
|
GL.PolygonMode(TriangleFace.FrontAndBack, (PolygonMode)last_polygon_mode[0]);
|
|
}
|
|
|
|
GL.Viewport(last_viewport[0], last_viewport[1], last_viewport[2], last_viewport[3]);
|
|
GL.Scissor(last_scissor_box[0], last_scissor_box[1], last_scissor_box[2], last_scissor_box[3]);
|
|
}
|
|
|
|
static void CreateFontsTexture()
|
|
{
|
|
var io = ImGui.GetIO();
|
|
RendererData* bd = GetBackendData();
|
|
|
|
ImGuiNative.ImFontAtlas_AddFontDefault(io.Fonts.NativePtr, null);
|
|
//io.Fonts.AddFontDefault();
|
|
io.Fonts.GetTexDataAsRGBA32(out byte* pixels, out int width, out int height);
|
|
|
|
int last_texture = GL.GetInteger(GetPName.TextureBinding2D);
|
|
bd->FontTexture = GL.GenTexture();
|
|
GL.BindTexture(TextureTarget.Texture2D, bd->FontTexture);
|
|
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Linear);
|
|
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Linear);
|
|
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (int)TextureWrapMode.ClampToEdge);
|
|
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int)TextureWrapMode.ClampToEdge);
|
|
GL.PixelStore(PixelStoreParameter.UnpackRowLength, 0);
|
|
GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgba, width, height, 0, PixelFormat.Rgba, PixelType.UnsignedByte, (IntPtr)pixels);
|
|
|
|
io.Fonts.SetTexID(bd->FontTexture);
|
|
|
|
GL.BindTexture(TextureTarget.Texture2D, last_texture);
|
|
|
|
if (bd->KHRDebugAvailable)
|
|
{
|
|
GL.ObjectLabel(ObjectLabelIdentifier.Texture, bd->FontTexture, -1, "OpenTK_ImGui: Font Texture");
|
|
}
|
|
}
|
|
|
|
static void DestroyFontsTexture()
|
|
{
|
|
var io = ImGui.GetIO();
|
|
RendererData* bd = GetBackendData();
|
|
|
|
if (bd->FontTexture != 0)
|
|
{
|
|
GL.DeleteTexture(bd->FontTexture);
|
|
io.Fonts.SetTexID(0);
|
|
bd->FontTexture = 0;
|
|
}
|
|
}
|
|
|
|
static bool CheckShader(int handle, string desc)
|
|
{
|
|
GL.GetShader(handle, ShaderParameter.CompileStatus, out int status);
|
|
GL.GetShader(handle, ShaderParameter.InfoLogLength, out int logLength);
|
|
if (status == 0)
|
|
{
|
|
Console.Error.WriteLine($"ERROR: ImguiImplOpenGL3.CheckShader: Failed to compile {desc}!");
|
|
}
|
|
if (logLength > 1)
|
|
{
|
|
string log = GL.GetShaderInfoLog(handle);
|
|
Console.Error.WriteLine(log);
|
|
}
|
|
return status == 1;
|
|
}
|
|
|
|
static bool CheckProgram(int handle, string desc)
|
|
{
|
|
GL.GetProgram(handle, GetProgramParameterName.LinkStatus, out int status);
|
|
GL.GetProgram(handle, GetProgramParameterName.InfoLogLength, out int logLength);
|
|
if (status == 0)
|
|
{
|
|
Console.Error.WriteLine($"ERROR: ImguiImplOpenGL3.CheckProgram: Failed to link {desc}!");
|
|
}
|
|
if (logLength > 1)
|
|
{
|
|
string log = GL.GetProgramInfoLog(handle);
|
|
Console.Error.WriteLine(log);
|
|
}
|
|
return status == 1;
|
|
}
|
|
|
|
static void CreateDeviceObjects()
|
|
{
|
|
RendererData* bd = GetBackendData();
|
|
|
|
int last_texture = GL.GetInteger(GetPName.TextureBinding2D);
|
|
int last_array_buffer = GL.GetInteger(GetPName.ArrayBufferBinding);
|
|
int last_pixel_unpack_buffer = GL.GetInteger(GetPName.PixelUnpackBufferBinding);
|
|
int last_vertex_array = GL.GetInteger(GetPName.VertexArray);
|
|
|
|
string vertex_shader_glsl_120 =
|
|
"""
|
|
uniform mat4 ProjMtx;
|
|
attribute vec2 Position;
|
|
attribute vec2 UV;
|
|
attribute vec4 Color;
|
|
varying vec2 Frag_UV;
|
|
varying vec4 Frag_Color;
|
|
void main()
|
|
{
|
|
Frag_UV = UV;
|
|
Frag_Color = Color;
|
|
gl_Position = vec4(Position.xy,0,1) * ProjMtx;
|
|
}
|
|
""";
|
|
|
|
string vertex_shader_glsl_130 =
|
|
"""
|
|
uniform mat4 ProjMtx;
|
|
in vec2 Position;
|
|
in vec2 UV;
|
|
in vec4 Color;
|
|
out vec2 Frag_UV;
|
|
out vec4 Frag_Color;
|
|
void main()
|
|
{
|
|
Frag_UV = UV;
|
|
Frag_Color = Color;
|
|
gl_Position = vec4(Position.xy,0,1) * ProjMtx;
|
|
}
|
|
""";
|
|
|
|
string vertex_shader_glsl_300_es =
|
|
"""
|
|
precision highp float;
|
|
layout(location = 0) in vec2 Position;
|
|
layout(location = 1) in vec2 UV;
|
|
layout(location = 2) in vec4 Color;
|
|
uniform mat4 ProjMtx;
|
|
out vec2 Frag_UV;
|
|
out vec4 Frag_Color;
|
|
void main()
|
|
{
|
|
Frag_UV = UV;
|
|
Frag_Color = Color;
|
|
gl_Position = vec4(Position.xy,0,1) * ProjMtx;
|
|
}
|
|
""";
|
|
|
|
string vertex_shader_glsl_410_core =
|
|
"""
|
|
layout(location = 0) in vec2 Position;
|
|
layout(location = 1) in vec2 UV;
|
|
layout(location = 2) in vec4 Color;
|
|
uniform mat4 ProjMtx;
|
|
out vec2 Frag_UV;
|
|
out vec4 Frag_Color;
|
|
void main()
|
|
{
|
|
Frag_UV = UV;
|
|
Frag_Color = Color;
|
|
gl_Position = vec4(Position.xy,0,1) * ProjMtx;
|
|
}
|
|
""";
|
|
|
|
string fragment_shader_glsl_120 =
|
|
"""
|
|
#ifdef GL_ES
|
|
precision mediump float;
|
|
#endif
|
|
uniform sampler2D Texture;
|
|
varying vec2 Frag_UV;
|
|
varying vec4 Frag_Color;
|
|
void main()
|
|
{
|
|
gl_FragColor = Frag_Color * texture2D(Texture, Frag_UV.st);
|
|
}
|
|
""";
|
|
|
|
string fragment_shader_glsl_130 =
|
|
"""
|
|
uniform sampler2D Texture;
|
|
in vec2 Frag_UV;
|
|
in vec4 Frag_Color;
|
|
out vec4 Out_Color;
|
|
void main()
|
|
{
|
|
Out_Color = Frag_Color * texture(Texture, Frag_UV.st);
|
|
}
|
|
""";
|
|
|
|
string fragment_shader_glsl_300_es =
|
|
"""
|
|
precision mediump float;
|
|
uniform sampler2D Texture;
|
|
in vec2 Frag_UV;
|
|
in vec4 Frag_Color;
|
|
layout(location = 0) out vec4 Out_Color;
|
|
void main()
|
|
{
|
|
Out_Color = Frag_Color * texture(Texture, Frag_UV.st);
|
|
}
|
|
""";
|
|
|
|
string fragment_shader_glsl_410_core =
|
|
"""
|
|
uniform sampler2D Texture;
|
|
in vec2 Frag_UV;
|
|
in vec4 Frag_Color;
|
|
layout(location = 0) out vec4 Out_Color;
|
|
void main()
|
|
{
|
|
Out_Color = Frag_Color * texture(Texture, Frag_UV.st);
|
|
}
|
|
""";
|
|
|
|
string vertex_shader;
|
|
string fragment_shader;
|
|
if (bd->GlslVersion < 130)
|
|
{
|
|
vertex_shader = vertex_shader_glsl_120;
|
|
fragment_shader = fragment_shader_glsl_120;
|
|
}
|
|
else if (bd->GlslVersion >= 410)
|
|
{
|
|
vertex_shader = vertex_shader_glsl_410_core;
|
|
fragment_shader = fragment_shader_glsl_410_core;
|
|
}
|
|
else if (bd->GlslVersion == 300)
|
|
{
|
|
vertex_shader = vertex_shader_glsl_300_es;
|
|
fragment_shader = fragment_shader_glsl_300_es;
|
|
}
|
|
else
|
|
{
|
|
vertex_shader = vertex_shader_glsl_130;
|
|
fragment_shader = fragment_shader_glsl_130;
|
|
}
|
|
|
|
vertex_shader = vertex_shader.Insert(0, $"#version {bd->GlslVersion}{Environment.NewLine}");
|
|
fragment_shader = fragment_shader.Insert(0, $"#version {bd->GlslVersion}{Environment.NewLine}");
|
|
|
|
int vert = GL.CreateShader(ShaderType.VertexShader);
|
|
// FIXME: Version string...
|
|
GL.ShaderSource(vert, vertex_shader);
|
|
GL.CompileShader(vert);
|
|
CheckShader(vert, "vertex shader");
|
|
|
|
int frag = GL.CreateShader(ShaderType.FragmentShader);
|
|
// FIXME: Version string...
|
|
GL.ShaderSource(frag, fragment_shader);
|
|
GL.CompileShader(frag);
|
|
CheckShader(frag, "fragment shader");
|
|
|
|
bd->ShaderHandle = GL.CreateProgram();
|
|
GL.AttachShader(bd->ShaderHandle, vert);
|
|
GL.AttachShader(bd->ShaderHandle, frag);
|
|
GL.LinkProgram(bd->ShaderHandle);
|
|
CheckProgram(bd->ShaderHandle, "shader program");
|
|
|
|
GL.DetachShader(bd->ShaderHandle, vert);
|
|
GL.DetachShader(bd->ShaderHandle, frag);
|
|
GL.DeleteShader(vert);
|
|
GL.DeleteShader(frag);
|
|
|
|
bd->UniformLocationTex = GL.GetUniformLocation(bd->ShaderHandle, "Texture");
|
|
bd->UniformLocationProjMtx = GL.GetUniformLocation(bd->ShaderHandle, "ProjMtx");
|
|
bd->AttribLocationVtxPos = GL.GetAttribLocation(bd->ShaderHandle, "Position");
|
|
bd->AttribLocationVtxUV = GL.GetAttribLocation(bd->ShaderHandle, "UV");
|
|
bd->AttribLocationVtxColor = GL.GetAttribLocation(bd->ShaderHandle, "Color");
|
|
|
|
bd->VboHandle = GL.GenBuffer();
|
|
bd->EboHandle = GL.GenBuffer();
|
|
|
|
CreateFontsTexture();
|
|
|
|
GL.BindTexture(TextureTarget.Texture2D, last_texture);
|
|
GL.BindBuffer(BufferTarget.ArrayBuffer, last_array_buffer);
|
|
GL.BindBuffer(BufferTarget.PixelUnpackBuffer, last_pixel_unpack_buffer);
|
|
GL.BindVertexArray(last_vertex_array);
|
|
|
|
if (bd->KHRDebugAvailable)
|
|
{
|
|
GL.ObjectLabel(ObjectLabelIdentifier.Buffer, bd->VboHandle, -1, "OpenTK_ImGui: VBO");
|
|
GL.ObjectLabel(ObjectLabelIdentifier.Buffer, bd->EboHandle, -1, "OpenTK_ImGui: EBO");
|
|
GL.ObjectLabel(ObjectLabelIdentifier.Shader, bd->ShaderHandle, -1, "OpenTK_ImGui: Shader");
|
|
}
|
|
}
|
|
|
|
static void DestroyDeviceObjects()
|
|
{
|
|
RendererData* bd = GetBackendData();
|
|
|
|
if (bd->VboHandle != 0)
|
|
{
|
|
GL.DeleteBuffer(bd->VboHandle);
|
|
bd->VboHandle = 0;
|
|
}
|
|
|
|
if (bd->EboHandle != 0)
|
|
{
|
|
GL.DeleteBuffer(bd->EboHandle);
|
|
bd->EboHandle = 0;
|
|
}
|
|
|
|
if (bd->ShaderHandle != 0)
|
|
{
|
|
GL.DeleteProgram(bd->ShaderHandle);
|
|
bd->ShaderHandle = 0;
|
|
}
|
|
|
|
DestroyFontsTexture();
|
|
}
|
|
|
|
static void InitMultiViewportSupport()
|
|
{
|
|
var platformIO = ImGui.GetPlatformIO();
|
|
platformIO.Renderer_RenderWindow = (IntPtr)(delegate* unmanaged[Cdecl]<ImGuiViewportPtr, void>)&Renderer_RenderWindow;
|
|
}
|
|
|
|
static void ShutdownMultiViewportSupport()
|
|
{
|
|
ImGui.DestroyPlatformWindows();
|
|
}
|
|
|
|
[UnmanagedCallersOnly(CallConvs = [typeof(CallConvCdecl)])]
|
|
static void Renderer_RenderWindow(ImGuiViewportPtr viewport)
|
|
{
|
|
if (viewport.Flags.HasFlag(ImGuiViewportFlags.NoRendererClear))
|
|
{
|
|
GL.ClearColor(Color4.Black);
|
|
GL.Clear(ClearBufferMask.ColorBufferBit);
|
|
}
|
|
RenderDrawData(viewport.DrawData);
|
|
}
|
|
}
|
|
}
|