mirror of
https://github.com/Bloodysharp/Imguimenu_cringe.git
synced 2025-01-03 08:03:29 +08:00
Add files via upload
This commit is contained in:
parent
def7534b40
commit
110173520d
430
backend/imgui_impl_allegro5.cpp
Normal file
430
backend/imgui_impl_allegro5.cpp
Normal file
@ -0,0 +1,430 @@
|
|||||||
|
// dear imgui: Renderer + Platform Backend for Allegro 5
|
||||||
|
// (Info: Allegro 5 is a cross-platform general purpose library for handling windows, inputs, graphics, etc.)
|
||||||
|
|
||||||
|
// Implemented features:
|
||||||
|
// [X] Renderer: User texture binding. Use 'ALLEGRO_BITMAP*' as ImTextureID. Read the FAQ about ImTextureID!
|
||||||
|
// [X] Platform: Clipboard support (from Allegro 5.1.12)
|
||||||
|
// [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'.
|
||||||
|
// Issues:
|
||||||
|
// [ ] Renderer: The renderer is suboptimal as we need to unindex our buffers and convert vertices manually.
|
||||||
|
// [ ] Platform: Missing gamepad support.
|
||||||
|
|
||||||
|
// You can copy and use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
||||||
|
// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
|
||||||
|
// Read online: https://github.com/ocornut/imgui/tree/master/docs
|
||||||
|
|
||||||
|
// CHANGELOG
|
||||||
|
// (minor and older changes stripped away, please see git history for details)
|
||||||
|
// 2021-02-18: Change blending equation to preserve alpha in output buffer.
|
||||||
|
// 2020-08-10: Inputs: Fixed horizontal mouse wheel direction.
|
||||||
|
// 2019-12-05: Inputs: Added support for ImGuiMouseCursor_NotAllowed mouse cursor.
|
||||||
|
// 2019-07-21: Inputs: Added mapping for ImGuiKey_KeyPadEnter.
|
||||||
|
// 2019-05-11: Inputs: Don't filter character value from ALLEGRO_EVENT_KEY_CHAR before calling AddInputCharacter().
|
||||||
|
// 2019-04-30: Renderer: Added support for special ImDrawCallback_ResetRenderState callback to reset render state.
|
||||||
|
// 2018-11-30: Platform: Added touchscreen support.
|
||||||
|
// 2018-11-30: Misc: Setting up io.BackendPlatformName/io.BackendRendererName so they can be displayed in the About Window.
|
||||||
|
// 2018-06-13: Platform: Added clipboard support (from Allegro 5.1.12).
|
||||||
|
// 2018-06-13: Renderer: Use draw_data->DisplayPos and draw_data->DisplaySize to setup projection matrix and clipping rectangle.
|
||||||
|
// 2018-06-13: Renderer: Backup/restore transform and clipping rectangle.
|
||||||
|
// 2018-06-11: Misc: Setup io.BackendFlags ImGuiBackendFlags_HasMouseCursors flag + honor ImGuiConfigFlags_NoMouseCursorChange flag.
|
||||||
|
// 2018-04-18: Misc: Renamed file from imgui_impl_a5.cpp to imgui_impl_allegro5.cpp.
|
||||||
|
// 2018-04-18: Misc: Added support for 32-bit vertex indices to avoid conversion at runtime. Added imconfig_allegro5.h to enforce 32-bit indices when included from imgui.h.
|
||||||
|
// 2018-02-16: Misc: Obsoleted the io.RenderDrawListsFn callback and exposed ImGui_ImplAllegro5_RenderDrawData() in the .h file so you can call it yourself.
|
||||||
|
// 2018-02-06: Misc: Removed call to ImGui::Shutdown() which is not available from 1.60 WIP, user needs to call CreateContext/DestroyContext themselves.
|
||||||
|
// 2018-02-06: Inputs: Added mapping for ImGuiKey_Space.
|
||||||
|
|
||||||
|
#include <stdint.h> // uint64_t
|
||||||
|
#include <cstring> // memcpy
|
||||||
|
#include "imgui.h"
|
||||||
|
#include "imgui_impl_allegro5.h"
|
||||||
|
|
||||||
|
// Allegro
|
||||||
|
#include <allegro5/allegro.h>
|
||||||
|
#include <allegro5/allegro_primitives.h>
|
||||||
|
#ifdef _WIN32
|
||||||
|
#include <allegro5/allegro_windows.h>
|
||||||
|
#endif
|
||||||
|
#define ALLEGRO_HAS_CLIPBOARD (ALLEGRO_VERSION_INT >= ((5 << 24) | (1 << 16) | (12 << 8))) // Clipboard only supported from Allegro 5.1.12
|
||||||
|
|
||||||
|
// Visual Studio warnings
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#pragma warning (disable: 4127) // condition expression is constant
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Data
|
||||||
|
static ALLEGRO_DISPLAY* g_Display = NULL;
|
||||||
|
static ALLEGRO_BITMAP* g_Texture = NULL;
|
||||||
|
static double g_Time = 0.0;
|
||||||
|
static ALLEGRO_MOUSE_CURSOR* g_MouseCursorInvisible = NULL;
|
||||||
|
static ALLEGRO_VERTEX_DECL* g_VertexDecl = NULL;
|
||||||
|
static char* g_ClipboardTextData = NULL;
|
||||||
|
|
||||||
|
struct ImDrawVertAllegro
|
||||||
|
{
|
||||||
|
ImVec2 pos;
|
||||||
|
ImVec2 uv;
|
||||||
|
ALLEGRO_COLOR col;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void ImGui_ImplAllegro5_SetupRenderState(ImDrawData* draw_data)
|
||||||
|
{
|
||||||
|
// Setup blending
|
||||||
|
al_set_separate_blender(ALLEGRO_ADD, ALLEGRO_ALPHA, ALLEGRO_INVERSE_ALPHA, ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_INVERSE_ALPHA);
|
||||||
|
|
||||||
|
// Setup orthographic projection matrix
|
||||||
|
// Our visible imgui space lies from draw_data->DisplayPos (top left) to draw_data->DisplayPos+data_data->DisplaySize (bottom right).
|
||||||
|
{
|
||||||
|
float L = draw_data->DisplayPos.x;
|
||||||
|
float R = draw_data->DisplayPos.x + draw_data->DisplaySize.x;
|
||||||
|
float T = draw_data->DisplayPos.y;
|
||||||
|
float B = draw_data->DisplayPos.y + draw_data->DisplaySize.y;
|
||||||
|
ALLEGRO_TRANSFORM transform;
|
||||||
|
al_identity_transform(&transform);
|
||||||
|
al_use_transform(&transform);
|
||||||
|
al_orthographic_transform(&transform, L, T, 1.0f, R, B, -1.0f);
|
||||||
|
al_use_projection_transform(&transform);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Render function.
|
||||||
|
void ImGui_ImplAllegro5_RenderDrawData(ImDrawData* draw_data)
|
||||||
|
{
|
||||||
|
// Avoid rendering when minimized
|
||||||
|
if (draw_data->DisplaySize.x <= 0.0f || draw_data->DisplaySize.y <= 0.0f)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Backup Allegro state that will be modified
|
||||||
|
ALLEGRO_TRANSFORM last_transform = *al_get_current_transform();
|
||||||
|
ALLEGRO_TRANSFORM last_projection_transform = *al_get_current_projection_transform();
|
||||||
|
int last_clip_x, last_clip_y, last_clip_w, last_clip_h;
|
||||||
|
al_get_clipping_rectangle(&last_clip_x, &last_clip_y, &last_clip_w, &last_clip_h);
|
||||||
|
int last_blender_op, last_blender_src, last_blender_dst;
|
||||||
|
al_get_blender(&last_blender_op, &last_blender_src, &last_blender_dst);
|
||||||
|
|
||||||
|
// Setup desired render state
|
||||||
|
ImGui_ImplAllegro5_SetupRenderState(draw_data);
|
||||||
|
|
||||||
|
// Render command lists
|
||||||
|
for (int n = 0; n < draw_data->CmdListsCount; n++)
|
||||||
|
{
|
||||||
|
const ImDrawList* cmd_list = draw_data->CmdLists[n];
|
||||||
|
|
||||||
|
// Allegro's implementation of al_draw_indexed_prim() for DX9 is completely broken. Unindex our buffers ourselves.
|
||||||
|
// FIXME-OPT: Unfortunately Allegro doesn't support 32-bit packed colors so we have to convert them to 4 float as well..
|
||||||
|
static ImVector<ImDrawVertAllegro> vertices;
|
||||||
|
vertices.resize(cmd_list->IdxBuffer.Size);
|
||||||
|
for (int i = 0; i < cmd_list->IdxBuffer.Size; i++)
|
||||||
|
{
|
||||||
|
const ImDrawVert* src_v = &cmd_list->VtxBuffer[cmd_list->IdxBuffer[i]];
|
||||||
|
ImDrawVertAllegro* dst_v = &vertices[i];
|
||||||
|
dst_v->pos = src_v->pos;
|
||||||
|
dst_v->uv = src_v->uv;
|
||||||
|
unsigned char* c = (unsigned char*)&src_v->col;
|
||||||
|
dst_v->col = al_map_rgba(c[0], c[1], c[2], c[3]);
|
||||||
|
}
|
||||||
|
|
||||||
|
const int* indices = NULL;
|
||||||
|
if (sizeof(ImDrawIdx) == 2)
|
||||||
|
{
|
||||||
|
// FIXME-OPT: Unfortunately Allegro doesn't support 16-bit indices.. You can '#define ImDrawIdx int' in imconfig.h to request Dear ImGui to output 32-bit indices.
|
||||||
|
// Otherwise, we convert them from 16-bit to 32-bit at runtime here, which works perfectly but is a little wasteful.
|
||||||
|
static ImVector<int> indices_converted;
|
||||||
|
indices_converted.resize(cmd_list->IdxBuffer.Size);
|
||||||
|
for (int i = 0; i < cmd_list->IdxBuffer.Size; ++i)
|
||||||
|
indices_converted[i] = (int)cmd_list->IdxBuffer.Data[i];
|
||||||
|
indices = indices_converted.Data;
|
||||||
|
}
|
||||||
|
else if (sizeof(ImDrawIdx) == 4)
|
||||||
|
{
|
||||||
|
indices = (const int*)cmd_list->IdxBuffer.Data;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Render command lists
|
||||||
|
int idx_offset = 0;
|
||||||
|
ImVec2 clip_off = draw_data->DisplayPos;
|
||||||
|
for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++)
|
||||||
|
{
|
||||||
|
const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i];
|
||||||
|
if (pcmd->UserCallback)
|
||||||
|
{
|
||||||
|
// User callback, registered via ImDrawList::AddCallback()
|
||||||
|
// (ImDrawCallback_ResetRenderState is a special callback value used by the user to request the renderer to reset render state.)
|
||||||
|
if (pcmd->UserCallback == ImDrawCallback_ResetRenderState)
|
||||||
|
ImGui_ImplAllegro5_SetupRenderState(draw_data);
|
||||||
|
else
|
||||||
|
pcmd->UserCallback(cmd_list, pcmd);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Draw
|
||||||
|
ALLEGRO_BITMAP* texture = (ALLEGRO_BITMAP*)pcmd->TextureId;
|
||||||
|
al_set_clipping_rectangle(pcmd->ClipRect.x - clip_off.x, pcmd->ClipRect.y - clip_off.y, pcmd->ClipRect.z - pcmd->ClipRect.x, pcmd->ClipRect.w - pcmd->ClipRect.y);
|
||||||
|
al_draw_prim(&vertices[0], g_VertexDecl, texture, idx_offset, idx_offset + pcmd->ElemCount, ALLEGRO_PRIM_TRIANGLE_LIST);
|
||||||
|
}
|
||||||
|
idx_offset += pcmd->ElemCount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Restore modified Allegro state
|
||||||
|
al_set_blender(last_blender_op, last_blender_src, last_blender_dst);
|
||||||
|
al_set_clipping_rectangle(last_clip_x, last_clip_y, last_clip_w, last_clip_h);
|
||||||
|
al_use_transform(&last_transform);
|
||||||
|
al_use_projection_transform(&last_projection_transform);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ImGui_ImplAllegro5_CreateDeviceObjects()
|
||||||
|
{
|
||||||
|
// Build texture atlas
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
unsigned char* pixels;
|
||||||
|
int width, height;
|
||||||
|
io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height);
|
||||||
|
|
||||||
|
// Create texture
|
||||||
|
int flags = al_get_new_bitmap_flags();
|
||||||
|
int fmt = al_get_new_bitmap_format();
|
||||||
|
al_set_new_bitmap_flags(ALLEGRO_MEMORY_BITMAP | ALLEGRO_MIN_LINEAR | ALLEGRO_MAG_LINEAR);
|
||||||
|
al_set_new_bitmap_format(ALLEGRO_PIXEL_FORMAT_ABGR_8888_LE);
|
||||||
|
ALLEGRO_BITMAP* img = al_create_bitmap(width, height);
|
||||||
|
al_set_new_bitmap_flags(flags);
|
||||||
|
al_set_new_bitmap_format(fmt);
|
||||||
|
if (!img)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
ALLEGRO_LOCKED_REGION* locked_img = al_lock_bitmap(img, al_get_bitmap_format(img), ALLEGRO_LOCK_WRITEONLY);
|
||||||
|
if (!locked_img)
|
||||||
|
{
|
||||||
|
al_destroy_bitmap(img);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
memcpy(locked_img->data, pixels, sizeof(int) * width * height);
|
||||||
|
al_unlock_bitmap(img);
|
||||||
|
|
||||||
|
// Convert software texture to hardware texture.
|
||||||
|
ALLEGRO_BITMAP* cloned_img = al_clone_bitmap(img);
|
||||||
|
al_destroy_bitmap(img);
|
||||||
|
if (!cloned_img)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Store our identifier
|
||||||
|
io.Fonts->SetTexID((void*)cloned_img);
|
||||||
|
g_Texture = cloned_img;
|
||||||
|
|
||||||
|
// Create an invisible mouse cursor
|
||||||
|
// Because al_hide_mouse_cursor() seems to mess up with the actual inputs..
|
||||||
|
ALLEGRO_BITMAP* mouse_cursor = al_create_bitmap(8, 8);
|
||||||
|
g_MouseCursorInvisible = al_create_mouse_cursor(mouse_cursor, 0, 0);
|
||||||
|
al_destroy_bitmap(mouse_cursor);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGui_ImplAllegro5_InvalidateDeviceObjects()
|
||||||
|
{
|
||||||
|
if (g_Texture)
|
||||||
|
{
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
io.Fonts->SetTexID(NULL);
|
||||||
|
al_destroy_bitmap(g_Texture);
|
||||||
|
g_Texture = NULL;
|
||||||
|
}
|
||||||
|
if (g_MouseCursorInvisible)
|
||||||
|
{
|
||||||
|
al_destroy_mouse_cursor(g_MouseCursorInvisible);
|
||||||
|
g_MouseCursorInvisible = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#if ALLEGRO_HAS_CLIPBOARD
|
||||||
|
static const char* ImGui_ImplAllegro5_GetClipboardText(void*)
|
||||||
|
{
|
||||||
|
if (g_ClipboardTextData)
|
||||||
|
al_free(g_ClipboardTextData);
|
||||||
|
g_ClipboardTextData = al_get_clipboard_text(g_Display);
|
||||||
|
return g_ClipboardTextData;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ImGui_ImplAllegro5_SetClipboardText(void*, const char* text)
|
||||||
|
{
|
||||||
|
al_set_clipboard_text(g_Display, text);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
bool ImGui_ImplAllegro5_Init(ALLEGRO_DISPLAY* display)
|
||||||
|
{
|
||||||
|
g_Display = display;
|
||||||
|
|
||||||
|
// Setup backend capabilities flags
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
io.BackendFlags |= ImGuiBackendFlags_HasMouseCursors; // We can honor GetMouseCursor() values (optional)
|
||||||
|
io.BackendPlatformName = io.BackendRendererName = "imgui_impl_allegro5";
|
||||||
|
|
||||||
|
// Create custom vertex declaration.
|
||||||
|
// Unfortunately Allegro doesn't support 32-bit packed colors so we have to convert them to 4 floats.
|
||||||
|
// We still use a custom declaration to use 'ALLEGRO_PRIM_TEX_COORD' instead of 'ALLEGRO_PRIM_TEX_COORD_PIXEL' else we can't do a reliable conversion.
|
||||||
|
ALLEGRO_VERTEX_ELEMENT elems[] =
|
||||||
|
{
|
||||||
|
{ ALLEGRO_PRIM_POSITION, ALLEGRO_PRIM_FLOAT_2, IM_OFFSETOF(ImDrawVertAllegro, pos) },
|
||||||
|
{ ALLEGRO_PRIM_TEX_COORD, ALLEGRO_PRIM_FLOAT_2, IM_OFFSETOF(ImDrawVertAllegro, uv) },
|
||||||
|
{ ALLEGRO_PRIM_COLOR_ATTR, 0, IM_OFFSETOF(ImDrawVertAllegro, col) },
|
||||||
|
{ 0, 0, 0 }
|
||||||
|
};
|
||||||
|
g_VertexDecl = al_create_vertex_decl(elems, sizeof(ImDrawVertAllegro));
|
||||||
|
|
||||||
|
io.KeyMap[ImGuiKey_Tab] = ALLEGRO_KEY_TAB;
|
||||||
|
io.KeyMap[ImGuiKey_LeftArrow] = ALLEGRO_KEY_LEFT;
|
||||||
|
io.KeyMap[ImGuiKey_RightArrow] = ALLEGRO_KEY_RIGHT;
|
||||||
|
io.KeyMap[ImGuiKey_UpArrow] = ALLEGRO_KEY_UP;
|
||||||
|
io.KeyMap[ImGuiKey_DownArrow] = ALLEGRO_KEY_DOWN;
|
||||||
|
io.KeyMap[ImGuiKey_PageUp] = ALLEGRO_KEY_PGUP;
|
||||||
|
io.KeyMap[ImGuiKey_PageDown] = ALLEGRO_KEY_PGDN;
|
||||||
|
io.KeyMap[ImGuiKey_Home] = ALLEGRO_KEY_HOME;
|
||||||
|
io.KeyMap[ImGuiKey_End] = ALLEGRO_KEY_END;
|
||||||
|
io.KeyMap[ImGuiKey_Insert] = ALLEGRO_KEY_INSERT;
|
||||||
|
io.KeyMap[ImGuiKey_Delete] = ALLEGRO_KEY_DELETE;
|
||||||
|
io.KeyMap[ImGuiKey_Backspace] = ALLEGRO_KEY_BACKSPACE;
|
||||||
|
io.KeyMap[ImGuiKey_Space] = ALLEGRO_KEY_SPACE;
|
||||||
|
io.KeyMap[ImGuiKey_Enter] = ALLEGRO_KEY_ENTER;
|
||||||
|
io.KeyMap[ImGuiKey_Escape] = ALLEGRO_KEY_ESCAPE;
|
||||||
|
io.KeyMap[ImGuiKey_KeyPadEnter] = ALLEGRO_KEY_PAD_ENTER;
|
||||||
|
io.KeyMap[ImGuiKey_A] = ALLEGRO_KEY_A;
|
||||||
|
io.KeyMap[ImGuiKey_C] = ALLEGRO_KEY_C;
|
||||||
|
io.KeyMap[ImGuiKey_V] = ALLEGRO_KEY_V;
|
||||||
|
io.KeyMap[ImGuiKey_X] = ALLEGRO_KEY_X;
|
||||||
|
io.KeyMap[ImGuiKey_Y] = ALLEGRO_KEY_Y;
|
||||||
|
io.KeyMap[ImGuiKey_Z] = ALLEGRO_KEY_Z;
|
||||||
|
io.MousePos = ImVec2(-FLT_MAX, -FLT_MAX);
|
||||||
|
|
||||||
|
#if ALLEGRO_HAS_CLIPBOARD
|
||||||
|
io.SetClipboardTextFn = ImGui_ImplAllegro5_SetClipboardText;
|
||||||
|
io.GetClipboardTextFn = ImGui_ImplAllegro5_GetClipboardText;
|
||||||
|
io.ClipboardUserData = NULL;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGui_ImplAllegro5_Shutdown()
|
||||||
|
{
|
||||||
|
ImGui_ImplAllegro5_InvalidateDeviceObjects();
|
||||||
|
|
||||||
|
g_Display = NULL;
|
||||||
|
g_Time = 0.0;
|
||||||
|
|
||||||
|
if (g_VertexDecl)
|
||||||
|
al_destroy_vertex_decl(g_VertexDecl);
|
||||||
|
g_VertexDecl = NULL;
|
||||||
|
|
||||||
|
if (g_ClipboardTextData)
|
||||||
|
al_free(g_ClipboardTextData);
|
||||||
|
g_ClipboardTextData = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// You can read the io.WantCaptureMouse, io.WantCaptureKeyboard flags to tell if dear imgui wants to use your inputs.
|
||||||
|
// - When io.WantCaptureMouse is true, do not dispatch mouse input data to your main application.
|
||||||
|
// - When io.WantCaptureKeyboard is true, do not dispatch keyboard input data to your main application.
|
||||||
|
// Generally you may always pass all inputs to dear imgui, and hide them from your application based on those two flags.
|
||||||
|
bool ImGui_ImplAllegro5_ProcessEvent(ALLEGRO_EVENT* ev)
|
||||||
|
{
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
|
||||||
|
switch (ev->type)
|
||||||
|
{
|
||||||
|
case ALLEGRO_EVENT_MOUSE_AXES:
|
||||||
|
if (ev->mouse.display == g_Display)
|
||||||
|
{
|
||||||
|
io.MouseWheel += ev->mouse.dz;
|
||||||
|
io.MouseWheelH -= ev->mouse.dw;
|
||||||
|
io.MousePos = ImVec2(ev->mouse.x, ev->mouse.y);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
case ALLEGRO_EVENT_MOUSE_BUTTON_DOWN:
|
||||||
|
case ALLEGRO_EVENT_MOUSE_BUTTON_UP:
|
||||||
|
if (ev->mouse.display == g_Display && ev->mouse.button <= 5)
|
||||||
|
io.MouseDown[ev->mouse.button - 1] = (ev->type == ALLEGRO_EVENT_MOUSE_BUTTON_DOWN);
|
||||||
|
return true;
|
||||||
|
case ALLEGRO_EVENT_TOUCH_MOVE:
|
||||||
|
if (ev->touch.display == g_Display)
|
||||||
|
io.MousePos = ImVec2(ev->touch.x, ev->touch.y);
|
||||||
|
return true;
|
||||||
|
case ALLEGRO_EVENT_TOUCH_BEGIN:
|
||||||
|
case ALLEGRO_EVENT_TOUCH_END:
|
||||||
|
case ALLEGRO_EVENT_TOUCH_CANCEL:
|
||||||
|
if (ev->touch.display == g_Display && ev->touch.primary)
|
||||||
|
io.MouseDown[0] = (ev->type == ALLEGRO_EVENT_TOUCH_BEGIN);
|
||||||
|
return true;
|
||||||
|
case ALLEGRO_EVENT_MOUSE_LEAVE_DISPLAY:
|
||||||
|
if (ev->mouse.display == g_Display)
|
||||||
|
io.MousePos = ImVec2(-FLT_MAX, -FLT_MAX);
|
||||||
|
return true;
|
||||||
|
case ALLEGRO_EVENT_KEY_CHAR:
|
||||||
|
if (ev->keyboard.display == g_Display)
|
||||||
|
if (ev->keyboard.unichar != 0)
|
||||||
|
io.AddInputCharacter((unsigned int)ev->keyboard.unichar);
|
||||||
|
return true;
|
||||||
|
case ALLEGRO_EVENT_KEY_DOWN:
|
||||||
|
case ALLEGRO_EVENT_KEY_UP:
|
||||||
|
if (ev->keyboard.display == g_Display)
|
||||||
|
io.KeysDown[ev->keyboard.keycode] = (ev->type == ALLEGRO_EVENT_KEY_DOWN);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ImGui_ImplAllegro5_UpdateMouseCursor()
|
||||||
|
{
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
if (io.ConfigFlags & ImGuiConfigFlags_NoMouseCursorChange)
|
||||||
|
return;
|
||||||
|
|
||||||
|
ImGuiMouseCursor imgui_cursor = ImGui::GetMouseCursor();
|
||||||
|
if (io.MouseDrawCursor || imgui_cursor == ImGuiMouseCursor_None)
|
||||||
|
{
|
||||||
|
// Hide OS mouse cursor if imgui is drawing it or if it wants no cursor
|
||||||
|
al_set_mouse_cursor(g_Display, g_MouseCursorInvisible);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ALLEGRO_SYSTEM_MOUSE_CURSOR cursor_id = ALLEGRO_SYSTEM_MOUSE_CURSOR_DEFAULT;
|
||||||
|
switch (imgui_cursor)
|
||||||
|
{
|
||||||
|
case ImGuiMouseCursor_TextInput: cursor_id = ALLEGRO_SYSTEM_MOUSE_CURSOR_EDIT; break;
|
||||||
|
case ImGuiMouseCursor_ResizeAll: cursor_id = ALLEGRO_SYSTEM_MOUSE_CURSOR_MOVE; break;
|
||||||
|
case ImGuiMouseCursor_ResizeNS: cursor_id = ALLEGRO_SYSTEM_MOUSE_CURSOR_RESIZE_N; break;
|
||||||
|
case ImGuiMouseCursor_ResizeEW: cursor_id = ALLEGRO_SYSTEM_MOUSE_CURSOR_RESIZE_E; break;
|
||||||
|
case ImGuiMouseCursor_ResizeNESW: cursor_id = ALLEGRO_SYSTEM_MOUSE_CURSOR_RESIZE_NE; break;
|
||||||
|
case ImGuiMouseCursor_ResizeNWSE: cursor_id = ALLEGRO_SYSTEM_MOUSE_CURSOR_RESIZE_NW; break;
|
||||||
|
case ImGuiMouseCursor_NotAllowed: cursor_id = ALLEGRO_SYSTEM_MOUSE_CURSOR_UNAVAILABLE; break;
|
||||||
|
}
|
||||||
|
al_set_system_mouse_cursor(g_Display, cursor_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGui_ImplAllegro5_NewFrame()
|
||||||
|
{
|
||||||
|
if (!g_Texture)
|
||||||
|
ImGui_ImplAllegro5_CreateDeviceObjects();
|
||||||
|
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
|
||||||
|
// Setup display size (every frame to accommodate for window resizing)
|
||||||
|
int w, h;
|
||||||
|
w = al_get_display_width(g_Display);
|
||||||
|
h = al_get_display_height(g_Display);
|
||||||
|
io.DisplaySize = ImVec2((float)w, (float)h);
|
||||||
|
|
||||||
|
// Setup time step
|
||||||
|
double current_time = al_get_time();
|
||||||
|
io.DeltaTime = g_Time > 0.0 ? (float)(current_time - g_Time) : (float)(1.0f / 60.0f);
|
||||||
|
g_Time = current_time;
|
||||||
|
|
||||||
|
// Setup inputs
|
||||||
|
ALLEGRO_KEYBOARD_STATE keys;
|
||||||
|
al_get_keyboard_state(&keys);
|
||||||
|
io.KeyCtrl = al_key_down(&keys, ALLEGRO_KEY_LCTRL) || al_key_down(&keys, ALLEGRO_KEY_RCTRL);
|
||||||
|
io.KeyShift = al_key_down(&keys, ALLEGRO_KEY_LSHIFT) || al_key_down(&keys, ALLEGRO_KEY_RSHIFT);
|
||||||
|
io.KeyAlt = al_key_down(&keys, ALLEGRO_KEY_ALT) || al_key_down(&keys, ALLEGRO_KEY_ALTGR);
|
||||||
|
io.KeySuper = al_key_down(&keys, ALLEGRO_KEY_LWIN) || al_key_down(&keys, ALLEGRO_KEY_RWIN);
|
||||||
|
|
||||||
|
ImGui_ImplAllegro5_UpdateMouseCursor();
|
||||||
|
}
|
30
backend/imgui_impl_allegro5.h
Normal file
30
backend/imgui_impl_allegro5.h
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
// dear imgui: Renderer + Platform Backend for Allegro 5
|
||||||
|
// (Info: Allegro 5 is a cross-platform general purpose library for handling windows, inputs, graphics, etc.)
|
||||||
|
|
||||||
|
// Implemented features:
|
||||||
|
// [X] Renderer: User texture binding. Use 'ALLEGRO_BITMAP*' as ImTextureID. Read the FAQ about ImTextureID!
|
||||||
|
// [X] Platform: Clipboard support (from Allegro 5.1.12)
|
||||||
|
// [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'.
|
||||||
|
// Issues:
|
||||||
|
// [ ] Renderer: The renderer is suboptimal as we need to unindex our buffers and convert vertices manually.
|
||||||
|
// [ ] Platform: Missing gamepad support.
|
||||||
|
|
||||||
|
// You can copy and use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
||||||
|
// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
|
||||||
|
// Read online: https://github.com/ocornut/imgui/tree/master/docs
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include "imgui.h" // IMGUI_IMPL_API
|
||||||
|
|
||||||
|
struct ALLEGRO_DISPLAY;
|
||||||
|
union ALLEGRO_EVENT;
|
||||||
|
|
||||||
|
IMGUI_IMPL_API bool ImGui_ImplAllegro5_Init(ALLEGRO_DISPLAY* display);
|
||||||
|
IMGUI_IMPL_API void ImGui_ImplAllegro5_Shutdown();
|
||||||
|
IMGUI_IMPL_API void ImGui_ImplAllegro5_NewFrame();
|
||||||
|
IMGUI_IMPL_API void ImGui_ImplAllegro5_RenderDrawData(ImDrawData* draw_data);
|
||||||
|
IMGUI_IMPL_API bool ImGui_ImplAllegro5_ProcessEvent(ALLEGRO_EVENT* event);
|
||||||
|
|
||||||
|
// Use if you want to reset your rendering device without losing Dear ImGui state.
|
||||||
|
IMGUI_IMPL_API bool ImGui_ImplAllegro5_CreateDeviceObjects();
|
||||||
|
IMGUI_IMPL_API void ImGui_ImplAllegro5_InvalidateDeviceObjects();
|
187
backend/imgui_impl_android.cpp
Normal file
187
backend/imgui_impl_android.cpp
Normal file
@ -0,0 +1,187 @@
|
|||||||
|
// dear imgui: Platform Binding for Android native app
|
||||||
|
// This needs to be used along with the OpenGL 3 Renderer (imgui_impl_opengl3)
|
||||||
|
|
||||||
|
// Implemented features:
|
||||||
|
// [X] Platform: Keyboard arrays indexed using AKEYCODE_* codes, e.g. ImGui::IsKeyPressed(AKEYCODE_SPACE).
|
||||||
|
// Missing features:
|
||||||
|
// [ ] Platform: Clipboard support.
|
||||||
|
// [ ] Platform: Gamepad support. Enable with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'.
|
||||||
|
// [ ] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. FIXME: Check if this is even possible with Android.
|
||||||
|
// Important:
|
||||||
|
// - FIXME: On-screen keyboard currently needs to be enabled by the application (see examples/ and issue #3446)
|
||||||
|
// - FIXME: Unicode character inputs needs to be passed by Dear ImGui by the application (see examples/ and issue #3446)
|
||||||
|
|
||||||
|
// You can copy and use unmodified imgui_impl_* files in your project. See main.cpp for an example of using this.
|
||||||
|
// If you are new to dear imgui, read examples/README.txt and read the documentation at the top of imgui.cpp.
|
||||||
|
// https://github.com/ocornut/imgui
|
||||||
|
|
||||||
|
// CHANGELOG
|
||||||
|
// (minor and older changes stripped away, please see git history for details)
|
||||||
|
// 2021-03-04: Initial version.
|
||||||
|
|
||||||
|
#include "imgui.h"
|
||||||
|
#include "imgui_impl_android.h"
|
||||||
|
#include <time.h>
|
||||||
|
#include <map>
|
||||||
|
#include <queue>
|
||||||
|
#include <android/native_window.h>
|
||||||
|
#include <android/input.h>
|
||||||
|
#include <android/keycodes.h>
|
||||||
|
#include <android/log.h>
|
||||||
|
|
||||||
|
// Android data
|
||||||
|
static double g_Time = 0.0;
|
||||||
|
static ANativeWindow* g_Window;
|
||||||
|
static char g_LogTag[] = "ImGuiExample";
|
||||||
|
static std::map<int32_t, std::queue<int32_t>> g_KeyEventQueues; // FIXME: Remove dependency on map and queue once we use upcoming input queue.
|
||||||
|
|
||||||
|
int32_t ImGui_ImplAndroid_HandleInputEvent(AInputEvent* input_event)
|
||||||
|
{
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
int32_t event_type = AInputEvent_getType(input_event);
|
||||||
|
switch (event_type)
|
||||||
|
{
|
||||||
|
case AINPUT_EVENT_TYPE_KEY:
|
||||||
|
{
|
||||||
|
int32_t event_key_code = AKeyEvent_getKeyCode(input_event);
|
||||||
|
int32_t event_action = AKeyEvent_getAction(input_event);
|
||||||
|
int32_t event_meta_state = AKeyEvent_getMetaState(input_event);
|
||||||
|
|
||||||
|
io.KeyCtrl = ((event_meta_state & AMETA_CTRL_ON) != 0);
|
||||||
|
io.KeyShift = ((event_meta_state & AMETA_SHIFT_ON) != 0);
|
||||||
|
io.KeyAlt = ((event_meta_state & AMETA_ALT_ON) != 0);
|
||||||
|
|
||||||
|
switch (event_action)
|
||||||
|
{
|
||||||
|
// FIXME: AKEY_EVENT_ACTION_DOWN and AKEY_EVENT_ACTION_UP occur at once as soon as a touch pointer
|
||||||
|
// goes up from a key. We use a simple key event queue/ and process one event per key per frame in
|
||||||
|
// ImGui_ImplAndroid_NewFrame()...or consider using IO queue, if suitable: https://github.com/ocornut/imgui/issues/2787
|
||||||
|
case AKEY_EVENT_ACTION_DOWN:
|
||||||
|
case AKEY_EVENT_ACTION_UP:
|
||||||
|
g_KeyEventQueues[event_key_code].push(event_action);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case AINPUT_EVENT_TYPE_MOTION:
|
||||||
|
{
|
||||||
|
int32_t event_action = AMotionEvent_getAction(input_event);
|
||||||
|
int32_t event_pointer_index = (event_action & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK) >> AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT;
|
||||||
|
event_action &= AMOTION_EVENT_ACTION_MASK;
|
||||||
|
switch (event_action)
|
||||||
|
{
|
||||||
|
case AMOTION_EVENT_ACTION_DOWN:
|
||||||
|
case AMOTION_EVENT_ACTION_UP:
|
||||||
|
// Physical mouse buttons (and probably other physical devices) also invoke the actions AMOTION_EVENT_ACTION_DOWN/_UP,
|
||||||
|
// but we have to process them separately to identify the actual button pressed. This is done below via
|
||||||
|
// AMOTION_EVENT_ACTION_BUTTON_PRESS/_RELEASE. Here, we only process "FINGER" input (and "UNKNOWN", as a fallback).
|
||||||
|
if((AMotionEvent_getToolType(input_event, event_pointer_index) == AMOTION_EVENT_TOOL_TYPE_FINGER)
|
||||||
|
|| (AMotionEvent_getToolType(input_event, event_pointer_index) == AMOTION_EVENT_TOOL_TYPE_UNKNOWN))
|
||||||
|
{
|
||||||
|
io.MouseDown[0] = (event_action == AMOTION_EVENT_ACTION_DOWN) ? true : false;
|
||||||
|
io.MousePos = ImVec2(AMotionEvent_getX(input_event, event_pointer_index), AMotionEvent_getY(input_event, event_pointer_index));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case AMOTION_EVENT_ACTION_BUTTON_PRESS:
|
||||||
|
case AMOTION_EVENT_ACTION_BUTTON_RELEASE:
|
||||||
|
{
|
||||||
|
int32_t button_state = AMotionEvent_getButtonState(input_event);
|
||||||
|
io.MouseDown[0] = (button_state & AMOTION_EVENT_BUTTON_PRIMARY) ? true : false;
|
||||||
|
io.MouseDown[1] = (button_state & AMOTION_EVENT_BUTTON_SECONDARY) ? true : false;
|
||||||
|
io.MouseDown[2] = (button_state & AMOTION_EVENT_BUTTON_TERTIARY) ? true : false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case AMOTION_EVENT_ACTION_HOVER_MOVE: // Hovering: Tool moves while NOT pressed (such as a physical mouse)
|
||||||
|
case AMOTION_EVENT_ACTION_MOVE: // Touch pointer moves while DOWN
|
||||||
|
io.MousePos = ImVec2(AMotionEvent_getX(input_event, event_pointer_index), AMotionEvent_getY(input_event, event_pointer_index));
|
||||||
|
break;
|
||||||
|
case AMOTION_EVENT_ACTION_SCROLL:
|
||||||
|
io.MouseWheel = AMotionEvent_getAxisValue(input_event, AMOTION_EVENT_AXIS_VSCROLL, event_pointer_index);
|
||||||
|
io.MouseWheelH = AMotionEvent_getAxisValue(input_event, AMOTION_EVENT_AXIS_HSCROLL, event_pointer_index);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ImGui_ImplAndroid_Init(ANativeWindow* window)
|
||||||
|
{
|
||||||
|
g_Window = window;
|
||||||
|
g_Time = 0.0;
|
||||||
|
|
||||||
|
// Setup backend capabilities flags
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
io.BackendPlatformName = "imgui_impl_android";
|
||||||
|
|
||||||
|
// Keyboard mapping. Dear ImGui will use those indices to peek into the io.KeysDown[] array.
|
||||||
|
io.KeyMap[ImGuiKey_Tab] = AKEYCODE_TAB;
|
||||||
|
io.KeyMap[ImGuiKey_LeftArrow] = AKEYCODE_DPAD_LEFT; // also covers physical keyboard arrow key
|
||||||
|
io.KeyMap[ImGuiKey_RightArrow] = AKEYCODE_DPAD_RIGHT; // also covers physical keyboard arrow key
|
||||||
|
io.KeyMap[ImGuiKey_UpArrow] = AKEYCODE_DPAD_UP; // also covers physical keyboard arrow key
|
||||||
|
io.KeyMap[ImGuiKey_DownArrow] = AKEYCODE_DPAD_DOWN; // also covers physical keyboard arrow key
|
||||||
|
io.KeyMap[ImGuiKey_PageUp] = AKEYCODE_PAGE_UP;
|
||||||
|
io.KeyMap[ImGuiKey_PageDown] = AKEYCODE_PAGE_DOWN;
|
||||||
|
io.KeyMap[ImGuiKey_Home] = AKEYCODE_MOVE_HOME;
|
||||||
|
io.KeyMap[ImGuiKey_End] = AKEYCODE_MOVE_END;
|
||||||
|
io.KeyMap[ImGuiKey_Insert] = AKEYCODE_INSERT;
|
||||||
|
io.KeyMap[ImGuiKey_Delete] = AKEYCODE_FORWARD_DEL;
|
||||||
|
io.KeyMap[ImGuiKey_Backspace] = AKEYCODE_DEL;
|
||||||
|
io.KeyMap[ImGuiKey_Space] = AKEYCODE_SPACE;
|
||||||
|
io.KeyMap[ImGuiKey_Enter] = AKEYCODE_ENTER;
|
||||||
|
io.KeyMap[ImGuiKey_Escape] = AKEYCODE_ESCAPE;
|
||||||
|
io.KeyMap[ImGuiKey_KeyPadEnter] = AKEYCODE_NUMPAD_ENTER;
|
||||||
|
io.KeyMap[ImGuiKey_A] = AKEYCODE_A;
|
||||||
|
io.KeyMap[ImGuiKey_C] = AKEYCODE_C;
|
||||||
|
io.KeyMap[ImGuiKey_V] = AKEYCODE_V;
|
||||||
|
io.KeyMap[ImGuiKey_X] = AKEYCODE_X;
|
||||||
|
io.KeyMap[ImGuiKey_Y] = AKEYCODE_Y;
|
||||||
|
io.KeyMap[ImGuiKey_Z] = AKEYCODE_Z;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGui_ImplAndroid_Shutdown()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGui_ImplAndroid_NewFrame()
|
||||||
|
{
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
IM_ASSERT(io.Fonts->IsBuilt() && "Font atlas not built! It is generally built by the renderer backend. Missing call to renderer _NewFrame() function? e.g. ImGui_ImplOpenGL3_NewFrame().");
|
||||||
|
|
||||||
|
// Process queued key events
|
||||||
|
// FIXME: This is a workaround for multiple key event actions occurring at once (see above) and can be removed once we use upcoming input queue.
|
||||||
|
for (auto& key_queue : g_KeyEventQueues)
|
||||||
|
{
|
||||||
|
if (key_queue.second.empty())
|
||||||
|
continue;
|
||||||
|
io.KeysDown[key_queue.first] = (key_queue.second.front() == AKEY_EVENT_ACTION_DOWN);
|
||||||
|
key_queue.second.pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Setup display size (every frame to accommodate for window resizing)
|
||||||
|
int32_t window_width = ANativeWindow_getWidth(g_Window);
|
||||||
|
int32_t window_height = ANativeWindow_getHeight(g_Window);
|
||||||
|
int display_width = window_width;
|
||||||
|
int display_height = window_height;
|
||||||
|
|
||||||
|
io.DisplaySize = ImVec2((float)window_width, (float)window_height);
|
||||||
|
if (window_width > 0 && window_height > 0)
|
||||||
|
io.DisplayFramebufferScale = ImVec2((float)display_width / window_width, (float)display_height / window_height);
|
||||||
|
|
||||||
|
// Setup time step
|
||||||
|
struct timespec current_timespec;
|
||||||
|
clock_gettime(CLOCK_MONOTONIC, ¤t_timespec);
|
||||||
|
double current_time = (double)(current_timespec.tv_sec) + (current_timespec.tv_nsec / 1000000000.0);
|
||||||
|
io.DeltaTime = g_Time > 0.0 ? (float)(current_time - g_Time) : (float)(1.0f / 60.0f);
|
||||||
|
g_Time = current_time;
|
||||||
|
}
|
26
backend/imgui_impl_android.h
Normal file
26
backend/imgui_impl_android.h
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
// dear imgui: Platform Binding for Android native app
|
||||||
|
// This needs to be used along with the OpenGL 3 Renderer (imgui_impl_opengl3)
|
||||||
|
|
||||||
|
// Implemented features:
|
||||||
|
// [X] Platform: Keyboard arrays indexed using AKEYCODE_* codes, e.g. ImGui::IsKeyPressed(AKEYCODE_SPACE).
|
||||||
|
// Missing features:
|
||||||
|
// [ ] Platform: Clipboard support.
|
||||||
|
// [ ] Platform: Gamepad support. Enable with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'.
|
||||||
|
// [ ] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. FIXME: Check if this is even possible with Android.
|
||||||
|
// Important:
|
||||||
|
// - FIXME: On-screen keyboard currently needs to be enabled by the application (see examples/ and issue #3446)
|
||||||
|
// - FIXME: Unicode character inputs needs to be passed by Dear ImGui by the application (see examples/ and issue #3446)
|
||||||
|
|
||||||
|
// You can copy and use unmodified imgui_impl_* files in your project. See main.cpp for an example of using this.
|
||||||
|
// If you are new to dear imgui, read examples/README.txt and read the documentation at the top of imgui.cpp.
|
||||||
|
// https://github.com/ocornut/imgui
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
struct ANativeWindow;
|
||||||
|
struct AInputEvent;
|
||||||
|
|
||||||
|
IMGUI_IMPL_API bool ImGui_ImplAndroid_Init(ANativeWindow* window);
|
||||||
|
IMGUI_IMPL_API int32_t ImGui_ImplAndroid_HandleInputEvent(AInputEvent* input_event);
|
||||||
|
IMGUI_IMPL_API void ImGui_ImplAndroid_Shutdown();
|
||||||
|
IMGUI_IMPL_API void ImGui_ImplAndroid_NewFrame();
|
536
backend/imgui_impl_dx10.cpp
Normal file
536
backend/imgui_impl_dx10.cpp
Normal file
@ -0,0 +1,536 @@
|
|||||||
|
// dear imgui: Renderer Backend for DirectX10
|
||||||
|
// This needs to be used along with a Platform Backend (e.g. Win32)
|
||||||
|
|
||||||
|
// Implemented features:
|
||||||
|
// [X] Renderer: User texture backend. Use 'ID3D10ShaderResourceView*' as ImTextureID. Read the FAQ about ImTextureID!
|
||||||
|
// [X] Renderer: Support for large meshes (64k+ vertices) with 16-bit indices.
|
||||||
|
|
||||||
|
// You can copy and use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
||||||
|
// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
|
||||||
|
// Read online: https://github.com/ocornut/imgui/tree/master/docs
|
||||||
|
|
||||||
|
// CHANGELOG
|
||||||
|
// (minor and older changes stripped away, please see git history for details)
|
||||||
|
// 2021-02-18: DirectX10: Change blending equation to preserve alpha in output buffer.
|
||||||
|
// 2019-07-21: DirectX10: Backup, clear and restore Geometry Shader is any is bound when calling ImGui_ImplDX10_RenderDrawData().
|
||||||
|
// 2019-05-29: DirectX10: Added support for large mesh (64K+ vertices), enable ImGuiBackendFlags_RendererHasVtxOffset flag.
|
||||||
|
// 2019-04-30: DirectX10: Added support for special ImDrawCallback_ResetRenderState callback to reset render state.
|
||||||
|
// 2018-12-03: Misc: Added #pragma comment statement to automatically link with d3dcompiler.lib when using D3DCompile().
|
||||||
|
// 2018-11-30: Misc: Setting up io.BackendRendererName so it can be displayed in the About Window.
|
||||||
|
// 2018-07-13: DirectX10: Fixed unreleased resources in Init and Shutdown functions.
|
||||||
|
// 2018-06-08: Misc: Extracted imgui_impl_dx10.cpp/.h away from the old combined DX10+Win32 example.
|
||||||
|
// 2018-06-08: DirectX10: Use draw_data->DisplayPos and draw_data->DisplaySize to setup projection matrix and clipping rectangle.
|
||||||
|
// 2018-04-09: Misc: Fixed erroneous call to io.Fonts->ClearInputData() + ClearTexData() that was left in DX10 example but removed in 1.47 (Nov 2015) on other backends.
|
||||||
|
// 2018-02-16: Misc: Obsoleted the io.RenderDrawListsFn callback and exposed ImGui_ImplDX10_RenderDrawData() in the .h file so you can call it yourself.
|
||||||
|
// 2018-02-06: Misc: Removed call to ImGui::Shutdown() which is not available from 1.60 WIP, user needs to call CreateContext/DestroyContext themselves.
|
||||||
|
// 2016-05-07: DirectX10: Disabling depth-write.
|
||||||
|
|
||||||
|
#include "imgui.h"
|
||||||
|
#include "imgui_impl_dx10.h"
|
||||||
|
|
||||||
|
// DirectX
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <d3d10_1.h>
|
||||||
|
#include <d3d10.h>
|
||||||
|
#include <d3dcompiler.h>
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#pragma comment(lib, "d3dcompiler") // Automatically link with d3dcompiler.lib as we are using D3DCompile() below.
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// DirectX data
|
||||||
|
static ID3D10Device* g_pd3dDevice = NULL;
|
||||||
|
static IDXGIFactory* g_pFactory = NULL;
|
||||||
|
static ID3D10Buffer* g_pVB = NULL;
|
||||||
|
static ID3D10Buffer* g_pIB = NULL;
|
||||||
|
static ID3D10VertexShader* g_pVertexShader = NULL;
|
||||||
|
static ID3D10InputLayout* g_pInputLayout = NULL;
|
||||||
|
static ID3D10Buffer* g_pVertexConstantBuffer = NULL;
|
||||||
|
static ID3D10PixelShader* g_pPixelShader = NULL;
|
||||||
|
static ID3D10SamplerState* g_pFontSampler = NULL;
|
||||||
|
static ID3D10ShaderResourceView*g_pFontTextureView = NULL;
|
||||||
|
static ID3D10RasterizerState* g_pRasterizerState = NULL;
|
||||||
|
static ID3D10BlendState* g_pBlendState = NULL;
|
||||||
|
static ID3D10DepthStencilState* g_pDepthStencilState = NULL;
|
||||||
|
static int g_VertexBufferSize = 5000, g_IndexBufferSize = 10000;
|
||||||
|
|
||||||
|
struct VERTEX_CONSTANT_BUFFER
|
||||||
|
{
|
||||||
|
float mvp[4][4];
|
||||||
|
};
|
||||||
|
|
||||||
|
static void ImGui_ImplDX10_SetupRenderState(ImDrawData* draw_data, ID3D10Device* ctx)
|
||||||
|
{
|
||||||
|
// Setup viewport
|
||||||
|
D3D10_VIEWPORT vp;
|
||||||
|
memset(&vp, 0, sizeof(D3D10_VIEWPORT));
|
||||||
|
vp.Width = (UINT)draw_data->DisplaySize.x;
|
||||||
|
vp.Height = (UINT)draw_data->DisplaySize.y;
|
||||||
|
vp.MinDepth = 0.0f;
|
||||||
|
vp.MaxDepth = 1.0f;
|
||||||
|
vp.TopLeftX = vp.TopLeftY = 0;
|
||||||
|
ctx->RSSetViewports(1, &vp);
|
||||||
|
|
||||||
|
// Bind shader and vertex buffers
|
||||||
|
unsigned int stride = sizeof(ImDrawVert);
|
||||||
|
unsigned int offset = 0;
|
||||||
|
ctx->IASetInputLayout(g_pInputLayout);
|
||||||
|
ctx->IASetVertexBuffers(0, 1, &g_pVB, &stride, &offset);
|
||||||
|
ctx->IASetIndexBuffer(g_pIB, sizeof(ImDrawIdx) == 2 ? DXGI_FORMAT_R16_UINT : DXGI_FORMAT_R32_UINT, 0);
|
||||||
|
ctx->IASetPrimitiveTopology(D3D10_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
|
||||||
|
ctx->VSSetShader(g_pVertexShader);
|
||||||
|
ctx->VSSetConstantBuffers(0, 1, &g_pVertexConstantBuffer);
|
||||||
|
ctx->PSSetShader(g_pPixelShader);
|
||||||
|
ctx->PSSetSamplers(0, 1, &g_pFontSampler);
|
||||||
|
ctx->GSSetShader(NULL);
|
||||||
|
|
||||||
|
// Setup render state
|
||||||
|
const float blend_factor[4] = { 0.f, 0.f, 0.f, 0.f };
|
||||||
|
ctx->OMSetBlendState(g_pBlendState, blend_factor, 0xffffffff);
|
||||||
|
ctx->OMSetDepthStencilState(g_pDepthStencilState, 0);
|
||||||
|
ctx->RSSetState(g_pRasterizerState);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Render function
|
||||||
|
void ImGui_ImplDX10_RenderDrawData(ImDrawData* draw_data)
|
||||||
|
{
|
||||||
|
// Avoid rendering when minimized
|
||||||
|
if (draw_data->DisplaySize.x <= 0.0f || draw_data->DisplaySize.y <= 0.0f)
|
||||||
|
return;
|
||||||
|
|
||||||
|
ID3D10Device* ctx = g_pd3dDevice;
|
||||||
|
|
||||||
|
// Create and grow vertex/index buffers if needed
|
||||||
|
if (!g_pVB || g_VertexBufferSize < draw_data->TotalVtxCount)
|
||||||
|
{
|
||||||
|
if (g_pVB) { g_pVB->Release(); g_pVB = NULL; }
|
||||||
|
g_VertexBufferSize = draw_data->TotalVtxCount + 5000;
|
||||||
|
D3D10_BUFFER_DESC desc;
|
||||||
|
memset(&desc, 0, sizeof(D3D10_BUFFER_DESC));
|
||||||
|
desc.Usage = D3D10_USAGE_DYNAMIC;
|
||||||
|
desc.ByteWidth = g_VertexBufferSize * sizeof(ImDrawVert);
|
||||||
|
desc.BindFlags = D3D10_BIND_VERTEX_BUFFER;
|
||||||
|
desc.CPUAccessFlags = D3D10_CPU_ACCESS_WRITE;
|
||||||
|
desc.MiscFlags = 0;
|
||||||
|
if (ctx->CreateBuffer(&desc, NULL, &g_pVB) < 0)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!g_pIB || g_IndexBufferSize < draw_data->TotalIdxCount)
|
||||||
|
{
|
||||||
|
if (g_pIB) { g_pIB->Release(); g_pIB = NULL; }
|
||||||
|
g_IndexBufferSize = draw_data->TotalIdxCount + 10000;
|
||||||
|
D3D10_BUFFER_DESC desc;
|
||||||
|
memset(&desc, 0, sizeof(D3D10_BUFFER_DESC));
|
||||||
|
desc.Usage = D3D10_USAGE_DYNAMIC;
|
||||||
|
desc.ByteWidth = g_IndexBufferSize * sizeof(ImDrawIdx);
|
||||||
|
desc.BindFlags = D3D10_BIND_INDEX_BUFFER;
|
||||||
|
desc.CPUAccessFlags = D3D10_CPU_ACCESS_WRITE;
|
||||||
|
if (ctx->CreateBuffer(&desc, NULL, &g_pIB) < 0)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy and convert all vertices into a single contiguous buffer
|
||||||
|
ImDrawVert* vtx_dst = NULL;
|
||||||
|
ImDrawIdx* idx_dst = NULL;
|
||||||
|
g_pVB->Map(D3D10_MAP_WRITE_DISCARD, 0, (void**)&vtx_dst);
|
||||||
|
g_pIB->Map(D3D10_MAP_WRITE_DISCARD, 0, (void**)&idx_dst);
|
||||||
|
for (int n = 0; n < draw_data->CmdListsCount; n++)
|
||||||
|
{
|
||||||
|
const ImDrawList* cmd_list = draw_data->CmdLists[n];
|
||||||
|
memcpy(vtx_dst, cmd_list->VtxBuffer.Data, cmd_list->VtxBuffer.Size * sizeof(ImDrawVert));
|
||||||
|
memcpy(idx_dst, cmd_list->IdxBuffer.Data, cmd_list->IdxBuffer.Size * sizeof(ImDrawIdx));
|
||||||
|
vtx_dst += cmd_list->VtxBuffer.Size;
|
||||||
|
idx_dst += cmd_list->IdxBuffer.Size;
|
||||||
|
}
|
||||||
|
g_pVB->Unmap();
|
||||||
|
g_pIB->Unmap();
|
||||||
|
|
||||||
|
// Setup orthographic projection matrix into our constant buffer
|
||||||
|
// Our visible imgui space lies from draw_data->DisplayPos (top left) to draw_data->DisplayPos+data_data->DisplaySize (bottom right). DisplayPos is (0,0) for single viewport apps.
|
||||||
|
{
|
||||||
|
void* mapped_resource;
|
||||||
|
if (g_pVertexConstantBuffer->Map(D3D10_MAP_WRITE_DISCARD, 0, &mapped_resource) != S_OK)
|
||||||
|
return;
|
||||||
|
VERTEX_CONSTANT_BUFFER* constant_buffer = (VERTEX_CONSTANT_BUFFER*)mapped_resource;
|
||||||
|
float L = draw_data->DisplayPos.x;
|
||||||
|
float R = draw_data->DisplayPos.x + draw_data->DisplaySize.x;
|
||||||
|
float T = draw_data->DisplayPos.y;
|
||||||
|
float B = draw_data->DisplayPos.y + draw_data->DisplaySize.y;
|
||||||
|
float mvp[4][4] =
|
||||||
|
{
|
||||||
|
{ 2.0f/(R-L), 0.0f, 0.0f, 0.0f },
|
||||||
|
{ 0.0f, 2.0f/(T-B), 0.0f, 0.0f },
|
||||||
|
{ 0.0f, 0.0f, 0.5f, 0.0f },
|
||||||
|
{ (R+L)/(L-R), (T+B)/(B-T), 0.5f, 1.0f },
|
||||||
|
};
|
||||||
|
memcpy(&constant_buffer->mvp, mvp, sizeof(mvp));
|
||||||
|
g_pVertexConstantBuffer->Unmap();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Backup DX state that will be modified to restore it afterwards (unfortunately this is very ugly looking and verbose. Close your eyes!)
|
||||||
|
struct BACKUP_DX10_STATE
|
||||||
|
{
|
||||||
|
UINT ScissorRectsCount, ViewportsCount;
|
||||||
|
D3D10_RECT ScissorRects[D3D10_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE];
|
||||||
|
D3D10_VIEWPORT Viewports[D3D10_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE];
|
||||||
|
ID3D10RasterizerState* RS;
|
||||||
|
ID3D10BlendState* BlendState;
|
||||||
|
FLOAT BlendFactor[4];
|
||||||
|
UINT SampleMask;
|
||||||
|
UINT StencilRef;
|
||||||
|
ID3D10DepthStencilState* DepthStencilState;
|
||||||
|
ID3D10ShaderResourceView* PSShaderResource;
|
||||||
|
ID3D10SamplerState* PSSampler;
|
||||||
|
ID3D10PixelShader* PS;
|
||||||
|
ID3D10VertexShader* VS;
|
||||||
|
ID3D10GeometryShader* GS;
|
||||||
|
D3D10_PRIMITIVE_TOPOLOGY PrimitiveTopology;
|
||||||
|
ID3D10Buffer* IndexBuffer, *VertexBuffer, *VSConstantBuffer;
|
||||||
|
UINT IndexBufferOffset, VertexBufferStride, VertexBufferOffset;
|
||||||
|
DXGI_FORMAT IndexBufferFormat;
|
||||||
|
ID3D10InputLayout* InputLayout;
|
||||||
|
};
|
||||||
|
BACKUP_DX10_STATE old;
|
||||||
|
old.ScissorRectsCount = old.ViewportsCount = D3D10_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE;
|
||||||
|
ctx->RSGetScissorRects(&old.ScissorRectsCount, old.ScissorRects);
|
||||||
|
ctx->RSGetViewports(&old.ViewportsCount, old.Viewports);
|
||||||
|
ctx->RSGetState(&old.RS);
|
||||||
|
ctx->OMGetBlendState(&old.BlendState, old.BlendFactor, &old.SampleMask);
|
||||||
|
ctx->OMGetDepthStencilState(&old.DepthStencilState, &old.StencilRef);
|
||||||
|
ctx->PSGetShaderResources(0, 1, &old.PSShaderResource);
|
||||||
|
ctx->PSGetSamplers(0, 1, &old.PSSampler);
|
||||||
|
ctx->PSGetShader(&old.PS);
|
||||||
|
ctx->VSGetShader(&old.VS);
|
||||||
|
ctx->VSGetConstantBuffers(0, 1, &old.VSConstantBuffer);
|
||||||
|
ctx->GSGetShader(&old.GS);
|
||||||
|
ctx->IAGetPrimitiveTopology(&old.PrimitiveTopology);
|
||||||
|
ctx->IAGetIndexBuffer(&old.IndexBuffer, &old.IndexBufferFormat, &old.IndexBufferOffset);
|
||||||
|
ctx->IAGetVertexBuffers(0, 1, &old.VertexBuffer, &old.VertexBufferStride, &old.VertexBufferOffset);
|
||||||
|
ctx->IAGetInputLayout(&old.InputLayout);
|
||||||
|
|
||||||
|
// Setup desired DX state
|
||||||
|
ImGui_ImplDX10_SetupRenderState(draw_data, ctx);
|
||||||
|
|
||||||
|
// Render command lists
|
||||||
|
// (Because we merged all buffers into a single one, we maintain our own offset into them)
|
||||||
|
int global_vtx_offset = 0;
|
||||||
|
int global_idx_offset = 0;
|
||||||
|
ImVec2 clip_off = draw_data->DisplayPos;
|
||||||
|
for (int n = 0; n < draw_data->CmdListsCount; n++)
|
||||||
|
{
|
||||||
|
const ImDrawList* cmd_list = draw_data->CmdLists[n];
|
||||||
|
for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++)
|
||||||
|
{
|
||||||
|
const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i];
|
||||||
|
if (pcmd->UserCallback)
|
||||||
|
{
|
||||||
|
// User callback, registered via ImDrawList::AddCallback()
|
||||||
|
// (ImDrawCallback_ResetRenderState is a special callback value used by the user to request the renderer to reset render state.)
|
||||||
|
if (pcmd->UserCallback == ImDrawCallback_ResetRenderState)
|
||||||
|
ImGui_ImplDX10_SetupRenderState(draw_data, ctx);
|
||||||
|
else
|
||||||
|
pcmd->UserCallback(cmd_list, pcmd);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Apply scissor/clipping rectangle
|
||||||
|
const D3D10_RECT r = { (LONG)(pcmd->ClipRect.x - clip_off.x), (LONG)(pcmd->ClipRect.y - clip_off.y), (LONG)(pcmd->ClipRect.z - clip_off.x), (LONG)(pcmd->ClipRect.w - clip_off.y)};
|
||||||
|
ctx->RSSetScissorRects(1, &r);
|
||||||
|
|
||||||
|
// Bind texture, Draw
|
||||||
|
ID3D10ShaderResourceView* texture_srv = (ID3D10ShaderResourceView*)pcmd->TextureId;
|
||||||
|
ctx->PSSetShaderResources(0, 1, &texture_srv);
|
||||||
|
ctx->DrawIndexed(pcmd->ElemCount, pcmd->IdxOffset + global_idx_offset, pcmd->VtxOffset + global_vtx_offset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
global_idx_offset += cmd_list->IdxBuffer.Size;
|
||||||
|
global_vtx_offset += cmd_list->VtxBuffer.Size;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Restore modified DX state
|
||||||
|
ctx->RSSetScissorRects(old.ScissorRectsCount, old.ScissorRects);
|
||||||
|
ctx->RSSetViewports(old.ViewportsCount, old.Viewports);
|
||||||
|
ctx->RSSetState(old.RS); if (old.RS) old.RS->Release();
|
||||||
|
ctx->OMSetBlendState(old.BlendState, old.BlendFactor, old.SampleMask); if (old.BlendState) old.BlendState->Release();
|
||||||
|
ctx->OMSetDepthStencilState(old.DepthStencilState, old.StencilRef); if (old.DepthStencilState) old.DepthStencilState->Release();
|
||||||
|
ctx->PSSetShaderResources(0, 1, &old.PSShaderResource); if (old.PSShaderResource) old.PSShaderResource->Release();
|
||||||
|
ctx->PSSetSamplers(0, 1, &old.PSSampler); if (old.PSSampler) old.PSSampler->Release();
|
||||||
|
ctx->PSSetShader(old.PS); if (old.PS) old.PS->Release();
|
||||||
|
ctx->VSSetShader(old.VS); if (old.VS) old.VS->Release();
|
||||||
|
ctx->GSSetShader(old.GS); if (old.GS) old.GS->Release();
|
||||||
|
ctx->VSSetConstantBuffers(0, 1, &old.VSConstantBuffer); if (old.VSConstantBuffer) old.VSConstantBuffer->Release();
|
||||||
|
ctx->IASetPrimitiveTopology(old.PrimitiveTopology);
|
||||||
|
ctx->IASetIndexBuffer(old.IndexBuffer, old.IndexBufferFormat, old.IndexBufferOffset); if (old.IndexBuffer) old.IndexBuffer->Release();
|
||||||
|
ctx->IASetVertexBuffers(0, 1, &old.VertexBuffer, &old.VertexBufferStride, &old.VertexBufferOffset); if (old.VertexBuffer) old.VertexBuffer->Release();
|
||||||
|
ctx->IASetInputLayout(old.InputLayout); if (old.InputLayout) old.InputLayout->Release();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ImGui_ImplDX10_CreateFontsTexture()
|
||||||
|
{
|
||||||
|
// Build texture atlas
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
unsigned char* pixels;
|
||||||
|
int width, height;
|
||||||
|
io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height);
|
||||||
|
|
||||||
|
// Upload texture to graphics system
|
||||||
|
{
|
||||||
|
D3D10_TEXTURE2D_DESC desc;
|
||||||
|
ZeroMemory(&desc, sizeof(desc));
|
||||||
|
desc.Width = width;
|
||||||
|
desc.Height = height;
|
||||||
|
desc.MipLevels = 1;
|
||||||
|
desc.ArraySize = 1;
|
||||||
|
desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
|
||||||
|
desc.SampleDesc.Count = 1;
|
||||||
|
desc.Usage = D3D10_USAGE_DEFAULT;
|
||||||
|
desc.BindFlags = D3D10_BIND_SHADER_RESOURCE;
|
||||||
|
desc.CPUAccessFlags = 0;
|
||||||
|
|
||||||
|
ID3D10Texture2D* pTexture = NULL;
|
||||||
|
D3D10_SUBRESOURCE_DATA subResource;
|
||||||
|
subResource.pSysMem = pixels;
|
||||||
|
subResource.SysMemPitch = desc.Width * 4;
|
||||||
|
subResource.SysMemSlicePitch = 0;
|
||||||
|
g_pd3dDevice->CreateTexture2D(&desc, &subResource, &pTexture);
|
||||||
|
|
||||||
|
// Create texture view
|
||||||
|
D3D10_SHADER_RESOURCE_VIEW_DESC srv_desc;
|
||||||
|
ZeroMemory(&srv_desc, sizeof(srv_desc));
|
||||||
|
srv_desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
|
||||||
|
srv_desc.ViewDimension = D3D10_SRV_DIMENSION_TEXTURE2D;
|
||||||
|
srv_desc.Texture2D.MipLevels = desc.MipLevels;
|
||||||
|
srv_desc.Texture2D.MostDetailedMip = 0;
|
||||||
|
g_pd3dDevice->CreateShaderResourceView(pTexture, &srv_desc, &g_pFontTextureView);
|
||||||
|
pTexture->Release();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Store our identifier
|
||||||
|
io.Fonts->SetTexID((ImTextureID)g_pFontTextureView);
|
||||||
|
|
||||||
|
// Create texture sampler
|
||||||
|
{
|
||||||
|
D3D10_SAMPLER_DESC desc;
|
||||||
|
ZeroMemory(&desc, sizeof(desc));
|
||||||
|
desc.Filter = D3D10_FILTER_MIN_MAG_MIP_LINEAR;
|
||||||
|
desc.AddressU = D3D10_TEXTURE_ADDRESS_WRAP;
|
||||||
|
desc.AddressV = D3D10_TEXTURE_ADDRESS_WRAP;
|
||||||
|
desc.AddressW = D3D10_TEXTURE_ADDRESS_WRAP;
|
||||||
|
desc.MipLODBias = 0.f;
|
||||||
|
desc.ComparisonFunc = D3D10_COMPARISON_ALWAYS;
|
||||||
|
desc.MinLOD = 0.f;
|
||||||
|
desc.MaxLOD = 0.f;
|
||||||
|
g_pd3dDevice->CreateSamplerState(&desc, &g_pFontSampler);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ImGui_ImplDX10_CreateDeviceObjects()
|
||||||
|
{
|
||||||
|
if (!g_pd3dDevice)
|
||||||
|
return false;
|
||||||
|
if (g_pFontSampler)
|
||||||
|
ImGui_ImplDX10_InvalidateDeviceObjects();
|
||||||
|
|
||||||
|
// By using D3DCompile() from <d3dcompiler.h> / d3dcompiler.lib, we introduce a dependency to a given version of d3dcompiler_XX.dll (see D3DCOMPILER_DLL_A)
|
||||||
|
// If you would like to use this DX10 sample code but remove this dependency you can:
|
||||||
|
// 1) compile once, save the compiled shader blobs into a file or source code and pass them to CreateVertexShader()/CreatePixelShader() [preferred solution]
|
||||||
|
// 2) use code to detect any version of the DLL and grab a pointer to D3DCompile from the DLL.
|
||||||
|
// See https://github.com/ocornut/imgui/pull/638 for sources and details.
|
||||||
|
|
||||||
|
// Create the vertex shader
|
||||||
|
{
|
||||||
|
static const char* vertexShader =
|
||||||
|
"cbuffer vertexBuffer : register(b0) \
|
||||||
|
{\
|
||||||
|
float4x4 ProjectionMatrix; \
|
||||||
|
};\
|
||||||
|
struct VS_INPUT\
|
||||||
|
{\
|
||||||
|
float2 pos : POSITION;\
|
||||||
|
float4 col : COLOR0;\
|
||||||
|
float2 uv : TEXCOORD0;\
|
||||||
|
};\
|
||||||
|
\
|
||||||
|
struct PS_INPUT\
|
||||||
|
{\
|
||||||
|
float4 pos : SV_POSITION;\
|
||||||
|
float4 col : COLOR0;\
|
||||||
|
float2 uv : TEXCOORD0;\
|
||||||
|
};\
|
||||||
|
\
|
||||||
|
PS_INPUT main(VS_INPUT input)\
|
||||||
|
{\
|
||||||
|
PS_INPUT output;\
|
||||||
|
output.pos = mul( ProjectionMatrix, float4(input.pos.xy, 0.f, 1.f));\
|
||||||
|
output.col = input.col;\
|
||||||
|
output.uv = input.uv;\
|
||||||
|
return output;\
|
||||||
|
}";
|
||||||
|
|
||||||
|
ID3DBlob* vertexShaderBlob;
|
||||||
|
if (FAILED(D3DCompile(vertexShader, strlen(vertexShader), NULL, NULL, NULL, "main", "vs_4_0", 0, 0, &vertexShaderBlob, NULL)))
|
||||||
|
return false; // NB: Pass ID3DBlob* pErrorBlob to D3DCompile() to get error showing in (const char*)pErrorBlob->GetBufferPointer(). Make sure to Release() the blob!
|
||||||
|
if (g_pd3dDevice->CreateVertexShader(vertexShaderBlob->GetBufferPointer(), vertexShaderBlob->GetBufferSize(), &g_pVertexShader) != S_OK)
|
||||||
|
{
|
||||||
|
vertexShaderBlob->Release();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the input layout
|
||||||
|
D3D10_INPUT_ELEMENT_DESC local_layout[] =
|
||||||
|
{
|
||||||
|
{ "POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, (UINT)IM_OFFSETOF(ImDrawVert, pos), D3D10_INPUT_PER_VERTEX_DATA, 0 },
|
||||||
|
{ "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, (UINT)IM_OFFSETOF(ImDrawVert, uv), D3D10_INPUT_PER_VERTEX_DATA, 0 },
|
||||||
|
{ "COLOR", 0, DXGI_FORMAT_R8G8B8A8_UNORM, 0, (UINT)IM_OFFSETOF(ImDrawVert, col), D3D10_INPUT_PER_VERTEX_DATA, 0 },
|
||||||
|
};
|
||||||
|
if (g_pd3dDevice->CreateInputLayout(local_layout, 3, vertexShaderBlob->GetBufferPointer(), vertexShaderBlob->GetBufferSize(), &g_pInputLayout) != S_OK)
|
||||||
|
{
|
||||||
|
vertexShaderBlob->Release();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
vertexShaderBlob->Release();
|
||||||
|
|
||||||
|
// Create the constant buffer
|
||||||
|
{
|
||||||
|
D3D10_BUFFER_DESC desc;
|
||||||
|
desc.ByteWidth = sizeof(VERTEX_CONSTANT_BUFFER);
|
||||||
|
desc.Usage = D3D10_USAGE_DYNAMIC;
|
||||||
|
desc.BindFlags = D3D10_BIND_CONSTANT_BUFFER;
|
||||||
|
desc.CPUAccessFlags = D3D10_CPU_ACCESS_WRITE;
|
||||||
|
desc.MiscFlags = 0;
|
||||||
|
g_pd3dDevice->CreateBuffer(&desc, NULL, &g_pVertexConstantBuffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the pixel shader
|
||||||
|
{
|
||||||
|
static const char* pixelShader =
|
||||||
|
"struct PS_INPUT\
|
||||||
|
{\
|
||||||
|
float4 pos : SV_POSITION;\
|
||||||
|
float4 col : COLOR0;\
|
||||||
|
float2 uv : TEXCOORD0;\
|
||||||
|
};\
|
||||||
|
sampler sampler0;\
|
||||||
|
Texture2D texture0;\
|
||||||
|
\
|
||||||
|
float4 main(PS_INPUT input) : SV_Target\
|
||||||
|
{\
|
||||||
|
float4 out_col = input.col * texture0.Sample(sampler0, input.uv); \
|
||||||
|
return out_col; \
|
||||||
|
}";
|
||||||
|
|
||||||
|
ID3DBlob* pixelShaderBlob;
|
||||||
|
if (FAILED(D3DCompile(pixelShader, strlen(pixelShader), NULL, NULL, NULL, "main", "ps_4_0", 0, 0, &pixelShaderBlob, NULL)))
|
||||||
|
return false; // NB: Pass ID3DBlob* pErrorBlob to D3DCompile() to get error showing in (const char*)pErrorBlob->GetBufferPointer(). Make sure to Release() the blob!
|
||||||
|
if (g_pd3dDevice->CreatePixelShader(pixelShaderBlob->GetBufferPointer(), pixelShaderBlob->GetBufferSize(), &g_pPixelShader) != S_OK)
|
||||||
|
{
|
||||||
|
pixelShaderBlob->Release();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
pixelShaderBlob->Release();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the blending setup
|
||||||
|
{
|
||||||
|
D3D10_BLEND_DESC desc;
|
||||||
|
ZeroMemory(&desc, sizeof(desc));
|
||||||
|
desc.AlphaToCoverageEnable = false;
|
||||||
|
desc.BlendEnable[0] = true;
|
||||||
|
desc.SrcBlend = D3D10_BLEND_SRC_ALPHA;
|
||||||
|
desc.DestBlend = D3D10_BLEND_INV_SRC_ALPHA;
|
||||||
|
desc.BlendOp = D3D10_BLEND_OP_ADD;
|
||||||
|
desc.SrcBlendAlpha = D3D10_BLEND_ONE;
|
||||||
|
desc.DestBlendAlpha = D3D10_BLEND_INV_SRC_ALPHA;
|
||||||
|
desc.BlendOpAlpha = D3D10_BLEND_OP_ADD;
|
||||||
|
desc.RenderTargetWriteMask[0] = D3D10_COLOR_WRITE_ENABLE_ALL;
|
||||||
|
g_pd3dDevice->CreateBlendState(&desc, &g_pBlendState);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the rasterizer state
|
||||||
|
{
|
||||||
|
D3D10_RASTERIZER_DESC desc;
|
||||||
|
ZeroMemory(&desc, sizeof(desc));
|
||||||
|
desc.FillMode = D3D10_FILL_SOLID;
|
||||||
|
desc.CullMode = D3D10_CULL_NONE;
|
||||||
|
desc.ScissorEnable = true;
|
||||||
|
desc.DepthClipEnable = true;
|
||||||
|
g_pd3dDevice->CreateRasterizerState(&desc, &g_pRasterizerState);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create depth-stencil State
|
||||||
|
{
|
||||||
|
D3D10_DEPTH_STENCIL_DESC desc;
|
||||||
|
ZeroMemory(&desc, sizeof(desc));
|
||||||
|
desc.DepthEnable = false;
|
||||||
|
desc.DepthWriteMask = D3D10_DEPTH_WRITE_MASK_ALL;
|
||||||
|
desc.DepthFunc = D3D10_COMPARISON_ALWAYS;
|
||||||
|
desc.StencilEnable = false;
|
||||||
|
desc.FrontFace.StencilFailOp = desc.FrontFace.StencilDepthFailOp = desc.FrontFace.StencilPassOp = D3D10_STENCIL_OP_KEEP;
|
||||||
|
desc.FrontFace.StencilFunc = D3D10_COMPARISON_ALWAYS;
|
||||||
|
desc.BackFace = desc.FrontFace;
|
||||||
|
g_pd3dDevice->CreateDepthStencilState(&desc, &g_pDepthStencilState);
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui_ImplDX10_CreateFontsTexture();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGui_ImplDX10_InvalidateDeviceObjects()
|
||||||
|
{
|
||||||
|
if (!g_pd3dDevice)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (g_pFontSampler) { g_pFontSampler->Release(); g_pFontSampler = NULL; }
|
||||||
|
if (g_pFontTextureView) { g_pFontTextureView->Release(); g_pFontTextureView = NULL; ImGui::GetIO().Fonts->SetTexID(NULL); } // We copied g_pFontTextureView to io.Fonts->TexID so let's clear that as well.
|
||||||
|
if (g_pIB) { g_pIB->Release(); g_pIB = NULL; }
|
||||||
|
if (g_pVB) { g_pVB->Release(); g_pVB = NULL; }
|
||||||
|
|
||||||
|
if (g_pBlendState) { g_pBlendState->Release(); g_pBlendState = NULL; }
|
||||||
|
if (g_pDepthStencilState) { g_pDepthStencilState->Release(); g_pDepthStencilState = NULL; }
|
||||||
|
if (g_pRasterizerState) { g_pRasterizerState->Release(); g_pRasterizerState = NULL; }
|
||||||
|
if (g_pPixelShader) { g_pPixelShader->Release(); g_pPixelShader = NULL; }
|
||||||
|
if (g_pVertexConstantBuffer) { g_pVertexConstantBuffer->Release(); g_pVertexConstantBuffer = NULL; }
|
||||||
|
if (g_pInputLayout) { g_pInputLayout->Release(); g_pInputLayout = NULL; }
|
||||||
|
if (g_pVertexShader) { g_pVertexShader->Release(); g_pVertexShader = NULL; }
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ImGui_ImplDX10_Init(ID3D10Device* device)
|
||||||
|
{
|
||||||
|
// Setup backend capabilities flags
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
io.BackendRendererName = "imgui_impl_dx10";
|
||||||
|
io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes.
|
||||||
|
|
||||||
|
// Get factory from device
|
||||||
|
IDXGIDevice* pDXGIDevice = NULL;
|
||||||
|
IDXGIAdapter* pDXGIAdapter = NULL;
|
||||||
|
IDXGIFactory* pFactory = NULL;
|
||||||
|
|
||||||
|
if (device->QueryInterface(IID_PPV_ARGS(&pDXGIDevice)) == S_OK)
|
||||||
|
if (pDXGIDevice->GetParent(IID_PPV_ARGS(&pDXGIAdapter)) == S_OK)
|
||||||
|
if (pDXGIAdapter->GetParent(IID_PPV_ARGS(&pFactory)) == S_OK)
|
||||||
|
{
|
||||||
|
g_pd3dDevice = device;
|
||||||
|
g_pFactory = pFactory;
|
||||||
|
}
|
||||||
|
if (pDXGIDevice) pDXGIDevice->Release();
|
||||||
|
if (pDXGIAdapter) pDXGIAdapter->Release();
|
||||||
|
g_pd3dDevice->AddRef();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGui_ImplDX10_Shutdown()
|
||||||
|
{
|
||||||
|
ImGui_ImplDX10_InvalidateDeviceObjects();
|
||||||
|
if (g_pFactory) { g_pFactory->Release(); g_pFactory = NULL; }
|
||||||
|
if (g_pd3dDevice) { g_pd3dDevice->Release(); g_pd3dDevice = NULL; }
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGui_ImplDX10_NewFrame()
|
||||||
|
{
|
||||||
|
if (!g_pFontSampler)
|
||||||
|
ImGui_ImplDX10_CreateDeviceObjects();
|
||||||
|
}
|
24
backend/imgui_impl_dx10.h
Normal file
24
backend/imgui_impl_dx10.h
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
// dear imgui: Renderer Backend for DirectX10
|
||||||
|
// This needs to be used along with a Platform Backend (e.g. Win32)
|
||||||
|
|
||||||
|
// Implemented features:
|
||||||
|
// [X] Renderer: User texture backend. Use 'ID3D10ShaderResourceView*' as ImTextureID. Read the FAQ about ImTextureID!
|
||||||
|
// [X] Renderer: Support for large meshes (64k+ vertices) with 16-bit indices.
|
||||||
|
|
||||||
|
// You can copy and use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
||||||
|
// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
|
||||||
|
// Read online: https://github.com/ocornut/imgui/tree/master/docs
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include "imgui.h" // IMGUI_IMPL_API
|
||||||
|
|
||||||
|
struct ID3D10Device;
|
||||||
|
|
||||||
|
IMGUI_IMPL_API bool ImGui_ImplDX10_Init(ID3D10Device* device);
|
||||||
|
IMGUI_IMPL_API void ImGui_ImplDX10_Shutdown();
|
||||||
|
IMGUI_IMPL_API void ImGui_ImplDX10_NewFrame();
|
||||||
|
IMGUI_IMPL_API void ImGui_ImplDX10_RenderDrawData(ImDrawData* draw_data);
|
||||||
|
|
||||||
|
// Use if you want to reset your rendering device without losing Dear ImGui state.
|
||||||
|
IMGUI_IMPL_API void ImGui_ImplDX10_InvalidateDeviceObjects();
|
||||||
|
IMGUI_IMPL_API bool ImGui_ImplDX10_CreateDeviceObjects();
|
551
backend/imgui_impl_dx11.cpp
Normal file
551
backend/imgui_impl_dx11.cpp
Normal file
@ -0,0 +1,551 @@
|
|||||||
|
// dear imgui: Renderer Backend for DirectX11
|
||||||
|
// This needs to be used along with a Platform Backend (e.g. Win32)
|
||||||
|
|
||||||
|
// Implemented features:
|
||||||
|
// [X] Renderer: User texture binding. Use 'ID3D11ShaderResourceView*' as ImTextureID. Read the FAQ about ImTextureID!
|
||||||
|
// [X] Renderer: Support for large meshes (64k+ vertices) with 16-bit indices.
|
||||||
|
|
||||||
|
// You can copy and use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
||||||
|
// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
|
||||||
|
// Read online: https://github.com/ocornut/imgui/tree/master/docs
|
||||||
|
|
||||||
|
// CHANGELOG
|
||||||
|
// (minor and older changes stripped away, please see git history for details)
|
||||||
|
// 2021-02-18: DirectX11: Change blending equation to preserve alpha in output buffer.
|
||||||
|
// 2019-08-01: DirectX11: Fixed code querying the Geometry Shader state (would generally error with Debug layer enabled).
|
||||||
|
// 2019-07-21: DirectX11: Backup, clear and restore Geometry Shader is any is bound when calling ImGui_ImplDX10_RenderDrawData. Clearing Hull/Domain/Compute shaders without backup/restore.
|
||||||
|
// 2019-05-29: DirectX11: Added support for large mesh (64K+ vertices), enable ImGuiBackendFlags_RendererHasVtxOffset flag.
|
||||||
|
// 2019-04-30: DirectX11: Added support for special ImDrawCallback_ResetRenderState callback to reset render state.
|
||||||
|
// 2018-12-03: Misc: Added #pragma comment statement to automatically link with d3dcompiler.lib when using D3DCompile().
|
||||||
|
// 2018-11-30: Misc: Setting up io.BackendRendererName so it can be displayed in the About Window.
|
||||||
|
// 2018-08-01: DirectX11: Querying for IDXGIFactory instead of IDXGIFactory1 to increase compatibility.
|
||||||
|
// 2018-07-13: DirectX11: Fixed unreleased resources in Init and Shutdown functions.
|
||||||
|
// 2018-06-08: Misc: Extracted imgui_impl_dx11.cpp/.h away from the old combined DX11+Win32 example.
|
||||||
|
// 2018-06-08: DirectX11: Use draw_data->DisplayPos and draw_data->DisplaySize to setup projection matrix and clipping rectangle.
|
||||||
|
// 2018-02-16: Misc: Obsoleted the io.RenderDrawListsFn callback and exposed ImGui_ImplDX11_RenderDrawData() in the .h file so you can call it yourself.
|
||||||
|
// 2018-02-06: Misc: Removed call to ImGui::Shutdown() which is not available from 1.60 WIP, user needs to call CreateContext/DestroyContext themselves.
|
||||||
|
// 2016-05-07: DirectX11: Disabling depth-write.
|
||||||
|
|
||||||
|
#include "imgui.h"
|
||||||
|
#include "imgui_impl_dx11.h"
|
||||||
|
|
||||||
|
// DirectX
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <d3d11.h>
|
||||||
|
#include <d3dcompiler.h>
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#pragma comment(lib, "d3dcompiler") // Automatically link with d3dcompiler.lib as we are using D3DCompile() below.
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// DirectX data
|
||||||
|
static ID3D11Device* g_pd3dDevice = NULL;
|
||||||
|
static ID3D11DeviceContext* g_pd3dDeviceContext = NULL;
|
||||||
|
static IDXGIFactory* g_pFactory = NULL;
|
||||||
|
static ID3D11Buffer* g_pVB = NULL;
|
||||||
|
static ID3D11Buffer* g_pIB = NULL;
|
||||||
|
static ID3D11VertexShader* g_pVertexShader = NULL;
|
||||||
|
static ID3D11InputLayout* g_pInputLayout = NULL;
|
||||||
|
static ID3D11Buffer* g_pVertexConstantBuffer = NULL;
|
||||||
|
static ID3D11PixelShader* g_pPixelShader = NULL;
|
||||||
|
static ID3D11SamplerState* g_pFontSampler = NULL;
|
||||||
|
static ID3D11ShaderResourceView*g_pFontTextureView = NULL;
|
||||||
|
static ID3D11RasterizerState* g_pRasterizerState = NULL;
|
||||||
|
static ID3D11BlendState* g_pBlendState = NULL;
|
||||||
|
static ID3D11DepthStencilState* g_pDepthStencilState = NULL;
|
||||||
|
static int g_VertexBufferSize = 5000, g_IndexBufferSize = 10000;
|
||||||
|
|
||||||
|
struct VERTEX_CONSTANT_BUFFER
|
||||||
|
{
|
||||||
|
float mvp[4][4];
|
||||||
|
};
|
||||||
|
|
||||||
|
static void ImGui_ImplDX11_SetupRenderState(ImDrawData* draw_data, ID3D11DeviceContext* ctx)
|
||||||
|
{
|
||||||
|
// Setup viewport
|
||||||
|
D3D11_VIEWPORT vp;
|
||||||
|
memset(&vp, 0, sizeof(D3D11_VIEWPORT));
|
||||||
|
vp.Width = draw_data->DisplaySize.x;
|
||||||
|
vp.Height = draw_data->DisplaySize.y;
|
||||||
|
vp.MinDepth = 0.0f;
|
||||||
|
vp.MaxDepth = 1.0f;
|
||||||
|
vp.TopLeftX = vp.TopLeftY = 0;
|
||||||
|
ctx->RSSetViewports(1, &vp);
|
||||||
|
|
||||||
|
// Setup shader and vertex buffers
|
||||||
|
unsigned int stride = sizeof(ImDrawVert);
|
||||||
|
unsigned int offset = 0;
|
||||||
|
ctx->IASetInputLayout(g_pInputLayout);
|
||||||
|
ctx->IASetVertexBuffers(0, 1, &g_pVB, &stride, &offset);
|
||||||
|
ctx->IASetIndexBuffer(g_pIB, sizeof(ImDrawIdx) == 2 ? DXGI_FORMAT_R16_UINT : DXGI_FORMAT_R32_UINT, 0);
|
||||||
|
ctx->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
|
||||||
|
ctx->VSSetShader(g_pVertexShader, NULL, 0);
|
||||||
|
ctx->VSSetConstantBuffers(0, 1, &g_pVertexConstantBuffer);
|
||||||
|
ctx->PSSetShader(g_pPixelShader, NULL, 0);
|
||||||
|
ctx->PSSetSamplers(0, 1, &g_pFontSampler);
|
||||||
|
ctx->GSSetShader(NULL, NULL, 0);
|
||||||
|
ctx->HSSetShader(NULL, NULL, 0); // In theory we should backup and restore this as well.. very infrequently used..
|
||||||
|
ctx->DSSetShader(NULL, NULL, 0); // In theory we should backup and restore this as well.. very infrequently used..
|
||||||
|
ctx->CSSetShader(NULL, NULL, 0); // In theory we should backup and restore this as well.. very infrequently used..
|
||||||
|
|
||||||
|
// Setup blend state
|
||||||
|
const float blend_factor[4] = { 0.f, 0.f, 0.f, 0.f };
|
||||||
|
ctx->OMSetBlendState(g_pBlendState, blend_factor, 0xffffffff);
|
||||||
|
ctx->OMSetDepthStencilState(g_pDepthStencilState, 0);
|
||||||
|
ctx->RSSetState(g_pRasterizerState);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Render function
|
||||||
|
void ImGui_ImplDX11_RenderDrawData(ImDrawData* draw_data)
|
||||||
|
{
|
||||||
|
// Avoid rendering when minimized
|
||||||
|
if (draw_data->DisplaySize.x <= 0.0f || draw_data->DisplaySize.y <= 0.0f)
|
||||||
|
return;
|
||||||
|
|
||||||
|
ID3D11DeviceContext* ctx = g_pd3dDeviceContext;
|
||||||
|
|
||||||
|
// Create and grow vertex/index buffers if needed
|
||||||
|
if (!g_pVB || g_VertexBufferSize < draw_data->TotalVtxCount)
|
||||||
|
{
|
||||||
|
if (g_pVB) { g_pVB->Release(); g_pVB = NULL; }
|
||||||
|
g_VertexBufferSize = draw_data->TotalVtxCount + 5000;
|
||||||
|
D3D11_BUFFER_DESC desc;
|
||||||
|
memset(&desc, 0, sizeof(D3D11_BUFFER_DESC));
|
||||||
|
desc.Usage = D3D11_USAGE_DYNAMIC;
|
||||||
|
desc.ByteWidth = g_VertexBufferSize * sizeof(ImDrawVert);
|
||||||
|
desc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
|
||||||
|
desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
|
||||||
|
desc.MiscFlags = 0;
|
||||||
|
if (g_pd3dDevice->CreateBuffer(&desc, NULL, &g_pVB) < 0)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!g_pIB || g_IndexBufferSize < draw_data->TotalIdxCount)
|
||||||
|
{
|
||||||
|
if (g_pIB) { g_pIB->Release(); g_pIB = NULL; }
|
||||||
|
g_IndexBufferSize = draw_data->TotalIdxCount + 10000;
|
||||||
|
D3D11_BUFFER_DESC desc;
|
||||||
|
memset(&desc, 0, sizeof(D3D11_BUFFER_DESC));
|
||||||
|
desc.Usage = D3D11_USAGE_DYNAMIC;
|
||||||
|
desc.ByteWidth = g_IndexBufferSize * sizeof(ImDrawIdx);
|
||||||
|
desc.BindFlags = D3D11_BIND_INDEX_BUFFER;
|
||||||
|
desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
|
||||||
|
if (g_pd3dDevice->CreateBuffer(&desc, NULL, &g_pIB) < 0)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Upload vertex/index data into a single contiguous GPU buffer
|
||||||
|
D3D11_MAPPED_SUBRESOURCE vtx_resource, idx_resource;
|
||||||
|
if (ctx->Map(g_pVB, 0, D3D11_MAP_WRITE_DISCARD, 0, &vtx_resource) != S_OK)
|
||||||
|
return;
|
||||||
|
if (ctx->Map(g_pIB, 0, D3D11_MAP_WRITE_DISCARD, 0, &idx_resource) != S_OK)
|
||||||
|
return;
|
||||||
|
ImDrawVert* vtx_dst = (ImDrawVert*)vtx_resource.pData;
|
||||||
|
ImDrawIdx* idx_dst = (ImDrawIdx*)idx_resource.pData;
|
||||||
|
for (int n = 0; n < draw_data->CmdListsCount; n++)
|
||||||
|
{
|
||||||
|
const ImDrawList* cmd_list = draw_data->CmdLists[n];
|
||||||
|
memcpy(vtx_dst, cmd_list->VtxBuffer.Data, cmd_list->VtxBuffer.Size * sizeof(ImDrawVert));
|
||||||
|
memcpy(idx_dst, cmd_list->IdxBuffer.Data, cmd_list->IdxBuffer.Size * sizeof(ImDrawIdx));
|
||||||
|
vtx_dst += cmd_list->VtxBuffer.Size;
|
||||||
|
idx_dst += cmd_list->IdxBuffer.Size;
|
||||||
|
}
|
||||||
|
ctx->Unmap(g_pVB, 0);
|
||||||
|
ctx->Unmap(g_pIB, 0);
|
||||||
|
|
||||||
|
// Setup orthographic projection matrix into our constant buffer
|
||||||
|
// Our visible imgui space lies from draw_data->DisplayPos (top left) to draw_data->DisplayPos+data_data->DisplaySize (bottom right). DisplayPos is (0,0) for single viewport apps.
|
||||||
|
{
|
||||||
|
D3D11_MAPPED_SUBRESOURCE mapped_resource;
|
||||||
|
if (ctx->Map(g_pVertexConstantBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mapped_resource) != S_OK)
|
||||||
|
return;
|
||||||
|
VERTEX_CONSTANT_BUFFER* constant_buffer = (VERTEX_CONSTANT_BUFFER*)mapped_resource.pData;
|
||||||
|
float L = draw_data->DisplayPos.x;
|
||||||
|
float R = draw_data->DisplayPos.x + draw_data->DisplaySize.x;
|
||||||
|
float T = draw_data->DisplayPos.y;
|
||||||
|
float B = draw_data->DisplayPos.y + draw_data->DisplaySize.y;
|
||||||
|
float mvp[4][4] =
|
||||||
|
{
|
||||||
|
{ 2.0f/(R-L), 0.0f, 0.0f, 0.0f },
|
||||||
|
{ 0.0f, 2.0f/(T-B), 0.0f, 0.0f },
|
||||||
|
{ 0.0f, 0.0f, 0.5f, 0.0f },
|
||||||
|
{ (R+L)/(L-R), (T+B)/(B-T), 0.5f, 1.0f },
|
||||||
|
};
|
||||||
|
memcpy(&constant_buffer->mvp, mvp, sizeof(mvp));
|
||||||
|
ctx->Unmap(g_pVertexConstantBuffer, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Backup DX state that will be modified to restore it afterwards (unfortunately this is very ugly looking and verbose. Close your eyes!)
|
||||||
|
struct BACKUP_DX11_STATE
|
||||||
|
{
|
||||||
|
UINT ScissorRectsCount, ViewportsCount;
|
||||||
|
D3D11_RECT ScissorRects[D3D11_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE];
|
||||||
|
D3D11_VIEWPORT Viewports[D3D11_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE];
|
||||||
|
ID3D11RasterizerState* RS;
|
||||||
|
ID3D11BlendState* BlendState;
|
||||||
|
FLOAT BlendFactor[4];
|
||||||
|
UINT SampleMask;
|
||||||
|
UINT StencilRef;
|
||||||
|
ID3D11DepthStencilState* DepthStencilState;
|
||||||
|
ID3D11ShaderResourceView* PSShaderResource;
|
||||||
|
ID3D11SamplerState* PSSampler;
|
||||||
|
ID3D11PixelShader* PS;
|
||||||
|
ID3D11VertexShader* VS;
|
||||||
|
ID3D11GeometryShader* GS;
|
||||||
|
UINT PSInstancesCount, VSInstancesCount, GSInstancesCount;
|
||||||
|
ID3D11ClassInstance *PSInstances[256], *VSInstances[256], *GSInstances[256]; // 256 is max according to PSSetShader documentation
|
||||||
|
D3D11_PRIMITIVE_TOPOLOGY PrimitiveTopology;
|
||||||
|
ID3D11Buffer* IndexBuffer, *VertexBuffer, *VSConstantBuffer;
|
||||||
|
UINT IndexBufferOffset, VertexBufferStride, VertexBufferOffset;
|
||||||
|
DXGI_FORMAT IndexBufferFormat;
|
||||||
|
ID3D11InputLayout* InputLayout;
|
||||||
|
};
|
||||||
|
BACKUP_DX11_STATE old;
|
||||||
|
old.ScissorRectsCount = old.ViewportsCount = D3D11_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE;
|
||||||
|
ctx->RSGetScissorRects(&old.ScissorRectsCount, old.ScissorRects);
|
||||||
|
ctx->RSGetViewports(&old.ViewportsCount, old.Viewports);
|
||||||
|
ctx->RSGetState(&old.RS);
|
||||||
|
ctx->OMGetBlendState(&old.BlendState, old.BlendFactor, &old.SampleMask);
|
||||||
|
ctx->OMGetDepthStencilState(&old.DepthStencilState, &old.StencilRef);
|
||||||
|
ctx->PSGetShaderResources(0, 1, &old.PSShaderResource);
|
||||||
|
ctx->PSGetSamplers(0, 1, &old.PSSampler);
|
||||||
|
old.PSInstancesCount = old.VSInstancesCount = old.GSInstancesCount = 256;
|
||||||
|
ctx->PSGetShader(&old.PS, old.PSInstances, &old.PSInstancesCount);
|
||||||
|
ctx->VSGetShader(&old.VS, old.VSInstances, &old.VSInstancesCount);
|
||||||
|
ctx->VSGetConstantBuffers(0, 1, &old.VSConstantBuffer);
|
||||||
|
ctx->GSGetShader(&old.GS, old.GSInstances, &old.GSInstancesCount);
|
||||||
|
|
||||||
|
ctx->IAGetPrimitiveTopology(&old.PrimitiveTopology);
|
||||||
|
ctx->IAGetIndexBuffer(&old.IndexBuffer, &old.IndexBufferFormat, &old.IndexBufferOffset);
|
||||||
|
ctx->IAGetVertexBuffers(0, 1, &old.VertexBuffer, &old.VertexBufferStride, &old.VertexBufferOffset);
|
||||||
|
ctx->IAGetInputLayout(&old.InputLayout);
|
||||||
|
|
||||||
|
// Setup desired DX state
|
||||||
|
ImGui_ImplDX11_SetupRenderState(draw_data, ctx);
|
||||||
|
|
||||||
|
// Render command lists
|
||||||
|
// (Because we merged all buffers into a single one, we maintain our own offset into them)
|
||||||
|
int global_idx_offset = 0;
|
||||||
|
int global_vtx_offset = 0;
|
||||||
|
ImVec2 clip_off = draw_data->DisplayPos;
|
||||||
|
for (int n = 0; n < draw_data->CmdListsCount; n++)
|
||||||
|
{
|
||||||
|
const ImDrawList* cmd_list = draw_data->CmdLists[n];
|
||||||
|
for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++)
|
||||||
|
{
|
||||||
|
const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i];
|
||||||
|
if (pcmd->UserCallback != NULL)
|
||||||
|
{
|
||||||
|
// User callback, registered via ImDrawList::AddCallback()
|
||||||
|
// (ImDrawCallback_ResetRenderState is a special callback value used by the user to request the renderer to reset render state.)
|
||||||
|
if (pcmd->UserCallback == ImDrawCallback_ResetRenderState)
|
||||||
|
ImGui_ImplDX11_SetupRenderState(draw_data, ctx);
|
||||||
|
else
|
||||||
|
pcmd->UserCallback(cmd_list, pcmd);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Apply scissor/clipping rectangle
|
||||||
|
const D3D11_RECT r = { (LONG)(pcmd->ClipRect.x - clip_off.x), (LONG)(pcmd->ClipRect.y - clip_off.y), (LONG)(pcmd->ClipRect.z - clip_off.x), (LONG)(pcmd->ClipRect.w - clip_off.y) };
|
||||||
|
ctx->RSSetScissorRects(1, &r);
|
||||||
|
|
||||||
|
// Bind texture, Draw
|
||||||
|
ID3D11ShaderResourceView* texture_srv = (ID3D11ShaderResourceView*)pcmd->TextureId;
|
||||||
|
ctx->PSSetShaderResources(0, 1, &texture_srv);
|
||||||
|
ctx->DrawIndexed(pcmd->ElemCount, pcmd->IdxOffset + global_idx_offset, pcmd->VtxOffset + global_vtx_offset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
global_idx_offset += cmd_list->IdxBuffer.Size;
|
||||||
|
global_vtx_offset += cmd_list->VtxBuffer.Size;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Restore modified DX state
|
||||||
|
ctx->RSSetScissorRects(old.ScissorRectsCount, old.ScissorRects);
|
||||||
|
ctx->RSSetViewports(old.ViewportsCount, old.Viewports);
|
||||||
|
ctx->RSSetState(old.RS); if (old.RS) old.RS->Release();
|
||||||
|
ctx->OMSetBlendState(old.BlendState, old.BlendFactor, old.SampleMask); if (old.BlendState) old.BlendState->Release();
|
||||||
|
ctx->OMSetDepthStencilState(old.DepthStencilState, old.StencilRef); if (old.DepthStencilState) old.DepthStencilState->Release();
|
||||||
|
ctx->PSSetShaderResources(0, 1, &old.PSShaderResource); if (old.PSShaderResource) old.PSShaderResource->Release();
|
||||||
|
ctx->PSSetSamplers(0, 1, &old.PSSampler); if (old.PSSampler) old.PSSampler->Release();
|
||||||
|
ctx->PSSetShader(old.PS, old.PSInstances, old.PSInstancesCount); if (old.PS) old.PS->Release();
|
||||||
|
for (UINT i = 0; i < old.PSInstancesCount; i++) if (old.PSInstances[i]) old.PSInstances[i]->Release();
|
||||||
|
ctx->VSSetShader(old.VS, old.VSInstances, old.VSInstancesCount); if (old.VS) old.VS->Release();
|
||||||
|
ctx->VSSetConstantBuffers(0, 1, &old.VSConstantBuffer); if (old.VSConstantBuffer) old.VSConstantBuffer->Release();
|
||||||
|
ctx->GSSetShader(old.GS, old.GSInstances, old.GSInstancesCount); if (old.GS) old.GS->Release();
|
||||||
|
for (UINT i = 0; i < old.VSInstancesCount; i++) if (old.VSInstances[i]) old.VSInstances[i]->Release();
|
||||||
|
ctx->IASetPrimitiveTopology(old.PrimitiveTopology);
|
||||||
|
ctx->IASetIndexBuffer(old.IndexBuffer, old.IndexBufferFormat, old.IndexBufferOffset); if (old.IndexBuffer) old.IndexBuffer->Release();
|
||||||
|
ctx->IASetVertexBuffers(0, 1, &old.VertexBuffer, &old.VertexBufferStride, &old.VertexBufferOffset); if (old.VertexBuffer) old.VertexBuffer->Release();
|
||||||
|
ctx->IASetInputLayout(old.InputLayout); if (old.InputLayout) old.InputLayout->Release();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ImGui_ImplDX11_CreateFontsTexture()
|
||||||
|
{
|
||||||
|
// Build texture atlas
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
unsigned char* pixels;
|
||||||
|
int width, height;
|
||||||
|
io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height);
|
||||||
|
|
||||||
|
// Upload texture to graphics system
|
||||||
|
{
|
||||||
|
D3D11_TEXTURE2D_DESC desc;
|
||||||
|
ZeroMemory(&desc, sizeof(desc));
|
||||||
|
desc.Width = width;
|
||||||
|
desc.Height = height;
|
||||||
|
desc.MipLevels = 1;
|
||||||
|
desc.ArraySize = 1;
|
||||||
|
desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
|
||||||
|
desc.SampleDesc.Count = 1;
|
||||||
|
desc.Usage = D3D11_USAGE_DEFAULT;
|
||||||
|
desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
|
||||||
|
desc.CPUAccessFlags = 0;
|
||||||
|
|
||||||
|
ID3D11Texture2D* pTexture = NULL;
|
||||||
|
D3D11_SUBRESOURCE_DATA subResource;
|
||||||
|
subResource.pSysMem = pixels;
|
||||||
|
subResource.SysMemPitch = desc.Width * 4;
|
||||||
|
subResource.SysMemSlicePitch = 0;
|
||||||
|
g_pd3dDevice->CreateTexture2D(&desc, &subResource, &pTexture);
|
||||||
|
|
||||||
|
// Create texture view
|
||||||
|
D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc;
|
||||||
|
ZeroMemory(&srvDesc, sizeof(srvDesc));
|
||||||
|
srvDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
|
||||||
|
srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
|
||||||
|
srvDesc.Texture2D.MipLevels = desc.MipLevels;
|
||||||
|
srvDesc.Texture2D.MostDetailedMip = 0;
|
||||||
|
g_pd3dDevice->CreateShaderResourceView(pTexture, &srvDesc, &g_pFontTextureView);
|
||||||
|
pTexture->Release();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Store our identifier
|
||||||
|
io.Fonts->SetTexID((ImTextureID)g_pFontTextureView);
|
||||||
|
|
||||||
|
// Create texture sampler
|
||||||
|
{
|
||||||
|
D3D11_SAMPLER_DESC desc;
|
||||||
|
ZeroMemory(&desc, sizeof(desc));
|
||||||
|
desc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR;
|
||||||
|
desc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP;
|
||||||
|
desc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP;
|
||||||
|
desc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP;
|
||||||
|
desc.MipLODBias = 0.f;
|
||||||
|
desc.ComparisonFunc = D3D11_COMPARISON_ALWAYS;
|
||||||
|
desc.MinLOD = 0.f;
|
||||||
|
desc.MaxLOD = 0.f;
|
||||||
|
g_pd3dDevice->CreateSamplerState(&desc, &g_pFontSampler);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ImGui_ImplDX11_CreateDeviceObjects()
|
||||||
|
{
|
||||||
|
if (!g_pd3dDevice)
|
||||||
|
return false;
|
||||||
|
if (g_pFontSampler)
|
||||||
|
ImGui_ImplDX11_InvalidateDeviceObjects();
|
||||||
|
|
||||||
|
// By using D3DCompile() from <d3dcompiler.h> / d3dcompiler.lib, we introduce a dependency to a given version of d3dcompiler_XX.dll (see D3DCOMPILER_DLL_A)
|
||||||
|
// If you would like to use this DX11 sample code but remove this dependency you can:
|
||||||
|
// 1) compile once, save the compiled shader blobs into a file or source code and pass them to CreateVertexShader()/CreatePixelShader() [preferred solution]
|
||||||
|
// 2) use code to detect any version of the DLL and grab a pointer to D3DCompile from the DLL.
|
||||||
|
// See https://github.com/ocornut/imgui/pull/638 for sources and details.
|
||||||
|
|
||||||
|
// Create the vertex shader
|
||||||
|
{
|
||||||
|
static const char* vertexShader =
|
||||||
|
"cbuffer vertexBuffer : register(b0) \
|
||||||
|
{\
|
||||||
|
float4x4 ProjectionMatrix; \
|
||||||
|
};\
|
||||||
|
struct VS_INPUT\
|
||||||
|
{\
|
||||||
|
float2 pos : POSITION;\
|
||||||
|
float4 col : COLOR0;\
|
||||||
|
float2 uv : TEXCOORD0;\
|
||||||
|
};\
|
||||||
|
\
|
||||||
|
struct PS_INPUT\
|
||||||
|
{\
|
||||||
|
float4 pos : SV_POSITION;\
|
||||||
|
float4 col : COLOR0;\
|
||||||
|
float2 uv : TEXCOORD0;\
|
||||||
|
};\
|
||||||
|
\
|
||||||
|
PS_INPUT main(VS_INPUT input)\
|
||||||
|
{\
|
||||||
|
PS_INPUT output;\
|
||||||
|
output.pos = mul( ProjectionMatrix, float4(input.pos.xy, 0.f, 1.f));\
|
||||||
|
output.col = input.col;\
|
||||||
|
output.uv = input.uv;\
|
||||||
|
return output;\
|
||||||
|
}";
|
||||||
|
|
||||||
|
ID3DBlob* vertexShaderBlob;
|
||||||
|
if (FAILED(D3DCompile(vertexShader, strlen(vertexShader), NULL, NULL, NULL, "main", "vs_4_0", 0, 0, &vertexShaderBlob, NULL)))
|
||||||
|
return false; // NB: Pass ID3DBlob* pErrorBlob to D3DCompile() to get error showing in (const char*)pErrorBlob->GetBufferPointer(). Make sure to Release() the blob!
|
||||||
|
if (g_pd3dDevice->CreateVertexShader(vertexShaderBlob->GetBufferPointer(), vertexShaderBlob->GetBufferSize(), NULL, &g_pVertexShader) != S_OK)
|
||||||
|
{
|
||||||
|
vertexShaderBlob->Release();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the input layout
|
||||||
|
D3D11_INPUT_ELEMENT_DESC local_layout[] =
|
||||||
|
{
|
||||||
|
{ "POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, (UINT)IM_OFFSETOF(ImDrawVert, pos), D3D11_INPUT_PER_VERTEX_DATA, 0 },
|
||||||
|
{ "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, (UINT)IM_OFFSETOF(ImDrawVert, uv), D3D11_INPUT_PER_VERTEX_DATA, 0 },
|
||||||
|
{ "COLOR", 0, DXGI_FORMAT_R8G8B8A8_UNORM, 0, (UINT)IM_OFFSETOF(ImDrawVert, col), D3D11_INPUT_PER_VERTEX_DATA, 0 },
|
||||||
|
};
|
||||||
|
if (g_pd3dDevice->CreateInputLayout(local_layout, 3, vertexShaderBlob->GetBufferPointer(), vertexShaderBlob->GetBufferSize(), &g_pInputLayout) != S_OK)
|
||||||
|
{
|
||||||
|
vertexShaderBlob->Release();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
vertexShaderBlob->Release();
|
||||||
|
|
||||||
|
// Create the constant buffer
|
||||||
|
{
|
||||||
|
D3D11_BUFFER_DESC desc;
|
||||||
|
desc.ByteWidth = sizeof(VERTEX_CONSTANT_BUFFER);
|
||||||
|
desc.Usage = D3D11_USAGE_DYNAMIC;
|
||||||
|
desc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
|
||||||
|
desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
|
||||||
|
desc.MiscFlags = 0;
|
||||||
|
g_pd3dDevice->CreateBuffer(&desc, NULL, &g_pVertexConstantBuffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the pixel shader
|
||||||
|
{
|
||||||
|
static const char* pixelShader =
|
||||||
|
"struct PS_INPUT\
|
||||||
|
{\
|
||||||
|
float4 pos : SV_POSITION;\
|
||||||
|
float4 col : COLOR0;\
|
||||||
|
float2 uv : TEXCOORD0;\
|
||||||
|
};\
|
||||||
|
sampler sampler0;\
|
||||||
|
Texture2D texture0;\
|
||||||
|
\
|
||||||
|
float4 main(PS_INPUT input) : SV_Target\
|
||||||
|
{\
|
||||||
|
float4 out_col = input.col * texture0.Sample(sampler0, input.uv); \
|
||||||
|
return out_col; \
|
||||||
|
}";
|
||||||
|
|
||||||
|
ID3DBlob* pixelShaderBlob;
|
||||||
|
if (FAILED(D3DCompile(pixelShader, strlen(pixelShader), NULL, NULL, NULL, "main", "ps_4_0", 0, 0, &pixelShaderBlob, NULL)))
|
||||||
|
return false; // NB: Pass ID3DBlob* pErrorBlob to D3DCompile() to get error showing in (const char*)pErrorBlob->GetBufferPointer(). Make sure to Release() the blob!
|
||||||
|
if (g_pd3dDevice->CreatePixelShader(pixelShaderBlob->GetBufferPointer(), pixelShaderBlob->GetBufferSize(), NULL, &g_pPixelShader) != S_OK)
|
||||||
|
{
|
||||||
|
pixelShaderBlob->Release();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
pixelShaderBlob->Release();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the blending setup
|
||||||
|
{
|
||||||
|
D3D11_BLEND_DESC desc;
|
||||||
|
ZeroMemory(&desc, sizeof(desc));
|
||||||
|
desc.AlphaToCoverageEnable = false;
|
||||||
|
desc.RenderTarget[0].BlendEnable = true;
|
||||||
|
desc.RenderTarget[0].SrcBlend = D3D11_BLEND_SRC_ALPHA;
|
||||||
|
desc.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC_ALPHA;
|
||||||
|
desc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD;
|
||||||
|
desc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE;
|
||||||
|
desc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_INV_SRC_ALPHA;
|
||||||
|
desc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD;
|
||||||
|
desc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL;
|
||||||
|
g_pd3dDevice->CreateBlendState(&desc, &g_pBlendState);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the rasterizer state
|
||||||
|
{
|
||||||
|
D3D11_RASTERIZER_DESC desc;
|
||||||
|
ZeroMemory(&desc, sizeof(desc));
|
||||||
|
desc.FillMode = D3D11_FILL_SOLID;
|
||||||
|
desc.CullMode = D3D11_CULL_NONE;
|
||||||
|
desc.ScissorEnable = true;
|
||||||
|
desc.DepthClipEnable = true;
|
||||||
|
g_pd3dDevice->CreateRasterizerState(&desc, &g_pRasterizerState);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create depth-stencil State
|
||||||
|
{
|
||||||
|
D3D11_DEPTH_STENCIL_DESC desc;
|
||||||
|
ZeroMemory(&desc, sizeof(desc));
|
||||||
|
desc.DepthEnable = false;
|
||||||
|
desc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL;
|
||||||
|
desc.DepthFunc = D3D11_COMPARISON_ALWAYS;
|
||||||
|
desc.StencilEnable = false;
|
||||||
|
desc.FrontFace.StencilFailOp = desc.FrontFace.StencilDepthFailOp = desc.FrontFace.StencilPassOp = D3D11_STENCIL_OP_KEEP;
|
||||||
|
desc.FrontFace.StencilFunc = D3D11_COMPARISON_ALWAYS;
|
||||||
|
desc.BackFace = desc.FrontFace;
|
||||||
|
g_pd3dDevice->CreateDepthStencilState(&desc, &g_pDepthStencilState);
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui_ImplDX11_CreateFontsTexture();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGui_ImplDX11_InvalidateDeviceObjects()
|
||||||
|
{
|
||||||
|
if (!g_pd3dDevice)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (g_pFontSampler) { g_pFontSampler->Release(); g_pFontSampler = NULL; }
|
||||||
|
if (g_pFontTextureView) { g_pFontTextureView->Release(); g_pFontTextureView = NULL; ImGui::GetIO().Fonts->SetTexID(NULL); } // We copied g_pFontTextureView to io.Fonts->TexID so let's clear that as well.
|
||||||
|
if (g_pIB) { g_pIB->Release(); g_pIB = NULL; }
|
||||||
|
if (g_pVB) { g_pVB->Release(); g_pVB = NULL; }
|
||||||
|
|
||||||
|
if (g_pBlendState) { g_pBlendState->Release(); g_pBlendState = NULL; }
|
||||||
|
if (g_pDepthStencilState) { g_pDepthStencilState->Release(); g_pDepthStencilState = NULL; }
|
||||||
|
if (g_pRasterizerState) { g_pRasterizerState->Release(); g_pRasterizerState = NULL; }
|
||||||
|
if (g_pPixelShader) { g_pPixelShader->Release(); g_pPixelShader = NULL; }
|
||||||
|
if (g_pVertexConstantBuffer) { g_pVertexConstantBuffer->Release(); g_pVertexConstantBuffer = NULL; }
|
||||||
|
if (g_pInputLayout) { g_pInputLayout->Release(); g_pInputLayout = NULL; }
|
||||||
|
if (g_pVertexShader) { g_pVertexShader->Release(); g_pVertexShader = NULL; }
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ImGui_ImplDX11_Init(ID3D11Device* device, ID3D11DeviceContext* device_context)
|
||||||
|
{
|
||||||
|
// Setup backend capabilities flags
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
io.BackendRendererName = "imgui_impl_dx11";
|
||||||
|
io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes.
|
||||||
|
|
||||||
|
// Get factory from device
|
||||||
|
IDXGIDevice* pDXGIDevice = NULL;
|
||||||
|
IDXGIAdapter* pDXGIAdapter = NULL;
|
||||||
|
IDXGIFactory* pFactory = NULL;
|
||||||
|
|
||||||
|
if (device->QueryInterface(IID_PPV_ARGS(&pDXGIDevice)) == S_OK)
|
||||||
|
if (pDXGIDevice->GetParent(IID_PPV_ARGS(&pDXGIAdapter)) == S_OK)
|
||||||
|
if (pDXGIAdapter->GetParent(IID_PPV_ARGS(&pFactory)) == S_OK)
|
||||||
|
{
|
||||||
|
g_pd3dDevice = device;
|
||||||
|
g_pd3dDeviceContext = device_context;
|
||||||
|
g_pFactory = pFactory;
|
||||||
|
}
|
||||||
|
if (pDXGIDevice) pDXGIDevice->Release();
|
||||||
|
if (pDXGIAdapter) pDXGIAdapter->Release();
|
||||||
|
g_pd3dDevice->AddRef();
|
||||||
|
g_pd3dDeviceContext->AddRef();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGui_ImplDX11_Shutdown()
|
||||||
|
{
|
||||||
|
ImGui_ImplDX11_InvalidateDeviceObjects();
|
||||||
|
if (g_pFactory) { g_pFactory->Release(); g_pFactory = NULL; }
|
||||||
|
if (g_pd3dDevice) { g_pd3dDevice->Release(); g_pd3dDevice = NULL; }
|
||||||
|
if (g_pd3dDeviceContext) { g_pd3dDeviceContext->Release(); g_pd3dDeviceContext = NULL; }
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGui_ImplDX11_NewFrame()
|
||||||
|
{
|
||||||
|
if (!g_pFontSampler)
|
||||||
|
ImGui_ImplDX11_CreateDeviceObjects();
|
||||||
|
}
|
25
backend/imgui_impl_dx11.h
Normal file
25
backend/imgui_impl_dx11.h
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
// dear imgui: Renderer Backend for DirectX11
|
||||||
|
// This needs to be used along with a Platform Backend (e.g. Win32)
|
||||||
|
|
||||||
|
// Implemented features:
|
||||||
|
// [X] Renderer: User texture binding. Use 'ID3D11ShaderResourceView*' as ImTextureID. Read the FAQ about ImTextureID!
|
||||||
|
// [X] Renderer: Support for large meshes (64k+ vertices) with 16-bit indices.
|
||||||
|
|
||||||
|
// You can copy and use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
||||||
|
// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
|
||||||
|
// Read online: https://github.com/ocornut/imgui/tree/master/docs
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include "imgui.h" // IMGUI_IMPL_API
|
||||||
|
|
||||||
|
struct ID3D11Device;
|
||||||
|
struct ID3D11DeviceContext;
|
||||||
|
|
||||||
|
IMGUI_IMPL_API bool ImGui_ImplDX11_Init(ID3D11Device* device, ID3D11DeviceContext* device_context);
|
||||||
|
IMGUI_IMPL_API void ImGui_ImplDX11_Shutdown();
|
||||||
|
IMGUI_IMPL_API void ImGui_ImplDX11_NewFrame();
|
||||||
|
IMGUI_IMPL_API void ImGui_ImplDX11_RenderDrawData(ImDrawData* draw_data);
|
||||||
|
|
||||||
|
// Use if you want to reset your rendering device without losing Dear ImGui state.
|
||||||
|
IMGUI_IMPL_API void ImGui_ImplDX11_InvalidateDeviceObjects();
|
||||||
|
IMGUI_IMPL_API bool ImGui_ImplDX11_CreateDeviceObjects();
|
700
backend/imgui_impl_dx12.cpp
Normal file
700
backend/imgui_impl_dx12.cpp
Normal file
@ -0,0 +1,700 @@
|
|||||||
|
// dear imgui: Renderer Backend for DirectX12
|
||||||
|
// This needs to be used along with a Platform Backend (e.g. Win32)
|
||||||
|
|
||||||
|
// Implemented features:
|
||||||
|
// [X] Renderer: User texture binding. Use 'D3D12_GPU_DESCRIPTOR_HANDLE' as ImTextureID. Read the FAQ about ImTextureID!
|
||||||
|
// [X] Renderer: Support for large meshes (64k+ vertices) with 16-bit indices.
|
||||||
|
|
||||||
|
// Important: to compile on 32-bit systems, this backend requires code to be compiled with '#define ImTextureID ImU64'.
|
||||||
|
// This is because we need ImTextureID to carry a 64-bit value and by default ImTextureID is defined as void*.
|
||||||
|
// This define is set in the example .vcxproj file and need to be replicated in your app or by adding it to your imconfig.h file.
|
||||||
|
|
||||||
|
// You can copy and use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
||||||
|
// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
|
||||||
|
// Read online: https://github.com/ocornut/imgui/tree/master/docs
|
||||||
|
|
||||||
|
// CHANGELOG
|
||||||
|
// (minor and older changes stripped away, please see git history for details)
|
||||||
|
// 2021-02-18: DirectX12: Change blending equation to preserve alpha in output buffer.
|
||||||
|
// 2021-01-11: DirectX12: Improve Windows 7 compatibility (for D3D12On7) by loading d3d12.dll dynamically.
|
||||||
|
// 2020-09-16: DirectX12: Avoid rendering calls with zero-sized scissor rectangle since it generates a validation layer warning.
|
||||||
|
// 2020-09-08: DirectX12: Clarified support for building on 32-bit systems by redefining ImTextureID.
|
||||||
|
// 2019-10-18: DirectX12: *BREAKING CHANGE* Added extra ID3D12DescriptorHeap parameter to ImGui_ImplDX12_Init() function.
|
||||||
|
// 2019-05-29: DirectX12: Added support for large mesh (64K+ vertices), enable ImGuiBackendFlags_RendererHasVtxOffset flag.
|
||||||
|
// 2019-04-30: DirectX12: Added support for special ImDrawCallback_ResetRenderState callback to reset render state.
|
||||||
|
// 2019-03-29: Misc: Various minor tidying up.
|
||||||
|
// 2018-12-03: Misc: Added #pragma comment statement to automatically link with d3dcompiler.lib when using D3DCompile().
|
||||||
|
// 2018-11-30: Misc: Setting up io.BackendRendererName so it can be displayed in the About Window.
|
||||||
|
// 2018-06-12: DirectX12: Moved the ID3D12GraphicsCommandList* parameter from NewFrame() to RenderDrawData().
|
||||||
|
// 2018-06-08: Misc: Extracted imgui_impl_dx12.cpp/.h away from the old combined DX12+Win32 example.
|
||||||
|
// 2018-06-08: DirectX12: Use draw_data->DisplayPos and draw_data->DisplaySize to setup projection matrix and clipping rectangle (to ease support for future multi-viewport).
|
||||||
|
// 2018-02-22: Merged into master with all Win32 code synchronized to other examples.
|
||||||
|
|
||||||
|
#include "imgui.h"
|
||||||
|
#include "imgui_impl_dx12.h"
|
||||||
|
|
||||||
|
// DirectX
|
||||||
|
#include <d3d12.h>
|
||||||
|
#include <dxgi1_4.h>
|
||||||
|
#include <d3dcompiler.h>
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#pragma comment(lib, "d3dcompiler") // Automatically link with d3dcompiler.lib as we are using D3DCompile() below.
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// DirectX data
|
||||||
|
static ID3D12Device* g_pd3dDevice = NULL;
|
||||||
|
static ID3D12RootSignature* g_pRootSignature = NULL;
|
||||||
|
static ID3D12PipelineState* g_pPipelineState = NULL;
|
||||||
|
static DXGI_FORMAT g_RTVFormat = DXGI_FORMAT_UNKNOWN;
|
||||||
|
static ID3D12Resource* g_pFontTextureResource = NULL;
|
||||||
|
static D3D12_CPU_DESCRIPTOR_HANDLE g_hFontSrvCpuDescHandle = {};
|
||||||
|
static D3D12_GPU_DESCRIPTOR_HANDLE g_hFontSrvGpuDescHandle = {};
|
||||||
|
|
||||||
|
struct FrameResources
|
||||||
|
{
|
||||||
|
ID3D12Resource* IndexBuffer;
|
||||||
|
ID3D12Resource* VertexBuffer;
|
||||||
|
int IndexBufferSize;
|
||||||
|
int VertexBufferSize;
|
||||||
|
};
|
||||||
|
static FrameResources* g_pFrameResources = NULL;
|
||||||
|
static UINT g_numFramesInFlight = 0;
|
||||||
|
static UINT g_frameIndex = UINT_MAX;
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
static void SafeRelease(T*& res)
|
||||||
|
{
|
||||||
|
if (res)
|
||||||
|
res->Release();
|
||||||
|
res = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct VERTEX_CONSTANT_BUFFER
|
||||||
|
{
|
||||||
|
float mvp[4][4];
|
||||||
|
};
|
||||||
|
|
||||||
|
static void ImGui_ImplDX12_SetupRenderState(ImDrawData* draw_data, ID3D12GraphicsCommandList* ctx, FrameResources* fr)
|
||||||
|
{
|
||||||
|
// Setup orthographic projection matrix into our constant buffer
|
||||||
|
// Our visible imgui space lies from draw_data->DisplayPos (top left) to draw_data->DisplayPos+data_data->DisplaySize (bottom right).
|
||||||
|
VERTEX_CONSTANT_BUFFER vertex_constant_buffer;
|
||||||
|
{
|
||||||
|
float L = draw_data->DisplayPos.x;
|
||||||
|
float R = draw_data->DisplayPos.x + draw_data->DisplaySize.x;
|
||||||
|
float T = draw_data->DisplayPos.y;
|
||||||
|
float B = draw_data->DisplayPos.y + draw_data->DisplaySize.y;
|
||||||
|
float mvp[4][4] =
|
||||||
|
{
|
||||||
|
{ 2.0f/(R-L), 0.0f, 0.0f, 0.0f },
|
||||||
|
{ 0.0f, 2.0f/(T-B), 0.0f, 0.0f },
|
||||||
|
{ 0.0f, 0.0f, 0.5f, 0.0f },
|
||||||
|
{ (R+L)/(L-R), (T+B)/(B-T), 0.5f, 1.0f },
|
||||||
|
};
|
||||||
|
memcpy(&vertex_constant_buffer.mvp, mvp, sizeof(mvp));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Setup viewport
|
||||||
|
D3D12_VIEWPORT vp;
|
||||||
|
memset(&vp, 0, sizeof(D3D12_VIEWPORT));
|
||||||
|
vp.Width = draw_data->DisplaySize.x;
|
||||||
|
vp.Height = draw_data->DisplaySize.y;
|
||||||
|
vp.MinDepth = 0.0f;
|
||||||
|
vp.MaxDepth = 1.0f;
|
||||||
|
vp.TopLeftX = vp.TopLeftY = 0.0f;
|
||||||
|
ctx->RSSetViewports(1, &vp);
|
||||||
|
|
||||||
|
// Bind shader and vertex buffers
|
||||||
|
unsigned int stride = sizeof(ImDrawVert);
|
||||||
|
unsigned int offset = 0;
|
||||||
|
D3D12_VERTEX_BUFFER_VIEW vbv;
|
||||||
|
memset(&vbv, 0, sizeof(D3D12_VERTEX_BUFFER_VIEW));
|
||||||
|
vbv.BufferLocation = fr->VertexBuffer->GetGPUVirtualAddress() + offset;
|
||||||
|
vbv.SizeInBytes = fr->VertexBufferSize * stride;
|
||||||
|
vbv.StrideInBytes = stride;
|
||||||
|
ctx->IASetVertexBuffers(0, 1, &vbv);
|
||||||
|
D3D12_INDEX_BUFFER_VIEW ibv;
|
||||||
|
memset(&ibv, 0, sizeof(D3D12_INDEX_BUFFER_VIEW));
|
||||||
|
ibv.BufferLocation = fr->IndexBuffer->GetGPUVirtualAddress();
|
||||||
|
ibv.SizeInBytes = fr->IndexBufferSize * sizeof(ImDrawIdx);
|
||||||
|
ibv.Format = sizeof(ImDrawIdx) == 2 ? DXGI_FORMAT_R16_UINT : DXGI_FORMAT_R32_UINT;
|
||||||
|
ctx->IASetIndexBuffer(&ibv);
|
||||||
|
ctx->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
|
||||||
|
ctx->SetPipelineState(g_pPipelineState);
|
||||||
|
ctx->SetGraphicsRootSignature(g_pRootSignature);
|
||||||
|
ctx->SetGraphicsRoot32BitConstants(0, 16, &vertex_constant_buffer, 0);
|
||||||
|
|
||||||
|
// Setup blend factor
|
||||||
|
const float blend_factor[4] = { 0.f, 0.f, 0.f, 0.f };
|
||||||
|
ctx->OMSetBlendFactor(blend_factor);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Render function
|
||||||
|
void ImGui_ImplDX12_RenderDrawData(ImDrawData* draw_data, ID3D12GraphicsCommandList* ctx)
|
||||||
|
{
|
||||||
|
// Avoid rendering when minimized
|
||||||
|
if (draw_data->DisplaySize.x <= 0.0f || draw_data->DisplaySize.y <= 0.0f)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// FIXME: I'm assuming that this only gets called once per frame!
|
||||||
|
// If not, we can't just re-allocate the IB or VB, we'll have to do a proper allocator.
|
||||||
|
g_frameIndex = g_frameIndex + 1;
|
||||||
|
FrameResources* fr = &g_pFrameResources[g_frameIndex % g_numFramesInFlight];
|
||||||
|
|
||||||
|
// Create and grow vertex/index buffers if needed
|
||||||
|
if (fr->VertexBuffer == NULL || fr->VertexBufferSize < draw_data->TotalVtxCount)
|
||||||
|
{
|
||||||
|
SafeRelease(fr->VertexBuffer);
|
||||||
|
fr->VertexBufferSize = draw_data->TotalVtxCount + 5000;
|
||||||
|
D3D12_HEAP_PROPERTIES props;
|
||||||
|
memset(&props, 0, sizeof(D3D12_HEAP_PROPERTIES));
|
||||||
|
props.Type = D3D12_HEAP_TYPE_UPLOAD;
|
||||||
|
props.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
|
||||||
|
props.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
|
||||||
|
D3D12_RESOURCE_DESC desc;
|
||||||
|
memset(&desc, 0, sizeof(D3D12_RESOURCE_DESC));
|
||||||
|
desc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
|
||||||
|
desc.Width = fr->VertexBufferSize * sizeof(ImDrawVert);
|
||||||
|
desc.Height = 1;
|
||||||
|
desc.DepthOrArraySize = 1;
|
||||||
|
desc.MipLevels = 1;
|
||||||
|
desc.Format = DXGI_FORMAT_UNKNOWN;
|
||||||
|
desc.SampleDesc.Count = 1;
|
||||||
|
desc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
|
||||||
|
desc.Flags = D3D12_RESOURCE_FLAG_NONE;
|
||||||
|
if (g_pd3dDevice->CreateCommittedResource(&props, D3D12_HEAP_FLAG_NONE, &desc, D3D12_RESOURCE_STATE_GENERIC_READ, NULL, IID_PPV_ARGS(&fr->VertexBuffer)) < 0)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (fr->IndexBuffer == NULL || fr->IndexBufferSize < draw_data->TotalIdxCount)
|
||||||
|
{
|
||||||
|
SafeRelease(fr->IndexBuffer);
|
||||||
|
fr->IndexBufferSize = draw_data->TotalIdxCount + 10000;
|
||||||
|
D3D12_HEAP_PROPERTIES props;
|
||||||
|
memset(&props, 0, sizeof(D3D12_HEAP_PROPERTIES));
|
||||||
|
props.Type = D3D12_HEAP_TYPE_UPLOAD;
|
||||||
|
props.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
|
||||||
|
props.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
|
||||||
|
D3D12_RESOURCE_DESC desc;
|
||||||
|
memset(&desc, 0, sizeof(D3D12_RESOURCE_DESC));
|
||||||
|
desc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
|
||||||
|
desc.Width = fr->IndexBufferSize * sizeof(ImDrawIdx);
|
||||||
|
desc.Height = 1;
|
||||||
|
desc.DepthOrArraySize = 1;
|
||||||
|
desc.MipLevels = 1;
|
||||||
|
desc.Format = DXGI_FORMAT_UNKNOWN;
|
||||||
|
desc.SampleDesc.Count = 1;
|
||||||
|
desc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
|
||||||
|
desc.Flags = D3D12_RESOURCE_FLAG_NONE;
|
||||||
|
if (g_pd3dDevice->CreateCommittedResource(&props, D3D12_HEAP_FLAG_NONE, &desc, D3D12_RESOURCE_STATE_GENERIC_READ, NULL, IID_PPV_ARGS(&fr->IndexBuffer)) < 0)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Upload vertex/index data into a single contiguous GPU buffer
|
||||||
|
void* vtx_resource, *idx_resource;
|
||||||
|
D3D12_RANGE range;
|
||||||
|
memset(&range, 0, sizeof(D3D12_RANGE));
|
||||||
|
if (fr->VertexBuffer->Map(0, &range, &vtx_resource) != S_OK)
|
||||||
|
return;
|
||||||
|
if (fr->IndexBuffer->Map(0, &range, &idx_resource) != S_OK)
|
||||||
|
return;
|
||||||
|
ImDrawVert* vtx_dst = (ImDrawVert*)vtx_resource;
|
||||||
|
ImDrawIdx* idx_dst = (ImDrawIdx*)idx_resource;
|
||||||
|
for (int n = 0; n < draw_data->CmdListsCount; n++)
|
||||||
|
{
|
||||||
|
const ImDrawList* cmd_list = draw_data->CmdLists[n];
|
||||||
|
memcpy(vtx_dst, cmd_list->VtxBuffer.Data, cmd_list->VtxBuffer.Size * sizeof(ImDrawVert));
|
||||||
|
memcpy(idx_dst, cmd_list->IdxBuffer.Data, cmd_list->IdxBuffer.Size * sizeof(ImDrawIdx));
|
||||||
|
vtx_dst += cmd_list->VtxBuffer.Size;
|
||||||
|
idx_dst += cmd_list->IdxBuffer.Size;
|
||||||
|
}
|
||||||
|
fr->VertexBuffer->Unmap(0, &range);
|
||||||
|
fr->IndexBuffer->Unmap(0, &range);
|
||||||
|
|
||||||
|
// Setup desired DX state
|
||||||
|
ImGui_ImplDX12_SetupRenderState(draw_data, ctx, fr);
|
||||||
|
|
||||||
|
// Render command lists
|
||||||
|
// (Because we merged all buffers into a single one, we maintain our own offset into them)
|
||||||
|
int global_vtx_offset = 0;
|
||||||
|
int global_idx_offset = 0;
|
||||||
|
ImVec2 clip_off = draw_data->DisplayPos;
|
||||||
|
for (int n = 0; n < draw_data->CmdListsCount; n++)
|
||||||
|
{
|
||||||
|
const ImDrawList* cmd_list = draw_data->CmdLists[n];
|
||||||
|
for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++)
|
||||||
|
{
|
||||||
|
const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i];
|
||||||
|
if (pcmd->UserCallback != NULL)
|
||||||
|
{
|
||||||
|
// User callback, registered via ImDrawList::AddCallback()
|
||||||
|
// (ImDrawCallback_ResetRenderState is a special callback value used by the user to request the renderer to reset render state.)
|
||||||
|
if (pcmd->UserCallback == ImDrawCallback_ResetRenderState)
|
||||||
|
ImGui_ImplDX12_SetupRenderState(draw_data, ctx, fr);
|
||||||
|
else
|
||||||
|
pcmd->UserCallback(cmd_list, pcmd);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Apply Scissor, Bind texture, Draw
|
||||||
|
const D3D12_RECT r = { (LONG)(pcmd->ClipRect.x - clip_off.x), (LONG)(pcmd->ClipRect.y - clip_off.y), (LONG)(pcmd->ClipRect.z - clip_off.x), (LONG)(pcmd->ClipRect.w - clip_off.y) };
|
||||||
|
if (r.right > r.left && r.bottom > r.top)
|
||||||
|
{
|
||||||
|
ctx->SetGraphicsRootDescriptorTable(1, *(D3D12_GPU_DESCRIPTOR_HANDLE*)&pcmd->TextureId);
|
||||||
|
ctx->RSSetScissorRects(1, &r);
|
||||||
|
ctx->DrawIndexedInstanced(pcmd->ElemCount, 1, pcmd->IdxOffset + global_idx_offset, pcmd->VtxOffset + global_vtx_offset, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
global_idx_offset += cmd_list->IdxBuffer.Size;
|
||||||
|
global_vtx_offset += cmd_list->VtxBuffer.Size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ImGui_ImplDX12_CreateFontsTexture()
|
||||||
|
{
|
||||||
|
// Build texture atlas
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
unsigned char* pixels;
|
||||||
|
int width, height;
|
||||||
|
io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height);
|
||||||
|
|
||||||
|
// Upload texture to graphics system
|
||||||
|
{
|
||||||
|
D3D12_HEAP_PROPERTIES props;
|
||||||
|
memset(&props, 0, sizeof(D3D12_HEAP_PROPERTIES));
|
||||||
|
props.Type = D3D12_HEAP_TYPE_DEFAULT;
|
||||||
|
props.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
|
||||||
|
props.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
|
||||||
|
|
||||||
|
D3D12_RESOURCE_DESC desc;
|
||||||
|
ZeroMemory(&desc, sizeof(desc));
|
||||||
|
desc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
|
||||||
|
desc.Alignment = 0;
|
||||||
|
desc.Width = width;
|
||||||
|
desc.Height = height;
|
||||||
|
desc.DepthOrArraySize = 1;
|
||||||
|
desc.MipLevels = 1;
|
||||||
|
desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
|
||||||
|
desc.SampleDesc.Count = 1;
|
||||||
|
desc.SampleDesc.Quality = 0;
|
||||||
|
desc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
|
||||||
|
desc.Flags = D3D12_RESOURCE_FLAG_NONE;
|
||||||
|
|
||||||
|
ID3D12Resource* pTexture = NULL;
|
||||||
|
g_pd3dDevice->CreateCommittedResource(&props, D3D12_HEAP_FLAG_NONE, &desc,
|
||||||
|
D3D12_RESOURCE_STATE_COPY_DEST, NULL, IID_PPV_ARGS(&pTexture));
|
||||||
|
|
||||||
|
UINT uploadPitch = (width * 4 + D3D12_TEXTURE_DATA_PITCH_ALIGNMENT - 1u) & ~(D3D12_TEXTURE_DATA_PITCH_ALIGNMENT - 1u);
|
||||||
|
UINT uploadSize = height * uploadPitch;
|
||||||
|
desc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
|
||||||
|
desc.Alignment = 0;
|
||||||
|
desc.Width = uploadSize;
|
||||||
|
desc.Height = 1;
|
||||||
|
desc.DepthOrArraySize = 1;
|
||||||
|
desc.MipLevels = 1;
|
||||||
|
desc.Format = DXGI_FORMAT_UNKNOWN;
|
||||||
|
desc.SampleDesc.Count = 1;
|
||||||
|
desc.SampleDesc.Quality = 0;
|
||||||
|
desc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
|
||||||
|
desc.Flags = D3D12_RESOURCE_FLAG_NONE;
|
||||||
|
|
||||||
|
props.Type = D3D12_HEAP_TYPE_UPLOAD;
|
||||||
|
props.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
|
||||||
|
props.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
|
||||||
|
|
||||||
|
ID3D12Resource* uploadBuffer = NULL;
|
||||||
|
HRESULT hr = g_pd3dDevice->CreateCommittedResource(&props, D3D12_HEAP_FLAG_NONE, &desc,
|
||||||
|
D3D12_RESOURCE_STATE_GENERIC_READ, NULL, IID_PPV_ARGS(&uploadBuffer));
|
||||||
|
IM_ASSERT(SUCCEEDED(hr));
|
||||||
|
|
||||||
|
void* mapped = NULL;
|
||||||
|
D3D12_RANGE range = { 0, uploadSize };
|
||||||
|
hr = uploadBuffer->Map(0, &range, &mapped);
|
||||||
|
IM_ASSERT(SUCCEEDED(hr));
|
||||||
|
for (int y = 0; y < height; y++)
|
||||||
|
memcpy((void*) ((uintptr_t) mapped + y * uploadPitch), pixels + y * width * 4, width * 4);
|
||||||
|
uploadBuffer->Unmap(0, &range);
|
||||||
|
|
||||||
|
D3D12_TEXTURE_COPY_LOCATION srcLocation = {};
|
||||||
|
srcLocation.pResource = uploadBuffer;
|
||||||
|
srcLocation.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT;
|
||||||
|
srcLocation.PlacedFootprint.Footprint.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
|
||||||
|
srcLocation.PlacedFootprint.Footprint.Width = width;
|
||||||
|
srcLocation.PlacedFootprint.Footprint.Height = height;
|
||||||
|
srcLocation.PlacedFootprint.Footprint.Depth = 1;
|
||||||
|
srcLocation.PlacedFootprint.Footprint.RowPitch = uploadPitch;
|
||||||
|
|
||||||
|
D3D12_TEXTURE_COPY_LOCATION dstLocation = {};
|
||||||
|
dstLocation.pResource = pTexture;
|
||||||
|
dstLocation.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
|
||||||
|
dstLocation.SubresourceIndex = 0;
|
||||||
|
|
||||||
|
D3D12_RESOURCE_BARRIER barrier = {};
|
||||||
|
barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
|
||||||
|
barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
|
||||||
|
barrier.Transition.pResource = pTexture;
|
||||||
|
barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
|
||||||
|
barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_COPY_DEST;
|
||||||
|
barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE;
|
||||||
|
|
||||||
|
ID3D12Fence* fence = NULL;
|
||||||
|
hr = g_pd3dDevice->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&fence));
|
||||||
|
IM_ASSERT(SUCCEEDED(hr));
|
||||||
|
|
||||||
|
HANDLE event = CreateEvent(0, 0, 0, 0);
|
||||||
|
IM_ASSERT(event != NULL);
|
||||||
|
|
||||||
|
D3D12_COMMAND_QUEUE_DESC queueDesc = {};
|
||||||
|
queueDesc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT;
|
||||||
|
queueDesc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE;
|
||||||
|
queueDesc.NodeMask = 1;
|
||||||
|
|
||||||
|
ID3D12CommandQueue* cmdQueue = NULL;
|
||||||
|
hr = g_pd3dDevice->CreateCommandQueue(&queueDesc, IID_PPV_ARGS(&cmdQueue));
|
||||||
|
IM_ASSERT(SUCCEEDED(hr));
|
||||||
|
|
||||||
|
ID3D12CommandAllocator* cmdAlloc = NULL;
|
||||||
|
hr = g_pd3dDevice->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&cmdAlloc));
|
||||||
|
IM_ASSERT(SUCCEEDED(hr));
|
||||||
|
|
||||||
|
ID3D12GraphicsCommandList* cmdList = NULL;
|
||||||
|
hr = g_pd3dDevice->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, cmdAlloc, NULL, IID_PPV_ARGS(&cmdList));
|
||||||
|
IM_ASSERT(SUCCEEDED(hr));
|
||||||
|
|
||||||
|
cmdList->CopyTextureRegion(&dstLocation, 0, 0, 0, &srcLocation, NULL);
|
||||||
|
cmdList->ResourceBarrier(1, &barrier);
|
||||||
|
|
||||||
|
hr = cmdList->Close();
|
||||||
|
IM_ASSERT(SUCCEEDED(hr));
|
||||||
|
|
||||||
|
cmdQueue->ExecuteCommandLists(1, (ID3D12CommandList* const*)&cmdList);
|
||||||
|
hr = cmdQueue->Signal(fence, 1);
|
||||||
|
IM_ASSERT(SUCCEEDED(hr));
|
||||||
|
|
||||||
|
fence->SetEventOnCompletion(1, event);
|
||||||
|
WaitForSingleObject(event, INFINITE);
|
||||||
|
|
||||||
|
cmdList->Release();
|
||||||
|
cmdAlloc->Release();
|
||||||
|
cmdQueue->Release();
|
||||||
|
CloseHandle(event);
|
||||||
|
fence->Release();
|
||||||
|
uploadBuffer->Release();
|
||||||
|
|
||||||
|
// Create texture view
|
||||||
|
D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc;
|
||||||
|
ZeroMemory(&srvDesc, sizeof(srvDesc));
|
||||||
|
srvDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
|
||||||
|
srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D;
|
||||||
|
srvDesc.Texture2D.MipLevels = desc.MipLevels;
|
||||||
|
srvDesc.Texture2D.MostDetailedMip = 0;
|
||||||
|
srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
|
||||||
|
g_pd3dDevice->CreateShaderResourceView(pTexture, &srvDesc, g_hFontSrvCpuDescHandle);
|
||||||
|
SafeRelease(g_pFontTextureResource);
|
||||||
|
g_pFontTextureResource = pTexture;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Store our identifier
|
||||||
|
static_assert(sizeof(ImTextureID) >= sizeof(g_hFontSrvGpuDescHandle.ptr), "Can't pack descriptor handle into TexID, 32-bit not supported yet.");
|
||||||
|
io.Fonts->SetTexID((ImTextureID)g_hFontSrvGpuDescHandle.ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ImGui_ImplDX12_CreateDeviceObjects()
|
||||||
|
{
|
||||||
|
if (!g_pd3dDevice)
|
||||||
|
return false;
|
||||||
|
if (g_pPipelineState)
|
||||||
|
ImGui_ImplDX12_InvalidateDeviceObjects();
|
||||||
|
|
||||||
|
// Create the root signature
|
||||||
|
{
|
||||||
|
D3D12_DESCRIPTOR_RANGE descRange = {};
|
||||||
|
descRange.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV;
|
||||||
|
descRange.NumDescriptors = 1;
|
||||||
|
descRange.BaseShaderRegister = 0;
|
||||||
|
descRange.RegisterSpace = 0;
|
||||||
|
descRange.OffsetInDescriptorsFromTableStart = 0;
|
||||||
|
|
||||||
|
D3D12_ROOT_PARAMETER param[2] = {};
|
||||||
|
|
||||||
|
param[0].ParameterType = D3D12_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS;
|
||||||
|
param[0].Constants.ShaderRegister = 0;
|
||||||
|
param[0].Constants.RegisterSpace = 0;
|
||||||
|
param[0].Constants.Num32BitValues = 16;
|
||||||
|
param[0].ShaderVisibility = D3D12_SHADER_VISIBILITY_VERTEX;
|
||||||
|
|
||||||
|
param[1].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
|
||||||
|
param[1].DescriptorTable.NumDescriptorRanges = 1;
|
||||||
|
param[1].DescriptorTable.pDescriptorRanges = &descRange;
|
||||||
|
param[1].ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL;
|
||||||
|
|
||||||
|
D3D12_STATIC_SAMPLER_DESC staticSampler = {};
|
||||||
|
staticSampler.Filter = D3D12_FILTER_MIN_MAG_MIP_LINEAR;
|
||||||
|
staticSampler.AddressU = D3D12_TEXTURE_ADDRESS_MODE_WRAP;
|
||||||
|
staticSampler.AddressV = D3D12_TEXTURE_ADDRESS_MODE_WRAP;
|
||||||
|
staticSampler.AddressW = D3D12_TEXTURE_ADDRESS_MODE_WRAP;
|
||||||
|
staticSampler.MipLODBias = 0.f;
|
||||||
|
staticSampler.MaxAnisotropy = 0;
|
||||||
|
staticSampler.ComparisonFunc = D3D12_COMPARISON_FUNC_ALWAYS;
|
||||||
|
staticSampler.BorderColor = D3D12_STATIC_BORDER_COLOR_TRANSPARENT_BLACK;
|
||||||
|
staticSampler.MinLOD = 0.f;
|
||||||
|
staticSampler.MaxLOD = 0.f;
|
||||||
|
staticSampler.ShaderRegister = 0;
|
||||||
|
staticSampler.RegisterSpace = 0;
|
||||||
|
staticSampler.ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL;
|
||||||
|
|
||||||
|
D3D12_ROOT_SIGNATURE_DESC desc = {};
|
||||||
|
desc.NumParameters = _countof(param);
|
||||||
|
desc.pParameters = param;
|
||||||
|
desc.NumStaticSamplers = 1;
|
||||||
|
desc.pStaticSamplers = &staticSampler;
|
||||||
|
desc.Flags =
|
||||||
|
D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT |
|
||||||
|
D3D12_ROOT_SIGNATURE_FLAG_DENY_HULL_SHADER_ROOT_ACCESS |
|
||||||
|
D3D12_ROOT_SIGNATURE_FLAG_DENY_DOMAIN_SHADER_ROOT_ACCESS |
|
||||||
|
D3D12_ROOT_SIGNATURE_FLAG_DENY_GEOMETRY_SHADER_ROOT_ACCESS;
|
||||||
|
|
||||||
|
// Load d3d12.dll and D3D12SerializeRootSignature() function address dynamically to facilitate using with D3D12On7.
|
||||||
|
// See if any version of d3d12.dll is already loaded in the process. If so, give preference to that.
|
||||||
|
static HINSTANCE d3d12_dll = ::GetModuleHandleA("d3d12.dll");
|
||||||
|
if (d3d12_dll == NULL)
|
||||||
|
{
|
||||||
|
// Attempt to load d3d12.dll from local directories. This will only succeed if
|
||||||
|
// (1) the current OS is Windows 7, and
|
||||||
|
// (2) there exists a version of d3d12.dll for Windows 7 (D3D12On7) in one of the following directories.
|
||||||
|
// See https://github.com/ocornut/imgui/pull/3696 for details.
|
||||||
|
const char* localD3d12Paths[] = { ".\\d3d12.dll", ".\\d3d12on7\\d3d12.dll", ".\\12on7\\d3d12.dll" }; // A. current directory, B. used by some games, C. used in Microsoft D3D12On7 sample
|
||||||
|
for (int i = 0; i < IM_ARRAYSIZE(localD3d12Paths); i++)
|
||||||
|
if ((d3d12_dll = ::LoadLibraryA(localD3d12Paths[i])) != NULL)
|
||||||
|
break;
|
||||||
|
|
||||||
|
// If failed, we are on Windows >= 10.
|
||||||
|
if (d3d12_dll == NULL)
|
||||||
|
d3d12_dll = ::LoadLibraryA("d3d12.dll");
|
||||||
|
|
||||||
|
if (d3d12_dll == NULL)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
PFN_D3D12_SERIALIZE_ROOT_SIGNATURE D3D12SerializeRootSignatureFn = (PFN_D3D12_SERIALIZE_ROOT_SIGNATURE)::GetProcAddress(d3d12_dll, "D3D12SerializeRootSignature");
|
||||||
|
if (D3D12SerializeRootSignatureFn == NULL)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
ID3DBlob* blob = NULL;
|
||||||
|
if (D3D12SerializeRootSignatureFn(&desc, D3D_ROOT_SIGNATURE_VERSION_1, &blob, NULL) != S_OK)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
g_pd3dDevice->CreateRootSignature(0, blob->GetBufferPointer(), blob->GetBufferSize(), IID_PPV_ARGS(&g_pRootSignature));
|
||||||
|
blob->Release();
|
||||||
|
}
|
||||||
|
|
||||||
|
// By using D3DCompile() from <d3dcompiler.h> / d3dcompiler.lib, we introduce a dependency to a given version of d3dcompiler_XX.dll (see D3DCOMPILER_DLL_A)
|
||||||
|
// If you would like to use this DX12 sample code but remove this dependency you can:
|
||||||
|
// 1) compile once, save the compiled shader blobs into a file or source code and pass them to CreateVertexShader()/CreatePixelShader() [preferred solution]
|
||||||
|
// 2) use code to detect any version of the DLL and grab a pointer to D3DCompile from the DLL.
|
||||||
|
// See https://github.com/ocornut/imgui/pull/638 for sources and details.
|
||||||
|
|
||||||
|
D3D12_GRAPHICS_PIPELINE_STATE_DESC psoDesc;
|
||||||
|
memset(&psoDesc, 0, sizeof(D3D12_GRAPHICS_PIPELINE_STATE_DESC));
|
||||||
|
psoDesc.NodeMask = 1;
|
||||||
|
psoDesc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
|
||||||
|
psoDesc.pRootSignature = g_pRootSignature;
|
||||||
|
psoDesc.SampleMask = UINT_MAX;
|
||||||
|
psoDesc.NumRenderTargets = 1;
|
||||||
|
psoDesc.RTVFormats[0] = g_RTVFormat;
|
||||||
|
psoDesc.SampleDesc.Count = 1;
|
||||||
|
psoDesc.Flags = D3D12_PIPELINE_STATE_FLAG_NONE;
|
||||||
|
|
||||||
|
ID3DBlob* vertexShaderBlob;
|
||||||
|
ID3DBlob* pixelShaderBlob;
|
||||||
|
|
||||||
|
// Create the vertex shader
|
||||||
|
{
|
||||||
|
static const char* vertexShader =
|
||||||
|
"cbuffer vertexBuffer : register(b0) \
|
||||||
|
{\
|
||||||
|
float4x4 ProjectionMatrix; \
|
||||||
|
};\
|
||||||
|
struct VS_INPUT\
|
||||||
|
{\
|
||||||
|
float2 pos : POSITION;\
|
||||||
|
float4 col : COLOR0;\
|
||||||
|
float2 uv : TEXCOORD0;\
|
||||||
|
};\
|
||||||
|
\
|
||||||
|
struct PS_INPUT\
|
||||||
|
{\
|
||||||
|
float4 pos : SV_POSITION;\
|
||||||
|
float4 col : COLOR0;\
|
||||||
|
float2 uv : TEXCOORD0;\
|
||||||
|
};\
|
||||||
|
\
|
||||||
|
PS_INPUT main(VS_INPUT input)\
|
||||||
|
{\
|
||||||
|
PS_INPUT output;\
|
||||||
|
output.pos = mul( ProjectionMatrix, float4(input.pos.xy, 0.f, 1.f));\
|
||||||
|
output.col = input.col;\
|
||||||
|
output.uv = input.uv;\
|
||||||
|
return output;\
|
||||||
|
}";
|
||||||
|
|
||||||
|
if (FAILED(D3DCompile(vertexShader, strlen(vertexShader), NULL, NULL, NULL, "main", "vs_5_0", 0, 0, &vertexShaderBlob, NULL)))
|
||||||
|
return false; // NB: Pass ID3D10Blob* pErrorBlob to D3DCompile() to get error showing in (const char*)pErrorBlob->GetBufferPointer(). Make sure to Release() the blob!
|
||||||
|
psoDesc.VS = { vertexShaderBlob->GetBufferPointer(), vertexShaderBlob->GetBufferSize() };
|
||||||
|
|
||||||
|
// Create the input layout
|
||||||
|
static D3D12_INPUT_ELEMENT_DESC local_layout[] =
|
||||||
|
{
|
||||||
|
{ "POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, (UINT)IM_OFFSETOF(ImDrawVert, pos), D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },
|
||||||
|
{ "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, (UINT)IM_OFFSETOF(ImDrawVert, uv), D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },
|
||||||
|
{ "COLOR", 0, DXGI_FORMAT_R8G8B8A8_UNORM, 0, (UINT)IM_OFFSETOF(ImDrawVert, col), D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },
|
||||||
|
};
|
||||||
|
psoDesc.InputLayout = { local_layout, 3 };
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the pixel shader
|
||||||
|
{
|
||||||
|
static const char* pixelShader =
|
||||||
|
"struct PS_INPUT\
|
||||||
|
{\
|
||||||
|
float4 pos : SV_POSITION;\
|
||||||
|
float4 col : COLOR0;\
|
||||||
|
float2 uv : TEXCOORD0;\
|
||||||
|
};\
|
||||||
|
SamplerState sampler0 : register(s0);\
|
||||||
|
Texture2D texture0 : register(t0);\
|
||||||
|
\
|
||||||
|
float4 main(PS_INPUT input) : SV_Target\
|
||||||
|
{\
|
||||||
|
float4 out_col = input.col * texture0.Sample(sampler0, input.uv); \
|
||||||
|
return out_col; \
|
||||||
|
}";
|
||||||
|
|
||||||
|
if (FAILED(D3DCompile(pixelShader, strlen(pixelShader), NULL, NULL, NULL, "main", "ps_5_0", 0, 0, &pixelShaderBlob, NULL)))
|
||||||
|
{
|
||||||
|
vertexShaderBlob->Release();
|
||||||
|
return false; // NB: Pass ID3D10Blob* pErrorBlob to D3DCompile() to get error showing in (const char*)pErrorBlob->GetBufferPointer(). Make sure to Release() the blob!
|
||||||
|
}
|
||||||
|
psoDesc.PS = { pixelShaderBlob->GetBufferPointer(), pixelShaderBlob->GetBufferSize() };
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the blending setup
|
||||||
|
{
|
||||||
|
D3D12_BLEND_DESC& desc = psoDesc.BlendState;
|
||||||
|
desc.AlphaToCoverageEnable = false;
|
||||||
|
desc.RenderTarget[0].BlendEnable = true;
|
||||||
|
desc.RenderTarget[0].SrcBlend = D3D12_BLEND_SRC_ALPHA;
|
||||||
|
desc.RenderTarget[0].DestBlend = D3D12_BLEND_INV_SRC_ALPHA;
|
||||||
|
desc.RenderTarget[0].BlendOp = D3D12_BLEND_OP_ADD;
|
||||||
|
desc.RenderTarget[0].SrcBlendAlpha = D3D12_BLEND_ONE;
|
||||||
|
desc.RenderTarget[0].DestBlendAlpha = D3D12_BLEND_INV_SRC_ALPHA;
|
||||||
|
desc.RenderTarget[0].BlendOpAlpha = D3D12_BLEND_OP_ADD;
|
||||||
|
desc.RenderTarget[0].RenderTargetWriteMask = D3D12_COLOR_WRITE_ENABLE_ALL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the rasterizer state
|
||||||
|
{
|
||||||
|
D3D12_RASTERIZER_DESC& desc = psoDesc.RasterizerState;
|
||||||
|
desc.FillMode = D3D12_FILL_MODE_SOLID;
|
||||||
|
desc.CullMode = D3D12_CULL_MODE_NONE;
|
||||||
|
desc.FrontCounterClockwise = FALSE;
|
||||||
|
desc.DepthBias = D3D12_DEFAULT_DEPTH_BIAS;
|
||||||
|
desc.DepthBiasClamp = D3D12_DEFAULT_DEPTH_BIAS_CLAMP;
|
||||||
|
desc.SlopeScaledDepthBias = D3D12_DEFAULT_SLOPE_SCALED_DEPTH_BIAS;
|
||||||
|
desc.DepthClipEnable = true;
|
||||||
|
desc.MultisampleEnable = FALSE;
|
||||||
|
desc.AntialiasedLineEnable = FALSE;
|
||||||
|
desc.ForcedSampleCount = 0;
|
||||||
|
desc.ConservativeRaster = D3D12_CONSERVATIVE_RASTERIZATION_MODE_OFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create depth-stencil State
|
||||||
|
{
|
||||||
|
D3D12_DEPTH_STENCIL_DESC& desc = psoDesc.DepthStencilState;
|
||||||
|
desc.DepthEnable = false;
|
||||||
|
desc.DepthWriteMask = D3D12_DEPTH_WRITE_MASK_ALL;
|
||||||
|
desc.DepthFunc = D3D12_COMPARISON_FUNC_ALWAYS;
|
||||||
|
desc.StencilEnable = false;
|
||||||
|
desc.FrontFace.StencilFailOp = desc.FrontFace.StencilDepthFailOp = desc.FrontFace.StencilPassOp = D3D12_STENCIL_OP_KEEP;
|
||||||
|
desc.FrontFace.StencilFunc = D3D12_COMPARISON_FUNC_ALWAYS;
|
||||||
|
desc.BackFace = desc.FrontFace;
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT result_pipeline_state = g_pd3dDevice->CreateGraphicsPipelineState(&psoDesc, IID_PPV_ARGS(&g_pPipelineState));
|
||||||
|
vertexShaderBlob->Release();
|
||||||
|
pixelShaderBlob->Release();
|
||||||
|
if (result_pipeline_state != S_OK)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
ImGui_ImplDX12_CreateFontsTexture();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGui_ImplDX12_InvalidateDeviceObjects()
|
||||||
|
{
|
||||||
|
if (!g_pd3dDevice)
|
||||||
|
return;
|
||||||
|
|
||||||
|
SafeRelease(g_pRootSignature);
|
||||||
|
SafeRelease(g_pPipelineState);
|
||||||
|
SafeRelease(g_pFontTextureResource);
|
||||||
|
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
io.Fonts->SetTexID(NULL); // We copied g_pFontTextureView to io.Fonts->TexID so let's clear that as well.
|
||||||
|
|
||||||
|
for (UINT i = 0; i < g_numFramesInFlight; i++)
|
||||||
|
{
|
||||||
|
FrameResources* fr = &g_pFrameResources[i];
|
||||||
|
SafeRelease(fr->IndexBuffer);
|
||||||
|
SafeRelease(fr->VertexBuffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ImGui_ImplDX12_Init(ID3D12Device* device, int num_frames_in_flight, DXGI_FORMAT rtv_format, ID3D12DescriptorHeap* cbv_srv_heap,
|
||||||
|
D3D12_CPU_DESCRIPTOR_HANDLE font_srv_cpu_desc_handle, D3D12_GPU_DESCRIPTOR_HANDLE font_srv_gpu_desc_handle)
|
||||||
|
{
|
||||||
|
// Setup backend capabilities flags
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
io.BackendRendererName = "imgui_impl_dx12";
|
||||||
|
io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes.
|
||||||
|
|
||||||
|
g_pd3dDevice = device;
|
||||||
|
g_RTVFormat = rtv_format;
|
||||||
|
g_hFontSrvCpuDescHandle = font_srv_cpu_desc_handle;
|
||||||
|
g_hFontSrvGpuDescHandle = font_srv_gpu_desc_handle;
|
||||||
|
g_pFrameResources = new FrameResources[num_frames_in_flight];
|
||||||
|
g_numFramesInFlight = num_frames_in_flight;
|
||||||
|
g_frameIndex = UINT_MAX;
|
||||||
|
IM_UNUSED(cbv_srv_heap); // Unused in master branch (will be used by multi-viewports)
|
||||||
|
|
||||||
|
// Create buffers with a default size (they will later be grown as needed)
|
||||||
|
for (int i = 0; i < num_frames_in_flight; i++)
|
||||||
|
{
|
||||||
|
FrameResources* fr = &g_pFrameResources[i];
|
||||||
|
fr->IndexBuffer = NULL;
|
||||||
|
fr->VertexBuffer = NULL;
|
||||||
|
fr->IndexBufferSize = 10000;
|
||||||
|
fr->VertexBufferSize = 5000;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGui_ImplDX12_Shutdown()
|
||||||
|
{
|
||||||
|
ImGui_ImplDX12_InvalidateDeviceObjects();
|
||||||
|
delete[] g_pFrameResources;
|
||||||
|
g_pFrameResources = NULL;
|
||||||
|
g_pd3dDevice = NULL;
|
||||||
|
g_hFontSrvCpuDescHandle.ptr = 0;
|
||||||
|
g_hFontSrvGpuDescHandle.ptr = 0;
|
||||||
|
g_numFramesInFlight = 0;
|
||||||
|
g_frameIndex = UINT_MAX;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGui_ImplDX12_NewFrame()
|
||||||
|
{
|
||||||
|
if (!g_pPipelineState)
|
||||||
|
ImGui_ImplDX12_CreateDeviceObjects();
|
||||||
|
}
|
48
backend/imgui_impl_dx12.h
Normal file
48
backend/imgui_impl_dx12.h
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
// dear imgui: Renderer Backend for DirectX12
|
||||||
|
// This needs to be used along with a Platform Backend (e.g. Win32)
|
||||||
|
|
||||||
|
// Implemented features:
|
||||||
|
// [X] Renderer: User texture binding. Use 'D3D12_GPU_DESCRIPTOR_HANDLE' as ImTextureID. Read the FAQ about ImTextureID!
|
||||||
|
// [X] Renderer: Support for large meshes (64k+ vertices) with 16-bit indices.
|
||||||
|
|
||||||
|
// Important: to compile on 32-bit systems, this backend requires code to be compiled with '#define ImTextureID ImU64'.
|
||||||
|
// This is because we need ImTextureID to carry a 64-bit value and by default ImTextureID is defined as void*.
|
||||||
|
// This define is set in the example .vcxproj file and need to be replicated in your app or by adding it to your imconfig.h file.
|
||||||
|
|
||||||
|
// You can copy and use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
||||||
|
// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
|
||||||
|
// Read online: https://github.com/ocornut/imgui/tree/master/docs
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include "imgui.h" // IMGUI_IMPL_API
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#pragma warning (push)
|
||||||
|
#pragma warning (disable: 4471) // a forward declaration of an unscoped enumeration must have an underlying type
|
||||||
|
#endif
|
||||||
|
|
||||||
|
enum DXGI_FORMAT;
|
||||||
|
struct ID3D12Device;
|
||||||
|
struct ID3D12DescriptorHeap;
|
||||||
|
struct ID3D12GraphicsCommandList;
|
||||||
|
struct D3D12_CPU_DESCRIPTOR_HANDLE;
|
||||||
|
struct D3D12_GPU_DESCRIPTOR_HANDLE;
|
||||||
|
|
||||||
|
// cmd_list is the command list that the implementation will use to render imgui draw lists.
|
||||||
|
// Before calling the render function, caller must prepare cmd_list by resetting it and setting the appropriate
|
||||||
|
// render target and descriptor heap that contains font_srv_cpu_desc_handle/font_srv_gpu_desc_handle.
|
||||||
|
// font_srv_cpu_desc_handle and font_srv_gpu_desc_handle are handles to a single SRV descriptor to use for the internal font texture.
|
||||||
|
IMGUI_IMPL_API bool ImGui_ImplDX12_Init(ID3D12Device* device, int num_frames_in_flight, DXGI_FORMAT rtv_format, ID3D12DescriptorHeap* cbv_srv_heap,
|
||||||
|
D3D12_CPU_DESCRIPTOR_HANDLE font_srv_cpu_desc_handle, D3D12_GPU_DESCRIPTOR_HANDLE font_srv_gpu_desc_handle);
|
||||||
|
IMGUI_IMPL_API void ImGui_ImplDX12_Shutdown();
|
||||||
|
IMGUI_IMPL_API void ImGui_ImplDX12_NewFrame();
|
||||||
|
IMGUI_IMPL_API void ImGui_ImplDX12_RenderDrawData(ImDrawData* draw_data, ID3D12GraphicsCommandList* graphics_command_list);
|
||||||
|
|
||||||
|
// Use if you want to reset your rendering device without losing Dear ImGui state.
|
||||||
|
IMGUI_IMPL_API void ImGui_ImplDX12_InvalidateDeviceObjects();
|
||||||
|
IMGUI_IMPL_API bool ImGui_ImplDX12_CreateDeviceObjects();
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#pragma warning (pop)
|
||||||
|
#endif
|
||||||
|
|
314
backend/imgui_impl_dx9.cpp
Normal file
314
backend/imgui_impl_dx9.cpp
Normal file
@ -0,0 +1,314 @@
|
|||||||
|
// dear imgui: Renderer Backend for DirectX9
|
||||||
|
// This needs to be used along with a Platform Backend (e.g. Win32)
|
||||||
|
|
||||||
|
// Implemented features:
|
||||||
|
// [X] Renderer: User texture binding. Use 'LPDIRECT3DTEXTURE9' as ImTextureID. Read the FAQ about ImTextureID!
|
||||||
|
// [X] Renderer: Support for large meshes (64k+ vertices) with 16-bit indices.
|
||||||
|
|
||||||
|
// You can copy and use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
||||||
|
// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
|
||||||
|
// Read online: https://github.com/ocornut/imgui/tree/master/docs
|
||||||
|
|
||||||
|
// CHANGELOG
|
||||||
|
// (minor and older changes stripped away, please see git history for details)
|
||||||
|
// 2021-03-18: DirectX9: Calling IDirect3DStateBlock9::Capture() after CreateStateBlock() as a workaround for state restoring issues (see #3857).
|
||||||
|
// 2021-03-03: DirectX9: Added support for IMGUI_USE_BGRA_PACKED_COLOR in user's imconfig file.
|
||||||
|
// 2021-02-18: DirectX9: Change blending equation to preserve alpha in output buffer.
|
||||||
|
// 2019-05-29: DirectX9: Added support for large mesh (64K+ vertices), enable ImGuiBackendFlags_RendererHasVtxOffset flag.
|
||||||
|
// 2019-04-30: DirectX9: Added support for special ImDrawCallback_ResetRenderState callback to reset render state.
|
||||||
|
// 2019-03-29: Misc: Fixed erroneous assert in ImGui_ImplDX9_InvalidateDeviceObjects().
|
||||||
|
// 2019-01-16: Misc: Disabled fog before drawing UI's. Fixes issue #2288.
|
||||||
|
// 2018-11-30: Misc: Setting up io.BackendRendererName so it can be displayed in the About Window.
|
||||||
|
// 2018-06-08: Misc: Extracted imgui_impl_dx9.cpp/.h away from the old combined DX9+Win32 example.
|
||||||
|
// 2018-06-08: DirectX9: Use draw_data->DisplayPos and draw_data->DisplaySize to setup projection matrix and clipping rectangle.
|
||||||
|
// 2018-05-07: Render: Saving/restoring Transform because they don't seem to be included in the StateBlock. Setting shading mode to Gouraud.
|
||||||
|
// 2018-02-16: Misc: Obsoleted the io.RenderDrawListsFn callback and exposed ImGui_ImplDX9_RenderDrawData() in the .h file so you can call it yourself.
|
||||||
|
// 2018-02-06: Misc: Removed call to ImGui::Shutdown() which is not available from 1.60 WIP, user needs to call CreateContext/DestroyContext themselves.
|
||||||
|
|
||||||
|
#include "imgui.h"
|
||||||
|
#include "imgui_impl_dx9.h"
|
||||||
|
|
||||||
|
// DirectX
|
||||||
|
#include <d3d9.h>
|
||||||
|
|
||||||
|
// DirectX data
|
||||||
|
static LPDIRECT3DDEVICE9 g_pd3dDevice = NULL;
|
||||||
|
static LPDIRECT3DVERTEXBUFFER9 g_pVB = NULL;
|
||||||
|
static LPDIRECT3DINDEXBUFFER9 g_pIB = NULL;
|
||||||
|
static LPDIRECT3DTEXTURE9 g_FontTexture = NULL;
|
||||||
|
static int g_VertexBufferSize = 5000, g_IndexBufferSize = 10000;
|
||||||
|
|
||||||
|
struct CUSTOMVERTEX
|
||||||
|
{
|
||||||
|
float pos[3];
|
||||||
|
D3DCOLOR col;
|
||||||
|
float uv[2];
|
||||||
|
};
|
||||||
|
#define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZ|D3DFVF_DIFFUSE|D3DFVF_TEX1)
|
||||||
|
|
||||||
|
#ifdef IMGUI_USE_BGRA_PACKED_COLOR
|
||||||
|
#define IMGUI_COL_TO_DX9_ARGB(_COL) (_COL)
|
||||||
|
#else
|
||||||
|
#define IMGUI_COL_TO_DX9_ARGB(_COL) (((_COL) & 0xFF00FF00) | (((_COL) & 0xFF0000) >> 16) | (((_COL) & 0xFF) << 16))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static void ImGui_ImplDX9_SetupRenderState(ImDrawData* draw_data)
|
||||||
|
{
|
||||||
|
// Setup viewport
|
||||||
|
D3DVIEWPORT9 vp;
|
||||||
|
vp.X = vp.Y = 0;
|
||||||
|
vp.Width = (DWORD)draw_data->DisplaySize.x;
|
||||||
|
vp.Height = (DWORD)draw_data->DisplaySize.y;
|
||||||
|
vp.MinZ = 0.0f;
|
||||||
|
vp.MaxZ = 1.0f;
|
||||||
|
g_pd3dDevice->SetViewport(&vp);
|
||||||
|
|
||||||
|
// Setup render state: fixed-pipeline, alpha-blending, no face culling, no depth testing, shade mode (for gradient)
|
||||||
|
g_pd3dDevice->SetPixelShader(NULL);
|
||||||
|
g_pd3dDevice->SetVertexShader(NULL);
|
||||||
|
g_pd3dDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
|
||||||
|
g_pd3dDevice->SetRenderState(D3DRS_LIGHTING, FALSE);
|
||||||
|
g_pd3dDevice->SetRenderState(D3DRS_ZENABLE, FALSE);
|
||||||
|
g_pd3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
|
||||||
|
g_pd3dDevice->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE);
|
||||||
|
g_pd3dDevice->SetRenderState(D3DRS_BLENDOP, D3DBLENDOP_ADD);
|
||||||
|
g_pd3dDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
|
||||||
|
g_pd3dDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
|
||||||
|
g_pd3dDevice->SetRenderState(D3DRS_SEPARATEALPHABLENDENABLE, TRUE);
|
||||||
|
g_pd3dDevice->SetRenderState(D3DRS_SRCBLENDALPHA, D3DBLEND_ONE);
|
||||||
|
g_pd3dDevice->SetRenderState(D3DRS_DESTBLENDALPHA, D3DBLEND_INVSRCALPHA);
|
||||||
|
g_pd3dDevice->SetRenderState(D3DRS_SCISSORTESTENABLE, TRUE);
|
||||||
|
g_pd3dDevice->SetRenderState(D3DRS_SHADEMODE, D3DSHADE_GOURAUD);
|
||||||
|
g_pd3dDevice->SetRenderState(D3DRS_FOGENABLE, FALSE);
|
||||||
|
g_pd3dDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE);
|
||||||
|
g_pd3dDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
|
||||||
|
g_pd3dDevice->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE);
|
||||||
|
g_pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_MODULATE);
|
||||||
|
g_pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
|
||||||
|
g_pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE);
|
||||||
|
g_pd3dDevice->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
|
||||||
|
g_pd3dDevice->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
|
||||||
|
|
||||||
|
// Setup orthographic projection matrix
|
||||||
|
// Our visible imgui space lies from draw_data->DisplayPos (top left) to draw_data->DisplayPos+data_data->DisplaySize (bottom right). DisplayPos is (0,0) for single viewport apps.
|
||||||
|
// Being agnostic of whether <d3dx9.h> or <DirectXMath.h> can be used, we aren't relying on D3DXMatrixIdentity()/D3DXMatrixOrthoOffCenterLH() or DirectX::XMMatrixIdentity()/DirectX::XMMatrixOrthographicOffCenterLH()
|
||||||
|
{
|
||||||
|
float L = draw_data->DisplayPos.x + 0.5f;
|
||||||
|
float R = draw_data->DisplayPos.x + draw_data->DisplaySize.x + 0.5f;
|
||||||
|
float T = draw_data->DisplayPos.y + 0.5f;
|
||||||
|
float B = draw_data->DisplayPos.y + draw_data->DisplaySize.y + 0.5f;
|
||||||
|
D3DMATRIX mat_identity = { { { 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f } } };
|
||||||
|
D3DMATRIX mat_projection =
|
||||||
|
{ { {
|
||||||
|
2.0f/(R-L), 0.0f, 0.0f, 0.0f,
|
||||||
|
0.0f, 2.0f/(T-B), 0.0f, 0.0f,
|
||||||
|
0.0f, 0.0f, 0.5f, 0.0f,
|
||||||
|
(L+R)/(L-R), (T+B)/(B-T), 0.5f, 1.0f
|
||||||
|
} } };
|
||||||
|
g_pd3dDevice->SetTransform(D3DTS_WORLD, &mat_identity);
|
||||||
|
g_pd3dDevice->SetTransform(D3DTS_VIEW, &mat_identity);
|
||||||
|
g_pd3dDevice->SetTransform(D3DTS_PROJECTION, &mat_projection);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Render function.
|
||||||
|
void ImGui_ImplDX9_RenderDrawData(ImDrawData* draw_data)
|
||||||
|
{
|
||||||
|
// Avoid rendering when minimized
|
||||||
|
if (draw_data->DisplaySize.x <= 0.0f || draw_data->DisplaySize.y <= 0.0f)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Create and grow buffers if needed
|
||||||
|
if (!g_pVB || g_VertexBufferSize < draw_data->TotalVtxCount)
|
||||||
|
{
|
||||||
|
if (g_pVB) { g_pVB->Release(); g_pVB = NULL; }
|
||||||
|
g_VertexBufferSize = draw_data->TotalVtxCount + 5000;
|
||||||
|
if (g_pd3dDevice->CreateVertexBuffer(g_VertexBufferSize * sizeof(CUSTOMVERTEX), D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY, D3DFVF_CUSTOMVERTEX, D3DPOOL_DEFAULT, &g_pVB, NULL) < 0)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!g_pIB || g_IndexBufferSize < draw_data->TotalIdxCount)
|
||||||
|
{
|
||||||
|
if (g_pIB) { g_pIB->Release(); g_pIB = NULL; }
|
||||||
|
g_IndexBufferSize = draw_data->TotalIdxCount + 10000;
|
||||||
|
if (g_pd3dDevice->CreateIndexBuffer(g_IndexBufferSize * sizeof(ImDrawIdx), D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY, sizeof(ImDrawIdx) == 2 ? D3DFMT_INDEX16 : D3DFMT_INDEX32, D3DPOOL_DEFAULT, &g_pIB, NULL) < 0)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Backup the DX9 state
|
||||||
|
IDirect3DStateBlock9* d3d9_state_block = NULL;
|
||||||
|
if (g_pd3dDevice->CreateStateBlock(D3DSBT_ALL, &d3d9_state_block) < 0)
|
||||||
|
return;
|
||||||
|
if (d3d9_state_block->Capture() < 0)
|
||||||
|
{
|
||||||
|
d3d9_state_block->Release();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Backup the DX9 transform (DX9 documentation suggests that it is included in the StateBlock but it doesn't appear to)
|
||||||
|
D3DMATRIX last_world, last_view, last_projection;
|
||||||
|
g_pd3dDevice->GetTransform(D3DTS_WORLD, &last_world);
|
||||||
|
g_pd3dDevice->GetTransform(D3DTS_VIEW, &last_view);
|
||||||
|
g_pd3dDevice->GetTransform(D3DTS_PROJECTION, &last_projection);
|
||||||
|
|
||||||
|
// Copy and convert all vertices into a single contiguous buffer, convert colors to DX9 default format.
|
||||||
|
// FIXME-OPT: This is a minor waste of resource, the ideal is to use imconfig.h and
|
||||||
|
// 1) to avoid repacking colors: #define IMGUI_USE_BGRA_PACKED_COLOR
|
||||||
|
// 2) to avoid repacking vertices: #define IMGUI_OVERRIDE_DRAWVERT_STRUCT_LAYOUT struct ImDrawVert { ImVec2 pos; float z; ImU32 col; ImVec2 uv; }
|
||||||
|
CUSTOMVERTEX* vtx_dst;
|
||||||
|
ImDrawIdx* idx_dst;
|
||||||
|
if (g_pVB->Lock(0, (UINT)(draw_data->TotalVtxCount * sizeof(CUSTOMVERTEX)), (void**)&vtx_dst, D3DLOCK_DISCARD) < 0)
|
||||||
|
return;
|
||||||
|
if (g_pIB->Lock(0, (UINT)(draw_data->TotalIdxCount * sizeof(ImDrawIdx)), (void**)&idx_dst, D3DLOCK_DISCARD) < 0)
|
||||||
|
return;
|
||||||
|
for (int n = 0; n < draw_data->CmdListsCount; n++)
|
||||||
|
{
|
||||||
|
const ImDrawList* cmd_list = draw_data->CmdLists[n];
|
||||||
|
const ImDrawVert* vtx_src = cmd_list->VtxBuffer.Data;
|
||||||
|
for (int i = 0; i < cmd_list->VtxBuffer.Size; i++)
|
||||||
|
{
|
||||||
|
vtx_dst->pos[0] = vtx_src->pos.x;
|
||||||
|
vtx_dst->pos[1] = vtx_src->pos.y;
|
||||||
|
vtx_dst->pos[2] = 0.0f;
|
||||||
|
vtx_dst->col = IMGUI_COL_TO_DX9_ARGB(vtx_src->col);
|
||||||
|
vtx_dst->uv[0] = vtx_src->uv.x;
|
||||||
|
vtx_dst->uv[1] = vtx_src->uv.y;
|
||||||
|
vtx_dst++;
|
||||||
|
vtx_src++;
|
||||||
|
}
|
||||||
|
memcpy(idx_dst, cmd_list->IdxBuffer.Data, cmd_list->IdxBuffer.Size * sizeof(ImDrawIdx));
|
||||||
|
idx_dst += cmd_list->IdxBuffer.Size;
|
||||||
|
}
|
||||||
|
g_pVB->Unlock();
|
||||||
|
g_pIB->Unlock();
|
||||||
|
g_pd3dDevice->SetStreamSource(0, g_pVB, 0, sizeof(CUSTOMVERTEX));
|
||||||
|
g_pd3dDevice->SetIndices(g_pIB);
|
||||||
|
g_pd3dDevice->SetFVF(D3DFVF_CUSTOMVERTEX);
|
||||||
|
|
||||||
|
// Setup desired DX state
|
||||||
|
ImGui_ImplDX9_SetupRenderState(draw_data);
|
||||||
|
|
||||||
|
// Render command lists
|
||||||
|
// (Because we merged all buffers into a single one, we maintain our own offset into them)
|
||||||
|
int global_vtx_offset = 0;
|
||||||
|
int global_idx_offset = 0;
|
||||||
|
ImVec2 clip_off = draw_data->DisplayPos;
|
||||||
|
for (int n = 0; n < draw_data->CmdListsCount; n++)
|
||||||
|
{
|
||||||
|
const ImDrawList* cmd_list = draw_data->CmdLists[n];
|
||||||
|
for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++)
|
||||||
|
{
|
||||||
|
const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i];
|
||||||
|
if (pcmd->UserCallback != NULL)
|
||||||
|
{
|
||||||
|
// User callback, registered via ImDrawList::AddCallback()
|
||||||
|
// (ImDrawCallback_ResetRenderState is a special callback value used by the user to request the renderer to reset render state.)
|
||||||
|
if (pcmd->UserCallback == ImDrawCallback_ResetRenderState)
|
||||||
|
ImGui_ImplDX9_SetupRenderState(draw_data);
|
||||||
|
else
|
||||||
|
pcmd->UserCallback(cmd_list, pcmd);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const RECT r = { (LONG)(pcmd->ClipRect.x - clip_off.x), (LONG)(pcmd->ClipRect.y - clip_off.y), (LONG)(pcmd->ClipRect.z - clip_off.x), (LONG)(pcmd->ClipRect.w - clip_off.y) };
|
||||||
|
const LPDIRECT3DTEXTURE9 texture = (LPDIRECT3DTEXTURE9)pcmd->TextureId;
|
||||||
|
g_pd3dDevice->SetTexture(0, texture);
|
||||||
|
g_pd3dDevice->SetScissorRect(&r);
|
||||||
|
g_pd3dDevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, pcmd->VtxOffset + global_vtx_offset, 0, (UINT)cmd_list->VtxBuffer.Size, pcmd->IdxOffset + global_idx_offset, pcmd->ElemCount / 3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
global_idx_offset += cmd_list->IdxBuffer.Size;
|
||||||
|
global_vtx_offset += cmd_list->VtxBuffer.Size;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Restore the DX9 transform
|
||||||
|
g_pd3dDevice->SetTransform(D3DTS_WORLD, &last_world);
|
||||||
|
g_pd3dDevice->SetTransform(D3DTS_VIEW, &last_view);
|
||||||
|
g_pd3dDevice->SetTransform(D3DTS_PROJECTION, &last_projection);
|
||||||
|
|
||||||
|
// Restore the DX9 state
|
||||||
|
d3d9_state_block->Apply();
|
||||||
|
d3d9_state_block->Release();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ImGui_ImplDX9_Init(IDirect3DDevice9* device)
|
||||||
|
{
|
||||||
|
// Setup backend capabilities flags
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
io.BackendRendererName = "imgui_impl_dx9";
|
||||||
|
io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes.
|
||||||
|
|
||||||
|
g_pd3dDevice = device;
|
||||||
|
g_pd3dDevice->AddRef();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGui_ImplDX9_Shutdown()
|
||||||
|
{
|
||||||
|
ImGui_ImplDX9_InvalidateDeviceObjects();
|
||||||
|
if (g_pd3dDevice) { g_pd3dDevice->Release(); g_pd3dDevice = NULL; }
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool ImGui_ImplDX9_CreateFontsTexture()
|
||||||
|
{
|
||||||
|
// Build texture atlas
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
unsigned char* pixels;
|
||||||
|
int width, height, bytes_per_pixel;
|
||||||
|
io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height, &bytes_per_pixel);
|
||||||
|
|
||||||
|
// Convert RGBA32 to BGRA32 (because RGBA32 is not well supported by DX9 devices)
|
||||||
|
#ifndef IMGUI_USE_BGRA_PACKED_COLOR
|
||||||
|
if (io.Fonts->TexPixelsUseColors)
|
||||||
|
{
|
||||||
|
ImU32* dst_start = (ImU32*)ImGui::MemAlloc(width * height * bytes_per_pixel);
|
||||||
|
for (ImU32* src = (ImU32*)pixels, *dst = dst_start, *dst_end = dst_start + width * height; dst < dst_end; src++, dst++)
|
||||||
|
*dst = IMGUI_COL_TO_DX9_ARGB(*src);
|
||||||
|
pixels = (unsigned char*)dst_start;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Upload texture to graphics system
|
||||||
|
g_FontTexture = NULL;
|
||||||
|
if (g_pd3dDevice->CreateTexture(width, height, 1, D3DUSAGE_DYNAMIC, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &g_FontTexture, NULL) < 0)
|
||||||
|
return false;
|
||||||
|
D3DLOCKED_RECT tex_locked_rect;
|
||||||
|
if (g_FontTexture->LockRect(0, &tex_locked_rect, NULL, 0) != D3D_OK)
|
||||||
|
return false;
|
||||||
|
for (int y = 0; y < height; y++)
|
||||||
|
memcpy((unsigned char*)tex_locked_rect.pBits + tex_locked_rect.Pitch * y, pixels + (width * bytes_per_pixel) * y, (width * bytes_per_pixel));
|
||||||
|
g_FontTexture->UnlockRect(0);
|
||||||
|
|
||||||
|
// Store our identifier
|
||||||
|
io.Fonts->SetTexID((ImTextureID)g_FontTexture);
|
||||||
|
|
||||||
|
#ifndef IMGUI_USE_BGRA_PACKED_COLOR
|
||||||
|
if (io.Fonts->TexPixelsUseColors)
|
||||||
|
ImGui::MemFree(pixels);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ImGui_ImplDX9_CreateDeviceObjects()
|
||||||
|
{
|
||||||
|
if (!g_pd3dDevice)
|
||||||
|
return false;
|
||||||
|
if (!ImGui_ImplDX9_CreateFontsTexture())
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGui_ImplDX9_InvalidateDeviceObjects()
|
||||||
|
{
|
||||||
|
if (!g_pd3dDevice)
|
||||||
|
return;
|
||||||
|
if (g_pVB) { g_pVB->Release(); g_pVB = NULL; }
|
||||||
|
if (g_pIB) { g_pIB->Release(); g_pIB = NULL; }
|
||||||
|
if (g_FontTexture) { g_FontTexture->Release(); g_FontTexture = NULL; ImGui::GetIO().Fonts->SetTexID(NULL); } // We copied g_pFontTextureView to io.Fonts->TexID so let's clear that as well.
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGui_ImplDX9_NewFrame()
|
||||||
|
{
|
||||||
|
if (!g_FontTexture)
|
||||||
|
ImGui_ImplDX9_CreateDeviceObjects();
|
||||||
|
}
|
24
backend/imgui_impl_dx9.h
Normal file
24
backend/imgui_impl_dx9.h
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
// dear imgui: Renderer Backend for DirectX9
|
||||||
|
// This needs to be used along with a Platform Backend (e.g. Win32)
|
||||||
|
|
||||||
|
// Implemented features:
|
||||||
|
// [X] Renderer: User texture binding. Use 'LPDIRECT3DTEXTURE9' as ImTextureID. Read the FAQ about ImTextureID!
|
||||||
|
// [X] Renderer: Support for large meshes (64k+ vertices) with 16-bit indices.
|
||||||
|
|
||||||
|
// You can copy and use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
||||||
|
// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
|
||||||
|
// Read online: https://github.com/ocornut/imgui/tree/master/docs
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include "imgui.h" // IMGUI_IMPL_API
|
||||||
|
|
||||||
|
struct IDirect3DDevice9;
|
||||||
|
|
||||||
|
IMGUI_IMPL_API bool ImGui_ImplDX9_Init(IDirect3DDevice9* device);
|
||||||
|
IMGUI_IMPL_API void ImGui_ImplDX9_Shutdown();
|
||||||
|
IMGUI_IMPL_API void ImGui_ImplDX9_NewFrame();
|
||||||
|
IMGUI_IMPL_API void ImGui_ImplDX9_RenderDrawData(ImDrawData* draw_data);
|
||||||
|
|
||||||
|
// Use if you want to reset your rendering device without losing Dear ImGui state.
|
||||||
|
IMGUI_IMPL_API bool ImGui_ImplDX9_CreateDeviceObjects();
|
||||||
|
IMGUI_IMPL_API void ImGui_ImplDX9_InvalidateDeviceObjects();
|
374
backend/imgui_impl_glfw.cpp
Normal file
374
backend/imgui_impl_glfw.cpp
Normal file
@ -0,0 +1,374 @@
|
|||||||
|
// dear imgui: Platform Backend for GLFW
|
||||||
|
// This needs to be used along with a Renderer (e.g. OpenGL3, Vulkan, WebGPU..)
|
||||||
|
// (Info: GLFW is a cross-platform general purpose library for handling windows, inputs, OpenGL/Vulkan graphics context creation, etc.)
|
||||||
|
// (Requires: GLFW 3.1+)
|
||||||
|
|
||||||
|
// Implemented features:
|
||||||
|
// [X] Platform: Clipboard support.
|
||||||
|
// [X] Platform: Gamepad support. Enable with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'.
|
||||||
|
// [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange' (note: the resizing cursors requires GLFW 3.4+).
|
||||||
|
// [X] Platform: Keyboard arrays indexed using GLFW_KEY_* codes, e.g. ImGui::IsKeyPressed(GLFW_KEY_SPACE).
|
||||||
|
|
||||||
|
// You can copy and use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
||||||
|
// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
|
||||||
|
// Read online: https://github.com/ocornut/imgui/tree/master/docs
|
||||||
|
|
||||||
|
// CHANGELOG
|
||||||
|
// (minor and older changes stripped away, please see git history for details)
|
||||||
|
// 2020-01-17: Inputs: Disable error callback while assigning mouse cursors because some X11 setup don't have them and it generates errors.
|
||||||
|
// 2019-12-05: Inputs: Added support for new mouse cursors added in GLFW 3.4+ (resizing cursors, not allowed cursor).
|
||||||
|
// 2019-10-18: Misc: Previously installed user callbacks are now restored on shutdown.
|
||||||
|
// 2019-07-21: Inputs: Added mapping for ImGuiKey_KeyPadEnter.
|
||||||
|
// 2019-05-11: Inputs: Don't filter value from character callback before calling AddInputCharacter().
|
||||||
|
// 2019-03-12: Misc: Preserve DisplayFramebufferScale when main window is minimized.
|
||||||
|
// 2018-11-30: Misc: Setting up io.BackendPlatformName so it can be displayed in the About Window.
|
||||||
|
// 2018-11-07: Inputs: When installing our GLFW callbacks, we save user's previously installed ones - if any - and chain call them.
|
||||||
|
// 2018-08-01: Inputs: Workaround for Emscripten which doesn't seem to handle focus related calls.
|
||||||
|
// 2018-06-29: Inputs: Added support for the ImGuiMouseCursor_Hand cursor.
|
||||||
|
// 2018-06-08: Misc: Extracted imgui_impl_glfw.cpp/.h away from the old combined GLFW+OpenGL/Vulkan examples.
|
||||||
|
// 2018-03-20: Misc: Setup io.BackendFlags ImGuiBackendFlags_HasMouseCursors flag + honor ImGuiConfigFlags_NoMouseCursorChange flag.
|
||||||
|
// 2018-02-20: Inputs: Added support for mouse cursors (ImGui::GetMouseCursor() value, passed to glfwSetCursor()).
|
||||||
|
// 2018-02-06: Misc: Removed call to ImGui::Shutdown() which is not available from 1.60 WIP, user needs to call CreateContext/DestroyContext themselves.
|
||||||
|
// 2018-02-06: Inputs: Added mapping for ImGuiKey_Space.
|
||||||
|
// 2018-01-25: Inputs: Added gamepad support if ImGuiConfigFlags_NavEnableGamepad is set.
|
||||||
|
// 2018-01-25: Inputs: Honoring the io.WantSetMousePos by repositioning the mouse (when using navigation and ImGuiConfigFlags_NavMoveMouse is set).
|
||||||
|
// 2018-01-20: Inputs: Added Horizontal Mouse Wheel support.
|
||||||
|
// 2018-01-18: Inputs: Added mapping for ImGuiKey_Insert.
|
||||||
|
// 2017-08-25: Inputs: MousePos set to -FLT_MAX,-FLT_MAX when mouse is unavailable/missing (instead of -1,-1).
|
||||||
|
// 2016-10-15: Misc: Added a void* user_data parameter to Clipboard function handlers.
|
||||||
|
|
||||||
|
#include "imgui.h"
|
||||||
|
#include "imgui_impl_glfw.h"
|
||||||
|
|
||||||
|
// GLFW
|
||||||
|
#include <GLFW/glfw3.h>
|
||||||
|
#ifdef _WIN32
|
||||||
|
#undef APIENTRY
|
||||||
|
#define GLFW_EXPOSE_NATIVE_WIN32
|
||||||
|
#include <GLFW/glfw3native.h> // for glfwGetWin32Window
|
||||||
|
#endif
|
||||||
|
#define GLFW_HAS_WINDOW_TOPMOST (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3200) // 3.2+ GLFW_FLOATING
|
||||||
|
#define GLFW_HAS_WINDOW_HOVERED (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3300) // 3.3+ GLFW_HOVERED
|
||||||
|
#define GLFW_HAS_WINDOW_ALPHA (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3300) // 3.3+ glfwSetWindowOpacity
|
||||||
|
#define GLFW_HAS_PER_MONITOR_DPI (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3300) // 3.3+ glfwGetMonitorContentScale
|
||||||
|
#define GLFW_HAS_VULKAN (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3200) // 3.2+ glfwCreateWindowSurface
|
||||||
|
#ifdef GLFW_RESIZE_NESW_CURSOR // let's be nice to people who pulled GLFW between 2019-04-16 (3.4 define) and 2019-11-29 (cursors defines) // FIXME: Remove when GLFW 3.4 is released?
|
||||||
|
#define GLFW_HAS_NEW_CURSORS (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3400) // 3.4+ GLFW_RESIZE_ALL_CURSOR, GLFW_RESIZE_NESW_CURSOR, GLFW_RESIZE_NWSE_CURSOR, GLFW_NOT_ALLOWED_CURSOR
|
||||||
|
#else
|
||||||
|
#define GLFW_HAS_NEW_CURSORS (0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Data
|
||||||
|
enum GlfwClientApi
|
||||||
|
{
|
||||||
|
GlfwClientApi_Unknown,
|
||||||
|
GlfwClientApi_OpenGL,
|
||||||
|
GlfwClientApi_Vulkan
|
||||||
|
};
|
||||||
|
static GLFWwindow* g_Window = NULL; // Main window
|
||||||
|
static GlfwClientApi g_ClientApi = GlfwClientApi_Unknown;
|
||||||
|
static double g_Time = 0.0;
|
||||||
|
static bool g_MouseJustPressed[ImGuiMouseButton_COUNT] = {};
|
||||||
|
static GLFWcursor* g_MouseCursors[ImGuiMouseCursor_COUNT] = {};
|
||||||
|
static bool g_InstalledCallbacks = false;
|
||||||
|
|
||||||
|
// Chain GLFW callbacks: our callbacks will call the user's previously installed callbacks, if any.
|
||||||
|
static GLFWmousebuttonfun g_PrevUserCallbackMousebutton = NULL;
|
||||||
|
static GLFWscrollfun g_PrevUserCallbackScroll = NULL;
|
||||||
|
static GLFWkeyfun g_PrevUserCallbackKey = NULL;
|
||||||
|
static GLFWcharfun g_PrevUserCallbackChar = NULL;
|
||||||
|
|
||||||
|
static const char* ImGui_ImplGlfw_GetClipboardText(void* user_data)
|
||||||
|
{
|
||||||
|
return glfwGetClipboardString((GLFWwindow*)user_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ImGui_ImplGlfw_SetClipboardText(void* user_data, const char* text)
|
||||||
|
{
|
||||||
|
glfwSetClipboardString((GLFWwindow*)user_data, text);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGui_ImplGlfw_MouseButtonCallback(GLFWwindow* window, int button, int action, int mods)
|
||||||
|
{
|
||||||
|
if (g_PrevUserCallbackMousebutton != NULL)
|
||||||
|
g_PrevUserCallbackMousebutton(window, button, action, mods);
|
||||||
|
|
||||||
|
if (action == GLFW_PRESS && button >= 0 && button < IM_ARRAYSIZE(g_MouseJustPressed))
|
||||||
|
g_MouseJustPressed[button] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGui_ImplGlfw_ScrollCallback(GLFWwindow* window, double xoffset, double yoffset)
|
||||||
|
{
|
||||||
|
if (g_PrevUserCallbackScroll != NULL)
|
||||||
|
g_PrevUserCallbackScroll(window, xoffset, yoffset);
|
||||||
|
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
io.MouseWheelH += (float)xoffset;
|
||||||
|
io.MouseWheel += (float)yoffset;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGui_ImplGlfw_KeyCallback(GLFWwindow* window, int key, int scancode, int action, int mods)
|
||||||
|
{
|
||||||
|
if (g_PrevUserCallbackKey != NULL)
|
||||||
|
g_PrevUserCallbackKey(window, key, scancode, action, mods);
|
||||||
|
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
if (action == GLFW_PRESS)
|
||||||
|
io.KeysDown[key] = true;
|
||||||
|
if (action == GLFW_RELEASE)
|
||||||
|
io.KeysDown[key] = false;
|
||||||
|
|
||||||
|
// Modifiers are not reliable across systems
|
||||||
|
io.KeyCtrl = io.KeysDown[GLFW_KEY_LEFT_CONTROL] || io.KeysDown[GLFW_KEY_RIGHT_CONTROL];
|
||||||
|
io.KeyShift = io.KeysDown[GLFW_KEY_LEFT_SHIFT] || io.KeysDown[GLFW_KEY_RIGHT_SHIFT];
|
||||||
|
io.KeyAlt = io.KeysDown[GLFW_KEY_LEFT_ALT] || io.KeysDown[GLFW_KEY_RIGHT_ALT];
|
||||||
|
#ifdef _WIN32
|
||||||
|
io.KeySuper = false;
|
||||||
|
#else
|
||||||
|
io.KeySuper = io.KeysDown[GLFW_KEY_LEFT_SUPER] || io.KeysDown[GLFW_KEY_RIGHT_SUPER];
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGui_ImplGlfw_CharCallback(GLFWwindow* window, unsigned int c)
|
||||||
|
{
|
||||||
|
if (g_PrevUserCallbackChar != NULL)
|
||||||
|
g_PrevUserCallbackChar(window, c);
|
||||||
|
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
io.AddInputCharacter(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool ImGui_ImplGlfw_Init(GLFWwindow* window, bool install_callbacks, GlfwClientApi client_api)
|
||||||
|
{
|
||||||
|
g_Window = window;
|
||||||
|
g_Time = 0.0;
|
||||||
|
|
||||||
|
// Setup backend capabilities flags
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
io.BackendFlags |= ImGuiBackendFlags_HasMouseCursors; // We can honor GetMouseCursor() values (optional)
|
||||||
|
io.BackendFlags |= ImGuiBackendFlags_HasSetMousePos; // We can honor io.WantSetMousePos requests (optional, rarely used)
|
||||||
|
io.BackendPlatformName = "imgui_impl_glfw";
|
||||||
|
|
||||||
|
// Keyboard mapping. Dear ImGui will use those indices to peek into the io.KeysDown[] array.
|
||||||
|
io.KeyMap[ImGuiKey_Tab] = GLFW_KEY_TAB;
|
||||||
|
io.KeyMap[ImGuiKey_LeftArrow] = GLFW_KEY_LEFT;
|
||||||
|
io.KeyMap[ImGuiKey_RightArrow] = GLFW_KEY_RIGHT;
|
||||||
|
io.KeyMap[ImGuiKey_UpArrow] = GLFW_KEY_UP;
|
||||||
|
io.KeyMap[ImGuiKey_DownArrow] = GLFW_KEY_DOWN;
|
||||||
|
io.KeyMap[ImGuiKey_PageUp] = GLFW_KEY_PAGE_UP;
|
||||||
|
io.KeyMap[ImGuiKey_PageDown] = GLFW_KEY_PAGE_DOWN;
|
||||||
|
io.KeyMap[ImGuiKey_Home] = GLFW_KEY_HOME;
|
||||||
|
io.KeyMap[ImGuiKey_End] = GLFW_KEY_END;
|
||||||
|
io.KeyMap[ImGuiKey_Insert] = GLFW_KEY_INSERT;
|
||||||
|
io.KeyMap[ImGuiKey_Delete] = GLFW_KEY_DELETE;
|
||||||
|
io.KeyMap[ImGuiKey_Backspace] = GLFW_KEY_BACKSPACE;
|
||||||
|
io.KeyMap[ImGuiKey_Space] = GLFW_KEY_SPACE;
|
||||||
|
io.KeyMap[ImGuiKey_Enter] = GLFW_KEY_ENTER;
|
||||||
|
io.KeyMap[ImGuiKey_Escape] = GLFW_KEY_ESCAPE;
|
||||||
|
io.KeyMap[ImGuiKey_KeyPadEnter] = GLFW_KEY_KP_ENTER;
|
||||||
|
io.KeyMap[ImGuiKey_A] = GLFW_KEY_A;
|
||||||
|
io.KeyMap[ImGuiKey_C] = GLFW_KEY_C;
|
||||||
|
io.KeyMap[ImGuiKey_V] = GLFW_KEY_V;
|
||||||
|
io.KeyMap[ImGuiKey_X] = GLFW_KEY_X;
|
||||||
|
io.KeyMap[ImGuiKey_Y] = GLFW_KEY_Y;
|
||||||
|
io.KeyMap[ImGuiKey_Z] = GLFW_KEY_Z;
|
||||||
|
|
||||||
|
io.SetClipboardTextFn = ImGui_ImplGlfw_SetClipboardText;
|
||||||
|
io.GetClipboardTextFn = ImGui_ImplGlfw_GetClipboardText;
|
||||||
|
io.ClipboardUserData = g_Window;
|
||||||
|
#if defined(_WIN32)
|
||||||
|
io.ImeWindowHandle = (void*)glfwGetWin32Window(g_Window);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Create mouse cursors
|
||||||
|
// (By design, on X11 cursors are user configurable and some cursors may be missing. When a cursor doesn't exist,
|
||||||
|
// GLFW will emit an error which will often be printed by the app, so we temporarily disable error reporting.
|
||||||
|
// Missing cursors will return NULL and our _UpdateMouseCursor() function will use the Arrow cursor instead.)
|
||||||
|
GLFWerrorfun prev_error_callback = glfwSetErrorCallback(NULL);
|
||||||
|
g_MouseCursors[ImGuiMouseCursor_Arrow] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR);
|
||||||
|
g_MouseCursors[ImGuiMouseCursor_TextInput] = glfwCreateStandardCursor(GLFW_IBEAM_CURSOR);
|
||||||
|
g_MouseCursors[ImGuiMouseCursor_ResizeNS] = glfwCreateStandardCursor(GLFW_VRESIZE_CURSOR);
|
||||||
|
g_MouseCursors[ImGuiMouseCursor_ResizeEW] = glfwCreateStandardCursor(GLFW_HRESIZE_CURSOR);
|
||||||
|
g_MouseCursors[ImGuiMouseCursor_Hand] = glfwCreateStandardCursor(GLFW_HAND_CURSOR);
|
||||||
|
#if GLFW_HAS_NEW_CURSORS
|
||||||
|
g_MouseCursors[ImGuiMouseCursor_ResizeAll] = glfwCreateStandardCursor(GLFW_RESIZE_ALL_CURSOR);
|
||||||
|
g_MouseCursors[ImGuiMouseCursor_ResizeNESW] = glfwCreateStandardCursor(GLFW_RESIZE_NESW_CURSOR);
|
||||||
|
g_MouseCursors[ImGuiMouseCursor_ResizeNWSE] = glfwCreateStandardCursor(GLFW_RESIZE_NWSE_CURSOR);
|
||||||
|
g_MouseCursors[ImGuiMouseCursor_NotAllowed] = glfwCreateStandardCursor(GLFW_NOT_ALLOWED_CURSOR);
|
||||||
|
#else
|
||||||
|
g_MouseCursors[ImGuiMouseCursor_ResizeAll] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR);
|
||||||
|
g_MouseCursors[ImGuiMouseCursor_ResizeNESW] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR);
|
||||||
|
g_MouseCursors[ImGuiMouseCursor_ResizeNWSE] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR);
|
||||||
|
g_MouseCursors[ImGuiMouseCursor_NotAllowed] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR);
|
||||||
|
#endif
|
||||||
|
glfwSetErrorCallback(prev_error_callback);
|
||||||
|
|
||||||
|
// Chain GLFW callbacks: our callbacks will call the user's previously installed callbacks, if any.
|
||||||
|
g_PrevUserCallbackMousebutton = NULL;
|
||||||
|
g_PrevUserCallbackScroll = NULL;
|
||||||
|
g_PrevUserCallbackKey = NULL;
|
||||||
|
g_PrevUserCallbackChar = NULL;
|
||||||
|
if (install_callbacks)
|
||||||
|
{
|
||||||
|
g_InstalledCallbacks = true;
|
||||||
|
g_PrevUserCallbackMousebutton = glfwSetMouseButtonCallback(window, ImGui_ImplGlfw_MouseButtonCallback);
|
||||||
|
g_PrevUserCallbackScroll = glfwSetScrollCallback(window, ImGui_ImplGlfw_ScrollCallback);
|
||||||
|
g_PrevUserCallbackKey = glfwSetKeyCallback(window, ImGui_ImplGlfw_KeyCallback);
|
||||||
|
g_PrevUserCallbackChar = glfwSetCharCallback(window, ImGui_ImplGlfw_CharCallback);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_ClientApi = client_api;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ImGui_ImplGlfw_InitForOpenGL(GLFWwindow* window, bool install_callbacks)
|
||||||
|
{
|
||||||
|
return ImGui_ImplGlfw_Init(window, install_callbacks, GlfwClientApi_OpenGL);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ImGui_ImplGlfw_InitForVulkan(GLFWwindow* window, bool install_callbacks)
|
||||||
|
{
|
||||||
|
return ImGui_ImplGlfw_Init(window, install_callbacks, GlfwClientApi_Vulkan);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ImGui_ImplGlfw_InitForOther(GLFWwindow* window, bool install_callbacks)
|
||||||
|
{
|
||||||
|
return ImGui_ImplGlfw_Init(window, install_callbacks, GlfwClientApi_Unknown);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGui_ImplGlfw_Shutdown()
|
||||||
|
{
|
||||||
|
if (g_InstalledCallbacks)
|
||||||
|
{
|
||||||
|
glfwSetMouseButtonCallback(g_Window, g_PrevUserCallbackMousebutton);
|
||||||
|
glfwSetScrollCallback(g_Window, g_PrevUserCallbackScroll);
|
||||||
|
glfwSetKeyCallback(g_Window, g_PrevUserCallbackKey);
|
||||||
|
glfwSetCharCallback(g_Window, g_PrevUserCallbackChar);
|
||||||
|
g_InstalledCallbacks = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (ImGuiMouseCursor cursor_n = 0; cursor_n < ImGuiMouseCursor_COUNT; cursor_n++)
|
||||||
|
{
|
||||||
|
glfwDestroyCursor(g_MouseCursors[cursor_n]);
|
||||||
|
g_MouseCursors[cursor_n] = NULL;
|
||||||
|
}
|
||||||
|
g_ClientApi = GlfwClientApi_Unknown;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ImGui_ImplGlfw_UpdateMousePosAndButtons()
|
||||||
|
{
|
||||||
|
// Update buttons
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
for (int i = 0; i < IM_ARRAYSIZE(io.MouseDown); i++)
|
||||||
|
{
|
||||||
|
// If a mouse press event came, always pass it as "mouse held this frame", so we don't miss click-release events that are shorter than 1 frame.
|
||||||
|
io.MouseDown[i] = g_MouseJustPressed[i] || glfwGetMouseButton(g_Window, i) != 0;
|
||||||
|
g_MouseJustPressed[i] = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update mouse position
|
||||||
|
const ImVec2 mouse_pos_backup = io.MousePos;
|
||||||
|
io.MousePos = ImVec2(-FLT_MAX, -FLT_MAX);
|
||||||
|
#ifdef __EMSCRIPTEN__
|
||||||
|
const bool focused = true; // Emscripten
|
||||||
|
#else
|
||||||
|
const bool focused = glfwGetWindowAttrib(g_Window, GLFW_FOCUSED) != 0;
|
||||||
|
#endif
|
||||||
|
if (focused)
|
||||||
|
{
|
||||||
|
if (io.WantSetMousePos)
|
||||||
|
{
|
||||||
|
glfwSetCursorPos(g_Window, (double)mouse_pos_backup.x, (double)mouse_pos_backup.y);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
double mouse_x, mouse_y;
|
||||||
|
glfwGetCursorPos(g_Window, &mouse_x, &mouse_y);
|
||||||
|
io.MousePos = ImVec2((float)mouse_x, (float)mouse_y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ImGui_ImplGlfw_UpdateMouseCursor()
|
||||||
|
{
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
if ((io.ConfigFlags & ImGuiConfigFlags_NoMouseCursorChange) || glfwGetInputMode(g_Window, GLFW_CURSOR) == GLFW_CURSOR_DISABLED)
|
||||||
|
return;
|
||||||
|
|
||||||
|
ImGuiMouseCursor imgui_cursor = ImGui::GetMouseCursor();
|
||||||
|
if (imgui_cursor == ImGuiMouseCursor_None || io.MouseDrawCursor)
|
||||||
|
{
|
||||||
|
// Hide OS mouse cursor if imgui is drawing it or if it wants no cursor
|
||||||
|
glfwSetInputMode(g_Window, GLFW_CURSOR, GLFW_CURSOR_HIDDEN);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Show OS mouse cursor
|
||||||
|
// FIXME-PLATFORM: Unfocused windows seems to fail changing the mouse cursor with GLFW 3.2, but 3.3 works here.
|
||||||
|
glfwSetCursor(g_Window, g_MouseCursors[imgui_cursor] ? g_MouseCursors[imgui_cursor] : g_MouseCursors[ImGuiMouseCursor_Arrow]);
|
||||||
|
glfwSetInputMode(g_Window, GLFW_CURSOR, GLFW_CURSOR_NORMAL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ImGui_ImplGlfw_UpdateGamepads()
|
||||||
|
{
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
memset(io.NavInputs, 0, sizeof(io.NavInputs));
|
||||||
|
if ((io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Update gamepad inputs
|
||||||
|
#define MAP_BUTTON(NAV_NO, BUTTON_NO) { if (buttons_count > BUTTON_NO && buttons[BUTTON_NO] == GLFW_PRESS) io.NavInputs[NAV_NO] = 1.0f; }
|
||||||
|
#define MAP_ANALOG(NAV_NO, AXIS_NO, V0, V1) { float v = (axes_count > AXIS_NO) ? axes[AXIS_NO] : V0; v = (v - V0) / (V1 - V0); if (v > 1.0f) v = 1.0f; if (io.NavInputs[NAV_NO] < v) io.NavInputs[NAV_NO] = v; }
|
||||||
|
int axes_count = 0, buttons_count = 0;
|
||||||
|
const float* axes = glfwGetJoystickAxes(GLFW_JOYSTICK_1, &axes_count);
|
||||||
|
const unsigned char* buttons = glfwGetJoystickButtons(GLFW_JOYSTICK_1, &buttons_count);
|
||||||
|
MAP_BUTTON(ImGuiNavInput_Activate, 0); // Cross / A
|
||||||
|
MAP_BUTTON(ImGuiNavInput_Cancel, 1); // Circle / B
|
||||||
|
MAP_BUTTON(ImGuiNavInput_Menu, 2); // Square / X
|
||||||
|
MAP_BUTTON(ImGuiNavInput_Input, 3); // Triangle / Y
|
||||||
|
MAP_BUTTON(ImGuiNavInput_DpadLeft, 13); // D-Pad Left
|
||||||
|
MAP_BUTTON(ImGuiNavInput_DpadRight, 11); // D-Pad Right
|
||||||
|
MAP_BUTTON(ImGuiNavInput_DpadUp, 10); // D-Pad Up
|
||||||
|
MAP_BUTTON(ImGuiNavInput_DpadDown, 12); // D-Pad Down
|
||||||
|
MAP_BUTTON(ImGuiNavInput_FocusPrev, 4); // L1 / LB
|
||||||
|
MAP_BUTTON(ImGuiNavInput_FocusNext, 5); // R1 / RB
|
||||||
|
MAP_BUTTON(ImGuiNavInput_TweakSlow, 4); // L1 / LB
|
||||||
|
MAP_BUTTON(ImGuiNavInput_TweakFast, 5); // R1 / RB
|
||||||
|
MAP_ANALOG(ImGuiNavInput_LStickLeft, 0, -0.3f, -0.9f);
|
||||||
|
MAP_ANALOG(ImGuiNavInput_LStickRight,0, +0.3f, +0.9f);
|
||||||
|
MAP_ANALOG(ImGuiNavInput_LStickUp, 1, +0.3f, +0.9f);
|
||||||
|
MAP_ANALOG(ImGuiNavInput_LStickDown, 1, -0.3f, -0.9f);
|
||||||
|
#undef MAP_BUTTON
|
||||||
|
#undef MAP_ANALOG
|
||||||
|
if (axes_count > 0 && buttons_count > 0)
|
||||||
|
io.BackendFlags |= ImGuiBackendFlags_HasGamepad;
|
||||||
|
else
|
||||||
|
io.BackendFlags &= ~ImGuiBackendFlags_HasGamepad;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGui_ImplGlfw_NewFrame()
|
||||||
|
{
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
IM_ASSERT(io.Fonts->IsBuilt() && "Font atlas not built! It is generally built by the renderer backend. Missing call to renderer _NewFrame() function? e.g. ImGui_ImplOpenGL3_NewFrame().");
|
||||||
|
|
||||||
|
// Setup display size (every frame to accommodate for window resizing)
|
||||||
|
int w, h;
|
||||||
|
int display_w, display_h;
|
||||||
|
glfwGetWindowSize(g_Window, &w, &h);
|
||||||
|
glfwGetFramebufferSize(g_Window, &display_w, &display_h);
|
||||||
|
io.DisplaySize = ImVec2((float)w, (float)h);
|
||||||
|
if (w > 0 && h > 0)
|
||||||
|
io.DisplayFramebufferScale = ImVec2((float)display_w / w, (float)display_h / h);
|
||||||
|
|
||||||
|
// Setup time step
|
||||||
|
double current_time = glfwGetTime();
|
||||||
|
io.DeltaTime = g_Time > 0.0 ? (float)(current_time - g_Time) : (float)(1.0f / 60.0f);
|
||||||
|
g_Time = current_time;
|
||||||
|
|
||||||
|
ImGui_ImplGlfw_UpdateMousePosAndButtons();
|
||||||
|
ImGui_ImplGlfw_UpdateMouseCursor();
|
||||||
|
|
||||||
|
// Update game controllers (if enabled and available)
|
||||||
|
ImGui_ImplGlfw_UpdateGamepads();
|
||||||
|
}
|
36
backend/imgui_impl_glfw.h
Normal file
36
backend/imgui_impl_glfw.h
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
// dear imgui: Platform Backend for GLFW
|
||||||
|
// This needs to be used along with a Renderer (e.g. OpenGL3, Vulkan, WebGPU..)
|
||||||
|
// (Info: GLFW is a cross-platform general purpose library for handling windows, inputs, OpenGL/Vulkan graphics context creation, etc.)
|
||||||
|
|
||||||
|
// Implemented features:
|
||||||
|
// [X] Platform: Clipboard support.
|
||||||
|
// [X] Platform: Gamepad support. Enable with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'.
|
||||||
|
// [x] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. FIXME: 3 cursors types are missing from GLFW.
|
||||||
|
// [X] Platform: Keyboard arrays indexed using GLFW_KEY_* codes, e.g. ImGui::IsKeyPressed(GLFW_KEY_SPACE).
|
||||||
|
|
||||||
|
// You can copy and use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
||||||
|
// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
|
||||||
|
// Read online: https://github.com/ocornut/imgui/tree/master/docs
|
||||||
|
|
||||||
|
// About GLSL version:
|
||||||
|
// The 'glsl_version' initialization parameter defaults to "#version 150" if NULL.
|
||||||
|
// Only override if your GL version doesn't handle this GLSL version. Keep NULL if unsure!
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include "imgui.h" // IMGUI_IMPL_API
|
||||||
|
|
||||||
|
struct GLFWwindow;
|
||||||
|
|
||||||
|
IMGUI_IMPL_API bool ImGui_ImplGlfw_InitForOpenGL(GLFWwindow* window, bool install_callbacks);
|
||||||
|
IMGUI_IMPL_API bool ImGui_ImplGlfw_InitForVulkan(GLFWwindow* window, bool install_callbacks);
|
||||||
|
IMGUI_IMPL_API bool ImGui_ImplGlfw_InitForOther(GLFWwindow* window, bool install_callbacks);
|
||||||
|
IMGUI_IMPL_API void ImGui_ImplGlfw_Shutdown();
|
||||||
|
IMGUI_IMPL_API void ImGui_ImplGlfw_NewFrame();
|
||||||
|
|
||||||
|
// GLFW callbacks
|
||||||
|
// - When calling Init with 'install_callbacks=true': GLFW callbacks will be installed for you. They will call user's previously installed callbacks, if any.
|
||||||
|
// - When calling Init with 'install_callbacks=false': GLFW callbacks won't be installed. You will need to call those function yourself from your own GLFW callbacks.
|
||||||
|
IMGUI_IMPL_API void ImGui_ImplGlfw_MouseButtonCallback(GLFWwindow* window, int button, int action, int mods);
|
||||||
|
IMGUI_IMPL_API void ImGui_ImplGlfw_ScrollCallback(GLFWwindow* window, double xoffset, double yoffset);
|
||||||
|
IMGUI_IMPL_API void ImGui_ImplGlfw_KeyCallback(GLFWwindow* window, int key, int scancode, int action, int mods);
|
||||||
|
IMGUI_IMPL_API void ImGui_ImplGlfw_CharCallback(GLFWwindow* window, unsigned int c);
|
216
backend/imgui_impl_glut.cpp
Normal file
216
backend/imgui_impl_glut.cpp
Normal file
@ -0,0 +1,216 @@
|
|||||||
|
// dear imgui: Platform Backend for GLUT/FreeGLUT
|
||||||
|
// This needs to be used along with a Renderer (e.g. OpenGL2)
|
||||||
|
|
||||||
|
// !!! GLUT/FreeGLUT IS OBSOLETE PREHISTORIC SOFTWARE. Using GLUT is not recommended unless you really miss the 90's. !!!
|
||||||
|
// !!! If someone or something is teaching you GLUT today, you are being abused. Please show some resistance. !!!
|
||||||
|
// !!! Nowadays, prefer using GLFW or SDL instead!
|
||||||
|
|
||||||
|
// Issues:
|
||||||
|
// [ ] Platform: GLUT is unable to distinguish e.g. Backspace from CTRL+H or TAB from CTRL+I
|
||||||
|
// [ ] Platform: Missing mouse cursor shape/visibility support.
|
||||||
|
// [ ] Platform: Missing clipboard support (not supported by Glut).
|
||||||
|
// [ ] Platform: Missing gamepad support.
|
||||||
|
|
||||||
|
// You can copy and use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
||||||
|
// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
|
||||||
|
// Read online: https://github.com/ocornut/imgui/tree/master/docs
|
||||||
|
|
||||||
|
// CHANGELOG
|
||||||
|
// (minor and older changes stripped away, please see git history for details)
|
||||||
|
// 2019-04-03: Misc: Renamed imgui_impl_freeglut.cpp/.h to imgui_impl_glut.cpp/.h.
|
||||||
|
// 2019-03-25: Misc: Made io.DeltaTime always above zero.
|
||||||
|
// 2018-11-30: Misc: Setting up io.BackendPlatformName so it can be displayed in the About Window.
|
||||||
|
// 2018-03-22: Added GLUT Platform binding.
|
||||||
|
|
||||||
|
#include "imgui.h"
|
||||||
|
#include "imgui_impl_glut.h"
|
||||||
|
#ifdef __APPLE__
|
||||||
|
#include <GLUT/glut.h>
|
||||||
|
#else
|
||||||
|
#include <GL/freeglut.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#pragma warning (disable: 4505) // unreferenced local function has been removed (stb stuff)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static int g_Time = 0; // Current time, in milliseconds
|
||||||
|
|
||||||
|
bool ImGui_ImplGLUT_Init()
|
||||||
|
{
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
|
||||||
|
#ifdef FREEGLUT
|
||||||
|
io.BackendPlatformName = "imgui_impl_glut (freeglut)";
|
||||||
|
#else
|
||||||
|
io.BackendPlatformName = "imgui_impl_glut";
|
||||||
|
#endif
|
||||||
|
|
||||||
|
g_Time = 0;
|
||||||
|
|
||||||
|
// Glut has 1 function for characters and one for "special keys". We map the characters in the 0..255 range and the keys above.
|
||||||
|
io.KeyMap[ImGuiKey_Tab] = '\t'; // == 9 == CTRL+I
|
||||||
|
io.KeyMap[ImGuiKey_LeftArrow] = 256 + GLUT_KEY_LEFT;
|
||||||
|
io.KeyMap[ImGuiKey_RightArrow] = 256 + GLUT_KEY_RIGHT;
|
||||||
|
io.KeyMap[ImGuiKey_UpArrow] = 256 + GLUT_KEY_UP;
|
||||||
|
io.KeyMap[ImGuiKey_DownArrow] = 256 + GLUT_KEY_DOWN;
|
||||||
|
io.KeyMap[ImGuiKey_PageUp] = 256 + GLUT_KEY_PAGE_UP;
|
||||||
|
io.KeyMap[ImGuiKey_PageDown] = 256 + GLUT_KEY_PAGE_DOWN;
|
||||||
|
io.KeyMap[ImGuiKey_Home] = 256 + GLUT_KEY_HOME;
|
||||||
|
io.KeyMap[ImGuiKey_End] = 256 + GLUT_KEY_END;
|
||||||
|
io.KeyMap[ImGuiKey_Insert] = 256 + GLUT_KEY_INSERT;
|
||||||
|
io.KeyMap[ImGuiKey_Delete] = 127;
|
||||||
|
io.KeyMap[ImGuiKey_Backspace] = 8; // == CTRL+H
|
||||||
|
io.KeyMap[ImGuiKey_Space] = ' ';
|
||||||
|
io.KeyMap[ImGuiKey_Enter] = 13; // == CTRL+M
|
||||||
|
io.KeyMap[ImGuiKey_Escape] = 27;
|
||||||
|
io.KeyMap[ImGuiKey_KeyPadEnter] = 13; // == CTRL+M
|
||||||
|
io.KeyMap[ImGuiKey_A] = 'A';
|
||||||
|
io.KeyMap[ImGuiKey_C] = 'C';
|
||||||
|
io.KeyMap[ImGuiKey_V] = 'V';
|
||||||
|
io.KeyMap[ImGuiKey_X] = 'X';
|
||||||
|
io.KeyMap[ImGuiKey_Y] = 'Y';
|
||||||
|
io.KeyMap[ImGuiKey_Z] = 'Z';
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGui_ImplGLUT_InstallFuncs()
|
||||||
|
{
|
||||||
|
glutReshapeFunc(ImGui_ImplGLUT_ReshapeFunc);
|
||||||
|
glutMotionFunc(ImGui_ImplGLUT_MotionFunc);
|
||||||
|
glutPassiveMotionFunc(ImGui_ImplGLUT_MotionFunc);
|
||||||
|
glutMouseFunc(ImGui_ImplGLUT_MouseFunc);
|
||||||
|
#ifdef __FREEGLUT_EXT_H__
|
||||||
|
glutMouseWheelFunc(ImGui_ImplGLUT_MouseWheelFunc);
|
||||||
|
#endif
|
||||||
|
glutKeyboardFunc(ImGui_ImplGLUT_KeyboardFunc);
|
||||||
|
glutKeyboardUpFunc(ImGui_ImplGLUT_KeyboardUpFunc);
|
||||||
|
glutSpecialFunc(ImGui_ImplGLUT_SpecialFunc);
|
||||||
|
glutSpecialUpFunc(ImGui_ImplGLUT_SpecialUpFunc);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGui_ImplGLUT_Shutdown()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGui_ImplGLUT_NewFrame()
|
||||||
|
{
|
||||||
|
// Setup time step
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
int current_time = glutGet(GLUT_ELAPSED_TIME);
|
||||||
|
int delta_time_ms = (current_time - g_Time);
|
||||||
|
if (delta_time_ms <= 0)
|
||||||
|
delta_time_ms = 1;
|
||||||
|
io.DeltaTime = delta_time_ms / 1000.0f;
|
||||||
|
g_Time = current_time;
|
||||||
|
|
||||||
|
// Start the frame
|
||||||
|
ImGui::NewFrame();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ImGui_ImplGLUT_UpdateKeyboardMods()
|
||||||
|
{
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
int mods = glutGetModifiers();
|
||||||
|
io.KeyCtrl = (mods & GLUT_ACTIVE_CTRL) != 0;
|
||||||
|
io.KeyShift = (mods & GLUT_ACTIVE_SHIFT) != 0;
|
||||||
|
io.KeyAlt = (mods & GLUT_ACTIVE_ALT) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGui_ImplGLUT_KeyboardFunc(unsigned char c, int x, int y)
|
||||||
|
{
|
||||||
|
// Send character to imgui
|
||||||
|
//printf("char_down_func %d '%c'\n", c, c);
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
if (c >= 32)
|
||||||
|
io.AddInputCharacter((unsigned int)c);
|
||||||
|
|
||||||
|
// Store letters in KeysDown[] array as both uppercase and lowercase + Handle GLUT translating CTRL+A..CTRL+Z as 1..26.
|
||||||
|
// This is a hacky mess but GLUT is unable to distinguish e.g. a TAB key from CTRL+I so this is probably the best we can do here.
|
||||||
|
if (c >= 1 && c <= 26)
|
||||||
|
io.KeysDown[c] = io.KeysDown[c - 1 + 'a'] = io.KeysDown[c - 1 + 'A'] = true;
|
||||||
|
else if (c >= 'a' && c <= 'z')
|
||||||
|
io.KeysDown[c] = io.KeysDown[c - 'a' + 'A'] = true;
|
||||||
|
else if (c >= 'A' && c <= 'Z')
|
||||||
|
io.KeysDown[c] = io.KeysDown[c - 'A' + 'a'] = true;
|
||||||
|
else
|
||||||
|
io.KeysDown[c] = true;
|
||||||
|
ImGui_ImplGLUT_UpdateKeyboardMods();
|
||||||
|
(void)x; (void)y; // Unused
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGui_ImplGLUT_KeyboardUpFunc(unsigned char c, int x, int y)
|
||||||
|
{
|
||||||
|
//printf("char_up_func %d '%c'\n", c, c);
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
if (c >= 1 && c <= 26)
|
||||||
|
io.KeysDown[c] = io.KeysDown[c - 1 + 'a'] = io.KeysDown[c - 1 + 'A'] = false;
|
||||||
|
else if (c >= 'a' && c <= 'z')
|
||||||
|
io.KeysDown[c] = io.KeysDown[c - 'a' + 'A'] = false;
|
||||||
|
else if (c >= 'A' && c <= 'Z')
|
||||||
|
io.KeysDown[c] = io.KeysDown[c - 'A' + 'a'] = false;
|
||||||
|
else
|
||||||
|
io.KeysDown[c] = false;
|
||||||
|
ImGui_ImplGLUT_UpdateKeyboardMods();
|
||||||
|
(void)x; (void)y; // Unused
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGui_ImplGLUT_SpecialFunc(int key, int x, int y)
|
||||||
|
{
|
||||||
|
//printf("key_down_func %d\n", key);
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
if (key + 256 < IM_ARRAYSIZE(io.KeysDown))
|
||||||
|
io.KeysDown[key + 256] = true;
|
||||||
|
ImGui_ImplGLUT_UpdateKeyboardMods();
|
||||||
|
(void)x; (void)y; // Unused
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGui_ImplGLUT_SpecialUpFunc(int key, int x, int y)
|
||||||
|
{
|
||||||
|
//printf("key_up_func %d\n", key);
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
if (key + 256 < IM_ARRAYSIZE(io.KeysDown))
|
||||||
|
io.KeysDown[key + 256] = false;
|
||||||
|
ImGui_ImplGLUT_UpdateKeyboardMods();
|
||||||
|
(void)x; (void)y; // Unused
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGui_ImplGLUT_MouseFunc(int glut_button, int state, int x, int y)
|
||||||
|
{
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
io.MousePos = ImVec2((float)x, (float)y);
|
||||||
|
int button = -1;
|
||||||
|
if (glut_button == GLUT_LEFT_BUTTON) button = 0;
|
||||||
|
if (glut_button == GLUT_RIGHT_BUTTON) button = 1;
|
||||||
|
if (glut_button == GLUT_MIDDLE_BUTTON) button = 2;
|
||||||
|
if (button != -1 && state == GLUT_DOWN)
|
||||||
|
io.MouseDown[button] = true;
|
||||||
|
if (button != -1 && state == GLUT_UP)
|
||||||
|
io.MouseDown[button] = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef __FREEGLUT_EXT_H__
|
||||||
|
void ImGui_ImplGLUT_MouseWheelFunc(int button, int dir, int x, int y)
|
||||||
|
{
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
io.MousePos = ImVec2((float)x, (float)y);
|
||||||
|
if (dir > 0)
|
||||||
|
io.MouseWheel += 1.0;
|
||||||
|
else if (dir < 0)
|
||||||
|
io.MouseWheel -= 1.0;
|
||||||
|
(void)button; // Unused
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void ImGui_ImplGLUT_ReshapeFunc(int w, int h)
|
||||||
|
{
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
io.DisplaySize = ImVec2((float)w, (float)h);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGui_ImplGLUT_MotionFunc(int x, int y)
|
||||||
|
{
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
io.MousePos = ImVec2((float)x, (float)y);
|
||||||
|
}
|
36
backend/imgui_impl_glut.h
Normal file
36
backend/imgui_impl_glut.h
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
// dear imgui: Platform Backend for GLUT/FreeGLUT
|
||||||
|
// This needs to be used along with a Renderer (e.g. OpenGL2)
|
||||||
|
|
||||||
|
// !!! GLUT/FreeGLUT IS OBSOLETE PREHISTORIC SOFTWARE. Using GLUT is not recommended unless you really miss the 90's. !!!
|
||||||
|
// !!! If someone or something is teaching you GLUT today, you are being abused. Please show some resistance. !!!
|
||||||
|
// !!! Nowadays, prefer using GLFW or SDL instead!
|
||||||
|
|
||||||
|
// Issues:
|
||||||
|
// [ ] Platform: GLUT is unable to distinguish e.g. Backspace from CTRL+H or TAB from CTRL+I
|
||||||
|
// [ ] Platform: Missing mouse cursor shape/visibility support.
|
||||||
|
// [ ] Platform: Missing clipboard support (not supported by Glut).
|
||||||
|
// [ ] Platform: Missing gamepad support.
|
||||||
|
|
||||||
|
// You can copy and use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
||||||
|
// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
|
||||||
|
// Read online: https://github.com/ocornut/imgui/tree/master/docs
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include "imgui.h" // IMGUI_IMPL_API
|
||||||
|
|
||||||
|
IMGUI_IMPL_API bool ImGui_ImplGLUT_Init();
|
||||||
|
IMGUI_IMPL_API void ImGui_ImplGLUT_InstallFuncs();
|
||||||
|
IMGUI_IMPL_API void ImGui_ImplGLUT_Shutdown();
|
||||||
|
IMGUI_IMPL_API void ImGui_ImplGLUT_NewFrame();
|
||||||
|
|
||||||
|
// You can call ImGui_ImplGLUT_InstallFuncs() to get all those functions installed automatically,
|
||||||
|
// or call them yourself from your own GLUT handlers. We are using the same weird names as GLUT for consistency..
|
||||||
|
//---------------------------------------- GLUT name --------------------------------------------- Decent Name ---------
|
||||||
|
IMGUI_IMPL_API void ImGui_ImplGLUT_ReshapeFunc(int w, int h); // ~ ResizeFunc
|
||||||
|
IMGUI_IMPL_API void ImGui_ImplGLUT_MotionFunc(int x, int y); // ~ MouseMoveFunc
|
||||||
|
IMGUI_IMPL_API void ImGui_ImplGLUT_MouseFunc(int button, int state, int x, int y); // ~ MouseButtonFunc
|
||||||
|
IMGUI_IMPL_API void ImGui_ImplGLUT_MouseWheelFunc(int button, int dir, int x, int y); // ~ MouseWheelFunc
|
||||||
|
IMGUI_IMPL_API void ImGui_ImplGLUT_KeyboardFunc(unsigned char c, int x, int y); // ~ CharPressedFunc
|
||||||
|
IMGUI_IMPL_API void ImGui_ImplGLUT_KeyboardUpFunc(unsigned char c, int x, int y); // ~ CharReleasedFunc
|
||||||
|
IMGUI_IMPL_API void ImGui_ImplGLUT_SpecialFunc(int key, int x, int y); // ~ KeyPressedFunc
|
||||||
|
IMGUI_IMPL_API void ImGui_ImplGLUT_SpecialUpFunc(int key, int x, int y); // ~ KeyReleasedFunc
|
316
backend/imgui_impl_marmalade.cpp
Normal file
316
backend/imgui_impl_marmalade.cpp
Normal file
@ -0,0 +1,316 @@
|
|||||||
|
// dear imgui: Renderer + Platform Backend for Marmalade + IwGx
|
||||||
|
// Marmalade code: Copyright (C) 2015 by Giovanni Zito (this file is part of Dear ImGui)
|
||||||
|
|
||||||
|
// Implemented features:
|
||||||
|
// [X] Renderer: User texture binding. Use 'CIwTexture*' as ImTextureID. Read the FAQ about ImTextureID!
|
||||||
|
// Missing features:
|
||||||
|
// [ ] Renderer: Clipping rectangles are not honored.
|
||||||
|
|
||||||
|
// You can copy and use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
||||||
|
// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
|
||||||
|
// Read online: https://github.com/ocornut/imgui/tree/master/docs
|
||||||
|
|
||||||
|
// CHANGELOG
|
||||||
|
// (minor and older changes stripped away, please see git history for details)
|
||||||
|
// 2019-07-21: Inputs: Added mapping for ImGuiKey_KeyPadEnter.
|
||||||
|
// 2019-05-11: Inputs: Don't filter value from character callback before calling AddInputCharacter().
|
||||||
|
// 2018-11-30: Misc: Setting up io.BackendPlatformName/io.BackendRendererName so they can be displayed in the About Window.
|
||||||
|
// 2018-02-16: Misc: Obsoleted the io.RenderDrawListsFn callback and exposed ImGui_Marmalade_RenderDrawData() in the .h file so you can call it yourself.
|
||||||
|
// 2018-02-06: Misc: Removed call to ImGui::Shutdown() which is not available from 1.60 WIP, user needs to call CreateContext/DestroyContext themselves.
|
||||||
|
// 2018-02-06: Inputs: Added mapping for ImGuiKey_Space.
|
||||||
|
|
||||||
|
#include "imgui.h"
|
||||||
|
#include "imgui_impl_marmalade.h"
|
||||||
|
|
||||||
|
#include <s3eClipboard.h>
|
||||||
|
#include <s3ePointer.h>
|
||||||
|
#include <s3eKeyboard.h>
|
||||||
|
#include <IwTexture.h>
|
||||||
|
#include <IwGx.h>
|
||||||
|
|
||||||
|
// Data
|
||||||
|
static double g_Time = 0.0f;
|
||||||
|
static bool g_MousePressed[3] = { false, false, false };
|
||||||
|
static CIwTexture* g_FontTexture = NULL;
|
||||||
|
static char* g_ClipboardText = NULL;
|
||||||
|
static bool g_osdKeyboardEnabled = false;
|
||||||
|
|
||||||
|
// use this setting to scale the interface - e.g. on device you could use 2 or 3 scale factor
|
||||||
|
static ImVec2 g_RenderScale = ImVec2(1.0f, 1.0f);
|
||||||
|
|
||||||
|
// Render function.
|
||||||
|
void ImGui_Marmalade_RenderDrawData(ImDrawData* draw_data)
|
||||||
|
{
|
||||||
|
// Avoid rendering when minimized
|
||||||
|
if (draw_data->DisplaySize.x <= 0.0f || draw_data->DisplaySize.y <= 0.0f)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Render command lists
|
||||||
|
for (int n = 0; n < draw_data->CmdListsCount; n++)
|
||||||
|
{
|
||||||
|
const ImDrawList* cmd_list = draw_data->CmdLists[n];
|
||||||
|
const ImDrawIdx* idx_buffer = cmd_list->IdxBuffer.Data;
|
||||||
|
const int nVert = cmd_list->VtxBuffer.Size;
|
||||||
|
CIwFVec2* pVertStream = IW_GX_ALLOC(CIwFVec2, nVert);
|
||||||
|
CIwFVec2* pUVStream = IW_GX_ALLOC(CIwFVec2, nVert);
|
||||||
|
CIwColour* pColStream = IW_GX_ALLOC(CIwColour, nVert);
|
||||||
|
|
||||||
|
for (int i = 0; i < nVert; i++)
|
||||||
|
{
|
||||||
|
// FIXME-OPT: optimize multiplication on GPU using vertex shader/projection matrix.
|
||||||
|
pVertStream[i].x = cmd_list->VtxBuffer[i].pos.x * g_RenderScale.x;
|
||||||
|
pVertStream[i].y = cmd_list->VtxBuffer[i].pos.y * g_RenderScale.y;
|
||||||
|
pUVStream[i].x = cmd_list->VtxBuffer[i].uv.x;
|
||||||
|
pUVStream[i].y = cmd_list->VtxBuffer[i].uv.y;
|
||||||
|
pColStream[i] = cmd_list->VtxBuffer[i].col;
|
||||||
|
}
|
||||||
|
|
||||||
|
IwGxSetVertStreamScreenSpace(pVertStream, nVert);
|
||||||
|
IwGxSetUVStream(pUVStream);
|
||||||
|
IwGxSetColStream(pColStream, nVert);
|
||||||
|
IwGxSetNormStream(0);
|
||||||
|
|
||||||
|
for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++)
|
||||||
|
{
|
||||||
|
const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i];
|
||||||
|
if (pcmd->UserCallback)
|
||||||
|
{
|
||||||
|
pcmd->UserCallback(cmd_list, pcmd);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// FIXME: Not honoring ClipRect fields.
|
||||||
|
CIwMaterial* pCurrentMaterial = IW_GX_ALLOC_MATERIAL();
|
||||||
|
pCurrentMaterial->SetShadeMode(CIwMaterial::SHADE_FLAT);
|
||||||
|
pCurrentMaterial->SetCullMode(CIwMaterial::CULL_NONE);
|
||||||
|
pCurrentMaterial->SetFiltering(false);
|
||||||
|
pCurrentMaterial->SetAlphaMode(CIwMaterial::ALPHA_BLEND);
|
||||||
|
pCurrentMaterial->SetDepthWriteMode(CIwMaterial::DEPTH_WRITE_NORMAL);
|
||||||
|
pCurrentMaterial->SetAlphaTestMode(CIwMaterial::ALPHATEST_DISABLED);
|
||||||
|
pCurrentMaterial->SetTexture((CIwTexture*)pcmd->TextureId);
|
||||||
|
IwGxSetMaterial(pCurrentMaterial);
|
||||||
|
IwGxDrawPrims(IW_GX_TRI_LIST, (uint16*)idx_buffer, pcmd->ElemCount);
|
||||||
|
}
|
||||||
|
idx_buffer += pcmd->ElemCount;
|
||||||
|
}
|
||||||
|
IwGxFlush();
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: restore modified state (i.e. mvp matrix)
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char* ImGui_Marmalade_GetClipboardText(void* /*user_data*/)
|
||||||
|
{
|
||||||
|
if (!s3eClipboardAvailable())
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (int size = s3eClipboardGetText(NULL, 0))
|
||||||
|
{
|
||||||
|
if (g_ClipboardText)
|
||||||
|
delete[] g_ClipboardText;
|
||||||
|
g_ClipboardText = new char[size];
|
||||||
|
g_ClipboardText[0] = '\0';
|
||||||
|
s3eClipboardGetText(g_ClipboardText, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
return g_ClipboardText;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ImGui_Marmalade_SetClipboardText(void* /*user_data*/, const char* text)
|
||||||
|
{
|
||||||
|
if (s3eClipboardAvailable())
|
||||||
|
s3eClipboardSetText(text);
|
||||||
|
}
|
||||||
|
|
||||||
|
int32 ImGui_Marmalade_PointerButtonEventCallback(void* system_data, void* user_data)
|
||||||
|
{
|
||||||
|
// pEvent->m_Button is of type s3ePointerButton and indicates which mouse
|
||||||
|
// button was pressed. For touchscreen this should always have the value
|
||||||
|
// S3E_POINTER_BUTTON_SELECT
|
||||||
|
s3ePointerEvent* pEvent = (s3ePointerEvent*)system_data;
|
||||||
|
|
||||||
|
if (pEvent->m_Pressed == 1)
|
||||||
|
{
|
||||||
|
if (pEvent->m_Button == S3E_POINTER_BUTTON_LEFTMOUSE)
|
||||||
|
g_MousePressed[0] = true;
|
||||||
|
if (pEvent->m_Button == S3E_POINTER_BUTTON_RIGHTMOUSE)
|
||||||
|
g_MousePressed[1] = true;
|
||||||
|
if (pEvent->m_Button == S3E_POINTER_BUTTON_MIDDLEMOUSE)
|
||||||
|
g_MousePressed[2] = true;
|
||||||
|
if (pEvent->m_Button == S3E_POINTER_BUTTON_MOUSEWHEELUP)
|
||||||
|
io.MouseWheel += pEvent->m_y;
|
||||||
|
if (pEvent->m_Button == S3E_POINTER_BUTTON_MOUSEWHEELDOWN)
|
||||||
|
io.MouseWheel += pEvent->m_y;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32 ImGui_Marmalade_KeyCallback(void* system_data, void* user_data)
|
||||||
|
{
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
s3eKeyboardEvent* e = (s3eKeyboardEvent*)system_data;
|
||||||
|
if (e->m_Pressed == 1)
|
||||||
|
io.KeysDown[e->m_Key] = true;
|
||||||
|
if (e->m_Pressed == 0)
|
||||||
|
io.KeysDown[e->m_Key] = false;
|
||||||
|
|
||||||
|
io.KeyCtrl = s3eKeyboardGetState(s3eKeyLeftControl) == S3E_KEY_STATE_DOWN || s3eKeyboardGetState(s3eKeyRightControl) == S3E_KEY_STATE_DOWN;
|
||||||
|
io.KeyShift = s3eKeyboardGetState(s3eKeyLeftShift) == S3E_KEY_STATE_DOWN || s3eKeyboardGetState(s3eKeyRightShift) == S3E_KEY_STATE_DOWN;
|
||||||
|
io.KeyAlt = s3eKeyboardGetState(s3eKeyLeftAlt) == S3E_KEY_STATE_DOWN || s3eKeyboardGetState(s3eKeyRightAlt) == S3E_KEY_STATE_DOWN;
|
||||||
|
io.KeySuper = s3eKeyboardGetState(s3eKeyLeftWindows) == S3E_KEY_STATE_DOWN || s3eKeyboardGetState(s3eKeyRightWindows) == S3E_KEY_STATE_DOWN;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32 ImGui_Marmalade_CharCallback(void* system_data, void* user_data)
|
||||||
|
{
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
s3eKeyboardCharEvent* e = (s3eKeyboardCharEvent*)system_data;
|
||||||
|
io.AddInputCharacter((unsigned int)e->m_Char);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ImGui_Marmalade_CreateDeviceObjects()
|
||||||
|
{
|
||||||
|
// Build texture atlas
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
unsigned char* pixels;
|
||||||
|
int width, height;
|
||||||
|
io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height);
|
||||||
|
|
||||||
|
// Upload texture to graphics system
|
||||||
|
g_FontTexture = new CIwTexture();
|
||||||
|
g_FontTexture->SetModifiable(true);
|
||||||
|
CIwImage& image = g_FontTexture->GetImage();
|
||||||
|
image.SetFormat(CIwImage::ARGB_8888);
|
||||||
|
image.SetWidth(width);
|
||||||
|
image.SetHeight(height);
|
||||||
|
image.SetBuffers(); // allocates and own buffers
|
||||||
|
image.ReadTexels(pixels);
|
||||||
|
g_FontTexture->SetMipMapping(false);
|
||||||
|
g_FontTexture->SetFiltering(false);
|
||||||
|
g_FontTexture->Upload();
|
||||||
|
|
||||||
|
// Store our identifier
|
||||||
|
io.Fonts->SetTexID((ImTextureID)g_FontTexture);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGui_Marmalade_InvalidateDeviceObjects()
|
||||||
|
{
|
||||||
|
if (g_ClipboardText)
|
||||||
|
{
|
||||||
|
delete[] g_ClipboardText;
|
||||||
|
g_ClipboardText = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (g_FontTexture)
|
||||||
|
{
|
||||||
|
ImGui::GetIO().Fonts->SetTexID(0);
|
||||||
|
delete g_FontTexture;
|
||||||
|
g_FontTexture = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ImGui_Marmalade_Init(bool install_callbacks)
|
||||||
|
{
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
io.BackendPlatformName = io.BackendRendererName = "imgui_impl_marmalade";
|
||||||
|
|
||||||
|
// Keyboard mapping. Dear ImGui will use those indices to peek into the io.KeysDown[] array.
|
||||||
|
io.KeyMap[ImGuiKey_Tab] = s3eKeyTab
|
||||||
|
io.KeyMap[ImGuiKey_LeftArrow] = s3eKeyLeft;
|
||||||
|
io.KeyMap[ImGuiKey_RightArrow] = s3eKeyRight;
|
||||||
|
io.KeyMap[ImGuiKey_UpArrow] = s3eKeyUp;
|
||||||
|
io.KeyMap[ImGuiKey_DownArrow] = s3eKeyDown;
|
||||||
|
io.KeyMap[ImGuiKey_PageUp] = s3eKeyPageUp;
|
||||||
|
io.KeyMap[ImGuiKey_PageDown] = s3eKeyPageDown;
|
||||||
|
io.KeyMap[ImGuiKey_Home] = s3eKeyHome;
|
||||||
|
io.KeyMap[ImGuiKey_End] = s3eKeyEnd;
|
||||||
|
io.KeyMap[ImGuiKey_Insert] = s3eKeyInsert;
|
||||||
|
io.KeyMap[ImGuiKey_Delete] = s3eKeyDelete;
|
||||||
|
io.KeyMap[ImGuiKey_Backspace] = s3eKeyBackspace;
|
||||||
|
io.KeyMap[ImGuiKey_Space] = s3eKeySpace;
|
||||||
|
io.KeyMap[ImGuiKey_Enter] = s3eKeyEnter;
|
||||||
|
io.KeyMap[ImGuiKey_Escape] = s3eKeyEsc;
|
||||||
|
io.KeyMap[ImGuiKey_KeyPadEnter] = s3eKeyNumPadEnter;
|
||||||
|
io.KeyMap[ImGuiKey_A] = s3eKeyA;
|
||||||
|
io.KeyMap[ImGuiKey_C] = s3eKeyC;
|
||||||
|
io.KeyMap[ImGuiKey_V] = s3eKeyV;
|
||||||
|
io.KeyMap[ImGuiKey_X] = s3eKeyX;
|
||||||
|
io.KeyMap[ImGuiKey_Y] = s3eKeyY;
|
||||||
|
io.KeyMap[ImGuiKey_Z] = s3eKeyZ;
|
||||||
|
|
||||||
|
io.SetClipboardTextFn = ImGui_Marmalade_SetClipboardText;
|
||||||
|
io.GetClipboardTextFn = ImGui_Marmalade_GetClipboardText;
|
||||||
|
|
||||||
|
if (install_callbacks)
|
||||||
|
{
|
||||||
|
s3ePointerRegister(S3E_POINTER_BUTTON_EVENT, ImGui_Marmalade_PointerButtonEventCallback, 0);
|
||||||
|
s3eKeyboardRegister(S3E_KEYBOARD_KEY_EVENT, ImGui_Marmalade_KeyCallback, 0);
|
||||||
|
s3eKeyboardRegister(S3E_KEYBOARD_CHAR_EVENT, ImGui_Marmalade_CharCallback, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGui_Marmalade_Shutdown()
|
||||||
|
{
|
||||||
|
ImGui_Marmalade_InvalidateDeviceObjects();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGui_Marmalade_NewFrame()
|
||||||
|
{
|
||||||
|
if (!g_FontTexture)
|
||||||
|
ImGui_Marmalade_CreateDeviceObjects();
|
||||||
|
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
|
||||||
|
// Setup display size (every frame to accommodate for window resizing)
|
||||||
|
int w = IwGxGetScreenWidth(), h = IwGxGetScreenHeight();
|
||||||
|
io.DisplaySize = ImVec2((float)w, (float)h);
|
||||||
|
// For retina display or other situations where window coordinates are different from framebuffer coordinates. User storage only, presently not used by ImGui.
|
||||||
|
io.DisplayFramebufferScale = g_scale;
|
||||||
|
|
||||||
|
// Setup time step
|
||||||
|
double current_time = s3eTimerGetUST() / 1000.0f;
|
||||||
|
io.DeltaTime = g_Time > 0.0 ? (float)(current_time - g_Time) : (float)(1.0f / 60.0f);
|
||||||
|
g_Time = current_time;
|
||||||
|
|
||||||
|
double mouse_x, mouse_y;
|
||||||
|
mouse_x = s3ePointerGetX();
|
||||||
|
mouse_y = s3ePointerGetY();
|
||||||
|
io.MousePos = ImVec2((float)mouse_x / g_scale.x, (float)mouse_y / g_scale.y); // Mouse position (set to -FLT_MAX,-FLT_MAX if no mouse / on another screen, etc.)
|
||||||
|
|
||||||
|
for (int i = 0; i < 3; i++)
|
||||||
|
{
|
||||||
|
io.MouseDown[i] = g_MousePressed[i] || s3ePointerGetState((s3ePointerButton)i) != S3E_POINTER_STATE_UP; // If a mouse press event came, always pass it as "mouse held this frame", so we don't miss click-release events that are shorter than 1 frame.
|
||||||
|
g_MousePressed[i] = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Hide OS mouse cursor if ImGui is drawing it
|
||||||
|
// s3ePointerSetInt(S3E_POINTER_HIDE_CURSOR,(io.MouseDrawCursor ? 0 : 1));
|
||||||
|
|
||||||
|
// Show/hide OSD keyboard
|
||||||
|
if (io.WantTextInput)
|
||||||
|
{
|
||||||
|
// Some text input widget is active?
|
||||||
|
if (!g_osdKeyboardEnabled)
|
||||||
|
{
|
||||||
|
g_osdKeyboardEnabled = true;
|
||||||
|
s3eKeyboardSetInt(S3E_KEYBOARD_GET_CHAR, 1); // show OSD keyboard
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// No text input widget is active
|
||||||
|
if (g_osdKeyboardEnabled)
|
||||||
|
{
|
||||||
|
g_osdKeyboardEnabled = false;
|
||||||
|
s3eKeyboardSetInt(S3E_KEYBOARD_GET_CHAR, 0); // hide OSD keyboard
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
27
backend/imgui_impl_marmalade.h
Normal file
27
backend/imgui_impl_marmalade.h
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
// dear imgui: Renderer + Platform Backend for Marmalade + IwGx
|
||||||
|
// Marmalade code: Copyright (C) 2015 by Giovanni Zito (this file is part of Dear ImGui)
|
||||||
|
|
||||||
|
// Implemented features:
|
||||||
|
// [X] Renderer: User texture binding. Use 'CIwTexture*' as ImTextureID. Read the FAQ about ImTextureID!
|
||||||
|
|
||||||
|
// You can copy and use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
||||||
|
// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
|
||||||
|
// Read online: https://github.com/ocornut/imgui/tree/master/docs
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include "imgui.h" // IMGUI_IMPL_API
|
||||||
|
|
||||||
|
IMGUI_IMPL_API bool ImGui_Marmalade_Init(bool install_callbacks);
|
||||||
|
IMGUI_IMPL_API void ImGui_Marmalade_Shutdown();
|
||||||
|
IMGUI_IMPL_API void ImGui_Marmalade_NewFrame();
|
||||||
|
IMGUI_IMPL_API void ImGui_Marmalade_RenderDrawData(ImDrawData* draw_data);
|
||||||
|
|
||||||
|
// Use if you want to reset your rendering device without losing Dear ImGui state.
|
||||||
|
IMGUI_IMPL_API void ImGui_Marmalade_InvalidateDeviceObjects();
|
||||||
|
IMGUI_IMPL_API bool ImGui_Marmalade_CreateDeviceObjects();
|
||||||
|
|
||||||
|
// Callbacks (installed by default if you enable 'install_callbacks' during initialization)
|
||||||
|
// You can also handle inputs yourself and use those as a reference.
|
||||||
|
IMGUI_IMPL_API int32 ImGui_Marmalade_PointerButtonEventCallback(void* system_data, void* user_data);
|
||||||
|
IMGUI_IMPL_API int32 ImGui_Marmalade_KeyCallback(void* system_data, void* user_data);
|
||||||
|
IMGUI_IMPL_API int32 ImGui_Marmalade_CharCallback(void* system_data, void* user_data);
|
28
backend/imgui_impl_metal.h
Normal file
28
backend/imgui_impl_metal.h
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
// dear imgui: Renderer Backend for Metal
|
||||||
|
// This needs to be used along with a Platform Backend (e.g. OSX)
|
||||||
|
|
||||||
|
// Implemented features:
|
||||||
|
// [X] Renderer: User texture binding. Use 'MTLTexture' as ImTextureID. Read the FAQ about ImTextureID!
|
||||||
|
// [X] Renderer: Support for large meshes (64k+ vertices) with 16-bit indices.
|
||||||
|
|
||||||
|
// You can copy and use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
||||||
|
// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
|
||||||
|
// Read online: https://github.com/ocornut/imgui/tree/master/docs
|
||||||
|
|
||||||
|
#include "imgui.h" // IMGUI_IMPL_API
|
||||||
|
|
||||||
|
@class MTLRenderPassDescriptor;
|
||||||
|
@protocol MTLDevice, MTLCommandBuffer, MTLRenderCommandEncoder;
|
||||||
|
|
||||||
|
IMGUI_IMPL_API bool ImGui_ImplMetal_Init(id<MTLDevice> device);
|
||||||
|
IMGUI_IMPL_API void ImGui_ImplMetal_Shutdown();
|
||||||
|
IMGUI_IMPL_API void ImGui_ImplMetal_NewFrame(MTLRenderPassDescriptor* renderPassDescriptor);
|
||||||
|
IMGUI_IMPL_API void ImGui_ImplMetal_RenderDrawData(ImDrawData* draw_data,
|
||||||
|
id<MTLCommandBuffer> commandBuffer,
|
||||||
|
id<MTLRenderCommandEncoder> commandEncoder);
|
||||||
|
|
||||||
|
// Called by Init/NewFrame/Shutdown
|
||||||
|
IMGUI_IMPL_API bool ImGui_ImplMetal_CreateFontsTexture(id<MTLDevice> device);
|
||||||
|
IMGUI_IMPL_API void ImGui_ImplMetal_DestroyFontsTexture();
|
||||||
|
IMGUI_IMPL_API bool ImGui_ImplMetal_CreateDeviceObjects(id<MTLDevice> device);
|
||||||
|
IMGUI_IMPL_API void ImGui_ImplMetal_DestroyDeviceObjects();
|
552
backend/imgui_impl_metal.mm
Normal file
552
backend/imgui_impl_metal.mm
Normal file
@ -0,0 +1,552 @@
|
|||||||
|
// dear imgui: Renderer Backend for Metal
|
||||||
|
// This needs to be used along with a Platform Backend (e.g. OSX)
|
||||||
|
|
||||||
|
// Implemented features:
|
||||||
|
// [X] Renderer: User texture binding. Use 'MTLTexture' as ImTextureID. Read the FAQ about ImTextureID!
|
||||||
|
// [X] Renderer: Support for large meshes (64k+ vertices) with 16-bit indices.
|
||||||
|
|
||||||
|
// You can copy and use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
||||||
|
// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
|
||||||
|
// Read online: https://github.com/ocornut/imgui/tree/master/docs
|
||||||
|
|
||||||
|
// CHANGELOG
|
||||||
|
// (minor and older changes stripped away, please see git history for details)
|
||||||
|
// 2021-02-18: Metal: Change blending equation to preserve alpha in output buffer.
|
||||||
|
// 2021-01-25: Metal: Fixed texture storage mode when building on Mac Catalyst.
|
||||||
|
// 2019-05-29: Metal: Added support for large mesh (64K+ vertices), enable ImGuiBackendFlags_RendererHasVtxOffset flag.
|
||||||
|
// 2019-04-30: Metal: Added support for special ImDrawCallback_ResetRenderState callback to reset render state.
|
||||||
|
// 2019-02-11: Metal: Projecting clipping rectangles correctly using draw_data->FramebufferScale to allow multi-viewports for retina display.
|
||||||
|
// 2018-11-30: Misc: Setting up io.BackendRendererName so it can be displayed in the About Window.
|
||||||
|
// 2018-07-05: Metal: Added new Metal backend implementation.
|
||||||
|
|
||||||
|
#include "imgui.h"
|
||||||
|
#include "imgui_impl_metal.h"
|
||||||
|
|
||||||
|
#import <Metal/Metal.h>
|
||||||
|
// #import <QuartzCore/CAMetalLayer.h> // Not supported in XCode 9.2. Maybe a macro to detect the SDK version can be used (something like #if MACOS_SDK >= 10.13 ...)
|
||||||
|
#import <simd/simd.h>
|
||||||
|
|
||||||
|
#pragma mark - Support classes
|
||||||
|
|
||||||
|
// A wrapper around a MTLBuffer object that knows the last time it was reused
|
||||||
|
@interface MetalBuffer : NSObject
|
||||||
|
@property (nonatomic, strong) id<MTLBuffer> buffer;
|
||||||
|
@property (nonatomic, assign) NSTimeInterval lastReuseTime;
|
||||||
|
- (instancetype)initWithBuffer:(id<MTLBuffer>)buffer;
|
||||||
|
@end
|
||||||
|
|
||||||
|
// An object that encapsulates the data necessary to uniquely identify a
|
||||||
|
// render pipeline state. These are used as cache keys.
|
||||||
|
@interface FramebufferDescriptor : NSObject<NSCopying>
|
||||||
|
@property (nonatomic, assign) unsigned long sampleCount;
|
||||||
|
@property (nonatomic, assign) MTLPixelFormat colorPixelFormat;
|
||||||
|
@property (nonatomic, assign) MTLPixelFormat depthPixelFormat;
|
||||||
|
@property (nonatomic, assign) MTLPixelFormat stencilPixelFormat;
|
||||||
|
- (instancetype)initWithRenderPassDescriptor:(MTLRenderPassDescriptor *)renderPassDescriptor;
|
||||||
|
@end
|
||||||
|
|
||||||
|
// A singleton that stores long-lived objects that are needed by the Metal
|
||||||
|
// renderer backend. Stores the render pipeline state cache and the default
|
||||||
|
// font texture, and manages the reusable buffer cache.
|
||||||
|
@interface MetalContext : NSObject
|
||||||
|
@property (nonatomic, strong) id<MTLDepthStencilState> depthStencilState;
|
||||||
|
@property (nonatomic, strong) FramebufferDescriptor *framebufferDescriptor; // framebuffer descriptor for current frame; transient
|
||||||
|
@property (nonatomic, strong) NSMutableDictionary *renderPipelineStateCache; // pipeline cache; keyed on framebuffer descriptors
|
||||||
|
@property (nonatomic, strong, nullable) id<MTLTexture> fontTexture;
|
||||||
|
@property (nonatomic, strong) NSMutableArray<MetalBuffer *> *bufferCache;
|
||||||
|
@property (nonatomic, assign) NSTimeInterval lastBufferCachePurge;
|
||||||
|
- (void)makeDeviceObjectsWithDevice:(id<MTLDevice>)device;
|
||||||
|
- (void)makeFontTextureWithDevice:(id<MTLDevice>)device;
|
||||||
|
- (MetalBuffer *)dequeueReusableBufferOfLength:(NSUInteger)length device:(id<MTLDevice>)device;
|
||||||
|
- (void)enqueueReusableBuffer:(MetalBuffer *)buffer;
|
||||||
|
- (id<MTLRenderPipelineState>)renderPipelineStateForFrameAndDevice:(id<MTLDevice>)device;
|
||||||
|
- (void)emptyRenderPipelineStateCache;
|
||||||
|
- (void)setupRenderState:(ImDrawData *)drawData
|
||||||
|
commandBuffer:(id<MTLCommandBuffer>)commandBuffer
|
||||||
|
commandEncoder:(id<MTLRenderCommandEncoder>)commandEncoder
|
||||||
|
renderPipelineState:(id<MTLRenderPipelineState>)renderPipelineState
|
||||||
|
vertexBuffer:(MetalBuffer *)vertexBuffer
|
||||||
|
vertexBufferOffset:(size_t)vertexBufferOffset;
|
||||||
|
- (void)renderDrawData:(ImDrawData *)drawData
|
||||||
|
commandBuffer:(id<MTLCommandBuffer>)commandBuffer
|
||||||
|
commandEncoder:(id<MTLRenderCommandEncoder>)commandEncoder;
|
||||||
|
@end
|
||||||
|
|
||||||
|
static MetalContext *g_sharedMetalContext = nil;
|
||||||
|
|
||||||
|
#pragma mark - ImGui API implementation
|
||||||
|
|
||||||
|
bool ImGui_ImplMetal_Init(id<MTLDevice> device)
|
||||||
|
{
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
io.BackendRendererName = "imgui_impl_metal";
|
||||||
|
io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes.
|
||||||
|
|
||||||
|
static dispatch_once_t onceToken;
|
||||||
|
dispatch_once(&onceToken, ^{
|
||||||
|
g_sharedMetalContext = [[MetalContext alloc] init];
|
||||||
|
});
|
||||||
|
|
||||||
|
ImGui_ImplMetal_CreateDeviceObjects(device);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGui_ImplMetal_Shutdown()
|
||||||
|
{
|
||||||
|
ImGui_ImplMetal_DestroyDeviceObjects();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGui_ImplMetal_NewFrame(MTLRenderPassDescriptor *renderPassDescriptor)
|
||||||
|
{
|
||||||
|
IM_ASSERT(g_sharedMetalContext != nil && "No Metal context. Did you call ImGui_ImplMetal_Init() ?");
|
||||||
|
|
||||||
|
g_sharedMetalContext.framebufferDescriptor = [[FramebufferDescriptor alloc] initWithRenderPassDescriptor:renderPassDescriptor];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Metal Render function.
|
||||||
|
void ImGui_ImplMetal_RenderDrawData(ImDrawData* draw_data, id<MTLCommandBuffer> commandBuffer, id<MTLRenderCommandEncoder> commandEncoder)
|
||||||
|
{
|
||||||
|
[g_sharedMetalContext renderDrawData:draw_data commandBuffer:commandBuffer commandEncoder:commandEncoder];
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ImGui_ImplMetal_CreateFontsTexture(id<MTLDevice> device)
|
||||||
|
{
|
||||||
|
[g_sharedMetalContext makeFontTextureWithDevice:device];
|
||||||
|
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
io.Fonts->SetTexID((__bridge void *)g_sharedMetalContext.fontTexture); // ImTextureID == void*
|
||||||
|
|
||||||
|
return (g_sharedMetalContext.fontTexture != nil);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGui_ImplMetal_DestroyFontsTexture()
|
||||||
|
{
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
g_sharedMetalContext.fontTexture = nil;
|
||||||
|
io.Fonts->SetTexID(nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ImGui_ImplMetal_CreateDeviceObjects(id<MTLDevice> device)
|
||||||
|
{
|
||||||
|
[g_sharedMetalContext makeDeviceObjectsWithDevice:device];
|
||||||
|
|
||||||
|
ImGui_ImplMetal_CreateFontsTexture(device);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGui_ImplMetal_DestroyDeviceObjects()
|
||||||
|
{
|
||||||
|
ImGui_ImplMetal_DestroyFontsTexture();
|
||||||
|
[g_sharedMetalContext emptyRenderPipelineStateCache];
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark - MetalBuffer implementation
|
||||||
|
|
||||||
|
@implementation MetalBuffer
|
||||||
|
- (instancetype)initWithBuffer:(id<MTLBuffer>)buffer
|
||||||
|
{
|
||||||
|
if ((self = [super init]))
|
||||||
|
{
|
||||||
|
_buffer = buffer;
|
||||||
|
_lastReuseTime = [NSDate date].timeIntervalSince1970;
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
@end
|
||||||
|
|
||||||
|
#pragma mark - FramebufferDescriptor implementation
|
||||||
|
|
||||||
|
@implementation FramebufferDescriptor
|
||||||
|
- (instancetype)initWithRenderPassDescriptor:(MTLRenderPassDescriptor *)renderPassDescriptor
|
||||||
|
{
|
||||||
|
if ((self = [super init]))
|
||||||
|
{
|
||||||
|
_sampleCount = renderPassDescriptor.colorAttachments[0].texture.sampleCount;
|
||||||
|
_colorPixelFormat = renderPassDescriptor.colorAttachments[0].texture.pixelFormat;
|
||||||
|
_depthPixelFormat = renderPassDescriptor.depthAttachment.texture.pixelFormat;
|
||||||
|
_stencilPixelFormat = renderPassDescriptor.stencilAttachment.texture.pixelFormat;
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (nonnull id)copyWithZone:(nullable NSZone *)zone
|
||||||
|
{
|
||||||
|
FramebufferDescriptor *copy = [[FramebufferDescriptor allocWithZone:zone] init];
|
||||||
|
copy.sampleCount = self.sampleCount;
|
||||||
|
copy.colorPixelFormat = self.colorPixelFormat;
|
||||||
|
copy.depthPixelFormat = self.depthPixelFormat;
|
||||||
|
copy.stencilPixelFormat = self.stencilPixelFormat;
|
||||||
|
return copy;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSUInteger)hash
|
||||||
|
{
|
||||||
|
NSUInteger sc = _sampleCount & 0x3;
|
||||||
|
NSUInteger cf = _colorPixelFormat & 0x3FF;
|
||||||
|
NSUInteger df = _depthPixelFormat & 0x3FF;
|
||||||
|
NSUInteger sf = _stencilPixelFormat & 0x3FF;
|
||||||
|
NSUInteger hash = (sf << 22) | (df << 12) | (cf << 2) | sc;
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)isEqual:(id)object
|
||||||
|
{
|
||||||
|
FramebufferDescriptor *other = object;
|
||||||
|
if (![other isKindOfClass:[FramebufferDescriptor class]])
|
||||||
|
return NO;
|
||||||
|
return other.sampleCount == self.sampleCount &&
|
||||||
|
other.colorPixelFormat == self.colorPixelFormat &&
|
||||||
|
other.depthPixelFormat == self.depthPixelFormat &&
|
||||||
|
other.stencilPixelFormat == self.stencilPixelFormat;
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
#pragma mark - MetalContext implementation
|
||||||
|
|
||||||
|
@implementation MetalContext
|
||||||
|
- (instancetype)init {
|
||||||
|
if ((self = [super init]))
|
||||||
|
{
|
||||||
|
_renderPipelineStateCache = [NSMutableDictionary dictionary];
|
||||||
|
_bufferCache = [NSMutableArray array];
|
||||||
|
_lastBufferCachePurge = [NSDate date].timeIntervalSince1970;
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)makeDeviceObjectsWithDevice:(id<MTLDevice>)device
|
||||||
|
{
|
||||||
|
MTLDepthStencilDescriptor *depthStencilDescriptor = [[MTLDepthStencilDescriptor alloc] init];
|
||||||
|
depthStencilDescriptor.depthWriteEnabled = NO;
|
||||||
|
depthStencilDescriptor.depthCompareFunction = MTLCompareFunctionAlways;
|
||||||
|
self.depthStencilState = [device newDepthStencilStateWithDescriptor:depthStencilDescriptor];
|
||||||
|
}
|
||||||
|
|
||||||
|
// We are retrieving and uploading the font atlas as a 4-channels RGBA texture here.
|
||||||
|
// In theory we could call GetTexDataAsAlpha8() and upload a 1-channel texture to save on memory access bandwidth.
|
||||||
|
// However, using a shader designed for 1-channel texture would make it less obvious to use the ImTextureID facility to render users own textures.
|
||||||
|
// You can make that change in your implementation.
|
||||||
|
- (void)makeFontTextureWithDevice:(id<MTLDevice>)device
|
||||||
|
{
|
||||||
|
ImGuiIO &io = ImGui::GetIO();
|
||||||
|
unsigned char* pixels;
|
||||||
|
int width, height;
|
||||||
|
io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height);
|
||||||
|
MTLTextureDescriptor *textureDescriptor = [MTLTextureDescriptor texture2DDescriptorWithPixelFormat:MTLPixelFormatRGBA8Unorm
|
||||||
|
width:(NSUInteger)width
|
||||||
|
height:(NSUInteger)height
|
||||||
|
mipmapped:NO];
|
||||||
|
textureDescriptor.usage = MTLTextureUsageShaderRead;
|
||||||
|
#if TARGET_OS_OSX || TARGET_OS_MACCATALYST
|
||||||
|
textureDescriptor.storageMode = MTLStorageModeManaged;
|
||||||
|
#else
|
||||||
|
textureDescriptor.storageMode = MTLStorageModeShared;
|
||||||
|
#endif
|
||||||
|
id <MTLTexture> texture = [device newTextureWithDescriptor:textureDescriptor];
|
||||||
|
[texture replaceRegion:MTLRegionMake2D(0, 0, (NSUInteger)width, (NSUInteger)height) mipmapLevel:0 withBytes:pixels bytesPerRow:(NSUInteger)width * 4];
|
||||||
|
self.fontTexture = texture;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (MetalBuffer *)dequeueReusableBufferOfLength:(NSUInteger)length device:(id<MTLDevice>)device
|
||||||
|
{
|
||||||
|
NSTimeInterval now = [NSDate date].timeIntervalSince1970;
|
||||||
|
|
||||||
|
// Purge old buffers that haven't been useful for a while
|
||||||
|
if (now - self.lastBufferCachePurge > 1.0)
|
||||||
|
{
|
||||||
|
NSMutableArray *survivors = [NSMutableArray array];
|
||||||
|
for (MetalBuffer *candidate in self.bufferCache)
|
||||||
|
{
|
||||||
|
if (candidate.lastReuseTime > self.lastBufferCachePurge)
|
||||||
|
{
|
||||||
|
[survivors addObject:candidate];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.bufferCache = [survivors mutableCopy];
|
||||||
|
self.lastBufferCachePurge = now;
|
||||||
|
}
|
||||||
|
|
||||||
|
// See if we have a buffer we can reuse
|
||||||
|
MetalBuffer *bestCandidate = nil;
|
||||||
|
for (MetalBuffer *candidate in self.bufferCache)
|
||||||
|
if (candidate.buffer.length >= length && (bestCandidate == nil || bestCandidate.lastReuseTime > candidate.lastReuseTime))
|
||||||
|
bestCandidate = candidate;
|
||||||
|
|
||||||
|
if (bestCandidate != nil)
|
||||||
|
{
|
||||||
|
[self.bufferCache removeObject:bestCandidate];
|
||||||
|
bestCandidate.lastReuseTime = now;
|
||||||
|
return bestCandidate;
|
||||||
|
}
|
||||||
|
|
||||||
|
// No luck; make a new buffer
|
||||||
|
id<MTLBuffer> backing = [device newBufferWithLength:length options:MTLResourceStorageModeShared];
|
||||||
|
return [[MetalBuffer alloc] initWithBuffer:backing];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)enqueueReusableBuffer:(MetalBuffer *)buffer
|
||||||
|
{
|
||||||
|
[self.bufferCache addObject:buffer];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (_Nullable id<MTLRenderPipelineState>)renderPipelineStateForFrameAndDevice:(id<MTLDevice>)device
|
||||||
|
{
|
||||||
|
// Try to retrieve a render pipeline state that is compatible with the framebuffer config for this frame
|
||||||
|
// The hit rate for this cache should be very near 100%.
|
||||||
|
id<MTLRenderPipelineState> renderPipelineState = self.renderPipelineStateCache[self.framebufferDescriptor];
|
||||||
|
|
||||||
|
if (renderPipelineState == nil)
|
||||||
|
{
|
||||||
|
// No luck; make a new render pipeline state
|
||||||
|
renderPipelineState = [self _renderPipelineStateForFramebufferDescriptor:self.framebufferDescriptor device:device];
|
||||||
|
// Cache render pipeline state for later reuse
|
||||||
|
self.renderPipelineStateCache[self.framebufferDescriptor] = renderPipelineState;
|
||||||
|
}
|
||||||
|
|
||||||
|
return renderPipelineState;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id<MTLRenderPipelineState>)_renderPipelineStateForFramebufferDescriptor:(FramebufferDescriptor *)descriptor device:(id<MTLDevice>)device
|
||||||
|
{
|
||||||
|
NSError *error = nil;
|
||||||
|
|
||||||
|
NSString *shaderSource = @""
|
||||||
|
"#include <metal_stdlib>\n"
|
||||||
|
"using namespace metal;\n"
|
||||||
|
"\n"
|
||||||
|
"struct Uniforms {\n"
|
||||||
|
" float4x4 projectionMatrix;\n"
|
||||||
|
"};\n"
|
||||||
|
"\n"
|
||||||
|
"struct VertexIn {\n"
|
||||||
|
" float2 position [[attribute(0)]];\n"
|
||||||
|
" float2 texCoords [[attribute(1)]];\n"
|
||||||
|
" uchar4 color [[attribute(2)]];\n"
|
||||||
|
"};\n"
|
||||||
|
"\n"
|
||||||
|
"struct VertexOut {\n"
|
||||||
|
" float4 position [[position]];\n"
|
||||||
|
" float2 texCoords;\n"
|
||||||
|
" float4 color;\n"
|
||||||
|
"};\n"
|
||||||
|
"\n"
|
||||||
|
"vertex VertexOut vertex_main(VertexIn in [[stage_in]],\n"
|
||||||
|
" constant Uniforms &uniforms [[buffer(1)]]) {\n"
|
||||||
|
" VertexOut out;\n"
|
||||||
|
" out.position = uniforms.projectionMatrix * float4(in.position, 0, 1);\n"
|
||||||
|
" out.texCoords = in.texCoords;\n"
|
||||||
|
" out.color = float4(in.color) / float4(255.0);\n"
|
||||||
|
" return out;\n"
|
||||||
|
"}\n"
|
||||||
|
"\n"
|
||||||
|
"fragment half4 fragment_main(VertexOut in [[stage_in]],\n"
|
||||||
|
" texture2d<half, access::sample> texture [[texture(0)]]) {\n"
|
||||||
|
" constexpr sampler linearSampler(coord::normalized, min_filter::linear, mag_filter::linear, mip_filter::linear);\n"
|
||||||
|
" half4 texColor = texture.sample(linearSampler, in.texCoords);\n"
|
||||||
|
" return half4(in.color) * texColor;\n"
|
||||||
|
"}\n";
|
||||||
|
|
||||||
|
id<MTLLibrary> library = [device newLibraryWithSource:shaderSource options:nil error:&error];
|
||||||
|
if (library == nil)
|
||||||
|
{
|
||||||
|
NSLog(@"Error: failed to create Metal library: %@", error);
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
id<MTLFunction> vertexFunction = [library newFunctionWithName:@"vertex_main"];
|
||||||
|
id<MTLFunction> fragmentFunction = [library newFunctionWithName:@"fragment_main"];
|
||||||
|
|
||||||
|
if (vertexFunction == nil || fragmentFunction == nil)
|
||||||
|
{
|
||||||
|
NSLog(@"Error: failed to find Metal shader functions in library: %@", error);
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
MTLVertexDescriptor *vertexDescriptor = [MTLVertexDescriptor vertexDescriptor];
|
||||||
|
vertexDescriptor.attributes[0].offset = IM_OFFSETOF(ImDrawVert, pos);
|
||||||
|
vertexDescriptor.attributes[0].format = MTLVertexFormatFloat2; // position
|
||||||
|
vertexDescriptor.attributes[0].bufferIndex = 0;
|
||||||
|
vertexDescriptor.attributes[1].offset = IM_OFFSETOF(ImDrawVert, uv);
|
||||||
|
vertexDescriptor.attributes[1].format = MTLVertexFormatFloat2; // texCoords
|
||||||
|
vertexDescriptor.attributes[1].bufferIndex = 0;
|
||||||
|
vertexDescriptor.attributes[2].offset = IM_OFFSETOF(ImDrawVert, col);
|
||||||
|
vertexDescriptor.attributes[2].format = MTLVertexFormatUChar4; // color
|
||||||
|
vertexDescriptor.attributes[2].bufferIndex = 0;
|
||||||
|
vertexDescriptor.layouts[0].stepRate = 1;
|
||||||
|
vertexDescriptor.layouts[0].stepFunction = MTLVertexStepFunctionPerVertex;
|
||||||
|
vertexDescriptor.layouts[0].stride = sizeof(ImDrawVert);
|
||||||
|
|
||||||
|
MTLRenderPipelineDescriptor *pipelineDescriptor = [[MTLRenderPipelineDescriptor alloc] init];
|
||||||
|
pipelineDescriptor.vertexFunction = vertexFunction;
|
||||||
|
pipelineDescriptor.fragmentFunction = fragmentFunction;
|
||||||
|
pipelineDescriptor.vertexDescriptor = vertexDescriptor;
|
||||||
|
pipelineDescriptor.sampleCount = self.framebufferDescriptor.sampleCount;
|
||||||
|
pipelineDescriptor.colorAttachments[0].pixelFormat = self.framebufferDescriptor.colorPixelFormat;
|
||||||
|
pipelineDescriptor.colorAttachments[0].blendingEnabled = YES;
|
||||||
|
pipelineDescriptor.colorAttachments[0].rgbBlendOperation = MTLBlendOperationAdd;
|
||||||
|
pipelineDescriptor.colorAttachments[0].sourceRGBBlendFactor = MTLBlendFactorSourceAlpha;
|
||||||
|
pipelineDescriptor.colorAttachments[0].destinationRGBBlendFactor = MTLBlendFactorOneMinusSourceAlpha;
|
||||||
|
pipelineDescriptor.colorAttachments[0].alphaBlendOperation = MTLBlendOperationAdd;
|
||||||
|
pipelineDescriptor.colorAttachments[0].sourceAlphaBlendFactor = MTLBlendFactorOne;
|
||||||
|
pipelineDescriptor.colorAttachments[0].destinationAlphaBlendFactor = MTLBlendFactorOneMinusSourceAlpha;
|
||||||
|
pipelineDescriptor.depthAttachmentPixelFormat = self.framebufferDescriptor.depthPixelFormat;
|
||||||
|
pipelineDescriptor.stencilAttachmentPixelFormat = self.framebufferDescriptor.stencilPixelFormat;
|
||||||
|
|
||||||
|
id<MTLRenderPipelineState> renderPipelineState = [device newRenderPipelineStateWithDescriptor:pipelineDescriptor error:&error];
|
||||||
|
if (error != nil)
|
||||||
|
{
|
||||||
|
NSLog(@"Error: failed to create Metal pipeline state: %@", error);
|
||||||
|
}
|
||||||
|
|
||||||
|
return renderPipelineState;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)emptyRenderPipelineStateCache
|
||||||
|
{
|
||||||
|
[self.renderPipelineStateCache removeAllObjects];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setupRenderState:(ImDrawData *)drawData
|
||||||
|
commandBuffer:(id<MTLCommandBuffer>)commandBuffer
|
||||||
|
commandEncoder:(id<MTLRenderCommandEncoder>)commandEncoder
|
||||||
|
renderPipelineState:(id<MTLRenderPipelineState>)renderPipelineState
|
||||||
|
vertexBuffer:(MetalBuffer *)vertexBuffer
|
||||||
|
vertexBufferOffset:(size_t)vertexBufferOffset
|
||||||
|
{
|
||||||
|
[commandEncoder setCullMode:MTLCullModeNone];
|
||||||
|
[commandEncoder setDepthStencilState:g_sharedMetalContext.depthStencilState];
|
||||||
|
|
||||||
|
// Setup viewport, orthographic projection matrix
|
||||||
|
// Our visible imgui space lies from draw_data->DisplayPos (top left) to
|
||||||
|
// draw_data->DisplayPos+data_data->DisplaySize (bottom right). DisplayMin is typically (0,0) for single viewport apps.
|
||||||
|
MTLViewport viewport =
|
||||||
|
{
|
||||||
|
.originX = 0.0,
|
||||||
|
.originY = 0.0,
|
||||||
|
.width = (double)(drawData->DisplaySize.x * drawData->FramebufferScale.x),
|
||||||
|
.height = (double)(drawData->DisplaySize.y * drawData->FramebufferScale.y),
|
||||||
|
.znear = 0.0,
|
||||||
|
.zfar = 1.0
|
||||||
|
};
|
||||||
|
[commandEncoder setViewport:viewport];
|
||||||
|
|
||||||
|
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;
|
||||||
|
float N = (float)viewport.znear;
|
||||||
|
float F = (float)viewport.zfar;
|
||||||
|
const float ortho_projection[4][4] =
|
||||||
|
{
|
||||||
|
{ 2.0f/(R-L), 0.0f, 0.0f, 0.0f },
|
||||||
|
{ 0.0f, 2.0f/(T-B), 0.0f, 0.0f },
|
||||||
|
{ 0.0f, 0.0f, 1/(F-N), 0.0f },
|
||||||
|
{ (R+L)/(L-R), (T+B)/(B-T), N/(F-N), 1.0f },
|
||||||
|
};
|
||||||
|
[commandEncoder setVertexBytes:&ortho_projection length:sizeof(ortho_projection) atIndex:1];
|
||||||
|
|
||||||
|
[commandEncoder setRenderPipelineState:renderPipelineState];
|
||||||
|
|
||||||
|
[commandEncoder setVertexBuffer:vertexBuffer.buffer offset:0 atIndex:0];
|
||||||
|
[commandEncoder setVertexBufferOffset:vertexBufferOffset atIndex:0];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)renderDrawData:(ImDrawData *)drawData
|
||||||
|
commandBuffer:(id<MTLCommandBuffer>)commandBuffer
|
||||||
|
commandEncoder:(id<MTLRenderCommandEncoder>)commandEncoder
|
||||||
|
{
|
||||||
|
// Avoid rendering when minimized, scale coordinates for retina displays (screen coordinates != framebuffer coordinates)
|
||||||
|
int fb_width = (int)(drawData->DisplaySize.x * drawData->FramebufferScale.x);
|
||||||
|
int fb_height = (int)(drawData->DisplaySize.y * drawData->FramebufferScale.y);
|
||||||
|
if (fb_width <= 0 || fb_height <= 0 || drawData->CmdListsCount == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
id<MTLRenderPipelineState> renderPipelineState = [self renderPipelineStateForFrameAndDevice:commandBuffer.device];
|
||||||
|
|
||||||
|
size_t vertexBufferLength = (size_t)drawData->TotalVtxCount * sizeof(ImDrawVert);
|
||||||
|
size_t indexBufferLength = (size_t)drawData->TotalIdxCount * sizeof(ImDrawIdx);
|
||||||
|
MetalBuffer* vertexBuffer = [self dequeueReusableBufferOfLength:vertexBufferLength device:commandBuffer.device];
|
||||||
|
MetalBuffer* indexBuffer = [self dequeueReusableBufferOfLength:indexBufferLength device:commandBuffer.device];
|
||||||
|
|
||||||
|
[self setupRenderState:drawData commandBuffer:commandBuffer commandEncoder:commandEncoder renderPipelineState:renderPipelineState vertexBuffer:vertexBuffer vertexBufferOffset:0];
|
||||||
|
|
||||||
|
// Will project scissor/clipping rectangles into framebuffer space
|
||||||
|
ImVec2 clip_off = drawData->DisplayPos; // (0,0) unless using multi-viewports
|
||||||
|
ImVec2 clip_scale = drawData->FramebufferScale; // (1,1) unless using retina display which are often (2,2)
|
||||||
|
|
||||||
|
// Render command lists
|
||||||
|
size_t vertexBufferOffset = 0;
|
||||||
|
size_t indexBufferOffset = 0;
|
||||||
|
for (int n = 0; n < drawData->CmdListsCount; n++)
|
||||||
|
{
|
||||||
|
const ImDrawList* cmd_list = drawData->CmdLists[n];
|
||||||
|
|
||||||
|
memcpy((char *)vertexBuffer.buffer.contents + vertexBufferOffset, cmd_list->VtxBuffer.Data, (size_t)cmd_list->VtxBuffer.Size * sizeof(ImDrawVert));
|
||||||
|
memcpy((char *)indexBuffer.buffer.contents + indexBufferOffset, cmd_list->IdxBuffer.Data, (size_t)cmd_list->IdxBuffer.Size * sizeof(ImDrawIdx));
|
||||||
|
|
||||||
|
for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++)
|
||||||
|
{
|
||||||
|
const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i];
|
||||||
|
if (pcmd->UserCallback)
|
||||||
|
{
|
||||||
|
// User callback, registered via ImDrawList::AddCallback()
|
||||||
|
// (ImDrawCallback_ResetRenderState is a special callback value used by the user to request the renderer to reset render state.)
|
||||||
|
if (pcmd->UserCallback == ImDrawCallback_ResetRenderState)
|
||||||
|
[self setupRenderState:drawData commandBuffer:commandBuffer commandEncoder:commandEncoder renderPipelineState:renderPipelineState vertexBuffer:vertexBuffer vertexBufferOffset:vertexBufferOffset];
|
||||||
|
else
|
||||||
|
pcmd->UserCallback(cmd_list, pcmd);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Project scissor/clipping rectangles into framebuffer space
|
||||||
|
ImVec4 clip_rect;
|
||||||
|
clip_rect.x = (pcmd->ClipRect.x - clip_off.x) * clip_scale.x;
|
||||||
|
clip_rect.y = (pcmd->ClipRect.y - clip_off.y) * clip_scale.y;
|
||||||
|
clip_rect.z = (pcmd->ClipRect.z - clip_off.x) * clip_scale.x;
|
||||||
|
clip_rect.w = (pcmd->ClipRect.w - clip_off.y) * clip_scale.y;
|
||||||
|
|
||||||
|
if (clip_rect.x < fb_width && clip_rect.y < fb_height && clip_rect.z >= 0.0f && clip_rect.w >= 0.0f)
|
||||||
|
{
|
||||||
|
// Apply scissor/clipping rectangle
|
||||||
|
MTLScissorRect scissorRect =
|
||||||
|
{
|
||||||
|
.x = NSUInteger(clip_rect.x),
|
||||||
|
.y = NSUInteger(clip_rect.y),
|
||||||
|
.width = NSUInteger(clip_rect.z - clip_rect.x),
|
||||||
|
.height = NSUInteger(clip_rect.w - clip_rect.y)
|
||||||
|
};
|
||||||
|
[commandEncoder setScissorRect:scissorRect];
|
||||||
|
|
||||||
|
|
||||||
|
// Bind texture, Draw
|
||||||
|
if (pcmd->TextureId != NULL)
|
||||||
|
[commandEncoder setFragmentTexture:(__bridge id<MTLTexture>)(pcmd->TextureId) atIndex:0];
|
||||||
|
|
||||||
|
[commandEncoder setVertexBufferOffset:(vertexBufferOffset + pcmd->VtxOffset * sizeof(ImDrawVert)) atIndex:0];
|
||||||
|
[commandEncoder drawIndexedPrimitives:MTLPrimitiveTypeTriangle
|
||||||
|
indexCount:pcmd->ElemCount
|
||||||
|
indexType:sizeof(ImDrawIdx) == 2 ? MTLIndexTypeUInt16 : MTLIndexTypeUInt32
|
||||||
|
indexBuffer:indexBuffer.buffer
|
||||||
|
indexBufferOffset:indexBufferOffset + pcmd->IdxOffset * sizeof(ImDrawIdx)];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
vertexBufferOffset += (size_t)cmd_list->VtxBuffer.Size * sizeof(ImDrawVert);
|
||||||
|
indexBufferOffset += (size_t)cmd_list->IdxBuffer.Size * sizeof(ImDrawIdx);
|
||||||
|
}
|
||||||
|
|
||||||
|
__weak id weakSelf = self;
|
||||||
|
[commandBuffer addCompletedHandler:^(id<MTLCommandBuffer>)
|
||||||
|
{
|
||||||
|
dispatch_async(dispatch_get_main_queue(), ^{
|
||||||
|
[weakSelf enqueueReusableBuffer:vertexBuffer];
|
||||||
|
[weakSelf enqueueReusableBuffer:indexBuffer];
|
||||||
|
});
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
258
backend/imgui_impl_opengl2.cpp
Normal file
258
backend/imgui_impl_opengl2.cpp
Normal file
@ -0,0 +1,258 @@
|
|||||||
|
// dear imgui: Renderer Backend for OpenGL2 (legacy OpenGL, fixed pipeline)
|
||||||
|
// This needs to be used along with a Platform Backend (e.g. GLFW, SDL, Win32, custom..)
|
||||||
|
|
||||||
|
// Implemented features:
|
||||||
|
// [X] Renderer: User texture binding. Use 'GLuint' OpenGL texture identifier as void*/ImTextureID. Read the FAQ about ImTextureID!
|
||||||
|
|
||||||
|
// You can copy and use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
||||||
|
// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
|
||||||
|
// Read online: https://github.com/ocornut/imgui/tree/master/docs
|
||||||
|
|
||||||
|
// **DO NOT USE THIS CODE IF YOUR CODE/ENGINE IS USING MODERN OPENGL (SHADERS, VBO, VAO, etc.)**
|
||||||
|
// **Prefer using the code in imgui_impl_opengl3.cpp**
|
||||||
|
// This code is mostly provided as a reference to learn how ImGui integration works, because it is shorter to read.
|
||||||
|
// If your code is using GL3+ context or any semi modern OpenGL calls, using this is likely to make everything more
|
||||||
|
// complicated, will require your code to reset every single OpenGL attributes to their initial state, and might
|
||||||
|
// confuse your GPU driver.
|
||||||
|
// The GL2 code is unable to reset attributes or even call e.g. "glUseProgram(0)" because they don't exist in that API.
|
||||||
|
|
||||||
|
// CHANGELOG
|
||||||
|
// (minor and older changes stripped away, please see git history for details)
|
||||||
|
// 2021-01-03: OpenGL: Backup, setup and restore GL_SHADE_MODEL state, disable GL_STENCIL_TEST and disable GL_NORMAL_ARRAY client state to increase compatibility with legacy OpenGL applications.
|
||||||
|
// 2020-01-23: OpenGL: Backup, setup and restore GL_TEXTURE_ENV to increase compatibility with legacy OpenGL applications.
|
||||||
|
// 2019-04-30: OpenGL: Added support for special ImDrawCallback_ResetRenderState callback to reset render state.
|
||||||
|
// 2019-02-11: OpenGL: Projecting clipping rectangles correctly using draw_data->FramebufferScale to allow multi-viewports for retina display.
|
||||||
|
// 2018-11-30: Misc: Setting up io.BackendRendererName so it can be displayed in the About Window.
|
||||||
|
// 2018-08-03: OpenGL: Disabling/restoring GL_LIGHTING and GL_COLOR_MATERIAL to increase compatibility with legacy OpenGL applications.
|
||||||
|
// 2018-06-08: Misc: Extracted imgui_impl_opengl2.cpp/.h away from the old combined GLFW/SDL+OpenGL2 examples.
|
||||||
|
// 2018-06-08: OpenGL: Use draw_data->DisplayPos and draw_data->DisplaySize to setup projection matrix and clipping rectangle.
|
||||||
|
// 2018-02-16: Misc: Obsoleted the io.RenderDrawListsFn callback and exposed ImGui_ImplOpenGL2_RenderDrawData() in the .h file so you can call it yourself.
|
||||||
|
// 2017-09-01: OpenGL: Save and restore current polygon mode.
|
||||||
|
// 2016-09-10: OpenGL: Uploading font texture as RGBA32 to increase compatibility with users shaders (not ideal).
|
||||||
|
// 2016-09-05: OpenGL: Fixed save and restore of current scissor rectangle.
|
||||||
|
|
||||||
|
#include "imgui.h"
|
||||||
|
#include "imgui_impl_opengl2.h"
|
||||||
|
#if defined(_MSC_VER) && _MSC_VER <= 1500 // MSVC 2008 or earlier
|
||||||
|
#include <stddef.h> // intptr_t
|
||||||
|
#else
|
||||||
|
#include <stdint.h> // intptr_t
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Include OpenGL header (without an OpenGL loader) requires a bit of fiddling
|
||||||
|
#if defined(_WIN32) && !defined(APIENTRY)
|
||||||
|
#define APIENTRY __stdcall // It is customary to use APIENTRY for OpenGL function pointer declarations on all platforms. Additionally, the Windows OpenGL header needs APIENTRY.
|
||||||
|
#endif
|
||||||
|
#if defined(_WIN32) && !defined(WINGDIAPI)
|
||||||
|
#define WINGDIAPI __declspec(dllimport) // Some Windows OpenGL headers need this
|
||||||
|
#endif
|
||||||
|
#if defined(__APPLE__)
|
||||||
|
#define GL_SILENCE_DEPRECATION
|
||||||
|
#include <OpenGL/gl.h>
|
||||||
|
#else
|
||||||
|
#include <GL/gl.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// OpenGL Data
|
||||||
|
static GLuint g_FontTexture = 0;
|
||||||
|
|
||||||
|
// Functions
|
||||||
|
bool ImGui_ImplOpenGL2_Init()
|
||||||
|
{
|
||||||
|
// Setup backend capabilities flags
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
io.BackendRendererName = "imgui_impl_opengl2";
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGui_ImplOpenGL2_Shutdown()
|
||||||
|
{
|
||||||
|
ImGui_ImplOpenGL2_DestroyDeviceObjects();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGui_ImplOpenGL2_NewFrame()
|
||||||
|
{
|
||||||
|
if (!g_FontTexture)
|
||||||
|
ImGui_ImplOpenGL2_CreateDeviceObjects();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ImGui_ImplOpenGL2_SetupRenderState(ImDrawData* draw_data, int fb_width, int fb_height)
|
||||||
|
{
|
||||||
|
// Setup render state: alpha-blending enabled, no face culling, no depth testing, scissor enabled, vertex/texcoord/color pointers, polygon fill.
|
||||||
|
glEnable(GL_BLEND);
|
||||||
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||||
|
//glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); // In order to composite our output buffer we need to preserve alpha
|
||||||
|
glDisable(GL_CULL_FACE);
|
||||||
|
glDisable(GL_DEPTH_TEST);
|
||||||
|
glDisable(GL_STENCIL_TEST);
|
||||||
|
glDisable(GL_LIGHTING);
|
||||||
|
glDisable(GL_COLOR_MATERIAL);
|
||||||
|
glEnable(GL_SCISSOR_TEST);
|
||||||
|
glEnableClientState(GL_VERTEX_ARRAY);
|
||||||
|
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||||
|
glEnableClientState(GL_COLOR_ARRAY);
|
||||||
|
glDisableClientState(GL_NORMAL_ARRAY);
|
||||||
|
glEnable(GL_TEXTURE_2D);
|
||||||
|
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
|
||||||
|
glShadeModel(GL_SMOOTH);
|
||||||
|
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
|
||||||
|
|
||||||
|
// If you are using this code with non-legacy OpenGL header/contexts (which you should not, prefer using imgui_impl_opengl3.cpp!!),
|
||||||
|
// you may need to backup/reset/restore other state, e.g. for current shader using the commented lines below.
|
||||||
|
// (DO NOT MODIFY THIS FILE! Add the code in your calling function)
|
||||||
|
// GLint last_program;
|
||||||
|
// glGetIntegerv(GL_CURRENT_PROGRAM, &last_program);
|
||||||
|
// glUseProgram(0);
|
||||||
|
// ImGui_ImplOpenGL2_RenderDrawData(...);
|
||||||
|
// glUseProgram(last_program)
|
||||||
|
// There are potentially many more states you could need to clear/setup that we can't access from default headers.
|
||||||
|
// e.g. glBindBuffer(GL_ARRAY_BUFFER, 0), glDisable(GL_TEXTURE_CUBE_MAP).
|
||||||
|
|
||||||
|
// Setup viewport, orthographic projection matrix
|
||||||
|
// Our visible imgui space lies from draw_data->DisplayPos (top left) to draw_data->DisplayPos+data_data->DisplaySize (bottom right). DisplayPos is (0,0) for single viewport apps.
|
||||||
|
glViewport(0, 0, (GLsizei)fb_width, (GLsizei)fb_height);
|
||||||
|
glMatrixMode(GL_PROJECTION);
|
||||||
|
glPushMatrix();
|
||||||
|
glLoadIdentity();
|
||||||
|
glOrtho(draw_data->DisplayPos.x, draw_data->DisplayPos.x + draw_data->DisplaySize.x, draw_data->DisplayPos.y + draw_data->DisplaySize.y, draw_data->DisplayPos.y, -1.0f, +1.0f);
|
||||||
|
glMatrixMode(GL_MODELVIEW);
|
||||||
|
glPushMatrix();
|
||||||
|
glLoadIdentity();
|
||||||
|
}
|
||||||
|
|
||||||
|
// OpenGL2 Render function.
|
||||||
|
// Note that this implementation is little overcomplicated because we are saving/setting up/restoring every OpenGL state explicitly.
|
||||||
|
// This is in order to be able to run within an OpenGL engine that doesn't do so.
|
||||||
|
void ImGui_ImplOpenGL2_RenderDrawData(ImDrawData* draw_data)
|
||||||
|
{
|
||||||
|
// Avoid rendering when minimized, scale coordinates for retina displays (screen coordinates != framebuffer coordinates)
|
||||||
|
int fb_width = (int)(draw_data->DisplaySize.x * draw_data->FramebufferScale.x);
|
||||||
|
int fb_height = (int)(draw_data->DisplaySize.y * draw_data->FramebufferScale.y);
|
||||||
|
if (fb_width == 0 || fb_height == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Backup GL state
|
||||||
|
GLint last_texture; glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture);
|
||||||
|
GLint last_polygon_mode[2]; glGetIntegerv(GL_POLYGON_MODE, last_polygon_mode);
|
||||||
|
GLint last_viewport[4]; glGetIntegerv(GL_VIEWPORT, last_viewport);
|
||||||
|
GLint last_scissor_box[4]; glGetIntegerv(GL_SCISSOR_BOX, last_scissor_box);
|
||||||
|
GLint last_shade_model; glGetIntegerv(GL_SHADE_MODEL, &last_shade_model);
|
||||||
|
GLint last_tex_env_mode; glGetTexEnviv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, &last_tex_env_mode);
|
||||||
|
glPushAttrib(GL_ENABLE_BIT | GL_COLOR_BUFFER_BIT | GL_TRANSFORM_BIT);
|
||||||
|
|
||||||
|
// Setup desired GL state
|
||||||
|
ImGui_ImplOpenGL2_SetupRenderState(draw_data, fb_width, fb_height);
|
||||||
|
|
||||||
|
// Will project scissor/clipping rectangles into framebuffer space
|
||||||
|
ImVec2 clip_off = draw_data->DisplayPos; // (0,0) unless using multi-viewports
|
||||||
|
ImVec2 clip_scale = draw_data->FramebufferScale; // (1,1) unless using retina display which are often (2,2)
|
||||||
|
|
||||||
|
// Render command lists
|
||||||
|
for (int n = 0; n < draw_data->CmdListsCount; n++)
|
||||||
|
{
|
||||||
|
const ImDrawList* cmd_list = draw_data->CmdLists[n];
|
||||||
|
const ImDrawVert* vtx_buffer = cmd_list->VtxBuffer.Data;
|
||||||
|
const ImDrawIdx* idx_buffer = cmd_list->IdxBuffer.Data;
|
||||||
|
glVertexPointer(2, GL_FLOAT, sizeof(ImDrawVert), (const GLvoid*)((const char*)vtx_buffer + IM_OFFSETOF(ImDrawVert, pos)));
|
||||||
|
glTexCoordPointer(2, GL_FLOAT, sizeof(ImDrawVert), (const GLvoid*)((const char*)vtx_buffer + IM_OFFSETOF(ImDrawVert, uv)));
|
||||||
|
glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(ImDrawVert), (const GLvoid*)((const char*)vtx_buffer + IM_OFFSETOF(ImDrawVert, col)));
|
||||||
|
|
||||||
|
for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++)
|
||||||
|
{
|
||||||
|
const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i];
|
||||||
|
if (pcmd->UserCallback)
|
||||||
|
{
|
||||||
|
// User callback, registered via ImDrawList::AddCallback()
|
||||||
|
// (ImDrawCallback_ResetRenderState is a special callback value used by the user to request the renderer to reset render state.)
|
||||||
|
if (pcmd->UserCallback == ImDrawCallback_ResetRenderState)
|
||||||
|
ImGui_ImplOpenGL2_SetupRenderState(draw_data, fb_width, fb_height);
|
||||||
|
else
|
||||||
|
pcmd->UserCallback(cmd_list, pcmd);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Project scissor/clipping rectangles into framebuffer space
|
||||||
|
ImVec4 clip_rect;
|
||||||
|
clip_rect.x = (pcmd->ClipRect.x - clip_off.x) * clip_scale.x;
|
||||||
|
clip_rect.y = (pcmd->ClipRect.y - clip_off.y) * clip_scale.y;
|
||||||
|
clip_rect.z = (pcmd->ClipRect.z - clip_off.x) * clip_scale.x;
|
||||||
|
clip_rect.w = (pcmd->ClipRect.w - clip_off.y) * clip_scale.y;
|
||||||
|
|
||||||
|
if (clip_rect.x < fb_width && clip_rect.y < fb_height && clip_rect.z >= 0.0f && clip_rect.w >= 0.0f)
|
||||||
|
{
|
||||||
|
// Apply scissor/clipping rectangle
|
||||||
|
glScissor((int)clip_rect.x, (int)(fb_height - clip_rect.w), (int)(clip_rect.z - clip_rect.x), (int)(clip_rect.w - clip_rect.y));
|
||||||
|
|
||||||
|
// Bind texture, Draw
|
||||||
|
glBindTexture(GL_TEXTURE_2D, (GLuint)(intptr_t)pcmd->TextureId);
|
||||||
|
glDrawElements(GL_TRIANGLES, (GLsizei)pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, idx_buffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
idx_buffer += pcmd->ElemCount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Restore modified GL state
|
||||||
|
glDisableClientState(GL_COLOR_ARRAY);
|
||||||
|
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||||
|
glDisableClientState(GL_VERTEX_ARRAY);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, (GLuint)last_texture);
|
||||||
|
glMatrixMode(GL_MODELVIEW);
|
||||||
|
glPopMatrix();
|
||||||
|
glMatrixMode(GL_PROJECTION);
|
||||||
|
glPopMatrix();
|
||||||
|
glPopAttrib();
|
||||||
|
glPolygonMode(GL_FRONT, (GLenum)last_polygon_mode[0]); glPolygonMode(GL_BACK, (GLenum)last_polygon_mode[1]);
|
||||||
|
glViewport(last_viewport[0], last_viewport[1], (GLsizei)last_viewport[2], (GLsizei)last_viewport[3]);
|
||||||
|
glScissor(last_scissor_box[0], last_scissor_box[1], (GLsizei)last_scissor_box[2], (GLsizei)last_scissor_box[3]);
|
||||||
|
glShadeModel(last_shade_model);
|
||||||
|
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, last_tex_env_mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ImGui_ImplOpenGL2_CreateFontsTexture()
|
||||||
|
{
|
||||||
|
// Build texture atlas
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
unsigned char* pixels;
|
||||||
|
int width, height;
|
||||||
|
io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); // Load as RGBA 32-bit (75% of the memory is wasted, but default font is so small) because it is more likely to be compatible with user's existing shaders. If your ImTextureId represent a higher-level concept than just a GL texture id, consider calling GetTexDataAsAlpha8() instead to save on GPU memory.
|
||||||
|
|
||||||
|
// Upload texture to graphics system
|
||||||
|
GLint last_texture;
|
||||||
|
glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture);
|
||||||
|
glGenTextures(1, &g_FontTexture);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, g_FontTexture);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||||
|
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
|
||||||
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
|
||||||
|
|
||||||
|
// Store our identifier
|
||||||
|
io.Fonts->SetTexID((ImTextureID)(intptr_t)g_FontTexture);
|
||||||
|
|
||||||
|
// Restore state
|
||||||
|
glBindTexture(GL_TEXTURE_2D, last_texture);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGui_ImplOpenGL2_DestroyFontsTexture()
|
||||||
|
{
|
||||||
|
if (g_FontTexture)
|
||||||
|
{
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
glDeleteTextures(1, &g_FontTexture);
|
||||||
|
io.Fonts->SetTexID(0);
|
||||||
|
g_FontTexture = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ImGui_ImplOpenGL2_CreateDeviceObjects()
|
||||||
|
{
|
||||||
|
return ImGui_ImplOpenGL2_CreateFontsTexture();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGui_ImplOpenGL2_DestroyDeviceObjects()
|
||||||
|
{
|
||||||
|
ImGui_ImplOpenGL2_DestroyFontsTexture();
|
||||||
|
}
|
31
backend/imgui_impl_opengl2.h
Normal file
31
backend/imgui_impl_opengl2.h
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
// dear imgui: Renderer Backend for OpenGL2 (legacy OpenGL, fixed pipeline)
|
||||||
|
// This needs to be used along with a Platform Backend (e.g. GLFW, SDL, Win32, custom..)
|
||||||
|
|
||||||
|
// Implemented features:
|
||||||
|
// [X] Renderer: User texture binding. Use 'GLuint' OpenGL texture identifier as void*/ImTextureID. Read the FAQ about ImTextureID!
|
||||||
|
|
||||||
|
// You can copy and use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
||||||
|
// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
|
||||||
|
// Read online: https://github.com/ocornut/imgui/tree/master/docs
|
||||||
|
|
||||||
|
// **DO NOT USE THIS CODE IF YOUR CODE/ENGINE IS USING MODERN OPENGL (SHADERS, VBO, VAO, etc.)**
|
||||||
|
// **Prefer using the code in imgui_impl_opengl3.cpp**
|
||||||
|
// This code is mostly provided as a reference to learn how ImGui integration works, because it is shorter to read.
|
||||||
|
// If your code is using GL3+ context or any semi modern OpenGL calls, using this is likely to make everything more
|
||||||
|
// complicated, will require your code to reset every single OpenGL attributes to their initial state, and might
|
||||||
|
// confuse your GPU driver.
|
||||||
|
// The GL2 code is unable to reset attributes or even call e.g. "glUseProgram(0)" because they don't exist in that API.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include "imgui.h" // IMGUI_IMPL_API
|
||||||
|
|
||||||
|
IMGUI_IMPL_API bool ImGui_ImplOpenGL2_Init();
|
||||||
|
IMGUI_IMPL_API void ImGui_ImplOpenGL2_Shutdown();
|
||||||
|
IMGUI_IMPL_API void ImGui_ImplOpenGL2_NewFrame();
|
||||||
|
IMGUI_IMPL_API void ImGui_ImplOpenGL2_RenderDrawData(ImDrawData* draw_data);
|
||||||
|
|
||||||
|
// Called by Init/NewFrame/Shutdown
|
||||||
|
IMGUI_IMPL_API bool ImGui_ImplOpenGL2_CreateFontsTexture();
|
||||||
|
IMGUI_IMPL_API void ImGui_ImplOpenGL2_DestroyFontsTexture();
|
||||||
|
IMGUI_IMPL_API bool ImGui_ImplOpenGL2_CreateDeviceObjects();
|
||||||
|
IMGUI_IMPL_API void ImGui_ImplOpenGL2_DestroyDeviceObjects();
|
724
backend/imgui_impl_opengl3.cpp
Normal file
724
backend/imgui_impl_opengl3.cpp
Normal file
@ -0,0 +1,724 @@
|
|||||||
|
// dear imgui: Renderer Backend for modern OpenGL with shaders / programmatic pipeline
|
||||||
|
// - Desktop GL: 2.x 3.x 4.x
|
||||||
|
// - Embedded GL: ES 2.0 (WebGL 1.0), ES 3.0 (WebGL 2.0)
|
||||||
|
// This needs to be used along with a Platform Backend (e.g. GLFW, SDL, Win32, custom..)
|
||||||
|
|
||||||
|
// Implemented features:
|
||||||
|
// [X] Renderer: User texture binding. Use 'GLuint' OpenGL texture identifier as void*/ImTextureID. Read the FAQ about ImTextureID!
|
||||||
|
// [x] Renderer: Desktop GL only: Support for large meshes (64k+ vertices) with 16-bit indices.
|
||||||
|
|
||||||
|
// You can copy and use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
||||||
|
// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
|
||||||
|
// Read online: https://github.com/ocornut/imgui/tree/master/docs
|
||||||
|
|
||||||
|
// CHANGELOG
|
||||||
|
// (minor and older changes stripped away, please see git history for details)
|
||||||
|
// 2021-04-06: OpenGL: Don't try to read GL_CLIP_ORIGIN unless we're OpenGL 4.5 or greater.
|
||||||
|
// 2021-02-18: OpenGL: Change blending equation to preserve alpha in output buffer.
|
||||||
|
// 2021-01-03: OpenGL: Backup, setup and restore GL_STENCIL_TEST state.
|
||||||
|
// 2020-10-23: OpenGL: Backup, setup and restore GL_PRIMITIVE_RESTART state.
|
||||||
|
// 2020-10-15: OpenGL: Use glGetString(GL_VERSION) instead of glGetIntegerv(GL_MAJOR_VERSION, ...) when the later returns zero (e.g. Desktop GL 2.x)
|
||||||
|
// 2020-09-17: OpenGL: Fix to avoid compiling/calling glBindSampler() on ES or pre 3.3 context which have the defines set by a loader.
|
||||||
|
// 2020-07-10: OpenGL: Added support for glad2 OpenGL loader.
|
||||||
|
// 2020-05-08: OpenGL: Made default GLSL version 150 (instead of 130) on OSX.
|
||||||
|
// 2020-04-21: OpenGL: Fixed handling of glClipControl(GL_UPPER_LEFT) by inverting projection matrix.
|
||||||
|
// 2020-04-12: OpenGL: Fixed context version check mistakenly testing for 4.0+ instead of 3.2+ to enable ImGuiBackendFlags_RendererHasVtxOffset.
|
||||||
|
// 2020-03-24: OpenGL: Added support for glbinding 2.x OpenGL loader.
|
||||||
|
// 2020-01-07: OpenGL: Added support for glbinding 3.x OpenGL loader.
|
||||||
|
// 2019-10-25: OpenGL: Using a combination of GL define and runtime GL version to decide whether to use glDrawElementsBaseVertex(). Fix building with pre-3.2 GL loaders.
|
||||||
|
// 2019-09-22: OpenGL: Detect default GL loader using __has_include compiler facility.
|
||||||
|
// 2019-09-16: OpenGL: Tweak initialization code to allow application calling ImGui_ImplOpenGL3_CreateFontsTexture() before the first NewFrame() call.
|
||||||
|
// 2019-05-29: OpenGL: Desktop GL only: Added support for large mesh (64K+ vertices), enable ImGuiBackendFlags_RendererHasVtxOffset flag.
|
||||||
|
// 2019-04-30: OpenGL: Added support for special ImDrawCallback_ResetRenderState callback to reset render state.
|
||||||
|
// 2019-03-29: OpenGL: Not calling glBindBuffer more than necessary in the render loop.
|
||||||
|
// 2019-03-15: OpenGL: Added a GL call + comments in ImGui_ImplOpenGL3_Init() to detect uninitialized GL function loaders early.
|
||||||
|
// 2019-03-03: OpenGL: Fix support for ES 2.0 (WebGL 1.0).
|
||||||
|
// 2019-02-20: OpenGL: Fix for OSX not supporting OpenGL 4.5, we don't try to read GL_CLIP_ORIGIN even if defined by the headers/loader.
|
||||||
|
// 2019-02-11: OpenGL: Projecting clipping rectangles correctly using draw_data->FramebufferScale to allow multi-viewports for retina display.
|
||||||
|
// 2019-02-01: OpenGL: Using GLSL 410 shaders for any version over 410 (e.g. 430, 450).
|
||||||
|
// 2018-11-30: Misc: Setting up io.BackendRendererName so it can be displayed in the About Window.
|
||||||
|
// 2018-11-13: OpenGL: Support for GL 4.5's glClipControl(GL_UPPER_LEFT) / GL_CLIP_ORIGIN.
|
||||||
|
// 2018-08-29: OpenGL: Added support for more OpenGL loaders: glew and glad, with comments indicative that any loader can be used.
|
||||||
|
// 2018-08-09: OpenGL: Default to OpenGL ES 3 on iOS and Android. GLSL version default to "#version 300 ES".
|
||||||
|
// 2018-07-30: OpenGL: Support for GLSL 300 ES and 410 core. Fixes for Emscripten compilation.
|
||||||
|
// 2018-07-10: OpenGL: Support for more GLSL versions (based on the GLSL version string). Added error output when shaders fail to compile/link.
|
||||||
|
// 2018-06-08: Misc: Extracted imgui_impl_opengl3.cpp/.h away from the old combined GLFW/SDL+OpenGL3 examples.
|
||||||
|
// 2018-06-08: OpenGL: Use draw_data->DisplayPos and draw_data->DisplaySize to setup projection matrix and clipping rectangle.
|
||||||
|
// 2018-05-25: OpenGL: Removed unnecessary backup/restore of GL_ELEMENT_ARRAY_BUFFER_BINDING since this is part of the VAO state.
|
||||||
|
// 2018-05-14: OpenGL: Making the call to glBindSampler() optional so 3.2 context won't fail if the function is a NULL pointer.
|
||||||
|
// 2018-03-06: OpenGL: Added const char* glsl_version parameter to ImGui_ImplOpenGL3_Init() so user can override the GLSL version e.g. "#version 150".
|
||||||
|
// 2018-02-23: OpenGL: Create the VAO in the render function so the setup can more easily be used with multiple shared GL context.
|
||||||
|
// 2018-02-16: Misc: Obsoleted the io.RenderDrawListsFn callback and exposed ImGui_ImplSdlGL3_RenderDrawData() in the .h file so you can call it yourself.
|
||||||
|
// 2018-01-07: OpenGL: Changed GLSL shader version from 330 to 150.
|
||||||
|
// 2017-09-01: OpenGL: Save and restore current bound sampler. Save and restore current polygon mode.
|
||||||
|
// 2017-05-01: OpenGL: Fixed save and restore of current blend func state.
|
||||||
|
// 2017-05-01: OpenGL: Fixed save and restore of current GL_ACTIVE_TEXTURE.
|
||||||
|
// 2016-09-05: OpenGL: Fixed save and restore of current scissor rectangle.
|
||||||
|
// 2016-07-29: OpenGL: Explicitly setting GL_UNPACK_ROW_LENGTH to reduce issues because SDL changes it. (#752)
|
||||||
|
|
||||||
|
//----------------------------------------
|
||||||
|
// OpenGL GLSL GLSL
|
||||||
|
// version version string
|
||||||
|
//----------------------------------------
|
||||||
|
// 2.0 110 "#version 110"
|
||||||
|
// 2.1 120 "#version 120"
|
||||||
|
// 3.0 130 "#version 130"
|
||||||
|
// 3.1 140 "#version 140"
|
||||||
|
// 3.2 150 "#version 150"
|
||||||
|
// 3.3 330 "#version 330 core"
|
||||||
|
// 4.0 400 "#version 400 core"
|
||||||
|
// 4.1 410 "#version 410 core"
|
||||||
|
// 4.2 420 "#version 410 core"
|
||||||
|
// 4.3 430 "#version 430 core"
|
||||||
|
// ES 2.0 100 "#version 100" = WebGL 1.0
|
||||||
|
// ES 3.0 300 "#version 300 es" = WebGL 2.0
|
||||||
|
//----------------------------------------
|
||||||
|
|
||||||
|
#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS)
|
||||||
|
#define _CRT_SECURE_NO_WARNINGS
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "imgui.h"
|
||||||
|
#include "imgui_impl_opengl3.h"
|
||||||
|
#include <stdio.h>
|
||||||
|
#if defined(_MSC_VER) && _MSC_VER <= 1500 // MSVC 2008 or earlier
|
||||||
|
#include <stddef.h> // intptr_t
|
||||||
|
#else
|
||||||
|
#include <stdint.h> // intptr_t
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// GL includes
|
||||||
|
#if defined(IMGUI_IMPL_OPENGL_ES2)
|
||||||
|
#include <GLES2/gl2.h>
|
||||||
|
#elif defined(IMGUI_IMPL_OPENGL_ES3)
|
||||||
|
#if (defined(__APPLE__) && (TARGET_OS_IOS || TARGET_OS_TV))
|
||||||
|
#include <OpenGLES/ES3/gl.h> // Use GL ES 3
|
||||||
|
#else
|
||||||
|
#include <GLES3/gl3.h> // Use GL ES 3
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
// About Desktop OpenGL function loaders:
|
||||||
|
// Modern desktop OpenGL doesn't have a standard portable header file to load OpenGL function pointers.
|
||||||
|
// Helper libraries are often used for this purpose! Here we are supporting a few common ones (gl3w, glew, glad).
|
||||||
|
// You may use another loader/header of your choice (glext, glLoadGen, etc.), or chose to manually implement your own.
|
||||||
|
#if defined(IMGUI_IMPL_OPENGL_LOADER_GL3W)
|
||||||
|
#include <GL/gl3w.h> // Needs to be initialized with gl3wInit() in user's code
|
||||||
|
#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLEW)
|
||||||
|
#include <GL/glew.h> // Needs to be initialized with glewInit() in user's code.
|
||||||
|
#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLAD)
|
||||||
|
#include <glad/glad.h> // Needs to be initialized with gladLoadGL() in user's code.
|
||||||
|
#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLAD2)
|
||||||
|
#include <glad/gl.h> // Needs to be initialized with gladLoadGL(...) or gladLoaderLoadGL() in user's code.
|
||||||
|
#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLBINDING2)
|
||||||
|
#ifndef GLFW_INCLUDE_NONE
|
||||||
|
#define GLFW_INCLUDE_NONE // GLFW including OpenGL headers causes ambiguity or multiple definition errors.
|
||||||
|
#endif
|
||||||
|
#include <glbinding/Binding.h> // Needs to be initialized with glbinding::Binding::initialize() in user's code.
|
||||||
|
#include <glbinding/gl/gl.h>
|
||||||
|
using namespace gl;
|
||||||
|
#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLBINDING3)
|
||||||
|
#ifndef GLFW_INCLUDE_NONE
|
||||||
|
#define GLFW_INCLUDE_NONE // GLFW including OpenGL headers causes ambiguity or multiple definition errors.
|
||||||
|
#endif
|
||||||
|
#include <glbinding/glbinding.h>// Needs to be initialized with glbinding::initialize() in user's code.
|
||||||
|
#include <glbinding/gl/gl.h>
|
||||||
|
using namespace gl;
|
||||||
|
#else
|
||||||
|
#include IMGUI_IMPL_OPENGL_LOADER_CUSTOM
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Desktop GL 3.2+ has glDrawElementsBaseVertex() which GL ES and WebGL don't have.
|
||||||
|
#if !defined(IMGUI_IMPL_OPENGL_ES2) && !defined(IMGUI_IMPL_OPENGL_ES3) && defined(GL_VERSION_3_2)
|
||||||
|
#define IMGUI_IMPL_OPENGL_MAY_HAVE_VTX_OFFSET
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Desktop GL 3.3+ has glBindSampler()
|
||||||
|
#if !defined(IMGUI_IMPL_OPENGL_ES2) && !defined(IMGUI_IMPL_OPENGL_ES3) && defined(GL_VERSION_3_3)
|
||||||
|
#define IMGUI_IMPL_OPENGL_MAY_HAVE_BIND_SAMPLER
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Desktop GL 3.1+ has GL_PRIMITIVE_RESTART state
|
||||||
|
#if !defined(IMGUI_IMPL_OPENGL_ES2) && !defined(IMGUI_IMPL_OPENGL_ES3) && defined(GL_VERSION_3_1)
|
||||||
|
#define IMGUI_IMPL_OPENGL_MAY_HAVE_PRIMITIVE_RESTART
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// OpenGL Data
|
||||||
|
static GLuint g_GlVersion = 0; // Extracted at runtime using GL_MAJOR_VERSION, GL_MINOR_VERSION queries (e.g. 320 for GL 3.2)
|
||||||
|
static char g_GlslVersionString[32] = ""; // Specified by user or detected based on compile time GL settings.
|
||||||
|
static GLuint g_FontTexture = 0;
|
||||||
|
static GLuint g_ShaderHandle = 0, g_VertHandle = 0, g_FragHandle = 0;
|
||||||
|
static GLint g_AttribLocationTex = 0, g_AttribLocationProjMtx = 0; // Uniforms location
|
||||||
|
static GLuint g_AttribLocationVtxPos = 0, g_AttribLocationVtxUV = 0, g_AttribLocationVtxColor = 0; // Vertex attributes location
|
||||||
|
static unsigned int g_VboHandle = 0, g_ElementsHandle = 0;
|
||||||
|
|
||||||
|
// Functions
|
||||||
|
bool ImGui_ImplOpenGL3_Init(const char* glsl_version)
|
||||||
|
{
|
||||||
|
// Query for GL version (e.g. 320 for GL 3.2)
|
||||||
|
#if !defined(IMGUI_IMPL_OPENGL_ES2)
|
||||||
|
GLint major = 0;
|
||||||
|
GLint minor = 0;
|
||||||
|
glGetIntegerv(GL_MAJOR_VERSION, &major);
|
||||||
|
glGetIntegerv(GL_MINOR_VERSION, &minor);
|
||||||
|
if (major == 0 && minor == 0)
|
||||||
|
{
|
||||||
|
// Query GL_VERSION in desktop GL 2.x, the string will start with "<major>.<minor>"
|
||||||
|
const char* gl_version = (const char*)glGetString(GL_VERSION);
|
||||||
|
sscanf(gl_version, "%d.%d", &major, &minor);
|
||||||
|
}
|
||||||
|
g_GlVersion = (GLuint)(major * 100 + minor * 10);
|
||||||
|
#else
|
||||||
|
g_GlVersion = 200; // GLES 2
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Setup backend capabilities flags
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
io.BackendRendererName = "imgui_impl_opengl3";
|
||||||
|
#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_VTX_OFFSET
|
||||||
|
if (g_GlVersion >= 320)
|
||||||
|
io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes.
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Store GLSL version string so we can refer to it later in case we recreate shaders.
|
||||||
|
// Note: GLSL version is NOT the same as GL version. Leave this to NULL if unsure.
|
||||||
|
#if defined(IMGUI_IMPL_OPENGL_ES2)
|
||||||
|
if (glsl_version == NULL)
|
||||||
|
glsl_version = "#version 100";
|
||||||
|
#elif defined(IMGUI_IMPL_OPENGL_ES3)
|
||||||
|
if (glsl_version == NULL)
|
||||||
|
glsl_version = "#version 300 es";
|
||||||
|
#elif defined(__APPLE__)
|
||||||
|
if (glsl_version == NULL)
|
||||||
|
glsl_version = "#version 150";
|
||||||
|
#else
|
||||||
|
if (glsl_version == NULL)
|
||||||
|
glsl_version = "#version 130";
|
||||||
|
#endif
|
||||||
|
IM_ASSERT((int)strlen(glsl_version) + 2 < IM_ARRAYSIZE(g_GlslVersionString));
|
||||||
|
strcpy(g_GlslVersionString, glsl_version);
|
||||||
|
strcat(g_GlslVersionString, "\n");
|
||||||
|
|
||||||
|
// Debugging construct to make it easily visible in the IDE and debugger which GL loader has been selected.
|
||||||
|
// The code actually never uses the 'gl_loader' variable! It is only here so you can read it!
|
||||||
|
// If auto-detection fails or doesn't select the same GL loader file as used by your application,
|
||||||
|
// you are likely to get a crash below.
|
||||||
|
// You can explicitly select a loader by using '#define IMGUI_IMPL_OPENGL_LOADER_XXX' in imconfig.h or compiler command-line.
|
||||||
|
const char* gl_loader = "Unknown";
|
||||||
|
IM_UNUSED(gl_loader);
|
||||||
|
#if defined(IMGUI_IMPL_OPENGL_LOADER_GL3W)
|
||||||
|
gl_loader = "GL3W";
|
||||||
|
#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLEW)
|
||||||
|
gl_loader = "GLEW";
|
||||||
|
#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLAD)
|
||||||
|
gl_loader = "GLAD";
|
||||||
|
#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLAD2)
|
||||||
|
gl_loader = "GLAD2";
|
||||||
|
#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLBINDING2)
|
||||||
|
gl_loader = "glbinding2";
|
||||||
|
#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLBINDING3)
|
||||||
|
gl_loader = "glbinding3";
|
||||||
|
#elif defined(IMGUI_IMPL_OPENGL_LOADER_CUSTOM)
|
||||||
|
gl_loader = "custom";
|
||||||
|
#else
|
||||||
|
gl_loader = "none";
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Make an arbitrary GL call (we don't actually need the result)
|
||||||
|
// IF YOU GET A CRASH HERE: it probably means that you haven't initialized the OpenGL function loader used by this code.
|
||||||
|
// Desktop OpenGL 3/4 need a function loader. See the IMGUI_IMPL_OPENGL_LOADER_xxx explanation above.
|
||||||
|
GLint current_texture;
|
||||||
|
glGetIntegerv(GL_TEXTURE_BINDING_2D, ¤t_texture);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGui_ImplOpenGL3_Shutdown()
|
||||||
|
{
|
||||||
|
ImGui_ImplOpenGL3_DestroyDeviceObjects();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGui_ImplOpenGL3_NewFrame()
|
||||||
|
{
|
||||||
|
if (!g_ShaderHandle)
|
||||||
|
ImGui_ImplOpenGL3_CreateDeviceObjects();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ImGui_ImplOpenGL3_SetupRenderState(ImDrawData* draw_data, int fb_width, int fb_height, GLuint vertex_array_object)
|
||||||
|
{
|
||||||
|
// Setup render state: alpha-blending enabled, no face culling, no depth testing, scissor enabled, polygon fill
|
||||||
|
glEnable(GL_BLEND);
|
||||||
|
glBlendEquation(GL_FUNC_ADD);
|
||||||
|
glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
|
||||||
|
glDisable(GL_CULL_FACE);
|
||||||
|
glDisable(GL_DEPTH_TEST);
|
||||||
|
glDisable(GL_STENCIL_TEST);
|
||||||
|
glEnable(GL_SCISSOR_TEST);
|
||||||
|
#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_PRIMITIVE_RESTART
|
||||||
|
if (g_GlVersion >= 310)
|
||||||
|
glDisable(GL_PRIMITIVE_RESTART);
|
||||||
|
#endif
|
||||||
|
#ifdef GL_POLYGON_MODE
|
||||||
|
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Support for GL 4.5 rarely used glClipControl(GL_UPPER_LEFT)
|
||||||
|
#if defined(GL_CLIP_ORIGIN)
|
||||||
|
bool clip_origin_lower_left = true;
|
||||||
|
if (g_GlVersion >= 450)
|
||||||
|
{
|
||||||
|
GLenum current_clip_origin = 0; glGetIntegerv(GL_CLIP_ORIGIN, (GLint*)¤t_clip_origin);
|
||||||
|
if (current_clip_origin == GL_UPPER_LEFT)
|
||||||
|
clip_origin_lower_left = false;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Setup viewport, orthographic projection matrix
|
||||||
|
// Our visible imgui space lies from draw_data->DisplayPos (top left) to draw_data->DisplayPos+data_data->DisplaySize (bottom right). DisplayPos is (0,0) for single viewport apps.
|
||||||
|
glViewport(0, 0, (GLsizei)fb_width, (GLsizei)fb_height);
|
||||||
|
float L = draw_data->DisplayPos.x;
|
||||||
|
float R = draw_data->DisplayPos.x + draw_data->DisplaySize.x;
|
||||||
|
float T = draw_data->DisplayPos.y;
|
||||||
|
float B = draw_data->DisplayPos.y + draw_data->DisplaySize.y;
|
||||||
|
#if defined(GL_CLIP_ORIGIN)
|
||||||
|
if (!clip_origin_lower_left) { float tmp = T; T = B; B = tmp; } // Swap top and bottom if origin is upper left
|
||||||
|
#endif
|
||||||
|
const float ortho_projection[4][4] =
|
||||||
|
{
|
||||||
|
{ 2.0f/(R-L), 0.0f, 0.0f, 0.0f },
|
||||||
|
{ 0.0f, 2.0f/(T-B), 0.0f, 0.0f },
|
||||||
|
{ 0.0f, 0.0f, -1.0f, 0.0f },
|
||||||
|
{ (R+L)/(L-R), (T+B)/(B-T), 0.0f, 1.0f },
|
||||||
|
};
|
||||||
|
glUseProgram(g_ShaderHandle);
|
||||||
|
glUniform1i(g_AttribLocationTex, 0);
|
||||||
|
glUniformMatrix4fv(g_AttribLocationProjMtx, 1, GL_FALSE, &ortho_projection[0][0]);
|
||||||
|
|
||||||
|
#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_BIND_SAMPLER
|
||||||
|
if (g_GlVersion >= 330)
|
||||||
|
glBindSampler(0, 0); // We use combined texture/sampler state. Applications using GL 3.3 may set that otherwise.
|
||||||
|
#endif
|
||||||
|
|
||||||
|
(void)vertex_array_object;
|
||||||
|
#ifndef IMGUI_IMPL_OPENGL_ES2
|
||||||
|
glBindVertexArray(vertex_array_object);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Bind vertex/index buffers and setup attributes for ImDrawVert
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, g_VboHandle);
|
||||||
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, g_ElementsHandle);
|
||||||
|
glEnableVertexAttribArray(g_AttribLocationVtxPos);
|
||||||
|
glEnableVertexAttribArray(g_AttribLocationVtxUV);
|
||||||
|
glEnableVertexAttribArray(g_AttribLocationVtxColor);
|
||||||
|
glVertexAttribPointer(g_AttribLocationVtxPos, 2, GL_FLOAT, GL_FALSE, sizeof(ImDrawVert), (GLvoid*)IM_OFFSETOF(ImDrawVert, pos));
|
||||||
|
glVertexAttribPointer(g_AttribLocationVtxUV, 2, GL_FLOAT, GL_FALSE, sizeof(ImDrawVert), (GLvoid*)IM_OFFSETOF(ImDrawVert, uv));
|
||||||
|
glVertexAttribPointer(g_AttribLocationVtxColor, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(ImDrawVert), (GLvoid*)IM_OFFSETOF(ImDrawVert, col));
|
||||||
|
}
|
||||||
|
|
||||||
|
// OpenGL3 Render function.
|
||||||
|
// Note that this implementation is little overcomplicated because we are saving/setting up/restoring every OpenGL state explicitly.
|
||||||
|
// This is in order to be able to run within an OpenGL engine that doesn't do so.
|
||||||
|
void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data)
|
||||||
|
{
|
||||||
|
// Avoid rendering when minimized, scale coordinates for retina displays (screen coordinates != framebuffer coordinates)
|
||||||
|
int fb_width = (int)(draw_data->DisplaySize.x * draw_data->FramebufferScale.x);
|
||||||
|
int fb_height = (int)(draw_data->DisplaySize.y * draw_data->FramebufferScale.y);
|
||||||
|
if (fb_width <= 0 || fb_height <= 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Backup GL state
|
||||||
|
GLenum last_active_texture; glGetIntegerv(GL_ACTIVE_TEXTURE, (GLint*)&last_active_texture);
|
||||||
|
glActiveTexture(GL_TEXTURE0);
|
||||||
|
GLuint last_program; glGetIntegerv(GL_CURRENT_PROGRAM, (GLint*)&last_program);
|
||||||
|
GLuint last_texture; glGetIntegerv(GL_TEXTURE_BINDING_2D, (GLint*)&last_texture);
|
||||||
|
#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_BIND_SAMPLER
|
||||||
|
GLuint last_sampler; if (g_GlVersion >= 330) { glGetIntegerv(GL_SAMPLER_BINDING, (GLint*)&last_sampler); } else { last_sampler = 0; }
|
||||||
|
#endif
|
||||||
|
GLuint last_array_buffer; glGetIntegerv(GL_ARRAY_BUFFER_BINDING, (GLint*)&last_array_buffer);
|
||||||
|
#ifndef IMGUI_IMPL_OPENGL_ES2
|
||||||
|
GLuint last_vertex_array_object; glGetIntegerv(GL_VERTEX_ARRAY_BINDING, (GLint*)&last_vertex_array_object);
|
||||||
|
#endif
|
||||||
|
#ifdef GL_POLYGON_MODE
|
||||||
|
GLint last_polygon_mode[2]; glGetIntegerv(GL_POLYGON_MODE, last_polygon_mode);
|
||||||
|
#endif
|
||||||
|
GLint last_viewport[4]; glGetIntegerv(GL_VIEWPORT, last_viewport);
|
||||||
|
GLint last_scissor_box[4]; glGetIntegerv(GL_SCISSOR_BOX, last_scissor_box);
|
||||||
|
GLenum last_blend_src_rgb; glGetIntegerv(GL_BLEND_SRC_RGB, (GLint*)&last_blend_src_rgb);
|
||||||
|
GLenum last_blend_dst_rgb; glGetIntegerv(GL_BLEND_DST_RGB, (GLint*)&last_blend_dst_rgb);
|
||||||
|
GLenum last_blend_src_alpha; glGetIntegerv(GL_BLEND_SRC_ALPHA, (GLint*)&last_blend_src_alpha);
|
||||||
|
GLenum last_blend_dst_alpha; glGetIntegerv(GL_BLEND_DST_ALPHA, (GLint*)&last_blend_dst_alpha);
|
||||||
|
GLenum last_blend_equation_rgb; glGetIntegerv(GL_BLEND_EQUATION_RGB, (GLint*)&last_blend_equation_rgb);
|
||||||
|
GLenum last_blend_equation_alpha; glGetIntegerv(GL_BLEND_EQUATION_ALPHA, (GLint*)&last_blend_equation_alpha);
|
||||||
|
GLboolean last_enable_blend = glIsEnabled(GL_BLEND);
|
||||||
|
GLboolean last_enable_cull_face = glIsEnabled(GL_CULL_FACE);
|
||||||
|
GLboolean last_enable_depth_test = glIsEnabled(GL_DEPTH_TEST);
|
||||||
|
GLboolean last_enable_stencil_test = glIsEnabled(GL_STENCIL_TEST);
|
||||||
|
GLboolean last_enable_scissor_test = glIsEnabled(GL_SCISSOR_TEST);
|
||||||
|
#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_PRIMITIVE_RESTART
|
||||||
|
GLboolean last_enable_primitive_restart = (g_GlVersion >= 310) ? glIsEnabled(GL_PRIMITIVE_RESTART) : GL_FALSE;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Setup desired GL state
|
||||||
|
// Recreate the VAO every time (this is to easily allow multiple GL contexts to be rendered to. VAO are not shared among GL contexts)
|
||||||
|
// The renderer would actually work without any VAO bound, but then our VertexAttrib calls would overwrite the default one currently bound.
|
||||||
|
GLuint vertex_array_object = 0;
|
||||||
|
#ifndef IMGUI_IMPL_OPENGL_ES2
|
||||||
|
glGenVertexArrays(1, &vertex_array_object);
|
||||||
|
#endif
|
||||||
|
ImGui_ImplOpenGL3_SetupRenderState(draw_data, fb_width, fb_height, vertex_array_object);
|
||||||
|
|
||||||
|
// Will project scissor/clipping rectangles into framebuffer space
|
||||||
|
ImVec2 clip_off = draw_data->DisplayPos; // (0,0) unless using multi-viewports
|
||||||
|
ImVec2 clip_scale = draw_data->FramebufferScale; // (1,1) unless using retina display which are often (2,2)
|
||||||
|
|
||||||
|
// Render command lists
|
||||||
|
for (int n = 0; n < draw_data->CmdListsCount; n++)
|
||||||
|
{
|
||||||
|
const ImDrawList* cmd_list = draw_data->CmdLists[n];
|
||||||
|
|
||||||
|
// Upload vertex/index buffers
|
||||||
|
glBufferData(GL_ARRAY_BUFFER, (GLsizeiptr)cmd_list->VtxBuffer.Size * (int)sizeof(ImDrawVert), (const GLvoid*)cmd_list->VtxBuffer.Data, GL_STREAM_DRAW);
|
||||||
|
glBufferData(GL_ELEMENT_ARRAY_BUFFER, (GLsizeiptr)cmd_list->IdxBuffer.Size * (int)sizeof(ImDrawIdx), (const GLvoid*)cmd_list->IdxBuffer.Data, GL_STREAM_DRAW);
|
||||||
|
|
||||||
|
for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++)
|
||||||
|
{
|
||||||
|
const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i];
|
||||||
|
if (pcmd->UserCallback != NULL)
|
||||||
|
{
|
||||||
|
// User callback, registered via ImDrawList::AddCallback()
|
||||||
|
// (ImDrawCallback_ResetRenderState is a special callback value used by the user to request the renderer to reset render state.)
|
||||||
|
if (pcmd->UserCallback == ImDrawCallback_ResetRenderState)
|
||||||
|
ImGui_ImplOpenGL3_SetupRenderState(draw_data, fb_width, fb_height, vertex_array_object);
|
||||||
|
else
|
||||||
|
pcmd->UserCallback(cmd_list, pcmd);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Project scissor/clipping rectangles into framebuffer space
|
||||||
|
ImVec4 clip_rect;
|
||||||
|
clip_rect.x = (pcmd->ClipRect.x - clip_off.x) * clip_scale.x;
|
||||||
|
clip_rect.y = (pcmd->ClipRect.y - clip_off.y) * clip_scale.y;
|
||||||
|
clip_rect.z = (pcmd->ClipRect.z - clip_off.x) * clip_scale.x;
|
||||||
|
clip_rect.w = (pcmd->ClipRect.w - clip_off.y) * clip_scale.y;
|
||||||
|
|
||||||
|
if (clip_rect.x < fb_width && clip_rect.y < fb_height && clip_rect.z >= 0.0f && clip_rect.w >= 0.0f)
|
||||||
|
{
|
||||||
|
// Apply scissor/clipping rectangle
|
||||||
|
glScissor((int)clip_rect.x, (int)(fb_height - clip_rect.w), (int)(clip_rect.z - clip_rect.x), (int)(clip_rect.w - clip_rect.y));
|
||||||
|
|
||||||
|
// Bind texture, Draw
|
||||||
|
glBindTexture(GL_TEXTURE_2D, (GLuint)(intptr_t)pcmd->TextureId);
|
||||||
|
#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_VTX_OFFSET
|
||||||
|
if (g_GlVersion >= 320)
|
||||||
|
glDrawElementsBaseVertex(GL_TRIANGLES, (GLsizei)pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, (void*)(intptr_t)(pcmd->IdxOffset * sizeof(ImDrawIdx)), (GLint)pcmd->VtxOffset);
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
glDrawElements(GL_TRIANGLES, (GLsizei)pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, (void*)(intptr_t)(pcmd->IdxOffset * sizeof(ImDrawIdx)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Destroy the temporary VAO
|
||||||
|
#ifndef IMGUI_IMPL_OPENGL_ES2
|
||||||
|
glDeleteVertexArrays(1, &vertex_array_object);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Restore modified GL state
|
||||||
|
glUseProgram(last_program);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, last_texture);
|
||||||
|
#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_BIND_SAMPLER
|
||||||
|
if (g_GlVersion >= 330)
|
||||||
|
glBindSampler(0, last_sampler);
|
||||||
|
#endif
|
||||||
|
glActiveTexture(last_active_texture);
|
||||||
|
#ifndef IMGUI_IMPL_OPENGL_ES2
|
||||||
|
glBindVertexArray(last_vertex_array_object);
|
||||||
|
#endif
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, last_array_buffer);
|
||||||
|
glBlendEquationSeparate(last_blend_equation_rgb, last_blend_equation_alpha);
|
||||||
|
glBlendFuncSeparate(last_blend_src_rgb, last_blend_dst_rgb, last_blend_src_alpha, last_blend_dst_alpha);
|
||||||
|
if (last_enable_blend) glEnable(GL_BLEND); else glDisable(GL_BLEND);
|
||||||
|
if (last_enable_cull_face) glEnable(GL_CULL_FACE); else glDisable(GL_CULL_FACE);
|
||||||
|
if (last_enable_depth_test) glEnable(GL_DEPTH_TEST); else glDisable(GL_DEPTH_TEST);
|
||||||
|
if (last_enable_stencil_test) glEnable(GL_STENCIL_TEST); else glDisable(GL_STENCIL_TEST);
|
||||||
|
if (last_enable_scissor_test) glEnable(GL_SCISSOR_TEST); else glDisable(GL_SCISSOR_TEST);
|
||||||
|
#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_PRIMITIVE_RESTART
|
||||||
|
if (g_GlVersion >= 310) { if (last_enable_primitive_restart) glEnable(GL_PRIMITIVE_RESTART); else glDisable(GL_PRIMITIVE_RESTART); }
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef GL_POLYGON_MODE
|
||||||
|
glPolygonMode(GL_FRONT_AND_BACK, (GLenum)last_polygon_mode[0]);
|
||||||
|
#endif
|
||||||
|
glViewport(last_viewport[0], last_viewport[1], (GLsizei)last_viewport[2], (GLsizei)last_viewport[3]);
|
||||||
|
glScissor(last_scissor_box[0], last_scissor_box[1], (GLsizei)last_scissor_box[2], (GLsizei)last_scissor_box[3]);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ImGui_ImplOpenGL3_CreateFontsTexture()
|
||||||
|
{
|
||||||
|
// Build texture atlas
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
unsigned char* pixels;
|
||||||
|
int width, height;
|
||||||
|
io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); // Load as RGBA 32-bit (75% of the memory is wasted, but default font is so small) because it is more likely to be compatible with user's existing shaders. If your ImTextureId represent a higher-level concept than just a GL texture id, consider calling GetTexDataAsAlpha8() instead to save on GPU memory.
|
||||||
|
|
||||||
|
// Upload texture to graphics system
|
||||||
|
GLint last_texture;
|
||||||
|
glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture);
|
||||||
|
glGenTextures(1, &g_FontTexture);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, g_FontTexture);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||||
|
#ifdef GL_UNPACK_ROW_LENGTH
|
||||||
|
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
|
||||||
|
#endif
|
||||||
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
|
||||||
|
|
||||||
|
// Store our identifier
|
||||||
|
io.Fonts->SetTexID((ImTextureID)(intptr_t)g_FontTexture);
|
||||||
|
|
||||||
|
// Restore state
|
||||||
|
glBindTexture(GL_TEXTURE_2D, last_texture);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGui_ImplOpenGL3_DestroyFontsTexture()
|
||||||
|
{
|
||||||
|
if (g_FontTexture)
|
||||||
|
{
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
glDeleteTextures(1, &g_FontTexture);
|
||||||
|
io.Fonts->SetTexID(0);
|
||||||
|
g_FontTexture = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If you get an error please report on github. You may try different GL context version or GLSL version. See GL<>GLSL version table at the top of this file.
|
||||||
|
static bool CheckShader(GLuint handle, const char* desc)
|
||||||
|
{
|
||||||
|
GLint status = 0, log_length = 0;
|
||||||
|
glGetShaderiv(handle, GL_COMPILE_STATUS, &status);
|
||||||
|
glGetShaderiv(handle, GL_INFO_LOG_LENGTH, &log_length);
|
||||||
|
if ((GLboolean)status == GL_FALSE)
|
||||||
|
fprintf(stderr, "ERROR: ImGui_ImplOpenGL3_CreateDeviceObjects: failed to compile %s!\n", desc);
|
||||||
|
if (log_length > 1)
|
||||||
|
{
|
||||||
|
ImVector<char> buf;
|
||||||
|
buf.resize((int)(log_length + 1));
|
||||||
|
glGetShaderInfoLog(handle, log_length, NULL, (GLchar*)buf.begin());
|
||||||
|
fprintf(stderr, "%s\n", buf.begin());
|
||||||
|
}
|
||||||
|
return (GLboolean)status == GL_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If you get an error please report on GitHub. You may try different GL context version or GLSL version.
|
||||||
|
static bool CheckProgram(GLuint handle, const char* desc)
|
||||||
|
{
|
||||||
|
GLint status = 0, log_length = 0;
|
||||||
|
glGetProgramiv(handle, GL_LINK_STATUS, &status);
|
||||||
|
glGetProgramiv(handle, GL_INFO_LOG_LENGTH, &log_length);
|
||||||
|
if ((GLboolean)status == GL_FALSE)
|
||||||
|
fprintf(stderr, "ERROR: ImGui_ImplOpenGL3_CreateDeviceObjects: failed to link %s! (with GLSL '%s')\n", desc, g_GlslVersionString);
|
||||||
|
if (log_length > 1)
|
||||||
|
{
|
||||||
|
ImVector<char> buf;
|
||||||
|
buf.resize((int)(log_length + 1));
|
||||||
|
glGetProgramInfoLog(handle, log_length, NULL, (GLchar*)buf.begin());
|
||||||
|
fprintf(stderr, "%s\n", buf.begin());
|
||||||
|
}
|
||||||
|
return (GLboolean)status == GL_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ImGui_ImplOpenGL3_CreateDeviceObjects()
|
||||||
|
{
|
||||||
|
// Backup GL state
|
||||||
|
GLint last_texture, last_array_buffer;
|
||||||
|
glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture);
|
||||||
|
glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &last_array_buffer);
|
||||||
|
#ifndef IMGUI_IMPL_OPENGL_ES2
|
||||||
|
GLint last_vertex_array;
|
||||||
|
glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &last_vertex_array);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Parse GLSL version string
|
||||||
|
int glsl_version = 130;
|
||||||
|
sscanf(g_GlslVersionString, "#version %d", &glsl_version);
|
||||||
|
|
||||||
|
const GLchar* vertex_shader_glsl_120 =
|
||||||
|
"uniform mat4 ProjMtx;\n"
|
||||||
|
"attribute vec2 Position;\n"
|
||||||
|
"attribute vec2 UV;\n"
|
||||||
|
"attribute vec4 Color;\n"
|
||||||
|
"varying vec2 Frag_UV;\n"
|
||||||
|
"varying vec4 Frag_Color;\n"
|
||||||
|
"void main()\n"
|
||||||
|
"{\n"
|
||||||
|
" Frag_UV = UV;\n"
|
||||||
|
" Frag_Color = Color;\n"
|
||||||
|
" gl_Position = ProjMtx * vec4(Position.xy,0,1);\n"
|
||||||
|
"}\n";
|
||||||
|
|
||||||
|
const GLchar* vertex_shader_glsl_130 =
|
||||||
|
"uniform mat4 ProjMtx;\n"
|
||||||
|
"in vec2 Position;\n"
|
||||||
|
"in vec2 UV;\n"
|
||||||
|
"in vec4 Color;\n"
|
||||||
|
"out vec2 Frag_UV;\n"
|
||||||
|
"out vec4 Frag_Color;\n"
|
||||||
|
"void main()\n"
|
||||||
|
"{\n"
|
||||||
|
" Frag_UV = UV;\n"
|
||||||
|
" Frag_Color = Color;\n"
|
||||||
|
" gl_Position = ProjMtx * vec4(Position.xy,0,1);\n"
|
||||||
|
"}\n";
|
||||||
|
|
||||||
|
const GLchar* vertex_shader_glsl_300_es =
|
||||||
|
"precision mediump float;\n"
|
||||||
|
"layout (location = 0) in vec2 Position;\n"
|
||||||
|
"layout (location = 1) in vec2 UV;\n"
|
||||||
|
"layout (location = 2) in vec4 Color;\n"
|
||||||
|
"uniform mat4 ProjMtx;\n"
|
||||||
|
"out vec2 Frag_UV;\n"
|
||||||
|
"out vec4 Frag_Color;\n"
|
||||||
|
"void main()\n"
|
||||||
|
"{\n"
|
||||||
|
" Frag_UV = UV;\n"
|
||||||
|
" Frag_Color = Color;\n"
|
||||||
|
" gl_Position = ProjMtx * vec4(Position.xy,0,1);\n"
|
||||||
|
"}\n";
|
||||||
|
|
||||||
|
const GLchar* vertex_shader_glsl_410_core =
|
||||||
|
"layout (location = 0) in vec2 Position;\n"
|
||||||
|
"layout (location = 1) in vec2 UV;\n"
|
||||||
|
"layout (location = 2) in vec4 Color;\n"
|
||||||
|
"uniform mat4 ProjMtx;\n"
|
||||||
|
"out vec2 Frag_UV;\n"
|
||||||
|
"out vec4 Frag_Color;\n"
|
||||||
|
"void main()\n"
|
||||||
|
"{\n"
|
||||||
|
" Frag_UV = UV;\n"
|
||||||
|
" Frag_Color = Color;\n"
|
||||||
|
" gl_Position = ProjMtx * vec4(Position.xy,0,1);\n"
|
||||||
|
"}\n";
|
||||||
|
|
||||||
|
const GLchar* fragment_shader_glsl_120 =
|
||||||
|
"#ifdef GL_ES\n"
|
||||||
|
" precision mediump float;\n"
|
||||||
|
"#endif\n"
|
||||||
|
"uniform sampler2D Texture;\n"
|
||||||
|
"varying vec2 Frag_UV;\n"
|
||||||
|
"varying vec4 Frag_Color;\n"
|
||||||
|
"void main()\n"
|
||||||
|
"{\n"
|
||||||
|
" gl_FragColor = Frag_Color * texture2D(Texture, Frag_UV.st);\n"
|
||||||
|
"}\n";
|
||||||
|
|
||||||
|
const GLchar* fragment_shader_glsl_130 =
|
||||||
|
"uniform sampler2D Texture;\n"
|
||||||
|
"in vec2 Frag_UV;\n"
|
||||||
|
"in vec4 Frag_Color;\n"
|
||||||
|
"out vec4 Out_Color;\n"
|
||||||
|
"void main()\n"
|
||||||
|
"{\n"
|
||||||
|
" Out_Color = Frag_Color * texture(Texture, Frag_UV.st);\n"
|
||||||
|
"}\n";
|
||||||
|
|
||||||
|
const GLchar* fragment_shader_glsl_300_es =
|
||||||
|
"precision mediump float;\n"
|
||||||
|
"uniform sampler2D Texture;\n"
|
||||||
|
"in vec2 Frag_UV;\n"
|
||||||
|
"in vec4 Frag_Color;\n"
|
||||||
|
"layout (location = 0) out vec4 Out_Color;\n"
|
||||||
|
"void main()\n"
|
||||||
|
"{\n"
|
||||||
|
" Out_Color = Frag_Color * texture(Texture, Frag_UV.st);\n"
|
||||||
|
"}\n";
|
||||||
|
|
||||||
|
const GLchar* fragment_shader_glsl_410_core =
|
||||||
|
"in vec2 Frag_UV;\n"
|
||||||
|
"in vec4 Frag_Color;\n"
|
||||||
|
"uniform sampler2D Texture;\n"
|
||||||
|
"layout (location = 0) out vec4 Out_Color;\n"
|
||||||
|
"void main()\n"
|
||||||
|
"{\n"
|
||||||
|
" Out_Color = Frag_Color * texture(Texture, Frag_UV.st);\n"
|
||||||
|
"}\n";
|
||||||
|
|
||||||
|
// Select shaders matching our GLSL versions
|
||||||
|
const GLchar* vertex_shader = NULL;
|
||||||
|
const GLchar* fragment_shader = NULL;
|
||||||
|
if (glsl_version < 130)
|
||||||
|
{
|
||||||
|
vertex_shader = vertex_shader_glsl_120;
|
||||||
|
fragment_shader = fragment_shader_glsl_120;
|
||||||
|
}
|
||||||
|
else if (glsl_version >= 410)
|
||||||
|
{
|
||||||
|
vertex_shader = vertex_shader_glsl_410_core;
|
||||||
|
fragment_shader = fragment_shader_glsl_410_core;
|
||||||
|
}
|
||||||
|
else if (glsl_version == 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create shaders
|
||||||
|
const GLchar* vertex_shader_with_version[2] = { g_GlslVersionString, vertex_shader };
|
||||||
|
g_VertHandle = glCreateShader(GL_VERTEX_SHADER);
|
||||||
|
glShaderSource(g_VertHandle, 2, vertex_shader_with_version, NULL);
|
||||||
|
glCompileShader(g_VertHandle);
|
||||||
|
CheckShader(g_VertHandle, "vertex shader");
|
||||||
|
|
||||||
|
const GLchar* fragment_shader_with_version[2] = { g_GlslVersionString, fragment_shader };
|
||||||
|
g_FragHandle = glCreateShader(GL_FRAGMENT_SHADER);
|
||||||
|
glShaderSource(g_FragHandle, 2, fragment_shader_with_version, NULL);
|
||||||
|
glCompileShader(g_FragHandle);
|
||||||
|
CheckShader(g_FragHandle, "fragment shader");
|
||||||
|
|
||||||
|
g_ShaderHandle = glCreateProgram();
|
||||||
|
glAttachShader(g_ShaderHandle, g_VertHandle);
|
||||||
|
glAttachShader(g_ShaderHandle, g_FragHandle);
|
||||||
|
glLinkProgram(g_ShaderHandle);
|
||||||
|
CheckProgram(g_ShaderHandle, "shader program");
|
||||||
|
|
||||||
|
g_AttribLocationTex = glGetUniformLocation(g_ShaderHandle, "Texture");
|
||||||
|
g_AttribLocationProjMtx = glGetUniformLocation(g_ShaderHandle, "ProjMtx");
|
||||||
|
g_AttribLocationVtxPos = (GLuint)glGetAttribLocation(g_ShaderHandle, "Position");
|
||||||
|
g_AttribLocationVtxUV = (GLuint)glGetAttribLocation(g_ShaderHandle, "UV");
|
||||||
|
g_AttribLocationVtxColor = (GLuint)glGetAttribLocation(g_ShaderHandle, "Color");
|
||||||
|
|
||||||
|
// Create buffers
|
||||||
|
glGenBuffers(1, &g_VboHandle);
|
||||||
|
glGenBuffers(1, &g_ElementsHandle);
|
||||||
|
|
||||||
|
ImGui_ImplOpenGL3_CreateFontsTexture();
|
||||||
|
|
||||||
|
// Restore modified GL state
|
||||||
|
glBindTexture(GL_TEXTURE_2D, last_texture);
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, last_array_buffer);
|
||||||
|
#ifndef IMGUI_IMPL_OPENGL_ES2
|
||||||
|
glBindVertexArray(last_vertex_array);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGui_ImplOpenGL3_DestroyDeviceObjects()
|
||||||
|
{
|
||||||
|
if (g_VboHandle) { glDeleteBuffers(1, &g_VboHandle); g_VboHandle = 0; }
|
||||||
|
if (g_ElementsHandle) { glDeleteBuffers(1, &g_ElementsHandle); g_ElementsHandle = 0; }
|
||||||
|
if (g_ShaderHandle && g_VertHandle) { glDetachShader(g_ShaderHandle, g_VertHandle); }
|
||||||
|
if (g_ShaderHandle && g_FragHandle) { glDetachShader(g_ShaderHandle, g_FragHandle); }
|
||||||
|
if (g_VertHandle) { glDeleteShader(g_VertHandle); g_VertHandle = 0; }
|
||||||
|
if (g_FragHandle) { glDeleteShader(g_FragHandle); g_FragHandle = 0; }
|
||||||
|
if (g_ShaderHandle) { glDeleteProgram(g_ShaderHandle); g_ShaderHandle = 0; }
|
||||||
|
|
||||||
|
ImGui_ImplOpenGL3_DestroyFontsTexture();
|
||||||
|
}
|
87
backend/imgui_impl_opengl3.h
Normal file
87
backend/imgui_impl_opengl3.h
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
// dear imgui: Renderer Backend for modern OpenGL with shaders / programmatic pipeline
|
||||||
|
// - Desktop GL: 2.x 3.x 4.x
|
||||||
|
// - Embedded GL: ES 2.0 (WebGL 1.0), ES 3.0 (WebGL 2.0)
|
||||||
|
// This needs to be used along with a Platform Backend (e.g. GLFW, SDL, Win32, custom..)
|
||||||
|
|
||||||
|
// Implemented features:
|
||||||
|
// [X] Renderer: User texture binding. Use 'GLuint' OpenGL texture identifier as void*/ImTextureID. Read the FAQ about ImTextureID!
|
||||||
|
// [x] Renderer: Desktop GL only: Support for large meshes (64k+ vertices) with 16-bit indices.
|
||||||
|
|
||||||
|
// You can copy and use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
||||||
|
// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
|
||||||
|
// Read online: https://github.com/ocornut/imgui/tree/master/docs
|
||||||
|
|
||||||
|
// About Desktop OpenGL function loaders:
|
||||||
|
// Modern Desktop OpenGL doesn't have a standard portable header file to load OpenGL function pointers.
|
||||||
|
// Helper libraries are often used for this purpose! Here we are supporting a few common ones (gl3w, glew, glad).
|
||||||
|
// You may use another loader/header of your choice (glext, glLoadGen, etc.), or chose to manually implement your own.
|
||||||
|
|
||||||
|
// About GLSL version:
|
||||||
|
// The 'glsl_version' initialization parameter should be NULL (default) or a "#version XXX" string.
|
||||||
|
// On computer platform the GLSL version default to "#version 130". On OpenGL ES 3 platform it defaults to "#version 300 es"
|
||||||
|
// Only override if your GL version doesn't handle this GLSL version. See GLSL version table at the top of imgui_impl_opengl3.cpp.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include "imgui.h" // IMGUI_IMPL_API
|
||||||
|
|
||||||
|
// Backend API
|
||||||
|
IMGUI_IMPL_API bool ImGui_ImplOpenGL3_Init(const char* glsl_version = NULL);
|
||||||
|
IMGUI_IMPL_API void ImGui_ImplOpenGL3_Shutdown();
|
||||||
|
IMGUI_IMPL_API void ImGui_ImplOpenGL3_NewFrame();
|
||||||
|
IMGUI_IMPL_API void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data);
|
||||||
|
|
||||||
|
// (Optional) Called by Init/NewFrame/Shutdown
|
||||||
|
IMGUI_IMPL_API bool ImGui_ImplOpenGL3_CreateFontsTexture();
|
||||||
|
IMGUI_IMPL_API void ImGui_ImplOpenGL3_DestroyFontsTexture();
|
||||||
|
IMGUI_IMPL_API bool ImGui_ImplOpenGL3_CreateDeviceObjects();
|
||||||
|
IMGUI_IMPL_API void ImGui_ImplOpenGL3_DestroyDeviceObjects();
|
||||||
|
|
||||||
|
// Specific OpenGL ES versions
|
||||||
|
//#define IMGUI_IMPL_OPENGL_ES2 // Auto-detected on Emscripten
|
||||||
|
//#define IMGUI_IMPL_OPENGL_ES3 // Auto-detected on iOS/Android
|
||||||
|
|
||||||
|
// Attempt to auto-detect the default Desktop GL loader based on available header files.
|
||||||
|
// If auto-detection fails or doesn't select the same GL loader file as used by your application,
|
||||||
|
// you are likely to get a crash in ImGui_ImplOpenGL3_Init().
|
||||||
|
// You can explicitly select a loader by using one of the '#define IMGUI_IMPL_OPENGL_LOADER_XXX' in imconfig.h or compiler command-line.
|
||||||
|
#if !defined(IMGUI_IMPL_OPENGL_ES2) \
|
||||||
|
&& !defined(IMGUI_IMPL_OPENGL_ES3) \
|
||||||
|
&& !defined(IMGUI_IMPL_OPENGL_LOADER_GL3W) \
|
||||||
|
&& !defined(IMGUI_IMPL_OPENGL_LOADER_GLEW) \
|
||||||
|
&& !defined(IMGUI_IMPL_OPENGL_LOADER_GLAD) \
|
||||||
|
&& !defined(IMGUI_IMPL_OPENGL_LOADER_GLAD2) \
|
||||||
|
&& !defined(IMGUI_IMPL_OPENGL_LOADER_GLBINDING2) \
|
||||||
|
&& !defined(IMGUI_IMPL_OPENGL_LOADER_GLBINDING3) \
|
||||||
|
&& !defined(IMGUI_IMPL_OPENGL_LOADER_CUSTOM)
|
||||||
|
|
||||||
|
// Try to detect GLES on matching platforms
|
||||||
|
#if defined(__APPLE__)
|
||||||
|
#include "TargetConditionals.h"
|
||||||
|
#endif
|
||||||
|
#if (defined(__APPLE__) && (TARGET_OS_IOS || TARGET_OS_TV)) || (defined(__ANDROID__))
|
||||||
|
#define IMGUI_IMPL_OPENGL_ES3 // iOS, Android -> GL ES 3, "#version 300 es"
|
||||||
|
#elif defined(__EMSCRIPTEN__)
|
||||||
|
#define IMGUI_IMPL_OPENGL_ES2 // Emscripten -> GL ES 2, "#version 100"
|
||||||
|
|
||||||
|
// Otherwise try to detect supported Desktop OpenGL loaders..
|
||||||
|
#elif defined(__has_include)
|
||||||
|
#if __has_include(<GL/glew.h>)
|
||||||
|
#define IMGUI_IMPL_OPENGL_LOADER_GLEW
|
||||||
|
#elif __has_include(<glad/glad.h>)
|
||||||
|
#define IMGUI_IMPL_OPENGL_LOADER_GLAD
|
||||||
|
#elif __has_include(<glad/gl.h>)
|
||||||
|
#define IMGUI_IMPL_OPENGL_LOADER_GLAD2
|
||||||
|
#elif __has_include(<GL/gl3w.h>)
|
||||||
|
#define IMGUI_IMPL_OPENGL_LOADER_GL3W
|
||||||
|
#elif __has_include(<glbinding/glbinding.h>)
|
||||||
|
#define IMGUI_IMPL_OPENGL_LOADER_GLBINDING3
|
||||||
|
#elif __has_include(<glbinding/Binding.h>)
|
||||||
|
#define IMGUI_IMPL_OPENGL_LOADER_GLBINDING2
|
||||||
|
#else
|
||||||
|
#error "Cannot detect OpenGL loader!"
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
#define IMGUI_IMPL_OPENGL_LOADER_GL3W // Default to GL3W embedded in our repository
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
23
backend/imgui_impl_osx.h
Normal file
23
backend/imgui_impl_osx.h
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
// dear imgui: Platform Backend for OSX / Cocoa
|
||||||
|
// This needs to be used along with a Renderer (e.g. OpenGL2, OpenGL3, Vulkan, Metal..)
|
||||||
|
// [ALPHA] Early backend, not well tested. If you want a portable application, prefer using the GLFW or SDL platform Backends on Mac.
|
||||||
|
|
||||||
|
// Implemented features:
|
||||||
|
// [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'.
|
||||||
|
// [X] Platform: OSX clipboard is supported within core Dear ImGui (no specific code in this backend).
|
||||||
|
// Issues:
|
||||||
|
// [ ] Platform: Keys are all generally very broken. Best using [event keycode] and not [event characters]..
|
||||||
|
|
||||||
|
// You can copy and use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
||||||
|
// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
|
||||||
|
// Read online: https://github.com/ocornut/imgui/tree/master/docs
|
||||||
|
|
||||||
|
#include "imgui.h" // IMGUI_IMPL_API
|
||||||
|
|
||||||
|
@class NSEvent;
|
||||||
|
@class NSView;
|
||||||
|
|
||||||
|
IMGUI_IMPL_API bool ImGui_ImplOSX_Init();
|
||||||
|
IMGUI_IMPL_API void ImGui_ImplOSX_Shutdown();
|
||||||
|
IMGUI_IMPL_API void ImGui_ImplOSX_NewFrame(NSView* _Nullable view);
|
||||||
|
IMGUI_IMPL_API bool ImGui_ImplOSX_HandleEvent(NSEvent* _Nonnull event, NSView* _Nullable view);
|
323
backend/imgui_impl_osx.mm
Normal file
323
backend/imgui_impl_osx.mm
Normal file
@ -0,0 +1,323 @@
|
|||||||
|
// dear imgui: Platform Backend for OSX / Cocoa
|
||||||
|
// This needs to be used along with a Renderer (e.g. OpenGL2, OpenGL3, Vulkan, Metal..)
|
||||||
|
// [ALPHA] Early backend, not well tested. If you want a portable application, prefer using the GLFW or SDL platform Backends on Mac.
|
||||||
|
|
||||||
|
// Implemented features:
|
||||||
|
// [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'.
|
||||||
|
// [X] Platform: OSX clipboard is supported within core Dear ImGui (no specific code in this backend).
|
||||||
|
// Issues:
|
||||||
|
// [ ] Platform: Keys are all generally very broken. Best using [event keycode] and not [event characters]..
|
||||||
|
|
||||||
|
// You can copy and use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
||||||
|
// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
|
||||||
|
// Read online: https://github.com/ocornut/imgui/tree/master/docs
|
||||||
|
|
||||||
|
#include "imgui.h"
|
||||||
|
#include "imgui_impl_osx.h"
|
||||||
|
#import <Cocoa/Cocoa.h>
|
||||||
|
|
||||||
|
// CHANGELOG
|
||||||
|
// (minor and older changes stripped away, please see git history for details)
|
||||||
|
// 2021-01-27: Inputs: Added a fix for mouse position not being reported when mouse buttons other than left one are down.
|
||||||
|
// 2020-10-28: Inputs: Added a fix for handling keypad-enter key.
|
||||||
|
// 2020-05-25: Inputs: Added a fix for missing trackpad clicks when done with "soft tap".
|
||||||
|
// 2019-12-05: Inputs: Added support for ImGuiMouseCursor_NotAllowed mouse cursor.
|
||||||
|
// 2019-10-11: Inputs: Fix using Backspace key.
|
||||||
|
// 2019-07-21: Re-added clipboard handlers as they are not enabled by default in core imgui.cpp (reverted 2019-05-18 change).
|
||||||
|
// 2019-05-28: Inputs: Added mouse cursor shape and visibility support.
|
||||||
|
// 2019-05-18: Misc: Removed clipboard handlers as they are now supported by core imgui.cpp.
|
||||||
|
// 2019-05-11: Inputs: Don't filter character values before calling AddInputCharacter() apart from 0xF700..0xFFFF range.
|
||||||
|
// 2018-11-30: Misc: Setting up io.BackendPlatformName so it can be displayed in the About Window.
|
||||||
|
// 2018-07-07: Initial version.
|
||||||
|
|
||||||
|
// Data
|
||||||
|
static CFAbsoluteTime g_Time = 0.0;
|
||||||
|
static NSCursor* g_MouseCursors[ImGuiMouseCursor_COUNT] = {};
|
||||||
|
static bool g_MouseCursorHidden = false;
|
||||||
|
static bool g_MouseJustPressed[ImGuiMouseButton_COUNT] = {};
|
||||||
|
static bool g_MouseDown[ImGuiMouseButton_COUNT] = {};
|
||||||
|
|
||||||
|
// Undocumented methods for creating cursors.
|
||||||
|
@interface NSCursor()
|
||||||
|
+ (id)_windowResizeNorthWestSouthEastCursor;
|
||||||
|
+ (id)_windowResizeNorthEastSouthWestCursor;
|
||||||
|
+ (id)_windowResizeNorthSouthCursor;
|
||||||
|
+ (id)_windowResizeEastWestCursor;
|
||||||
|
@end
|
||||||
|
|
||||||
|
// Functions
|
||||||
|
bool ImGui_ImplOSX_Init()
|
||||||
|
{
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
|
||||||
|
// Setup backend capabilities flags
|
||||||
|
io.BackendFlags |= ImGuiBackendFlags_HasMouseCursors; // We can honor GetMouseCursor() values (optional)
|
||||||
|
//io.BackendFlags |= ImGuiBackendFlags_HasSetMousePos; // We can honor io.WantSetMousePos requests (optional, rarely used)
|
||||||
|
//io.BackendFlags |= ImGuiBackendFlags_PlatformHasViewports; // We can create multi-viewports on the Platform side (optional)
|
||||||
|
//io.BackendFlags |= ImGuiBackendFlags_HasMouseHoveredViewport; // We can set io.MouseHoveredViewport correctly (optional, not easy)
|
||||||
|
io.BackendPlatformName = "imgui_impl_osx";
|
||||||
|
|
||||||
|
// Keyboard mapping. Dear ImGui will use those indices to peek into the io.KeyDown[] array.
|
||||||
|
const int offset_for_function_keys = 256 - 0xF700;
|
||||||
|
io.KeyMap[ImGuiKey_Tab] = '\t';
|
||||||
|
io.KeyMap[ImGuiKey_LeftArrow] = NSLeftArrowFunctionKey + offset_for_function_keys;
|
||||||
|
io.KeyMap[ImGuiKey_RightArrow] = NSRightArrowFunctionKey + offset_for_function_keys;
|
||||||
|
io.KeyMap[ImGuiKey_UpArrow] = NSUpArrowFunctionKey + offset_for_function_keys;
|
||||||
|
io.KeyMap[ImGuiKey_DownArrow] = NSDownArrowFunctionKey + offset_for_function_keys;
|
||||||
|
io.KeyMap[ImGuiKey_PageUp] = NSPageUpFunctionKey + offset_for_function_keys;
|
||||||
|
io.KeyMap[ImGuiKey_PageDown] = NSPageDownFunctionKey + offset_for_function_keys;
|
||||||
|
io.KeyMap[ImGuiKey_Home] = NSHomeFunctionKey + offset_for_function_keys;
|
||||||
|
io.KeyMap[ImGuiKey_End] = NSEndFunctionKey + offset_for_function_keys;
|
||||||
|
io.KeyMap[ImGuiKey_Insert] = NSInsertFunctionKey + offset_for_function_keys;
|
||||||
|
io.KeyMap[ImGuiKey_Delete] = NSDeleteFunctionKey + offset_for_function_keys;
|
||||||
|
io.KeyMap[ImGuiKey_Backspace] = 127;
|
||||||
|
io.KeyMap[ImGuiKey_Space] = 32;
|
||||||
|
io.KeyMap[ImGuiKey_Enter] = 13;
|
||||||
|
io.KeyMap[ImGuiKey_Escape] = 27;
|
||||||
|
io.KeyMap[ImGuiKey_KeyPadEnter] = 3;
|
||||||
|
io.KeyMap[ImGuiKey_A] = 'A';
|
||||||
|
io.KeyMap[ImGuiKey_C] = 'C';
|
||||||
|
io.KeyMap[ImGuiKey_V] = 'V';
|
||||||
|
io.KeyMap[ImGuiKey_X] = 'X';
|
||||||
|
io.KeyMap[ImGuiKey_Y] = 'Y';
|
||||||
|
io.KeyMap[ImGuiKey_Z] = 'Z';
|
||||||
|
|
||||||
|
// Load cursors. Some of them are undocumented.
|
||||||
|
g_MouseCursorHidden = false;
|
||||||
|
g_MouseCursors[ImGuiMouseCursor_Arrow] = [NSCursor arrowCursor];
|
||||||
|
g_MouseCursors[ImGuiMouseCursor_TextInput] = [NSCursor IBeamCursor];
|
||||||
|
g_MouseCursors[ImGuiMouseCursor_ResizeAll] = [NSCursor closedHandCursor];
|
||||||
|
g_MouseCursors[ImGuiMouseCursor_Hand] = [NSCursor pointingHandCursor];
|
||||||
|
g_MouseCursors[ImGuiMouseCursor_NotAllowed] = [NSCursor operationNotAllowedCursor];
|
||||||
|
g_MouseCursors[ImGuiMouseCursor_ResizeNS] = [NSCursor respondsToSelector:@selector(_windowResizeNorthSouthCursor)] ? [NSCursor _windowResizeNorthSouthCursor] : [NSCursor resizeUpDownCursor];
|
||||||
|
g_MouseCursors[ImGuiMouseCursor_ResizeEW] = [NSCursor respondsToSelector:@selector(_windowResizeEastWestCursor)] ? [NSCursor _windowResizeEastWestCursor] : [NSCursor resizeLeftRightCursor];
|
||||||
|
g_MouseCursors[ImGuiMouseCursor_ResizeNESW] = [NSCursor respondsToSelector:@selector(_windowResizeNorthEastSouthWestCursor)] ? [NSCursor _windowResizeNorthEastSouthWestCursor] : [NSCursor closedHandCursor];
|
||||||
|
g_MouseCursors[ImGuiMouseCursor_ResizeNWSE] = [NSCursor respondsToSelector:@selector(_windowResizeNorthWestSouthEastCursor)] ? [NSCursor _windowResizeNorthWestSouthEastCursor] : [NSCursor closedHandCursor];
|
||||||
|
|
||||||
|
// Note that imgui.cpp also include default OSX clipboard handlers which can be enabled
|
||||||
|
// by adding '#define IMGUI_ENABLE_OSX_DEFAULT_CLIPBOARD_FUNCTIONS' in imconfig.h and adding '-framework ApplicationServices' to your linker command-line.
|
||||||
|
// Since we are already in ObjC land here, it is easy for us to add a clipboard handler using the NSPasteboard api.
|
||||||
|
io.SetClipboardTextFn = [](void*, const char* str) -> void
|
||||||
|
{
|
||||||
|
NSPasteboard* pasteboard = [NSPasteboard generalPasteboard];
|
||||||
|
[pasteboard declareTypes:[NSArray arrayWithObject:NSPasteboardTypeString] owner:nil];
|
||||||
|
[pasteboard setString:[NSString stringWithUTF8String:str] forType:NSPasteboardTypeString];
|
||||||
|
};
|
||||||
|
|
||||||
|
io.GetClipboardTextFn = [](void*) -> const char*
|
||||||
|
{
|
||||||
|
NSPasteboard* pasteboard = [NSPasteboard generalPasteboard];
|
||||||
|
NSString* available = [pasteboard availableTypeFromArray: [NSArray arrayWithObject:NSPasteboardTypeString]];
|
||||||
|
if (![available isEqualToString:NSPasteboardTypeString])
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
NSString* string = [pasteboard stringForType:NSPasteboardTypeString];
|
||||||
|
if (string == nil)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
const char* string_c = (const char*)[string UTF8String];
|
||||||
|
size_t string_len = strlen(string_c);
|
||||||
|
static ImVector<char> s_clipboard;
|
||||||
|
s_clipboard.resize((int)string_len + 1);
|
||||||
|
strcpy(s_clipboard.Data, string_c);
|
||||||
|
return s_clipboard.Data;
|
||||||
|
};
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGui_ImplOSX_Shutdown()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ImGui_ImplOSX_UpdateMouseCursorAndButtons()
|
||||||
|
{
|
||||||
|
// Update buttons
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
for (int i = 0; i < IM_ARRAYSIZE(io.MouseDown); i++)
|
||||||
|
{
|
||||||
|
// If a mouse press event came, always pass it as "mouse held this frame", so we don't miss click-release events that are shorter than 1 frame.
|
||||||
|
io.MouseDown[i] = g_MouseJustPressed[i] || g_MouseDown[i];
|
||||||
|
g_MouseJustPressed[i] = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (io.ConfigFlags & ImGuiConfigFlags_NoMouseCursorChange)
|
||||||
|
return;
|
||||||
|
|
||||||
|
ImGuiMouseCursor imgui_cursor = ImGui::GetMouseCursor();
|
||||||
|
if (io.MouseDrawCursor || imgui_cursor == ImGuiMouseCursor_None)
|
||||||
|
{
|
||||||
|
// Hide OS mouse cursor if imgui is drawing it or if it wants no cursor
|
||||||
|
if (!g_MouseCursorHidden)
|
||||||
|
{
|
||||||
|
g_MouseCursorHidden = true;
|
||||||
|
[NSCursor hide];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Show OS mouse cursor
|
||||||
|
[g_MouseCursors[g_MouseCursors[imgui_cursor] ? imgui_cursor : ImGuiMouseCursor_Arrow] set];
|
||||||
|
if (g_MouseCursorHidden)
|
||||||
|
{
|
||||||
|
g_MouseCursorHidden = false;
|
||||||
|
[NSCursor unhide];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGui_ImplOSX_NewFrame(NSView* view)
|
||||||
|
{
|
||||||
|
// Setup display size
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
if (view)
|
||||||
|
{
|
||||||
|
const float dpi = (float)[view.window backingScaleFactor];
|
||||||
|
io.DisplaySize = ImVec2((float)view.bounds.size.width, (float)view.bounds.size.height);
|
||||||
|
io.DisplayFramebufferScale = ImVec2(dpi, dpi);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Setup time step
|
||||||
|
if (g_Time == 0.0)
|
||||||
|
g_Time = CFAbsoluteTimeGetCurrent();
|
||||||
|
CFAbsoluteTime current_time = CFAbsoluteTimeGetCurrent();
|
||||||
|
io.DeltaTime = (float)(current_time - g_Time);
|
||||||
|
g_Time = current_time;
|
||||||
|
|
||||||
|
ImGui_ImplOSX_UpdateMouseCursorAndButtons();
|
||||||
|
}
|
||||||
|
|
||||||
|
static int mapCharacterToKey(int c)
|
||||||
|
{
|
||||||
|
if (c >= 'a' && c <= 'z')
|
||||||
|
return c - 'a' + 'A';
|
||||||
|
if (c == 25) // SHIFT+TAB -> TAB
|
||||||
|
return 9;
|
||||||
|
if (c >= 0 && c < 256)
|
||||||
|
return c;
|
||||||
|
if (c >= 0xF700 && c < 0xF700 + 256)
|
||||||
|
return c - 0xF700 + 256;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void resetKeys()
|
||||||
|
{
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
for (int n = 0; n < IM_ARRAYSIZE(io.KeysDown); n++)
|
||||||
|
io.KeysDown[n] = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ImGui_ImplOSX_HandleEvent(NSEvent* event, NSView* view)
|
||||||
|
{
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
|
||||||
|
if (event.type == NSEventTypeLeftMouseDown || event.type == NSEventTypeRightMouseDown || event.type == NSEventTypeOtherMouseDown)
|
||||||
|
{
|
||||||
|
int button = (int)[event buttonNumber];
|
||||||
|
if (button >= 0 && button < IM_ARRAYSIZE(g_MouseDown))
|
||||||
|
g_MouseDown[button] = g_MouseJustPressed[button] = true;
|
||||||
|
return io.WantCaptureMouse;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event.type == NSEventTypeLeftMouseUp || event.type == NSEventTypeRightMouseUp || event.type == NSEventTypeOtherMouseUp)
|
||||||
|
{
|
||||||
|
int button = (int)[event buttonNumber];
|
||||||
|
if (button >= 0 && button < IM_ARRAYSIZE(g_MouseDown))
|
||||||
|
g_MouseDown[button] = false;
|
||||||
|
return io.WantCaptureMouse;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event.type == NSEventTypeMouseMoved || event.type == NSEventTypeLeftMouseDragged || event.type == NSEventTypeRightMouseDragged || event.type == NSEventTypeOtherMouseDragged)
|
||||||
|
{
|
||||||
|
NSPoint mousePoint = event.locationInWindow;
|
||||||
|
mousePoint = [view convertPoint:mousePoint fromView:nil];
|
||||||
|
mousePoint = NSMakePoint(mousePoint.x, view.bounds.size.height - mousePoint.y);
|
||||||
|
io.MousePos = ImVec2((float)mousePoint.x, (float)mousePoint.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event.type == NSEventTypeScrollWheel)
|
||||||
|
{
|
||||||
|
double wheel_dx = 0.0;
|
||||||
|
double wheel_dy = 0.0;
|
||||||
|
|
||||||
|
#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
|
||||||
|
if (floor(NSAppKitVersionNumber) > NSAppKitVersionNumber10_6)
|
||||||
|
{
|
||||||
|
wheel_dx = [event scrollingDeltaX];
|
||||||
|
wheel_dy = [event scrollingDeltaY];
|
||||||
|
if ([event hasPreciseScrollingDeltas])
|
||||||
|
{
|
||||||
|
wheel_dx *= 0.1;
|
||||||
|
wheel_dy *= 0.1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
#endif // MAC_OS_X_VERSION_MAX_ALLOWED
|
||||||
|
{
|
||||||
|
wheel_dx = [event deltaX];
|
||||||
|
wheel_dy = [event deltaY];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fabs(wheel_dx) > 0.0)
|
||||||
|
io.MouseWheelH += (float)wheel_dx * 0.1f;
|
||||||
|
if (fabs(wheel_dy) > 0.0)
|
||||||
|
io.MouseWheel += (float)wheel_dy * 0.1f;
|
||||||
|
return io.WantCaptureMouse;
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIXME: All the key handling is wrong and broken. Refer to GLFW's cocoa_init.mm and cocoa_window.mm.
|
||||||
|
if (event.type == NSEventTypeKeyDown)
|
||||||
|
{
|
||||||
|
NSString* str = [event characters];
|
||||||
|
NSUInteger len = [str length];
|
||||||
|
for (NSUInteger i = 0; i < len; i++)
|
||||||
|
{
|
||||||
|
int c = [str characterAtIndex:i];
|
||||||
|
if (!io.KeyCtrl && !(c >= 0xF700 && c <= 0xFFFF) && c != 127)
|
||||||
|
io.AddInputCharacter((unsigned int)c);
|
||||||
|
|
||||||
|
// We must reset in case we're pressing a sequence of special keys while keeping the command pressed
|
||||||
|
int key = mapCharacterToKey(c);
|
||||||
|
if (key != -1 && key < 256 && !io.KeyCtrl)
|
||||||
|
resetKeys();
|
||||||
|
if (key != -1)
|
||||||
|
io.KeysDown[key] = true;
|
||||||
|
}
|
||||||
|
return io.WantCaptureKeyboard;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event.type == NSEventTypeKeyUp)
|
||||||
|
{
|
||||||
|
NSString* str = [event characters];
|
||||||
|
NSUInteger len = [str length];
|
||||||
|
for (NSUInteger i = 0; i < len; i++)
|
||||||
|
{
|
||||||
|
int c = [str characterAtIndex:i];
|
||||||
|
int key = mapCharacterToKey(c);
|
||||||
|
if (key != -1)
|
||||||
|
io.KeysDown[key] = false;
|
||||||
|
}
|
||||||
|
return io.WantCaptureKeyboard;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event.type == NSEventTypeFlagsChanged)
|
||||||
|
{
|
||||||
|
unsigned int flags = [event modifierFlags] & NSEventModifierFlagDeviceIndependentFlagsMask;
|
||||||
|
|
||||||
|
bool oldKeyCtrl = io.KeyCtrl;
|
||||||
|
bool oldKeyShift = io.KeyShift;
|
||||||
|
bool oldKeyAlt = io.KeyAlt;
|
||||||
|
bool oldKeySuper = io.KeySuper;
|
||||||
|
io.KeyCtrl = flags & NSEventModifierFlagControl;
|
||||||
|
io.KeyShift = flags & NSEventModifierFlagShift;
|
||||||
|
io.KeyAlt = flags & NSEventModifierFlagOption;
|
||||||
|
io.KeySuper = flags & NSEventModifierFlagCommand;
|
||||||
|
|
||||||
|
// We must reset them as we will not receive any keyUp event if they where pressed with a modifier
|
||||||
|
if ((oldKeyShift && !io.KeyShift) || (oldKeyCtrl && !io.KeyCtrl) || (oldKeyAlt && !io.KeyAlt) || (oldKeySuper && !io.KeySuper))
|
||||||
|
resetKeys();
|
||||||
|
return io.WantCaptureKeyboard;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
377
backend/imgui_impl_sdl.cpp
Normal file
377
backend/imgui_impl_sdl.cpp
Normal file
@ -0,0 +1,377 @@
|
|||||||
|
// dear imgui: Platform Backend for SDL2
|
||||||
|
// This needs to be used along with a Renderer (e.g. DirectX11, OpenGL3, Vulkan..)
|
||||||
|
// (Info: SDL2 is a cross-platform general purpose library for handling windows, inputs, graphics context creation, etc.)
|
||||||
|
// (Requires: SDL 2.0. Prefer SDL 2.0.4+ for full feature support.)
|
||||||
|
|
||||||
|
// Implemented features:
|
||||||
|
// [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'.
|
||||||
|
// [X] Platform: Clipboard support.
|
||||||
|
// [X] Platform: Keyboard arrays indexed using SDL_SCANCODE_* codes, e.g. ImGui::IsKeyPressed(SDL_SCANCODE_SPACE).
|
||||||
|
// [X] Platform: Gamepad support. Enabled with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'.
|
||||||
|
// Missing features:
|
||||||
|
// [ ] Platform: SDL2 handling of IME under Windows appears to be broken and it explicitly disable the regular Windows IME. You can restore Windows IME by compiling SDL with SDL_DISABLE_WINDOWS_IME.
|
||||||
|
|
||||||
|
// You can copy and use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
||||||
|
// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
|
||||||
|
// Read online: https://github.com/ocornut/imgui/tree/master/docs
|
||||||
|
|
||||||
|
// CHANGELOG
|
||||||
|
// (minor and older changes stripped away, please see git history for details)
|
||||||
|
// 2021-03-22: Rework global mouse pos availability check listing supported platforms explicitly, effectively fixing mouse access on Raspberry Pi. (#2837, #3950)
|
||||||
|
// 2020-05-25: Misc: Report a zero display-size when window is minimized, to be consistent with other backends.
|
||||||
|
// 2020-02-20: Inputs: Fixed mapping for ImGuiKey_KeyPadEnter (using SDL_SCANCODE_KP_ENTER instead of SDL_SCANCODE_RETURN2).
|
||||||
|
// 2019-12-17: Inputs: On Wayland, use SDL_GetMouseState (because there is no global mouse state).
|
||||||
|
// 2019-12-05: Inputs: Added support for ImGuiMouseCursor_NotAllowed mouse cursor.
|
||||||
|
// 2019-07-21: Inputs: Added mapping for ImGuiKey_KeyPadEnter.
|
||||||
|
// 2019-04-23: Inputs: Added support for SDL_GameController (if ImGuiConfigFlags_NavEnableGamepad is set by user application).
|
||||||
|
// 2019-03-12: Misc: Preserve DisplayFramebufferScale when main window is minimized.
|
||||||
|
// 2018-12-21: Inputs: Workaround for Android/iOS which don't seem to handle focus related calls.
|
||||||
|
// 2018-11-30: Misc: Setting up io.BackendPlatformName so it can be displayed in the About Window.
|
||||||
|
// 2018-11-14: Changed the signature of ImGui_ImplSDL2_ProcessEvent() to take a 'const SDL_Event*'.
|
||||||
|
// 2018-08-01: Inputs: Workaround for Emscripten which doesn't seem to handle focus related calls.
|
||||||
|
// 2018-06-29: Inputs: Added support for the ImGuiMouseCursor_Hand cursor.
|
||||||
|
// 2018-06-08: Misc: Extracted imgui_impl_sdl.cpp/.h away from the old combined SDL2+OpenGL/Vulkan examples.
|
||||||
|
// 2018-06-08: Misc: ImGui_ImplSDL2_InitForOpenGL() now takes a SDL_GLContext parameter.
|
||||||
|
// 2018-05-09: Misc: Fixed clipboard paste memory leak (we didn't call SDL_FreeMemory on the data returned by SDL_GetClipboardText).
|
||||||
|
// 2018-03-20: Misc: Setup io.BackendFlags ImGuiBackendFlags_HasMouseCursors flag + honor ImGuiConfigFlags_NoMouseCursorChange flag.
|
||||||
|
// 2018-02-16: Inputs: Added support for mouse cursors, honoring ImGui::GetMouseCursor() value.
|
||||||
|
// 2018-02-06: Misc: Removed call to ImGui::Shutdown() which is not available from 1.60 WIP, user needs to call CreateContext/DestroyContext themselves.
|
||||||
|
// 2018-02-06: Inputs: Added mapping for ImGuiKey_Space.
|
||||||
|
// 2018-02-05: Misc: Using SDL_GetPerformanceCounter() instead of SDL_GetTicks() to be able to handle very high framerate (1000+ FPS).
|
||||||
|
// 2018-02-05: Inputs: Keyboard mapping is using scancodes everywhere instead of a confusing mixture of keycodes and scancodes.
|
||||||
|
// 2018-01-20: Inputs: Added Horizontal Mouse Wheel support.
|
||||||
|
// 2018-01-19: Inputs: When available (SDL 2.0.4+) using SDL_CaptureMouse() to retrieve coordinates outside of client area when dragging. Otherwise (SDL 2.0.3 and before) testing for SDL_WINDOW_INPUT_FOCUS instead of SDL_WINDOW_MOUSE_FOCUS.
|
||||||
|
// 2018-01-18: Inputs: Added mapping for ImGuiKey_Insert.
|
||||||
|
// 2017-08-25: Inputs: MousePos set to -FLT_MAX,-FLT_MAX when mouse is unavailable/missing (instead of -1,-1).
|
||||||
|
// 2016-10-15: Misc: Added a void* user_data parameter to Clipboard function handlers.
|
||||||
|
|
||||||
|
#include "imgui.h"
|
||||||
|
#include "imgui_impl_sdl.h"
|
||||||
|
|
||||||
|
// SDL
|
||||||
|
#include <SDL.h>
|
||||||
|
#include <SDL_syswm.h>
|
||||||
|
#if defined(__APPLE__)
|
||||||
|
#include "TargetConditionals.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define SDL_HAS_CAPTURE_AND_GLOBAL_MOUSE SDL_VERSION_ATLEAST(2,0,4)
|
||||||
|
#define SDL_HAS_VULKAN SDL_VERSION_ATLEAST(2,0,6)
|
||||||
|
|
||||||
|
// Data
|
||||||
|
static SDL_Window* g_Window = NULL;
|
||||||
|
static Uint64 g_Time = 0;
|
||||||
|
static bool g_MousePressed[3] = { false, false, false };
|
||||||
|
static SDL_Cursor* g_MouseCursors[ImGuiMouseCursor_COUNT] = {};
|
||||||
|
static char* g_ClipboardTextData = NULL;
|
||||||
|
static bool g_MouseCanUseGlobalState = true;
|
||||||
|
|
||||||
|
static const char* ImGui_ImplSDL2_GetClipboardText(void*)
|
||||||
|
{
|
||||||
|
if (g_ClipboardTextData)
|
||||||
|
SDL_free(g_ClipboardTextData);
|
||||||
|
g_ClipboardTextData = SDL_GetClipboardText();
|
||||||
|
return g_ClipboardTextData;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ImGui_ImplSDL2_SetClipboardText(void*, const char* text)
|
||||||
|
{
|
||||||
|
SDL_SetClipboardText(text);
|
||||||
|
}
|
||||||
|
|
||||||
|
// You can read the io.WantCaptureMouse, io.WantCaptureKeyboard flags to tell if dear imgui wants to use your inputs.
|
||||||
|
// - When io.WantCaptureMouse is true, do not dispatch mouse input data to your main application.
|
||||||
|
// - When io.WantCaptureKeyboard is true, do not dispatch keyboard input data to your main application.
|
||||||
|
// Generally you may always pass all inputs to dear imgui, and hide them from your application based on those two flags.
|
||||||
|
// If you have multiple SDL events and some of them are not meant to be used by dear imgui, you may need to filter events based on their windowID field.
|
||||||
|
bool ImGui_ImplSDL2_ProcessEvent(const SDL_Event* event)
|
||||||
|
{
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
switch (event->type)
|
||||||
|
{
|
||||||
|
case SDL_MOUSEWHEEL:
|
||||||
|
{
|
||||||
|
if (event->wheel.x > 0) io.MouseWheelH += 1;
|
||||||
|
if (event->wheel.x < 0) io.MouseWheelH -= 1;
|
||||||
|
if (event->wheel.y > 0) io.MouseWheel += 1;
|
||||||
|
if (event->wheel.y < 0) io.MouseWheel -= 1;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
case SDL_MOUSEBUTTONDOWN:
|
||||||
|
{
|
||||||
|
if (event->button.button == SDL_BUTTON_LEFT) g_MousePressed[0] = true;
|
||||||
|
if (event->button.button == SDL_BUTTON_RIGHT) g_MousePressed[1] = true;
|
||||||
|
if (event->button.button == SDL_BUTTON_MIDDLE) g_MousePressed[2] = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
case SDL_TEXTINPUT:
|
||||||
|
{
|
||||||
|
io.AddInputCharactersUTF8(event->text.text);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
case SDL_KEYDOWN:
|
||||||
|
case SDL_KEYUP:
|
||||||
|
{
|
||||||
|
int key = event->key.keysym.scancode;
|
||||||
|
IM_ASSERT(key >= 0 && key < IM_ARRAYSIZE(io.KeysDown));
|
||||||
|
io.KeysDown[key] = (event->type == SDL_KEYDOWN);
|
||||||
|
io.KeyShift = ((SDL_GetModState() & KMOD_SHIFT) != 0);
|
||||||
|
io.KeyCtrl = ((SDL_GetModState() & KMOD_CTRL) != 0);
|
||||||
|
io.KeyAlt = ((SDL_GetModState() & KMOD_ALT) != 0);
|
||||||
|
#ifdef _WIN32
|
||||||
|
io.KeySuper = false;
|
||||||
|
#else
|
||||||
|
io.KeySuper = ((SDL_GetModState() & KMOD_GUI) != 0);
|
||||||
|
#endif
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool ImGui_ImplSDL2_Init(SDL_Window* window)
|
||||||
|
{
|
||||||
|
g_Window = window;
|
||||||
|
|
||||||
|
// Setup backend capabilities flags
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
io.BackendFlags |= ImGuiBackendFlags_HasMouseCursors; // We can honor GetMouseCursor() values (optional)
|
||||||
|
io.BackendFlags |= ImGuiBackendFlags_HasSetMousePos; // We can honor io.WantSetMousePos requests (optional, rarely used)
|
||||||
|
io.BackendPlatformName = "imgui_impl_sdl";
|
||||||
|
|
||||||
|
// Keyboard mapping. Dear ImGui will use those indices to peek into the io.KeysDown[] array.
|
||||||
|
io.KeyMap[ImGuiKey_Tab] = SDL_SCANCODE_TAB;
|
||||||
|
io.KeyMap[ImGuiKey_LeftArrow] = SDL_SCANCODE_LEFT;
|
||||||
|
io.KeyMap[ImGuiKey_RightArrow] = SDL_SCANCODE_RIGHT;
|
||||||
|
io.KeyMap[ImGuiKey_UpArrow] = SDL_SCANCODE_UP;
|
||||||
|
io.KeyMap[ImGuiKey_DownArrow] = SDL_SCANCODE_DOWN;
|
||||||
|
io.KeyMap[ImGuiKey_PageUp] = SDL_SCANCODE_PAGEUP;
|
||||||
|
io.KeyMap[ImGuiKey_PageDown] = SDL_SCANCODE_PAGEDOWN;
|
||||||
|
io.KeyMap[ImGuiKey_Home] = SDL_SCANCODE_HOME;
|
||||||
|
io.KeyMap[ImGuiKey_End] = SDL_SCANCODE_END;
|
||||||
|
io.KeyMap[ImGuiKey_Insert] = SDL_SCANCODE_INSERT;
|
||||||
|
io.KeyMap[ImGuiKey_Delete] = SDL_SCANCODE_DELETE;
|
||||||
|
io.KeyMap[ImGuiKey_Backspace] = SDL_SCANCODE_BACKSPACE;
|
||||||
|
io.KeyMap[ImGuiKey_Space] = SDL_SCANCODE_SPACE;
|
||||||
|
io.KeyMap[ImGuiKey_Enter] = SDL_SCANCODE_RETURN;
|
||||||
|
io.KeyMap[ImGuiKey_Escape] = SDL_SCANCODE_ESCAPE;
|
||||||
|
io.KeyMap[ImGuiKey_KeyPadEnter] = SDL_SCANCODE_KP_ENTER;
|
||||||
|
io.KeyMap[ImGuiKey_A] = SDL_SCANCODE_A;
|
||||||
|
io.KeyMap[ImGuiKey_C] = SDL_SCANCODE_C;
|
||||||
|
io.KeyMap[ImGuiKey_V] = SDL_SCANCODE_V;
|
||||||
|
io.KeyMap[ImGuiKey_X] = SDL_SCANCODE_X;
|
||||||
|
io.KeyMap[ImGuiKey_Y] = SDL_SCANCODE_Y;
|
||||||
|
io.KeyMap[ImGuiKey_Z] = SDL_SCANCODE_Z;
|
||||||
|
|
||||||
|
io.SetClipboardTextFn = ImGui_ImplSDL2_SetClipboardText;
|
||||||
|
io.GetClipboardTextFn = ImGui_ImplSDL2_GetClipboardText;
|
||||||
|
io.ClipboardUserData = NULL;
|
||||||
|
|
||||||
|
// Load mouse cursors
|
||||||
|
g_MouseCursors[ImGuiMouseCursor_Arrow] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_ARROW);
|
||||||
|
g_MouseCursors[ImGuiMouseCursor_TextInput] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_IBEAM);
|
||||||
|
g_MouseCursors[ImGuiMouseCursor_ResizeAll] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZEALL);
|
||||||
|
g_MouseCursors[ImGuiMouseCursor_ResizeNS] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZENS);
|
||||||
|
g_MouseCursors[ImGuiMouseCursor_ResizeEW] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZEWE);
|
||||||
|
g_MouseCursors[ImGuiMouseCursor_ResizeNESW] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZENESW);
|
||||||
|
g_MouseCursors[ImGuiMouseCursor_ResizeNWSE] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZENWSE);
|
||||||
|
g_MouseCursors[ImGuiMouseCursor_Hand] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_HAND);
|
||||||
|
g_MouseCursors[ImGuiMouseCursor_NotAllowed] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_NO);
|
||||||
|
|
||||||
|
// Check and store if we are on a SDL backend that supports global mouse position
|
||||||
|
// ("wayland" and "rpi" don't support it, but we chose to use a white-list instead of a black-list)
|
||||||
|
const char* sdl_backend = SDL_GetCurrentVideoDriver();
|
||||||
|
const char* global_mouse_whitelist[] = { "windows", "cocoa", "x11", "DIVE", "VMAN" };
|
||||||
|
g_MouseCanUseGlobalState = false;
|
||||||
|
for (int n = 0; n < IM_ARRAYSIZE(global_mouse_whitelist); n++)
|
||||||
|
if (strncmp(sdl_backend, global_mouse_whitelist[n], strlen(global_mouse_whitelist[n])) == 0)
|
||||||
|
g_MouseCanUseGlobalState = true;
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
SDL_SysWMinfo wmInfo;
|
||||||
|
SDL_VERSION(&wmInfo.version);
|
||||||
|
SDL_GetWindowWMInfo(window, &wmInfo);
|
||||||
|
io.ImeWindowHandle = wmInfo.info.win.window;
|
||||||
|
#else
|
||||||
|
(void)window;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ImGui_ImplSDL2_InitForOpenGL(SDL_Window* window, void* sdl_gl_context)
|
||||||
|
{
|
||||||
|
(void)sdl_gl_context; // Viewport branch will need this.
|
||||||
|
return ImGui_ImplSDL2_Init(window);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ImGui_ImplSDL2_InitForVulkan(SDL_Window* window)
|
||||||
|
{
|
||||||
|
#if !SDL_HAS_VULKAN
|
||||||
|
IM_ASSERT(0 && "Unsupported");
|
||||||
|
#endif
|
||||||
|
return ImGui_ImplSDL2_Init(window);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ImGui_ImplSDL2_InitForD3D(SDL_Window* window)
|
||||||
|
{
|
||||||
|
#if !defined(_WIN32)
|
||||||
|
IM_ASSERT(0 && "Unsupported");
|
||||||
|
#endif
|
||||||
|
return ImGui_ImplSDL2_Init(window);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ImGui_ImplSDL2_InitForMetal(SDL_Window* window)
|
||||||
|
{
|
||||||
|
return ImGui_ImplSDL2_Init(window);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGui_ImplSDL2_Shutdown()
|
||||||
|
{
|
||||||
|
g_Window = NULL;
|
||||||
|
|
||||||
|
// Destroy last known clipboard data
|
||||||
|
if (g_ClipboardTextData)
|
||||||
|
SDL_free(g_ClipboardTextData);
|
||||||
|
g_ClipboardTextData = NULL;
|
||||||
|
|
||||||
|
// Destroy SDL mouse cursors
|
||||||
|
for (ImGuiMouseCursor cursor_n = 0; cursor_n < ImGuiMouseCursor_COUNT; cursor_n++)
|
||||||
|
SDL_FreeCursor(g_MouseCursors[cursor_n]);
|
||||||
|
memset(g_MouseCursors, 0, sizeof(g_MouseCursors));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ImGui_ImplSDL2_UpdateMousePosAndButtons()
|
||||||
|
{
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
|
||||||
|
// Set OS mouse position if requested (rarely used, only when ImGuiConfigFlags_NavEnableSetMousePos is enabled by user)
|
||||||
|
if (io.WantSetMousePos)
|
||||||
|
SDL_WarpMouseInWindow(g_Window, (int)io.MousePos.x, (int)io.MousePos.y);
|
||||||
|
else
|
||||||
|
io.MousePos = ImVec2(-FLT_MAX, -FLT_MAX);
|
||||||
|
|
||||||
|
int mx, my;
|
||||||
|
Uint32 mouse_buttons = SDL_GetMouseState(&mx, &my);
|
||||||
|
io.MouseDown[0] = g_MousePressed[0] || (mouse_buttons & SDL_BUTTON(SDL_BUTTON_LEFT)) != 0; // If a mouse press event came, always pass it as "mouse held this frame", so we don't miss click-release events that are shorter than 1 frame.
|
||||||
|
io.MouseDown[1] = g_MousePressed[1] || (mouse_buttons & SDL_BUTTON(SDL_BUTTON_RIGHT)) != 0;
|
||||||
|
io.MouseDown[2] = g_MousePressed[2] || (mouse_buttons & SDL_BUTTON(SDL_BUTTON_MIDDLE)) != 0;
|
||||||
|
g_MousePressed[0] = g_MousePressed[1] = g_MousePressed[2] = false;
|
||||||
|
|
||||||
|
#if SDL_HAS_CAPTURE_AND_GLOBAL_MOUSE && !defined(__EMSCRIPTEN__) && !defined(__ANDROID__) && !(defined(__APPLE__) && TARGET_OS_IOS)
|
||||||
|
SDL_Window* focused_window = SDL_GetKeyboardFocus();
|
||||||
|
if (g_Window == focused_window)
|
||||||
|
{
|
||||||
|
if (g_MouseCanUseGlobalState)
|
||||||
|
{
|
||||||
|
// SDL_GetMouseState() gives mouse position seemingly based on the last window entered/focused(?)
|
||||||
|
// The creation of a new windows at runtime and SDL_CaptureMouse both seems to severely mess up with that, so we retrieve that position globally.
|
||||||
|
// Won't use this workaround on SDL backends that have no global mouse position, like Wayland or RPI
|
||||||
|
int wx, wy;
|
||||||
|
SDL_GetWindowPosition(focused_window, &wx, &wy);
|
||||||
|
SDL_GetGlobalMouseState(&mx, &my);
|
||||||
|
mx -= wx;
|
||||||
|
my -= wy;
|
||||||
|
}
|
||||||
|
io.MousePos = ImVec2((float)mx, (float)my);
|
||||||
|
}
|
||||||
|
|
||||||
|
// SDL_CaptureMouse() let the OS know e.g. that our imgui drag outside the SDL window boundaries shouldn't e.g. trigger the OS window resize cursor.
|
||||||
|
// The function is only supported from SDL 2.0.4 (released Jan 2016)
|
||||||
|
bool any_mouse_button_down = ImGui::IsAnyMouseDown();
|
||||||
|
SDL_CaptureMouse(any_mouse_button_down ? SDL_TRUE : SDL_FALSE);
|
||||||
|
#else
|
||||||
|
if (SDL_GetWindowFlags(g_Window) & SDL_WINDOW_INPUT_FOCUS)
|
||||||
|
io.MousePos = ImVec2((float)mx, (float)my);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ImGui_ImplSDL2_UpdateMouseCursor()
|
||||||
|
{
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
if (io.ConfigFlags & ImGuiConfigFlags_NoMouseCursorChange)
|
||||||
|
return;
|
||||||
|
|
||||||
|
ImGuiMouseCursor imgui_cursor = ImGui::GetMouseCursor();
|
||||||
|
if (io.MouseDrawCursor || imgui_cursor == ImGuiMouseCursor_None)
|
||||||
|
{
|
||||||
|
// Hide OS mouse cursor if imgui is drawing it or if it wants no cursor
|
||||||
|
SDL_ShowCursor(SDL_FALSE);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Show OS mouse cursor
|
||||||
|
SDL_SetCursor(g_MouseCursors[imgui_cursor] ? g_MouseCursors[imgui_cursor] : g_MouseCursors[ImGuiMouseCursor_Arrow]);
|
||||||
|
SDL_ShowCursor(SDL_TRUE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ImGui_ImplSDL2_UpdateGamepads()
|
||||||
|
{
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
memset(io.NavInputs, 0, sizeof(io.NavInputs));
|
||||||
|
if ((io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Get gamepad
|
||||||
|
SDL_GameController* game_controller = SDL_GameControllerOpen(0);
|
||||||
|
if (!game_controller)
|
||||||
|
{
|
||||||
|
io.BackendFlags &= ~ImGuiBackendFlags_HasGamepad;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update gamepad inputs
|
||||||
|
#define MAP_BUTTON(NAV_NO, BUTTON_NO) { io.NavInputs[NAV_NO] = (SDL_GameControllerGetButton(game_controller, BUTTON_NO) != 0) ? 1.0f : 0.0f; }
|
||||||
|
#define MAP_ANALOG(NAV_NO, AXIS_NO, V0, V1) { float vn = (float)(SDL_GameControllerGetAxis(game_controller, AXIS_NO) - V0) / (float)(V1 - V0); if (vn > 1.0f) vn = 1.0f; if (vn > 0.0f && io.NavInputs[NAV_NO] < vn) io.NavInputs[NAV_NO] = vn; }
|
||||||
|
const int thumb_dead_zone = 8000; // SDL_gamecontroller.h suggests using this value.
|
||||||
|
MAP_BUTTON(ImGuiNavInput_Activate, SDL_CONTROLLER_BUTTON_A); // Cross / A
|
||||||
|
MAP_BUTTON(ImGuiNavInput_Cancel, SDL_CONTROLLER_BUTTON_B); // Circle / B
|
||||||
|
MAP_BUTTON(ImGuiNavInput_Menu, SDL_CONTROLLER_BUTTON_X); // Square / X
|
||||||
|
MAP_BUTTON(ImGuiNavInput_Input, SDL_CONTROLLER_BUTTON_Y); // Triangle / Y
|
||||||
|
MAP_BUTTON(ImGuiNavInput_DpadLeft, SDL_CONTROLLER_BUTTON_DPAD_LEFT); // D-Pad Left
|
||||||
|
MAP_BUTTON(ImGuiNavInput_DpadRight, SDL_CONTROLLER_BUTTON_DPAD_RIGHT); // D-Pad Right
|
||||||
|
MAP_BUTTON(ImGuiNavInput_DpadUp, SDL_CONTROLLER_BUTTON_DPAD_UP); // D-Pad Up
|
||||||
|
MAP_BUTTON(ImGuiNavInput_DpadDown, SDL_CONTROLLER_BUTTON_DPAD_DOWN); // D-Pad Down
|
||||||
|
MAP_BUTTON(ImGuiNavInput_FocusPrev, SDL_CONTROLLER_BUTTON_LEFTSHOULDER); // L1 / LB
|
||||||
|
MAP_BUTTON(ImGuiNavInput_FocusNext, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER); // R1 / RB
|
||||||
|
MAP_BUTTON(ImGuiNavInput_TweakSlow, SDL_CONTROLLER_BUTTON_LEFTSHOULDER); // L1 / LB
|
||||||
|
MAP_BUTTON(ImGuiNavInput_TweakFast, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER); // R1 / RB
|
||||||
|
MAP_ANALOG(ImGuiNavInput_LStickLeft, SDL_CONTROLLER_AXIS_LEFTX, -thumb_dead_zone, -32768);
|
||||||
|
MAP_ANALOG(ImGuiNavInput_LStickRight, SDL_CONTROLLER_AXIS_LEFTX, +thumb_dead_zone, +32767);
|
||||||
|
MAP_ANALOG(ImGuiNavInput_LStickUp, SDL_CONTROLLER_AXIS_LEFTY, -thumb_dead_zone, -32767);
|
||||||
|
MAP_ANALOG(ImGuiNavInput_LStickDown, SDL_CONTROLLER_AXIS_LEFTY, +thumb_dead_zone, +32767);
|
||||||
|
|
||||||
|
io.BackendFlags |= ImGuiBackendFlags_HasGamepad;
|
||||||
|
#undef MAP_BUTTON
|
||||||
|
#undef MAP_ANALOG
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGui_ImplSDL2_NewFrame(SDL_Window* window)
|
||||||
|
{
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
IM_ASSERT(io.Fonts->IsBuilt() && "Font atlas not built! It is generally built by the renderer backend. Missing call to renderer _NewFrame() function? e.g. ImGui_ImplOpenGL3_NewFrame().");
|
||||||
|
|
||||||
|
// Setup display size (every frame to accommodate for window resizing)
|
||||||
|
int w, h;
|
||||||
|
int display_w, display_h;
|
||||||
|
SDL_GetWindowSize(window, &w, &h);
|
||||||
|
if (SDL_GetWindowFlags(window) & SDL_WINDOW_MINIMIZED)
|
||||||
|
w = h = 0;
|
||||||
|
SDL_GL_GetDrawableSize(window, &display_w, &display_h);
|
||||||
|
io.DisplaySize = ImVec2((float)w, (float)h);
|
||||||
|
if (w > 0 && h > 0)
|
||||||
|
io.DisplayFramebufferScale = ImVec2((float)display_w / w, (float)display_h / h);
|
||||||
|
|
||||||
|
// Setup time step (we don't use SDL_GetTicks() because it is using millisecond resolution)
|
||||||
|
static Uint64 frequency = SDL_GetPerformanceFrequency();
|
||||||
|
Uint64 current_time = SDL_GetPerformanceCounter();
|
||||||
|
io.DeltaTime = g_Time > 0 ? (float)((double)(current_time - g_Time) / frequency) : (float)(1.0f / 60.0f);
|
||||||
|
g_Time = current_time;
|
||||||
|
|
||||||
|
ImGui_ImplSDL2_UpdateMousePosAndButtons();
|
||||||
|
ImGui_ImplSDL2_UpdateMouseCursor();
|
||||||
|
|
||||||
|
// Update game controllers (if enabled and available)
|
||||||
|
ImGui_ImplSDL2_UpdateGamepads();
|
||||||
|
}
|
29
backend/imgui_impl_sdl.h
Normal file
29
backend/imgui_impl_sdl.h
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
// dear imgui: Platform Backend for SDL2
|
||||||
|
// This needs to be used along with a Renderer (e.g. DirectX11, OpenGL3, Vulkan..)
|
||||||
|
// (Info: SDL2 is a cross-platform general purpose library for handling windows, inputs, graphics context creation, etc.)
|
||||||
|
|
||||||
|
// Implemented features:
|
||||||
|
// [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'.
|
||||||
|
// [X] Platform: Clipboard support.
|
||||||
|
// [X] Platform: Keyboard arrays indexed using SDL_SCANCODE_* codes, e.g. ImGui::IsKeyPressed(SDL_SCANCODE_SPACE).
|
||||||
|
// [X] Platform: Gamepad support. Enabled with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'.
|
||||||
|
// Missing features:
|
||||||
|
// [ ] Platform: SDL2 handling of IME under Windows appears to be broken and it explicitly disable the regular Windows IME. You can restore Windows IME by compiling SDL with SDL_DISABLE_WINDOWS_IME.
|
||||||
|
|
||||||
|
// You can copy and use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
||||||
|
// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
|
||||||
|
// Read online: https://github.com/ocornut/imgui/tree/master/docs
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include "imgui.h" // IMGUI_IMPL_API
|
||||||
|
|
||||||
|
struct SDL_Window;
|
||||||
|
typedef union SDL_Event SDL_Event;
|
||||||
|
|
||||||
|
IMGUI_IMPL_API bool ImGui_ImplSDL2_InitForOpenGL(SDL_Window* window, void* sdl_gl_context);
|
||||||
|
IMGUI_IMPL_API bool ImGui_ImplSDL2_InitForVulkan(SDL_Window* window);
|
||||||
|
IMGUI_IMPL_API bool ImGui_ImplSDL2_InitForD3D(SDL_Window* window);
|
||||||
|
IMGUI_IMPL_API bool ImGui_ImplSDL2_InitForMetal(SDL_Window* window);
|
||||||
|
IMGUI_IMPL_API void ImGui_ImplSDL2_Shutdown();
|
||||||
|
IMGUI_IMPL_API void ImGui_ImplSDL2_NewFrame(SDL_Window* window);
|
||||||
|
IMGUI_IMPL_API bool ImGui_ImplSDL2_ProcessEvent(const SDL_Event* event);
|
1416
backend/imgui_impl_vulkan.cpp
Normal file
1416
backend/imgui_impl_vulkan.cpp
Normal file
File diff suppressed because it is too large
Load Diff
148
backend/imgui_impl_vulkan.h
Normal file
148
backend/imgui_impl_vulkan.h
Normal file
@ -0,0 +1,148 @@
|
|||||||
|
// dear imgui: Renderer Backend for Vulkan
|
||||||
|
// This needs to be used along with a Platform Backend (e.g. GLFW, SDL, Win32, custom..)
|
||||||
|
|
||||||
|
// Implemented features:
|
||||||
|
// [X] Renderer: Support for large meshes (64k+ vertices) with 16-bit indices.
|
||||||
|
// Missing features:
|
||||||
|
// [ ] Renderer: User texture binding. Changes of ImTextureID aren't supported by this backend! See https://github.com/ocornut/imgui/pull/914
|
||||||
|
|
||||||
|
// You can copy and use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
||||||
|
// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
|
||||||
|
// Read online: https://github.com/ocornut/imgui/tree/master/docs
|
||||||
|
|
||||||
|
// The aim of imgui_impl_vulkan.h/.cpp is to be usable in your engine without any modification.
|
||||||
|
// IF YOU FEEL YOU NEED TO MAKE ANY CHANGE TO THIS CODE, please share them and your feedback at https://github.com/ocornut/imgui/
|
||||||
|
|
||||||
|
// Important note to the reader who wish to integrate imgui_impl_vulkan.cpp/.h in their own engine/app.
|
||||||
|
// - Common ImGui_ImplVulkan_XXX functions and structures are used to interface with imgui_impl_vulkan.cpp/.h.
|
||||||
|
// You will use those if you want to use this rendering backend in your engine/app.
|
||||||
|
// - Helper ImGui_ImplVulkanH_XXX functions and structures are only used by this example (main.cpp) and by
|
||||||
|
// the backend itself (imgui_impl_vulkan.cpp), but should PROBABLY NOT be used by your own engine/app code.
|
||||||
|
// Read comments in imgui_impl_vulkan.h.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include "imgui.h" // IMGUI_IMPL_API
|
||||||
|
|
||||||
|
// [Configuration] in order to use a custom Vulkan function loader:
|
||||||
|
// (1) You'll need to disable default Vulkan function prototypes.
|
||||||
|
// We provide a '#define IMGUI_IMPL_VULKAN_NO_PROTOTYPES' convenience configuration flag.
|
||||||
|
// In order to make sure this is visible from the imgui_impl_vulkan.cpp compilation unit:
|
||||||
|
// - Add '#define IMGUI_IMPL_VULKAN_NO_PROTOTYPES' in your imconfig.h file
|
||||||
|
// - Or as a compilation flag in your build system
|
||||||
|
// - Or uncomment here (not recommended because you'd be modifying imgui sources!)
|
||||||
|
// - Do not simply add it in a .cpp file!
|
||||||
|
// (2) Call ImGui_ImplVulkan_LoadFunctions() before ImGui_ImplVulkan_Init() with your custom function.
|
||||||
|
// If you have no idea what this is, leave it alone!
|
||||||
|
//#define IMGUI_IMPL_VULKAN_NO_PROTOTYPES
|
||||||
|
|
||||||
|
// Vulkan includes
|
||||||
|
#if defined(IMGUI_IMPL_VULKAN_NO_PROTOTYPES) && !defined(VK_NO_PROTOTYPES)
|
||||||
|
#define VK_NO_PROTOTYPES
|
||||||
|
#endif
|
||||||
|
#include <vulkan/vulkan.h>
|
||||||
|
|
||||||
|
// Initialization data, for ImGui_ImplVulkan_Init()
|
||||||
|
// [Please zero-clear before use!]
|
||||||
|
struct ImGui_ImplVulkan_InitInfo
|
||||||
|
{
|
||||||
|
VkInstance Instance;
|
||||||
|
VkPhysicalDevice PhysicalDevice;
|
||||||
|
VkDevice Device;
|
||||||
|
uint32_t QueueFamily;
|
||||||
|
VkQueue Queue;
|
||||||
|
VkPipelineCache PipelineCache;
|
||||||
|
VkDescriptorPool DescriptorPool;
|
||||||
|
uint32_t Subpass;
|
||||||
|
uint32_t MinImageCount; // >= 2
|
||||||
|
uint32_t ImageCount; // >= MinImageCount
|
||||||
|
VkSampleCountFlagBits MSAASamples; // >= VK_SAMPLE_COUNT_1_BIT
|
||||||
|
const VkAllocationCallbacks* Allocator;
|
||||||
|
void (*CheckVkResultFn)(VkResult err);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Called by user code
|
||||||
|
IMGUI_IMPL_API bool ImGui_ImplVulkan_Init(ImGui_ImplVulkan_InitInfo* info, VkRenderPass render_pass);
|
||||||
|
IMGUI_IMPL_API void ImGui_ImplVulkan_Shutdown();
|
||||||
|
IMGUI_IMPL_API void ImGui_ImplVulkan_NewFrame();
|
||||||
|
IMGUI_IMPL_API void ImGui_ImplVulkan_RenderDrawData(ImDrawData* draw_data, VkCommandBuffer command_buffer, VkPipeline pipeline = VK_NULL_HANDLE);
|
||||||
|
IMGUI_IMPL_API bool ImGui_ImplVulkan_CreateFontsTexture(VkCommandBuffer command_buffer);
|
||||||
|
IMGUI_IMPL_API void ImGui_ImplVulkan_DestroyFontUploadObjects();
|
||||||
|
IMGUI_IMPL_API void ImGui_ImplVulkan_SetMinImageCount(uint32_t min_image_count); // To override MinImageCount after initialization (e.g. if swap chain is recreated)
|
||||||
|
|
||||||
|
// Optional: load Vulkan functions with a custom function loader
|
||||||
|
// This is only useful with IMGUI_IMPL_VULKAN_NO_PROTOTYPES / VK_NO_PROTOTYPES
|
||||||
|
IMGUI_IMPL_API bool ImGui_ImplVulkan_LoadFunctions(PFN_vkVoidFunction(*loader_func)(const char* function_name, void* user_data), void* user_data = NULL);
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------
|
||||||
|
// Internal / Miscellaneous Vulkan Helpers
|
||||||
|
// (Used by example's main.cpp. Used by multi-viewport features. PROBABLY NOT used by your own engine/app.)
|
||||||
|
//-------------------------------------------------------------------------
|
||||||
|
// You probably do NOT need to use or care about those functions.
|
||||||
|
// Those functions only exist because:
|
||||||
|
// 1) they facilitate the readability and maintenance of the multiple main.cpp examples files.
|
||||||
|
// 2) the upcoming multi-viewport feature will need them internally.
|
||||||
|
// Generally we avoid exposing any kind of superfluous high-level helpers in the backends,
|
||||||
|
// but it is too much code to duplicate everywhere so we exceptionally expose them.
|
||||||
|
//
|
||||||
|
// Your engine/app will likely _already_ have code to setup all that stuff (swap chain, render pass, frame buffers, etc.).
|
||||||
|
// You may read this code to learn about Vulkan, but it is recommended you use you own custom tailored code to do equivalent work.
|
||||||
|
// (The ImGui_ImplVulkanH_XXX functions do not interact with any of the state used by the regular ImGui_ImplVulkan_XXX functions)
|
||||||
|
//-------------------------------------------------------------------------
|
||||||
|
|
||||||
|
struct ImGui_ImplVulkanH_Frame;
|
||||||
|
struct ImGui_ImplVulkanH_Window;
|
||||||
|
|
||||||
|
// Helpers
|
||||||
|
IMGUI_IMPL_API void ImGui_ImplVulkanH_CreateOrResizeWindow(VkInstance instance, VkPhysicalDevice physical_device, VkDevice device, ImGui_ImplVulkanH_Window* wnd, uint32_t queue_family, const VkAllocationCallbacks* allocator, int w, int h, uint32_t min_image_count);
|
||||||
|
IMGUI_IMPL_API void ImGui_ImplVulkanH_DestroyWindow(VkInstance instance, VkDevice device, ImGui_ImplVulkanH_Window* wnd, const VkAllocationCallbacks* allocator);
|
||||||
|
IMGUI_IMPL_API VkSurfaceFormatKHR ImGui_ImplVulkanH_SelectSurfaceFormat(VkPhysicalDevice physical_device, VkSurfaceKHR surface, const VkFormat* request_formats, int request_formats_count, VkColorSpaceKHR request_color_space);
|
||||||
|
IMGUI_IMPL_API VkPresentModeKHR ImGui_ImplVulkanH_SelectPresentMode(VkPhysicalDevice physical_device, VkSurfaceKHR surface, const VkPresentModeKHR* request_modes, int request_modes_count);
|
||||||
|
IMGUI_IMPL_API int ImGui_ImplVulkanH_GetMinImageCountFromPresentMode(VkPresentModeKHR present_mode);
|
||||||
|
|
||||||
|
// Helper structure to hold the data needed by one rendering frame
|
||||||
|
// (Used by example's main.cpp. Used by multi-viewport features. Probably NOT used by your own engine/app.)
|
||||||
|
// [Please zero-clear before use!]
|
||||||
|
struct ImGui_ImplVulkanH_Frame
|
||||||
|
{
|
||||||
|
VkCommandPool CommandPool;
|
||||||
|
VkCommandBuffer CommandBuffer;
|
||||||
|
VkFence Fence;
|
||||||
|
VkImage Backbuffer;
|
||||||
|
VkImageView BackbufferView;
|
||||||
|
VkFramebuffer Framebuffer;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ImGui_ImplVulkanH_FrameSemaphores
|
||||||
|
{
|
||||||
|
VkSemaphore ImageAcquiredSemaphore;
|
||||||
|
VkSemaphore RenderCompleteSemaphore;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Helper structure to hold the data needed by one rendering context into one OS window
|
||||||
|
// (Used by example's main.cpp. Used by multi-viewport features. Probably NOT used by your own engine/app.)
|
||||||
|
struct ImGui_ImplVulkanH_Window
|
||||||
|
{
|
||||||
|
int Width;
|
||||||
|
int Height;
|
||||||
|
VkSwapchainKHR Swapchain;
|
||||||
|
VkSurfaceKHR Surface;
|
||||||
|
VkSurfaceFormatKHR SurfaceFormat;
|
||||||
|
VkPresentModeKHR PresentMode;
|
||||||
|
VkRenderPass RenderPass;
|
||||||
|
VkPipeline Pipeline; // The window pipeline may uses a different VkRenderPass than the one passed in ImGui_ImplVulkan_InitInfo
|
||||||
|
bool ClearEnable;
|
||||||
|
VkClearValue ClearValue;
|
||||||
|
uint32_t FrameIndex; // Current frame being rendered to (0 <= FrameIndex < FrameInFlightCount)
|
||||||
|
uint32_t ImageCount; // Number of simultaneous in-flight frames (returned by vkGetSwapchainImagesKHR, usually derived from min_image_count)
|
||||||
|
uint32_t SemaphoreIndex; // Current set of swapchain wait semaphores we're using (needs to be distinct from per frame data)
|
||||||
|
ImGui_ImplVulkanH_Frame* Frames;
|
||||||
|
ImGui_ImplVulkanH_FrameSemaphores* FrameSemaphores;
|
||||||
|
|
||||||
|
ImGui_ImplVulkanH_Window()
|
||||||
|
{
|
||||||
|
memset(this, 0, sizeof(*this));
|
||||||
|
PresentMode = VK_PRESENT_MODE_MAX_ENUM_KHR;
|
||||||
|
ClearEnable = true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
783
backend/imgui_impl_wgpu.cpp
Normal file
783
backend/imgui_impl_wgpu.cpp
Normal file
@ -0,0 +1,783 @@
|
|||||||
|
// dear imgui: Renderer for WebGPU
|
||||||
|
// This needs to be used along with a Platform Binding (e.g. GLFW)
|
||||||
|
// (Please note that WebGPU is currently experimental, will not run on non-beta browsers, and may break.)
|
||||||
|
|
||||||
|
// Implemented features:
|
||||||
|
// [X] Renderer: User texture binding. Use 'WGPUTextureView' as ImTextureID. Read the FAQ about ImTextureID!
|
||||||
|
// [X] Renderer: Support for large meshes (64k+ vertices) with 16-bit indices.
|
||||||
|
|
||||||
|
// You can copy and use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
||||||
|
// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
|
||||||
|
// Read online: https://github.com/ocornut/imgui/tree/master/docs
|
||||||
|
|
||||||
|
// CHANGELOG
|
||||||
|
// (minor and older changes stripped away, please see git history for details)
|
||||||
|
// 2021-02-18: Change blending equation to preserve alpha in output buffer.
|
||||||
|
// 2021-01-28: Initial version.
|
||||||
|
|
||||||
|
#include "imgui.h"
|
||||||
|
#include "imgui_impl_wgpu.h"
|
||||||
|
#include <limits.h>
|
||||||
|
#include <webgpu/webgpu.h>
|
||||||
|
|
||||||
|
#define HAS_EMSCRIPTEN_VERSION(major, minor, tiny) (__EMSCRIPTEN_major__ > (major) || (__EMSCRIPTEN_major__ == (major) && __EMSCRIPTEN_minor__ > (minor)) || (__EMSCRIPTEN_major__ == (major) && __EMSCRIPTEN_minor__ == (minor) && __EMSCRIPTEN_tiny__ >= (tiny)))
|
||||||
|
|
||||||
|
// Dear ImGui prototypes from imgui_internal.h
|
||||||
|
extern ImGuiID ImHashData(const void* data_p, size_t data_size, ImU32 seed = 0);
|
||||||
|
|
||||||
|
// WebGPU data
|
||||||
|
static WGPUDevice g_wgpuDevice = NULL;
|
||||||
|
static WGPUTextureFormat g_renderTargetFormat = WGPUTextureFormat_Undefined;
|
||||||
|
static WGPURenderPipeline g_pipelineState = NULL;
|
||||||
|
|
||||||
|
struct RenderResources
|
||||||
|
{
|
||||||
|
WGPUTexture FontTexture; // Font texture
|
||||||
|
WGPUTextureView FontTextureView; // Texture view for font texture
|
||||||
|
WGPUSampler Sampler; // Sampler for the font texture
|
||||||
|
WGPUBuffer Uniforms; // Shader uniforms
|
||||||
|
WGPUBindGroup CommonBindGroup; // Resources bind-group to bind the common resources to pipeline
|
||||||
|
WGPUBindGroupLayout ImageBindGroupLayout; // Bind group layout for image textures
|
||||||
|
ImGuiStorage ImageBindGroups; // Resources bind-group to bind the font/image resources to pipeline (this is a key->value map)
|
||||||
|
WGPUBindGroup ImageBindGroup; // Default font-resource of Dear ImGui
|
||||||
|
};
|
||||||
|
static RenderResources g_resources;
|
||||||
|
|
||||||
|
struct FrameResources
|
||||||
|
{
|
||||||
|
WGPUBuffer IndexBuffer;
|
||||||
|
WGPUBuffer VertexBuffer;
|
||||||
|
ImDrawIdx* IndexBufferHost;
|
||||||
|
ImDrawVert* VertexBufferHost;
|
||||||
|
int IndexBufferSize;
|
||||||
|
int VertexBufferSize;
|
||||||
|
};
|
||||||
|
static FrameResources* g_pFrameResources = NULL;
|
||||||
|
static unsigned int g_numFramesInFlight = 0;
|
||||||
|
static unsigned int g_frameIndex = UINT_MAX;
|
||||||
|
|
||||||
|
struct Uniforms
|
||||||
|
{
|
||||||
|
float MVP[4][4];
|
||||||
|
};
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// SHADERS
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// glsl_shader.vert, compiled with:
|
||||||
|
// # glslangValidator -V -x -o glsl_shader.vert.u32 glsl_shader.vert
|
||||||
|
/*
|
||||||
|
#version 450 core
|
||||||
|
layout(location = 0) in vec2 aPos;
|
||||||
|
layout(location = 1) in vec2 aUV;
|
||||||
|
layout(location = 2) in vec4 aColor;
|
||||||
|
layout(set=0, binding = 0) uniform transform { mat4 mvp; };
|
||||||
|
|
||||||
|
out gl_PerVertex { vec4 gl_Position; };
|
||||||
|
layout(location = 0) out struct { vec4 Color; vec2 UV; } Out;
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
Out.Color = aColor;
|
||||||
|
Out.UV = aUV;
|
||||||
|
gl_Position = mvp * vec4(aPos, 0, 1);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
static uint32_t __glsl_shader_vert_spv[] =
|
||||||
|
{
|
||||||
|
0x07230203,0x00010000,0x00080007,0x0000002c,0x00000000,0x00020011,0x00000001,0x0006000b,
|
||||||
|
0x00000001,0x4c534c47,0x6474732e,0x3035342e,0x00000000,0x0003000e,0x00000000,0x00000001,
|
||||||
|
0x000a000f,0x00000000,0x00000004,0x6e69616d,0x00000000,0x0000000b,0x0000000f,0x00000015,
|
||||||
|
0x0000001b,0x00000023,0x00030003,0x00000002,0x000001c2,0x00040005,0x00000004,0x6e69616d,
|
||||||
|
0x00000000,0x00030005,0x00000009,0x00000000,0x00050006,0x00000009,0x00000000,0x6f6c6f43,
|
||||||
|
0x00000072,0x00040006,0x00000009,0x00000001,0x00005655,0x00030005,0x0000000b,0x0074754f,
|
||||||
|
0x00040005,0x0000000f,0x6c6f4361,0x0000726f,0x00030005,0x00000015,0x00565561,0x00060005,
|
||||||
|
0x00000019,0x505f6c67,0x65567265,0x78657472,0x00000000,0x00060006,0x00000019,0x00000000,
|
||||||
|
0x505f6c67,0x7469736f,0x006e6f69,0x00030005,0x0000001b,0x00000000,0x00050005,0x0000001d,
|
||||||
|
0x6e617274,0x726f6673,0x0000006d,0x00040006,0x0000001d,0x00000000,0x0070766d,0x00030005,
|
||||||
|
0x0000001f,0x00000000,0x00040005,0x00000023,0x736f5061,0x00000000,0x00040047,0x0000000b,
|
||||||
|
0x0000001e,0x00000000,0x00040047,0x0000000f,0x0000001e,0x00000002,0x00040047,0x00000015,
|
||||||
|
0x0000001e,0x00000001,0x00050048,0x00000019,0x00000000,0x0000000b,0x00000000,0x00030047,
|
||||||
|
0x00000019,0x00000002,0x00040048,0x0000001d,0x00000000,0x00000005,0x00050048,0x0000001d,
|
||||||
|
0x00000000,0x00000023,0x00000000,0x00050048,0x0000001d,0x00000000,0x00000007,0x00000010,
|
||||||
|
0x00030047,0x0000001d,0x00000002,0x00040047,0x0000001f,0x00000022,0x00000000,0x00040047,
|
||||||
|
0x0000001f,0x00000021,0x00000000,0x00040047,0x00000023,0x0000001e,0x00000000,0x00020013,
|
||||||
|
0x00000002,0x00030021,0x00000003,0x00000002,0x00030016,0x00000006,0x00000020,0x00040017,
|
||||||
|
0x00000007,0x00000006,0x00000004,0x00040017,0x00000008,0x00000006,0x00000002,0x0004001e,
|
||||||
|
0x00000009,0x00000007,0x00000008,0x00040020,0x0000000a,0x00000003,0x00000009,0x0004003b,
|
||||||
|
0x0000000a,0x0000000b,0x00000003,0x00040015,0x0000000c,0x00000020,0x00000001,0x0004002b,
|
||||||
|
0x0000000c,0x0000000d,0x00000000,0x00040020,0x0000000e,0x00000001,0x00000007,0x0004003b,
|
||||||
|
0x0000000e,0x0000000f,0x00000001,0x00040020,0x00000011,0x00000003,0x00000007,0x0004002b,
|
||||||
|
0x0000000c,0x00000013,0x00000001,0x00040020,0x00000014,0x00000001,0x00000008,0x0004003b,
|
||||||
|
0x00000014,0x00000015,0x00000001,0x00040020,0x00000017,0x00000003,0x00000008,0x0003001e,
|
||||||
|
0x00000019,0x00000007,0x00040020,0x0000001a,0x00000003,0x00000019,0x0004003b,0x0000001a,
|
||||||
|
0x0000001b,0x00000003,0x00040018,0x0000001c,0x00000007,0x00000004,0x0003001e,0x0000001d,
|
||||||
|
0x0000001c,0x00040020,0x0000001e,0x00000002,0x0000001d,0x0004003b,0x0000001e,0x0000001f,
|
||||||
|
0x00000002,0x00040020,0x00000020,0x00000002,0x0000001c,0x0004003b,0x00000014,0x00000023,
|
||||||
|
0x00000001,0x0004002b,0x00000006,0x00000025,0x00000000,0x0004002b,0x00000006,0x00000026,
|
||||||
|
0x3f800000,0x00050036,0x00000002,0x00000004,0x00000000,0x00000003,0x000200f8,0x00000005,
|
||||||
|
0x0004003d,0x00000007,0x00000010,0x0000000f,0x00050041,0x00000011,0x00000012,0x0000000b,
|
||||||
|
0x0000000d,0x0003003e,0x00000012,0x00000010,0x0004003d,0x00000008,0x00000016,0x00000015,
|
||||||
|
0x00050041,0x00000017,0x00000018,0x0000000b,0x00000013,0x0003003e,0x00000018,0x00000016,
|
||||||
|
0x00050041,0x00000020,0x00000021,0x0000001f,0x0000000d,0x0004003d,0x0000001c,0x00000022,
|
||||||
|
0x00000021,0x0004003d,0x00000008,0x00000024,0x00000023,0x00050051,0x00000006,0x00000027,
|
||||||
|
0x00000024,0x00000000,0x00050051,0x00000006,0x00000028,0x00000024,0x00000001,0x00070050,
|
||||||
|
0x00000007,0x00000029,0x00000027,0x00000028,0x00000025,0x00000026,0x00050091,0x00000007,
|
||||||
|
0x0000002a,0x00000022,0x00000029,0x00050041,0x00000011,0x0000002b,0x0000001b,0x0000000d,
|
||||||
|
0x0003003e,0x0000002b,0x0000002a,0x000100fd,0x00010038
|
||||||
|
};
|
||||||
|
|
||||||
|
// glsl_shader.frag, compiled with:
|
||||||
|
// # glslangValidator -V -x -o glsl_shader.frag.u32 glsl_shader.frag
|
||||||
|
/*
|
||||||
|
#version 450 core
|
||||||
|
layout(location = 0) out vec4 fColor;
|
||||||
|
layout(set=0, binding=1) uniform sampler s;
|
||||||
|
layout(set=1, binding=0) uniform texture2D t;
|
||||||
|
layout(location = 0) in struct { vec4 Color; vec2 UV; } In;
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
fColor = In.Color * texture(sampler2D(t, s), In.UV.st);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
static uint32_t __glsl_shader_frag_spv[] =
|
||||||
|
{
|
||||||
|
0x07230203,0x00010000,0x00080007,0x00000023,0x00000000,0x00020011,0x00000001,0x0006000b,
|
||||||
|
0x00000001,0x4c534c47,0x6474732e,0x3035342e,0x00000000,0x0003000e,0x00000000,0x00000001,
|
||||||
|
0x0007000f,0x00000004,0x00000004,0x6e69616d,0x00000000,0x00000009,0x0000000d,0x00030010,
|
||||||
|
0x00000004,0x00000007,0x00030003,0x00000002,0x000001c2,0x00040005,0x00000004,0x6e69616d,
|
||||||
|
0x00000000,0x00040005,0x00000009,0x6c6f4366,0x0000726f,0x00030005,0x0000000b,0x00000000,
|
||||||
|
0x00050006,0x0000000b,0x00000000,0x6f6c6f43,0x00000072,0x00040006,0x0000000b,0x00000001,
|
||||||
|
0x00005655,0x00030005,0x0000000d,0x00006e49,0x00030005,0x00000015,0x00000074,0x00030005,
|
||||||
|
0x00000019,0x00000073,0x00040047,0x00000009,0x0000001e,0x00000000,0x00040047,0x0000000d,
|
||||||
|
0x0000001e,0x00000000,0x00040047,0x00000015,0x00000022,0x00000001,0x00040047,0x00000015,
|
||||||
|
0x00000021,0x00000000,0x00040047,0x00000019,0x00000022,0x00000000,0x00040047,0x00000019,
|
||||||
|
0x00000021,0x00000001,0x00020013,0x00000002,0x00030021,0x00000003,0x00000002,0x00030016,
|
||||||
|
0x00000006,0x00000020,0x00040017,0x00000007,0x00000006,0x00000004,0x00040020,0x00000008,
|
||||||
|
0x00000003,0x00000007,0x0004003b,0x00000008,0x00000009,0x00000003,0x00040017,0x0000000a,
|
||||||
|
0x00000006,0x00000002,0x0004001e,0x0000000b,0x00000007,0x0000000a,0x00040020,0x0000000c,
|
||||||
|
0x00000001,0x0000000b,0x0004003b,0x0000000c,0x0000000d,0x00000001,0x00040015,0x0000000e,
|
||||||
|
0x00000020,0x00000001,0x0004002b,0x0000000e,0x0000000f,0x00000000,0x00040020,0x00000010,
|
||||||
|
0x00000001,0x00000007,0x00090019,0x00000013,0x00000006,0x00000001,0x00000000,0x00000000,
|
||||||
|
0x00000000,0x00000001,0x00000000,0x00040020,0x00000014,0x00000000,0x00000013,0x0004003b,
|
||||||
|
0x00000014,0x00000015,0x00000000,0x0002001a,0x00000017,0x00040020,0x00000018,0x00000000,
|
||||||
|
0x00000017,0x0004003b,0x00000018,0x00000019,0x00000000,0x0003001b,0x0000001b,0x00000013,
|
||||||
|
0x0004002b,0x0000000e,0x0000001d,0x00000001,0x00040020,0x0000001e,0x00000001,0x0000000a,
|
||||||
|
0x00050036,0x00000002,0x00000004,0x00000000,0x00000003,0x000200f8,0x00000005,0x00050041,
|
||||||
|
0x00000010,0x00000011,0x0000000d,0x0000000f,0x0004003d,0x00000007,0x00000012,0x00000011,
|
||||||
|
0x0004003d,0x00000013,0x00000016,0x00000015,0x0004003d,0x00000017,0x0000001a,0x00000019,
|
||||||
|
0x00050056,0x0000001b,0x0000001c,0x00000016,0x0000001a,0x00050041,0x0000001e,0x0000001f,
|
||||||
|
0x0000000d,0x0000001d,0x0004003d,0x0000000a,0x00000020,0x0000001f,0x00050057,0x00000007,
|
||||||
|
0x00000021,0x0000001c,0x00000020,0x00050085,0x00000007,0x00000022,0x00000012,0x00000021,
|
||||||
|
0x0003003e,0x00000009,0x00000022,0x000100fd,0x00010038
|
||||||
|
};
|
||||||
|
|
||||||
|
static void SafeRelease(ImDrawIdx*& res)
|
||||||
|
{
|
||||||
|
if (res)
|
||||||
|
delete[] res;
|
||||||
|
res = NULL;
|
||||||
|
}
|
||||||
|
static void SafeRelease(ImDrawVert*& res)
|
||||||
|
{
|
||||||
|
if (res)
|
||||||
|
delete[] res;
|
||||||
|
res = NULL;
|
||||||
|
}
|
||||||
|
static void SafeRelease(WGPUBindGroupLayout& res)
|
||||||
|
{
|
||||||
|
if (res)
|
||||||
|
wgpuBindGroupLayoutRelease(res);
|
||||||
|
res = NULL;
|
||||||
|
}
|
||||||
|
static void SafeRelease(WGPUBindGroup& res)
|
||||||
|
{
|
||||||
|
if (res)
|
||||||
|
wgpuBindGroupRelease(res);
|
||||||
|
res = NULL;
|
||||||
|
}
|
||||||
|
static void SafeRelease(WGPUBuffer& res)
|
||||||
|
{
|
||||||
|
if (res)
|
||||||
|
wgpuBufferRelease(res);
|
||||||
|
res = NULL;
|
||||||
|
}
|
||||||
|
static void SafeRelease(WGPURenderPipeline& res)
|
||||||
|
{
|
||||||
|
if (res)
|
||||||
|
wgpuRenderPipelineRelease(res);
|
||||||
|
res = NULL;
|
||||||
|
}
|
||||||
|
static void SafeRelease(WGPUSampler& res)
|
||||||
|
{
|
||||||
|
if (res)
|
||||||
|
wgpuSamplerRelease(res);
|
||||||
|
res = NULL;
|
||||||
|
}
|
||||||
|
static void SafeRelease(WGPUShaderModule& res)
|
||||||
|
{
|
||||||
|
if (res)
|
||||||
|
wgpuShaderModuleRelease(res);
|
||||||
|
res = NULL;
|
||||||
|
}
|
||||||
|
static void SafeRelease(WGPUTextureView& res)
|
||||||
|
{
|
||||||
|
if (res)
|
||||||
|
wgpuTextureViewRelease(res);
|
||||||
|
res = NULL;
|
||||||
|
}
|
||||||
|
static void SafeRelease(WGPUTexture& res)
|
||||||
|
{
|
||||||
|
if (res)
|
||||||
|
wgpuTextureRelease(res);
|
||||||
|
res = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void SafeRelease(RenderResources& res)
|
||||||
|
{
|
||||||
|
SafeRelease(res.FontTexture);
|
||||||
|
SafeRelease(res.FontTextureView);
|
||||||
|
SafeRelease(res.Sampler);
|
||||||
|
SafeRelease(res.Uniforms);
|
||||||
|
SafeRelease(res.CommonBindGroup);
|
||||||
|
SafeRelease(res.ImageBindGroupLayout);
|
||||||
|
SafeRelease(res.ImageBindGroup);
|
||||||
|
};
|
||||||
|
|
||||||
|
static void SafeRelease(FrameResources& res)
|
||||||
|
{
|
||||||
|
SafeRelease(res.IndexBuffer);
|
||||||
|
SafeRelease(res.VertexBuffer);
|
||||||
|
SafeRelease(res.IndexBufferHost);
|
||||||
|
SafeRelease(res.VertexBufferHost);
|
||||||
|
}
|
||||||
|
|
||||||
|
static WGPUProgrammableStageDescriptor ImGui_ImplWGPU_CreateShaderModule(uint32_t* binary_data, uint32_t binary_data_size)
|
||||||
|
{
|
||||||
|
WGPUShaderModuleSPIRVDescriptor spirv_desc = {};
|
||||||
|
spirv_desc.chain.sType = WGPUSType_ShaderModuleSPIRVDescriptor;
|
||||||
|
spirv_desc.codeSize = binary_data_size;
|
||||||
|
spirv_desc.code = binary_data;
|
||||||
|
|
||||||
|
WGPUShaderModuleDescriptor desc;
|
||||||
|
desc.nextInChain = reinterpret_cast<WGPUChainedStruct*>(&spirv_desc);
|
||||||
|
|
||||||
|
WGPUProgrammableStageDescriptor stage_desc = {};
|
||||||
|
stage_desc.module = wgpuDeviceCreateShaderModule(g_wgpuDevice, &desc);
|
||||||
|
stage_desc.entryPoint = "main";
|
||||||
|
return stage_desc;
|
||||||
|
}
|
||||||
|
|
||||||
|
static WGPUBindGroup ImGui_ImplWGPU_CreateImageBindGroup(WGPUBindGroupLayout layout, WGPUTextureView texture)
|
||||||
|
{
|
||||||
|
WGPUBindGroupEntry image_bg_entries[] = { { 0, 0, 0, 0, 0, texture } };
|
||||||
|
|
||||||
|
WGPUBindGroupDescriptor image_bg_descriptor = {};
|
||||||
|
image_bg_descriptor.layout = layout;
|
||||||
|
image_bg_descriptor.entryCount = sizeof(image_bg_entries) / sizeof(WGPUBindGroupEntry);
|
||||||
|
image_bg_descriptor.entries = image_bg_entries;
|
||||||
|
return wgpuDeviceCreateBindGroup(g_wgpuDevice, &image_bg_descriptor);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ImGui_ImplWGPU_SetupRenderState(ImDrawData* draw_data, WGPURenderPassEncoder ctx, FrameResources* fr)
|
||||||
|
{
|
||||||
|
// Setup orthographic projection matrix into our constant buffer
|
||||||
|
// Our visible imgui space lies from draw_data->DisplayPos (top left) to draw_data->DisplayPos+data_data->DisplaySize (bottom right).
|
||||||
|
{
|
||||||
|
float L = draw_data->DisplayPos.x;
|
||||||
|
float R = draw_data->DisplayPos.x + draw_data->DisplaySize.x;
|
||||||
|
float T = draw_data->DisplayPos.y;
|
||||||
|
float B = draw_data->DisplayPos.y + draw_data->DisplaySize.y;
|
||||||
|
float mvp[4][4] =
|
||||||
|
{
|
||||||
|
{ 2.0f/(R-L), 0.0f, 0.0f, 0.0f },
|
||||||
|
{ 0.0f, 2.0f/(T-B), 0.0f, 0.0f },
|
||||||
|
{ 0.0f, 0.0f, 0.5f, 0.0f },
|
||||||
|
{ (R+L)/(L-R), (T+B)/(B-T), 0.5f, 1.0f },
|
||||||
|
};
|
||||||
|
wgpuQueueWriteBuffer(wgpuDeviceGetDefaultQueue(g_wgpuDevice), g_resources.Uniforms, 0, mvp, sizeof(mvp));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Setup viewport
|
||||||
|
wgpuRenderPassEncoderSetViewport(ctx, 0, 0, draw_data->DisplaySize.x, draw_data->DisplaySize.y, 0, 1);
|
||||||
|
|
||||||
|
// Bind shader and vertex buffers
|
||||||
|
unsigned int stride = sizeof(ImDrawVert);
|
||||||
|
unsigned int offset = 0;
|
||||||
|
wgpuRenderPassEncoderSetVertexBuffer(ctx, 0, fr->VertexBuffer, offset, fr->VertexBufferSize * stride);
|
||||||
|
wgpuRenderPassEncoderSetIndexBuffer(ctx, fr->IndexBuffer, sizeof(ImDrawIdx) == 2 ? WGPUIndexFormat_Uint16 : WGPUIndexFormat_Uint32, 0, fr->IndexBufferSize * sizeof(ImDrawIdx));
|
||||||
|
wgpuRenderPassEncoderSetPipeline(ctx, g_pipelineState);
|
||||||
|
wgpuRenderPassEncoderSetBindGroup(ctx, 0, g_resources.CommonBindGroup, 0, NULL);
|
||||||
|
|
||||||
|
// Setup blend factor
|
||||||
|
WGPUColor blend_color = { 0.f, 0.f, 0.f, 0.f };
|
||||||
|
wgpuRenderPassEncoderSetBlendColor(ctx, &blend_color);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Render function
|
||||||
|
// (this used to be set in io.RenderDrawListsFn and called by ImGui::Render(), but you can now call this directly from your main loop)
|
||||||
|
void ImGui_ImplWGPU_RenderDrawData(ImDrawData* draw_data, WGPURenderPassEncoder pass_encoder)
|
||||||
|
{
|
||||||
|
// Avoid rendering when minimized
|
||||||
|
if (draw_data->DisplaySize.x <= 0.0f || draw_data->DisplaySize.y <= 0.0f)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// FIXME: Assuming that this only gets called once per frame!
|
||||||
|
// If not, we can't just re-allocate the IB or VB, we'll have to do a proper allocator.
|
||||||
|
g_frameIndex = g_frameIndex + 1;
|
||||||
|
FrameResources* fr = &g_pFrameResources[g_frameIndex % g_numFramesInFlight];
|
||||||
|
|
||||||
|
// Create and grow vertex/index buffers if needed
|
||||||
|
if (fr->VertexBuffer == NULL || fr->VertexBufferSize < draw_data->TotalVtxCount)
|
||||||
|
{
|
||||||
|
SafeRelease(fr->VertexBuffer);
|
||||||
|
SafeRelease(fr->VertexBufferHost);
|
||||||
|
fr->VertexBufferSize = draw_data->TotalVtxCount + 5000;
|
||||||
|
|
||||||
|
WGPUBufferDescriptor vb_desc =
|
||||||
|
{
|
||||||
|
NULL,
|
||||||
|
"Dear ImGui Vertex buffer",
|
||||||
|
WGPUBufferUsage_CopyDst | WGPUBufferUsage_Vertex,
|
||||||
|
fr->VertexBufferSize * sizeof(ImDrawVert),
|
||||||
|
false
|
||||||
|
};
|
||||||
|
fr->VertexBuffer = wgpuDeviceCreateBuffer(g_wgpuDevice, &vb_desc);
|
||||||
|
if (!fr->VertexBuffer)
|
||||||
|
return;
|
||||||
|
|
||||||
|
fr->VertexBufferHost = new ImDrawVert[fr->VertexBufferSize];
|
||||||
|
}
|
||||||
|
if (fr->IndexBuffer == NULL || fr->IndexBufferSize < draw_data->TotalIdxCount)
|
||||||
|
{
|
||||||
|
SafeRelease(fr->IndexBuffer);
|
||||||
|
SafeRelease(fr->IndexBufferHost);
|
||||||
|
fr->IndexBufferSize = draw_data->TotalIdxCount + 10000;
|
||||||
|
|
||||||
|
WGPUBufferDescriptor ib_desc =
|
||||||
|
{
|
||||||
|
NULL,
|
||||||
|
"Dear ImGui Index buffer",
|
||||||
|
WGPUBufferUsage_CopyDst | WGPUBufferUsage_Index,
|
||||||
|
fr->IndexBufferSize * sizeof(ImDrawIdx),
|
||||||
|
false
|
||||||
|
};
|
||||||
|
fr->IndexBuffer = wgpuDeviceCreateBuffer(g_wgpuDevice, &ib_desc);
|
||||||
|
if (!fr->IndexBuffer)
|
||||||
|
return;
|
||||||
|
|
||||||
|
fr->IndexBufferHost = new ImDrawIdx[fr->IndexBufferSize];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Upload vertex/index data into a single contiguous GPU buffer
|
||||||
|
ImDrawVert* vtx_dst = (ImDrawVert*)fr->VertexBufferHost;
|
||||||
|
ImDrawIdx* idx_dst = (ImDrawIdx*)fr->IndexBufferHost;
|
||||||
|
for (int n = 0; n < draw_data->CmdListsCount; n++)
|
||||||
|
{
|
||||||
|
const ImDrawList* cmd_list = draw_data->CmdLists[n];
|
||||||
|
memcpy(vtx_dst, cmd_list->VtxBuffer.Data, cmd_list->VtxBuffer.Size * sizeof(ImDrawVert));
|
||||||
|
memcpy(idx_dst, cmd_list->IdxBuffer.Data, cmd_list->IdxBuffer.Size * sizeof(ImDrawIdx));
|
||||||
|
vtx_dst += cmd_list->VtxBuffer.Size;
|
||||||
|
idx_dst += cmd_list->IdxBuffer.Size;
|
||||||
|
}
|
||||||
|
int64_t vb_write_size = ((char*)vtx_dst - (char*)fr->VertexBufferHost + 3) & ~3;
|
||||||
|
int64_t ib_write_size = ((char*)idx_dst - (char*)fr->IndexBufferHost + 3) & ~3;
|
||||||
|
wgpuQueueWriteBuffer(wgpuDeviceGetDefaultQueue(g_wgpuDevice), fr->VertexBuffer, 0, fr->VertexBufferHost, vb_write_size);
|
||||||
|
wgpuQueueWriteBuffer(wgpuDeviceGetDefaultQueue(g_wgpuDevice), fr->IndexBuffer, 0, fr->IndexBufferHost, ib_write_size);
|
||||||
|
|
||||||
|
// Setup desired render state
|
||||||
|
ImGui_ImplWGPU_SetupRenderState(draw_data, pass_encoder, fr);
|
||||||
|
|
||||||
|
// Render command lists
|
||||||
|
// (Because we merged all buffers into a single one, we maintain our own offset into them)
|
||||||
|
int global_vtx_offset = 0;
|
||||||
|
int global_idx_offset = 0;
|
||||||
|
ImVec2 clip_off = draw_data->DisplayPos;
|
||||||
|
for (int n = 0; n < draw_data->CmdListsCount; n++)
|
||||||
|
{
|
||||||
|
const ImDrawList* cmd_list = draw_data->CmdLists[n];
|
||||||
|
for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++)
|
||||||
|
{
|
||||||
|
const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i];
|
||||||
|
if (pcmd->UserCallback != NULL)
|
||||||
|
{
|
||||||
|
// User callback, registered via ImDrawList::AddCallback()
|
||||||
|
// (ImDrawCallback_ResetRenderState is a special callback value used by the user to request the renderer to reset render state.)
|
||||||
|
if (pcmd->UserCallback == ImDrawCallback_ResetRenderState)
|
||||||
|
ImGui_ImplWGPU_SetupRenderState(draw_data, pass_encoder, fr);
|
||||||
|
else
|
||||||
|
pcmd->UserCallback(cmd_list, pcmd);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Bind custom texture
|
||||||
|
auto bind_group = g_resources.ImageBindGroups.GetVoidPtr(ImHashData(&pcmd->TextureId, sizeof(ImTextureID)));
|
||||||
|
if (bind_group)
|
||||||
|
{
|
||||||
|
wgpuRenderPassEncoderSetBindGroup(pass_encoder, 1, (WGPUBindGroup)bind_group, 0, NULL);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
WGPUBindGroup image_bind_group = ImGui_ImplWGPU_CreateImageBindGroup(g_resources.ImageBindGroupLayout, (WGPUTextureView)pcmd->TextureId);
|
||||||
|
g_resources.ImageBindGroups.SetVoidPtr(ImHashData(&pcmd->TextureId, sizeof(ImTextureID)), image_bind_group);
|
||||||
|
wgpuRenderPassEncoderSetBindGroup(pass_encoder, 1, image_bind_group, 0, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply Scissor, Bind texture, Draw
|
||||||
|
uint32_t clip_rect[4];
|
||||||
|
clip_rect[0] = static_cast<uint32_t>(pcmd->ClipRect.x - clip_off.x);
|
||||||
|
clip_rect[1] = static_cast<uint32_t>(pcmd->ClipRect.y - clip_off.y);
|
||||||
|
clip_rect[2] = static_cast<uint32_t>(pcmd->ClipRect.z - clip_off.x);
|
||||||
|
clip_rect[3] = static_cast<uint32_t>(pcmd->ClipRect.w - clip_off.y);
|
||||||
|
wgpuRenderPassEncoderSetScissorRect(pass_encoder, clip_rect[0], clip_rect[1], clip_rect[2] - clip_rect[0], clip_rect[3] - clip_rect[1]);
|
||||||
|
wgpuRenderPassEncoderDrawIndexed(pass_encoder, pcmd->ElemCount, 1, pcmd->IdxOffset + global_idx_offset, pcmd->VtxOffset + global_vtx_offset, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
global_idx_offset += cmd_list->IdxBuffer.Size;
|
||||||
|
global_vtx_offset += cmd_list->VtxBuffer.Size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static WGPUBuffer ImGui_ImplWGPU_CreateBufferFromData(const WGPUDevice& device, const void* data, uint64_t size, WGPUBufferUsage usage)
|
||||||
|
{
|
||||||
|
WGPUBufferDescriptor descriptor = {};
|
||||||
|
descriptor.size = size;
|
||||||
|
descriptor.usage = usage | WGPUBufferUsage_CopyDst;
|
||||||
|
WGPUBuffer buffer = wgpuDeviceCreateBuffer(device, &descriptor);
|
||||||
|
|
||||||
|
WGPUQueue queue = wgpuDeviceGetDefaultQueue(g_wgpuDevice);
|
||||||
|
wgpuQueueWriteBuffer(queue, buffer, 0, data, size);
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ImGui_ImplWGPU_CreateFontsTexture()
|
||||||
|
{
|
||||||
|
// Build texture atlas
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
unsigned char* pixels;
|
||||||
|
int width, height, size_pp;
|
||||||
|
io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height, &size_pp);
|
||||||
|
|
||||||
|
// Upload texture to graphics system
|
||||||
|
{
|
||||||
|
WGPUTextureDescriptor tex_desc = {};
|
||||||
|
tex_desc.label = "Dear ImGui Font Texture";
|
||||||
|
tex_desc.dimension = WGPUTextureDimension_2D;
|
||||||
|
tex_desc.size.width = width;
|
||||||
|
tex_desc.size.height = height;
|
||||||
|
tex_desc.size.depth = 1;
|
||||||
|
tex_desc.sampleCount = 1;
|
||||||
|
tex_desc.format = WGPUTextureFormat_RGBA8Unorm;
|
||||||
|
tex_desc.mipLevelCount = 1;
|
||||||
|
tex_desc.usage = WGPUTextureUsage_CopyDst | WGPUTextureUsage_Sampled;
|
||||||
|
g_resources.FontTexture = wgpuDeviceCreateTexture(g_wgpuDevice, &tex_desc);
|
||||||
|
|
||||||
|
WGPUTextureViewDescriptor tex_view_desc = {};
|
||||||
|
tex_view_desc.format = WGPUTextureFormat_RGBA8Unorm;
|
||||||
|
tex_view_desc.dimension = WGPUTextureViewDimension_2D;
|
||||||
|
tex_view_desc.baseMipLevel = 0;
|
||||||
|
tex_view_desc.mipLevelCount = 1;
|
||||||
|
tex_view_desc.baseArrayLayer = 0;
|
||||||
|
tex_view_desc.arrayLayerCount = 1;
|
||||||
|
tex_view_desc.aspect = WGPUTextureAspect_All;
|
||||||
|
g_resources.FontTextureView = wgpuTextureCreateView(g_resources.FontTexture, &tex_view_desc);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Upload texture data
|
||||||
|
{
|
||||||
|
WGPUBuffer staging_buffer = ImGui_ImplWGPU_CreateBufferFromData(g_wgpuDevice, pixels, (uint32_t)(width * size_pp * height), WGPUBufferUsage_CopySrc);
|
||||||
|
|
||||||
|
WGPUBufferCopyView bufferCopyView = {};
|
||||||
|
bufferCopyView.buffer = staging_buffer;
|
||||||
|
bufferCopyView.layout.offset = 0;
|
||||||
|
bufferCopyView.layout.bytesPerRow = width * size_pp;
|
||||||
|
bufferCopyView.layout.rowsPerImage = height;
|
||||||
|
|
||||||
|
WGPUTextureCopyView textureCopyView = {};
|
||||||
|
textureCopyView.texture = g_resources.FontTexture;
|
||||||
|
textureCopyView.mipLevel = 0;
|
||||||
|
textureCopyView.origin = { 0, 0, 0 };
|
||||||
|
#if !defined(__EMSCRIPTEN__) || HAS_EMSCRIPTEN_VERSION(2, 0, 14)
|
||||||
|
textureCopyView.aspect = WGPUTextureAspect_All;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
WGPUExtent3D copySize = { (uint32_t)width, (uint32_t)height, 1 };
|
||||||
|
|
||||||
|
WGPUCommandEncoderDescriptor enc_desc = {};
|
||||||
|
WGPUCommandEncoder encoder = wgpuDeviceCreateCommandEncoder(g_wgpuDevice, &enc_desc);
|
||||||
|
wgpuCommandEncoderCopyBufferToTexture(encoder, &bufferCopyView, &textureCopyView, ©Size);
|
||||||
|
WGPUCommandBufferDescriptor cmd_buf_desc = {};
|
||||||
|
WGPUCommandBuffer copy = wgpuCommandEncoderFinish(encoder, &cmd_buf_desc);
|
||||||
|
WGPUQueue queue = wgpuDeviceGetDefaultQueue(g_wgpuDevice);
|
||||||
|
wgpuQueueSubmit(queue, 1, ©);
|
||||||
|
|
||||||
|
wgpuCommandEncoderRelease(encoder);
|
||||||
|
wgpuBufferRelease(staging_buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the associated sampler
|
||||||
|
{
|
||||||
|
WGPUSamplerDescriptor sampler_desc = {};
|
||||||
|
sampler_desc.minFilter = WGPUFilterMode_Linear;
|
||||||
|
sampler_desc.magFilter = WGPUFilterMode_Linear;
|
||||||
|
sampler_desc.mipmapFilter = WGPUFilterMode_Linear;
|
||||||
|
sampler_desc.addressModeU = WGPUAddressMode_Repeat;
|
||||||
|
sampler_desc.addressModeV = WGPUAddressMode_Repeat;
|
||||||
|
sampler_desc.addressModeW = WGPUAddressMode_Repeat;
|
||||||
|
#if !defined(__EMSCRIPTEN__) || HAS_EMSCRIPTEN_VERSION(2, 0, 14)
|
||||||
|
sampler_desc.maxAnisotropy = 1;
|
||||||
|
#endif
|
||||||
|
g_resources.Sampler = wgpuDeviceCreateSampler(g_wgpuDevice, &sampler_desc);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Store our identifier
|
||||||
|
static_assert(sizeof(ImTextureID) >= sizeof(g_resources.FontTexture), "Can't pack descriptor handle into TexID, 32-bit not supported yet.");
|
||||||
|
io.Fonts->SetTexID((ImTextureID)g_resources.FontTextureView);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ImGui_ImplWGPU_CreateUniformBuffer()
|
||||||
|
{
|
||||||
|
WGPUBufferDescriptor ub_desc =
|
||||||
|
{
|
||||||
|
NULL,
|
||||||
|
"Dear ImGui Uniform buffer",
|
||||||
|
WGPUBufferUsage_CopyDst | WGPUBufferUsage_Uniform,
|
||||||
|
sizeof(Uniforms),
|
||||||
|
false
|
||||||
|
};
|
||||||
|
g_resources.Uniforms = wgpuDeviceCreateBuffer(g_wgpuDevice, &ub_desc);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ImGui_ImplWGPU_CreateDeviceObjects()
|
||||||
|
{
|
||||||
|
if (!g_wgpuDevice)
|
||||||
|
return false;
|
||||||
|
if (g_pipelineState)
|
||||||
|
ImGui_ImplWGPU_InvalidateDeviceObjects();
|
||||||
|
|
||||||
|
// Create render pipeline
|
||||||
|
WGPURenderPipelineDescriptor graphics_pipeline_desc = {};
|
||||||
|
graphics_pipeline_desc.primitiveTopology = WGPUPrimitiveTopology_TriangleList;
|
||||||
|
graphics_pipeline_desc.sampleCount = 1;
|
||||||
|
graphics_pipeline_desc.sampleMask = UINT_MAX;
|
||||||
|
|
||||||
|
WGPUBindGroupLayoutEntry common_bg_layout_entries[2] = {};
|
||||||
|
common_bg_layout_entries[0].binding = 0;
|
||||||
|
common_bg_layout_entries[0].visibility = WGPUShaderStage_Vertex;
|
||||||
|
#if !defined(__EMSCRIPTEN__) || HAS_EMSCRIPTEN_VERSION(2, 0, 14)
|
||||||
|
common_bg_layout_entries[0].buffer.type = WGPUBufferBindingType_Uniform;
|
||||||
|
#else
|
||||||
|
common_bg_layout_entries[0].type = WGPUBindingType_UniformBuffer;
|
||||||
|
#endif
|
||||||
|
common_bg_layout_entries[1].binding = 1;
|
||||||
|
common_bg_layout_entries[1].visibility = WGPUShaderStage_Fragment;
|
||||||
|
#if !defined(__EMSCRIPTEN__) || HAS_EMSCRIPTEN_VERSION(2, 0, 14)
|
||||||
|
common_bg_layout_entries[1].sampler.type = WGPUSamplerBindingType_Filtering;
|
||||||
|
#else
|
||||||
|
common_bg_layout_entries[1].type = WGPUBindingType_Sampler;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
WGPUBindGroupLayoutEntry image_bg_layout_entries[1] = {};
|
||||||
|
image_bg_layout_entries[0].binding = 0;
|
||||||
|
image_bg_layout_entries[0].visibility = WGPUShaderStage_Fragment;
|
||||||
|
#if !defined(__EMSCRIPTEN__) || HAS_EMSCRIPTEN_VERSION(2, 0, 14)
|
||||||
|
image_bg_layout_entries[0].texture.sampleType = WGPUTextureSampleType_Float;
|
||||||
|
image_bg_layout_entries[0].texture.viewDimension = WGPUTextureViewDimension_2D;
|
||||||
|
#else
|
||||||
|
image_bg_layout_entries[0].type = WGPUBindingType_SampledTexture;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
WGPUBindGroupLayoutDescriptor common_bg_layout_desc = {};
|
||||||
|
common_bg_layout_desc.entryCount = 2;
|
||||||
|
common_bg_layout_desc.entries = common_bg_layout_entries;
|
||||||
|
|
||||||
|
WGPUBindGroupLayoutDescriptor image_bg_layout_desc = {};
|
||||||
|
image_bg_layout_desc.entryCount = 1;
|
||||||
|
image_bg_layout_desc.entries = image_bg_layout_entries;
|
||||||
|
|
||||||
|
WGPUBindGroupLayout bg_layouts[2];
|
||||||
|
bg_layouts[0] = wgpuDeviceCreateBindGroupLayout(g_wgpuDevice, &common_bg_layout_desc);
|
||||||
|
bg_layouts[1] = wgpuDeviceCreateBindGroupLayout(g_wgpuDevice, &image_bg_layout_desc);
|
||||||
|
|
||||||
|
WGPUPipelineLayoutDescriptor layout_desc = {};
|
||||||
|
layout_desc.bindGroupLayoutCount = 2;
|
||||||
|
layout_desc.bindGroupLayouts = bg_layouts;
|
||||||
|
graphics_pipeline_desc.layout = wgpuDeviceCreatePipelineLayout(g_wgpuDevice, &layout_desc);
|
||||||
|
|
||||||
|
// Create the vertex shader
|
||||||
|
WGPUProgrammableStageDescriptor vertex_shader_desc = ImGui_ImplWGPU_CreateShaderModule(__glsl_shader_vert_spv, sizeof(__glsl_shader_vert_spv) / sizeof(uint32_t));
|
||||||
|
graphics_pipeline_desc.vertexStage = vertex_shader_desc;
|
||||||
|
|
||||||
|
// Vertex input configuration
|
||||||
|
WGPUVertexAttributeDescriptor attribute_binding_desc[] =
|
||||||
|
{
|
||||||
|
{ WGPUVertexFormat_Float2, (uint64_t)IM_OFFSETOF(ImDrawVert, pos), 0 },
|
||||||
|
{ WGPUVertexFormat_Float2, (uint64_t)IM_OFFSETOF(ImDrawVert, uv), 1 },
|
||||||
|
{ WGPUVertexFormat_UChar4Norm, (uint64_t)IM_OFFSETOF(ImDrawVert, col), 2 },
|
||||||
|
};
|
||||||
|
|
||||||
|
WGPUVertexBufferLayoutDescriptor buffer_binding_desc;
|
||||||
|
buffer_binding_desc.arrayStride = sizeof(ImDrawVert);
|
||||||
|
buffer_binding_desc.stepMode = WGPUInputStepMode_Vertex;
|
||||||
|
buffer_binding_desc.attributeCount = 3;
|
||||||
|
buffer_binding_desc.attributes = attribute_binding_desc;
|
||||||
|
|
||||||
|
WGPUVertexStateDescriptor vertex_state_desc = {};
|
||||||
|
vertex_state_desc.indexFormat = WGPUIndexFormat_Undefined;
|
||||||
|
vertex_state_desc.vertexBufferCount = 1;
|
||||||
|
vertex_state_desc.vertexBuffers = &buffer_binding_desc;
|
||||||
|
|
||||||
|
graphics_pipeline_desc.vertexState = &vertex_state_desc;
|
||||||
|
|
||||||
|
// Create the pixel shader
|
||||||
|
WGPUProgrammableStageDescriptor pixel_shader_desc = ImGui_ImplWGPU_CreateShaderModule(__glsl_shader_frag_spv, sizeof(__glsl_shader_frag_spv) / sizeof(uint32_t));
|
||||||
|
graphics_pipeline_desc.fragmentStage = &pixel_shader_desc;
|
||||||
|
|
||||||
|
// Create the blending setup
|
||||||
|
WGPUColorStateDescriptor color_state = {};
|
||||||
|
{
|
||||||
|
color_state.format = g_renderTargetFormat;
|
||||||
|
color_state.alphaBlend.operation = WGPUBlendOperation_Add;
|
||||||
|
color_state.alphaBlend.srcFactor = WGPUBlendFactor_One;
|
||||||
|
color_state.alphaBlend.dstFactor = WGPUBlendFactor_OneMinusSrcAlpha;
|
||||||
|
color_state.colorBlend.operation = WGPUBlendOperation_Add;
|
||||||
|
color_state.colorBlend.srcFactor = WGPUBlendFactor_SrcAlpha;
|
||||||
|
color_state.colorBlend.dstFactor = WGPUBlendFactor_OneMinusSrcAlpha;
|
||||||
|
color_state.writeMask = WGPUColorWriteMask_All;
|
||||||
|
|
||||||
|
graphics_pipeline_desc.colorStateCount = 1;
|
||||||
|
graphics_pipeline_desc.colorStates = &color_state;
|
||||||
|
graphics_pipeline_desc.alphaToCoverageEnabled = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the rasterizer state
|
||||||
|
WGPURasterizationStateDescriptor raster_desc = {};
|
||||||
|
{
|
||||||
|
raster_desc.cullMode = WGPUCullMode_None;
|
||||||
|
raster_desc.frontFace = WGPUFrontFace_CW;
|
||||||
|
raster_desc.depthBias = 0;
|
||||||
|
raster_desc.depthBiasClamp = 0;
|
||||||
|
raster_desc.depthBiasSlopeScale = 0;
|
||||||
|
graphics_pipeline_desc.rasterizationState = &raster_desc;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create depth-stencil State
|
||||||
|
WGPUDepthStencilStateDescriptor depth_desc = {};
|
||||||
|
{
|
||||||
|
// Configure disabled state
|
||||||
|
depth_desc.format = WGPUTextureFormat_Undefined;
|
||||||
|
depth_desc.depthWriteEnabled = true;
|
||||||
|
depth_desc.depthCompare = WGPUCompareFunction_Always;
|
||||||
|
depth_desc.stencilReadMask = 0;
|
||||||
|
depth_desc.stencilWriteMask = 0;
|
||||||
|
depth_desc.stencilBack.compare = WGPUCompareFunction_Always;
|
||||||
|
depth_desc.stencilBack.failOp = WGPUStencilOperation_Keep;
|
||||||
|
depth_desc.stencilBack.depthFailOp = WGPUStencilOperation_Keep;
|
||||||
|
depth_desc.stencilBack.passOp = WGPUStencilOperation_Keep;
|
||||||
|
depth_desc.stencilFront.compare = WGPUCompareFunction_Always;
|
||||||
|
depth_desc.stencilFront.failOp = WGPUStencilOperation_Keep;
|
||||||
|
depth_desc.stencilFront.depthFailOp = WGPUStencilOperation_Keep;
|
||||||
|
depth_desc.stencilFront.passOp = WGPUStencilOperation_Keep;
|
||||||
|
|
||||||
|
// No depth buffer corresponds to no configuration
|
||||||
|
graphics_pipeline_desc.depthStencilState = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_pipelineState = wgpuDeviceCreateRenderPipeline(g_wgpuDevice, &graphics_pipeline_desc);
|
||||||
|
|
||||||
|
ImGui_ImplWGPU_CreateFontsTexture();
|
||||||
|
ImGui_ImplWGPU_CreateUniformBuffer();
|
||||||
|
|
||||||
|
// Create resource bind group
|
||||||
|
WGPUBindGroupEntry common_bg_entries[] =
|
||||||
|
{
|
||||||
|
{ 0, g_resources.Uniforms, 0, sizeof(Uniforms), 0, 0 },
|
||||||
|
{ 1, 0, 0, 0, g_resources.Sampler, 0 },
|
||||||
|
};
|
||||||
|
|
||||||
|
WGPUBindGroupDescriptor common_bg_descriptor = {};
|
||||||
|
common_bg_descriptor.layout = bg_layouts[0];
|
||||||
|
common_bg_descriptor.entryCount = sizeof(common_bg_entries) / sizeof(WGPUBindGroupEntry);
|
||||||
|
common_bg_descriptor.entries = common_bg_entries;
|
||||||
|
g_resources.CommonBindGroup = wgpuDeviceCreateBindGroup(g_wgpuDevice, &common_bg_descriptor);
|
||||||
|
g_resources.ImageBindGroupLayout = bg_layouts[1];
|
||||||
|
|
||||||
|
WGPUBindGroup image_bind_group = ImGui_ImplWGPU_CreateImageBindGroup(bg_layouts[1], g_resources.FontTextureView);
|
||||||
|
g_resources.ImageBindGroup = image_bind_group;
|
||||||
|
g_resources.ImageBindGroups.SetVoidPtr(ImHashData(&g_resources.FontTextureView, sizeof(ImTextureID)), image_bind_group);
|
||||||
|
|
||||||
|
SafeRelease(vertex_shader_desc.module);
|
||||||
|
SafeRelease(pixel_shader_desc.module);
|
||||||
|
SafeRelease(bg_layouts[0]);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGui_ImplWGPU_InvalidateDeviceObjects()
|
||||||
|
{
|
||||||
|
if (!g_wgpuDevice)
|
||||||
|
return;
|
||||||
|
|
||||||
|
SafeRelease(g_pipelineState);
|
||||||
|
SafeRelease(g_resources);
|
||||||
|
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
io.Fonts->SetTexID(NULL); // We copied g_pFontTextureView to io.Fonts->TexID so let's clear that as well.
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < g_numFramesInFlight; i++)
|
||||||
|
SafeRelease(g_pFrameResources[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ImGui_ImplWGPU_Init(WGPUDevice device, int num_frames_in_flight, WGPUTextureFormat rt_format)
|
||||||
|
{
|
||||||
|
// Setup backend capabilities flags
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
io.BackendRendererName = "imgui_impl_webgpu";
|
||||||
|
io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes.
|
||||||
|
|
||||||
|
g_wgpuDevice = device;
|
||||||
|
g_renderTargetFormat = rt_format;
|
||||||
|
g_pFrameResources = new FrameResources[num_frames_in_flight];
|
||||||
|
g_numFramesInFlight = num_frames_in_flight;
|
||||||
|
g_frameIndex = UINT_MAX;
|
||||||
|
|
||||||
|
g_resources.FontTexture = NULL;
|
||||||
|
g_resources.FontTextureView = NULL;
|
||||||
|
g_resources.Sampler = NULL;
|
||||||
|
g_resources.Uniforms = NULL;
|
||||||
|
g_resources.CommonBindGroup = NULL;
|
||||||
|
g_resources.ImageBindGroupLayout = NULL;
|
||||||
|
g_resources.ImageBindGroups.Data.reserve(100);
|
||||||
|
g_resources.ImageBindGroup = NULL;
|
||||||
|
|
||||||
|
// Create buffers with a default size (they will later be grown as needed)
|
||||||
|
for (int i = 0; i < num_frames_in_flight; i++)
|
||||||
|
{
|
||||||
|
FrameResources* fr = &g_pFrameResources[i];
|
||||||
|
fr->IndexBuffer = NULL;
|
||||||
|
fr->VertexBuffer = NULL;
|
||||||
|
fr->IndexBufferHost = NULL;
|
||||||
|
fr->VertexBufferHost = NULL;
|
||||||
|
fr->IndexBufferSize = 10000;
|
||||||
|
fr->VertexBufferSize = 5000;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGui_ImplWGPU_Shutdown()
|
||||||
|
{
|
||||||
|
ImGui_ImplWGPU_InvalidateDeviceObjects();
|
||||||
|
delete[] g_pFrameResources;
|
||||||
|
g_pFrameResources = NULL;
|
||||||
|
g_wgpuDevice = NULL;
|
||||||
|
g_numFramesInFlight = 0;
|
||||||
|
g_frameIndex = UINT_MAX;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGui_ImplWGPU_NewFrame()
|
||||||
|
{
|
||||||
|
if (!g_pipelineState)
|
||||||
|
ImGui_ImplWGPU_CreateDeviceObjects();
|
||||||
|
}
|
24
backend/imgui_impl_wgpu.h
Normal file
24
backend/imgui_impl_wgpu.h
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
// dear imgui: Renderer for WebGPU
|
||||||
|
// This needs to be used along with a Platform Binding (e.g. GLFW)
|
||||||
|
// (Please note that WebGPU is currently experimental, will not run on non-beta browsers, and may break.)
|
||||||
|
|
||||||
|
// Implemented features:
|
||||||
|
// [X] Renderer: User texture binding. Use 'WGPUTextureView' as ImTextureID. Read the FAQ about ImTextureID!
|
||||||
|
// [X] Renderer: Support for large meshes (64k+ vertices) with 16-bit indices.
|
||||||
|
|
||||||
|
// You can copy and use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
||||||
|
// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
|
||||||
|
// Read online: https://github.com/ocornut/imgui/tree/master/docs
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include "imgui.h" // IMGUI_IMPL_API
|
||||||
|
#include <webgpu/webgpu.h>
|
||||||
|
|
||||||
|
IMGUI_IMPL_API bool ImGui_ImplWGPU_Init(WGPUDevice device, int num_frames_in_flight, WGPUTextureFormat rt_format);
|
||||||
|
IMGUI_IMPL_API void ImGui_ImplWGPU_Shutdown();
|
||||||
|
IMGUI_IMPL_API void ImGui_ImplWGPU_NewFrame();
|
||||||
|
IMGUI_IMPL_API void ImGui_ImplWGPU_RenderDrawData(ImDrawData* draw_data, WGPURenderPassEncoder pass_encoder);
|
||||||
|
|
||||||
|
// Use if you want to reset your rendering device without losing Dear ImGui state.
|
||||||
|
IMGUI_IMPL_API void ImGui_ImplWGPU_InvalidateDeviceObjects();
|
||||||
|
IMGUI_IMPL_API bool ImGui_ImplWGPU_CreateDeviceObjects();
|
542
backend/imgui_impl_win32.cpp
Normal file
542
backend/imgui_impl_win32.cpp
Normal file
@ -0,0 +1,542 @@
|
|||||||
|
// dear imgui: Platform Backend for Windows (standard windows API for 32 and 64 bits applications)
|
||||||
|
// This needs to be used along with a Renderer (e.g. DirectX11, OpenGL3, Vulkan..)
|
||||||
|
|
||||||
|
// Implemented features:
|
||||||
|
// [X] Platform: Clipboard support (for Win32 this is actually part of core dear imgui)
|
||||||
|
// [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'.
|
||||||
|
// [X] Platform: Keyboard arrays indexed using VK_* Virtual Key Codes, e.g. ImGui::IsKeyPressed(VK_SPACE).
|
||||||
|
// [X] Platform: Gamepad support. Enabled with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'.
|
||||||
|
|
||||||
|
// You can copy and use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
||||||
|
// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
|
||||||
|
// Read online: https://github.com/ocornut/imgui/tree/master/docs
|
||||||
|
|
||||||
|
#include "imgui.h"
|
||||||
|
#include "imgui_impl_win32.h"
|
||||||
|
#ifndef WIN32_LEAN_AND_MEAN
|
||||||
|
#define WIN32_LEAN_AND_MEAN
|
||||||
|
#endif
|
||||||
|
#include <windows.h>
|
||||||
|
#include <tchar.h>
|
||||||
|
#include <dwmapi.h>
|
||||||
|
|
||||||
|
// Configuration flags to add in your imconfig.h file:
|
||||||
|
//#define IMGUI_IMPL_WIN32_DISABLE_GAMEPAD // Disable gamepad support (this used to be meaningful before <1.81) but we know load XInput dynamically so the option is less relevant now.
|
||||||
|
|
||||||
|
// Using XInput for gamepad (will load DLL dynamically)
|
||||||
|
#ifndef IMGUI_IMPL_WIN32_DISABLE_GAMEPAD
|
||||||
|
#include <XInput.h>
|
||||||
|
typedef DWORD (WINAPI *PFN_XInputGetCapabilities)(DWORD, DWORD, XINPUT_CAPABILITIES*);
|
||||||
|
typedef DWORD (WINAPI *PFN_XInputGetState)(DWORD, XINPUT_STATE*);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// CHANGELOG
|
||||||
|
// (minor and older changes stripped away, please see git history for details)
|
||||||
|
// 2021-03-23: Inputs: Clearing keyboard down array when losing focus (WM_KILLFOCUS).
|
||||||
|
// 2021-02-18: Added ImGui_ImplWin32_EnableAlphaCompositing(). Non Visual Studio users will need to link with dwmapi.lib (MinGW/gcc: use -ldwmapi).
|
||||||
|
// 2021-02-17: Fixed ImGui_ImplWin32_EnableDpiAwareness() attempting to get SetProcessDpiAwareness from shcore.dll on Windows 8 whereas it is only supported on Windows 8.1.
|
||||||
|
// 2021-01-25: Inputs: Dynamically loading XInput DLL.
|
||||||
|
// 2020-12-04: Misc: Fixed setting of io.DisplaySize to invalid/uninitialized data when after hwnd has been closed.
|
||||||
|
// 2020-03-03: Inputs: Calling AddInputCharacterUTF16() to support surrogate pairs leading to codepoint >= 0x10000 (for more complete CJK inputs)
|
||||||
|
// 2020-02-17: Added ImGui_ImplWin32_EnableDpiAwareness(), ImGui_ImplWin32_GetDpiScaleForHwnd(), ImGui_ImplWin32_GetDpiScaleForMonitor() helper functions.
|
||||||
|
// 2020-01-14: Inputs: Added support for #define IMGUI_IMPL_WIN32_DISABLE_GAMEPAD/IMGUI_IMPL_WIN32_DISABLE_LINKING_XINPUT.
|
||||||
|
// 2019-12-05: Inputs: Added support for ImGuiMouseCursor_NotAllowed mouse cursor.
|
||||||
|
// 2019-05-11: Inputs: Don't filter value from WM_CHAR before calling AddInputCharacter().
|
||||||
|
// 2019-01-17: Misc: Using GetForegroundWindow()+IsChild() instead of GetActiveWindow() to be compatible with windows created in a different thread or parent.
|
||||||
|
// 2019-01-17: Inputs: Added support for mouse buttons 4 and 5 via WM_XBUTTON* messages.
|
||||||
|
// 2019-01-15: Inputs: Added support for XInput gamepads (if ImGuiConfigFlags_NavEnableGamepad is set by user application).
|
||||||
|
// 2018-11-30: Misc: Setting up io.BackendPlatformName so it can be displayed in the About Window.
|
||||||
|
// 2018-06-29: Inputs: Added support for the ImGuiMouseCursor_Hand cursor.
|
||||||
|
// 2018-06-10: Inputs: Fixed handling of mouse wheel messages to support fine position messages (typically sent by track-pads).
|
||||||
|
// 2018-06-08: Misc: Extracted imgui_impl_win32.cpp/.h away from the old combined DX9/DX10/DX11/DX12 examples.
|
||||||
|
// 2018-03-20: Misc: Setup io.BackendFlags ImGuiBackendFlags_HasMouseCursors and ImGuiBackendFlags_HasSetMousePos flags + honor ImGuiConfigFlags_NoMouseCursorChange flag.
|
||||||
|
// 2018-02-20: Inputs: Added support for mouse cursors (ImGui::GetMouseCursor() value and WM_SETCURSOR message handling).
|
||||||
|
// 2018-02-06: Inputs: Added mapping for ImGuiKey_Space.
|
||||||
|
// 2018-02-06: Inputs: Honoring the io.WantSetMousePos by repositioning the mouse (when using navigation and ImGuiConfigFlags_NavMoveMouse is set).
|
||||||
|
// 2018-02-06: Misc: Removed call to ImGui::Shutdown() which is not available from 1.60 WIP, user needs to call CreateContext/DestroyContext themselves.
|
||||||
|
// 2018-01-20: Inputs: Added Horizontal Mouse Wheel support.
|
||||||
|
// 2018-01-08: Inputs: Added mapping for ImGuiKey_Insert.
|
||||||
|
// 2018-01-05: Inputs: Added WM_LBUTTONDBLCLK double-click handlers for window classes with the CS_DBLCLKS flag.
|
||||||
|
// 2017-10-23: Inputs: Added WM_SYSKEYDOWN / WM_SYSKEYUP handlers so e.g. the VK_MENU key can be read.
|
||||||
|
// 2017-10-23: Inputs: Using Win32 ::SetCapture/::GetCapture() to retrieve mouse positions outside the client area when dragging.
|
||||||
|
// 2016-11-12: Inputs: Only call Win32 ::SetCursor(NULL) when io.MouseDrawCursor is set.
|
||||||
|
|
||||||
|
// Win32 Data
|
||||||
|
static HWND g_hWnd = NULL;
|
||||||
|
static INT64 g_Time = 0;
|
||||||
|
static INT64 g_TicksPerSecond = 0;
|
||||||
|
static ImGuiMouseCursor g_LastMouseCursor = ImGuiMouseCursor_COUNT;
|
||||||
|
static bool g_HasGamepad = false;
|
||||||
|
static bool g_WantUpdateHasGamepad = true;
|
||||||
|
|
||||||
|
// XInput DLL and functions
|
||||||
|
#ifndef IMGUI_IMPL_WIN32_DISABLE_GAMEPAD
|
||||||
|
static HMODULE g_XInputDLL = NULL;
|
||||||
|
static PFN_XInputGetCapabilities g_XInputGetCapabilities = NULL;
|
||||||
|
static PFN_XInputGetState g_XInputGetState = NULL;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Functions
|
||||||
|
bool ImGui_ImplWin32_Init(void* hwnd)
|
||||||
|
{
|
||||||
|
if (!::QueryPerformanceFrequency((LARGE_INTEGER*)&g_TicksPerSecond))
|
||||||
|
return false;
|
||||||
|
if (!::QueryPerformanceCounter((LARGE_INTEGER*)&g_Time))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Setup backend capabilities flags
|
||||||
|
g_hWnd = (HWND)hwnd;
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
io.BackendFlags |= ImGuiBackendFlags_HasMouseCursors; // We can honor GetMouseCursor() values (optional)
|
||||||
|
io.BackendFlags |= ImGuiBackendFlags_HasSetMousePos; // We can honor io.WantSetMousePos requests (optional, rarely used)
|
||||||
|
io.BackendPlatformName = "imgui_impl_win32";
|
||||||
|
io.ImeWindowHandle = hwnd;
|
||||||
|
|
||||||
|
// Keyboard mapping. Dear ImGui will use those indices to peek into the io.KeysDown[] array that we will update during the application lifetime.
|
||||||
|
io.KeyMap[ImGuiKey_Tab] = VK_TAB;
|
||||||
|
io.KeyMap[ImGuiKey_LeftArrow] = VK_LEFT;
|
||||||
|
io.KeyMap[ImGuiKey_RightArrow] = VK_RIGHT;
|
||||||
|
io.KeyMap[ImGuiKey_UpArrow] = VK_UP;
|
||||||
|
io.KeyMap[ImGuiKey_DownArrow] = VK_DOWN;
|
||||||
|
io.KeyMap[ImGuiKey_PageUp] = VK_PRIOR;
|
||||||
|
io.KeyMap[ImGuiKey_PageDown] = VK_NEXT;
|
||||||
|
io.KeyMap[ImGuiKey_Home] = VK_HOME;
|
||||||
|
io.KeyMap[ImGuiKey_End] = VK_END;
|
||||||
|
io.KeyMap[ImGuiKey_Insert] = VK_INSERT;
|
||||||
|
io.KeyMap[ImGuiKey_Delete] = VK_DELETE;
|
||||||
|
io.KeyMap[ImGuiKey_Backspace] = VK_BACK;
|
||||||
|
io.KeyMap[ImGuiKey_Space] = VK_SPACE;
|
||||||
|
io.KeyMap[ImGuiKey_Enter] = VK_RETURN;
|
||||||
|
io.KeyMap[ImGuiKey_Escape] = VK_ESCAPE;
|
||||||
|
io.KeyMap[ImGuiKey_KeyPadEnter] = VK_RETURN;
|
||||||
|
io.KeyMap[ImGuiKey_A] = 'A';
|
||||||
|
io.KeyMap[ImGuiKey_C] = 'C';
|
||||||
|
io.KeyMap[ImGuiKey_V] = 'V';
|
||||||
|
io.KeyMap[ImGuiKey_X] = 'X';
|
||||||
|
io.KeyMap[ImGuiKey_Y] = 'Y';
|
||||||
|
io.KeyMap[ImGuiKey_Z] = 'Z';
|
||||||
|
|
||||||
|
// Dynamically load XInput library
|
||||||
|
#ifndef IMGUI_IMPL_WIN32_DISABLE_GAMEPAD
|
||||||
|
const char* xinput_dll_names[] =
|
||||||
|
{
|
||||||
|
"xinput1_4.dll", // Windows 8+
|
||||||
|
"xinput1_3.dll", // DirectX SDK
|
||||||
|
"xinput9_1_0.dll", // Windows Vista, Windows 7
|
||||||
|
"xinput1_2.dll", // DirectX SDK
|
||||||
|
"xinput1_1.dll" // DirectX SDK
|
||||||
|
};
|
||||||
|
for (int n = 0; n < IM_ARRAYSIZE(xinput_dll_names); n++)
|
||||||
|
if (HMODULE dll = ::LoadLibraryA(xinput_dll_names[n]))
|
||||||
|
{
|
||||||
|
g_XInputDLL = dll;
|
||||||
|
g_XInputGetCapabilities = (PFN_XInputGetCapabilities)::GetProcAddress(dll, "XInputGetCapabilities");
|
||||||
|
g_XInputGetState = (PFN_XInputGetState)::GetProcAddress(dll, "XInputGetState");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
#endif // IMGUI_IMPL_WIN32_DISABLE_GAMEPAD
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGui_ImplWin32_Shutdown()
|
||||||
|
{
|
||||||
|
// Unload XInput library
|
||||||
|
#ifndef IMGUI_IMPL_WIN32_DISABLE_GAMEPAD
|
||||||
|
if (g_XInputDLL)
|
||||||
|
::FreeLibrary(g_XInputDLL);
|
||||||
|
g_XInputDLL = NULL;
|
||||||
|
g_XInputGetCapabilities = NULL;
|
||||||
|
g_XInputGetState = NULL;
|
||||||
|
#endif // IMGUI_IMPL_WIN32_DISABLE_GAMEPAD
|
||||||
|
|
||||||
|
g_hWnd = NULL;
|
||||||
|
g_Time = 0;
|
||||||
|
g_TicksPerSecond = 0;
|
||||||
|
g_LastMouseCursor = ImGuiMouseCursor_COUNT;
|
||||||
|
g_HasGamepad = false;
|
||||||
|
g_WantUpdateHasGamepad = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool ImGui_ImplWin32_UpdateMouseCursor()
|
||||||
|
{
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
if (io.ConfigFlags & ImGuiConfigFlags_NoMouseCursorChange)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
ImGuiMouseCursor imgui_cursor = ImGui::GetMouseCursor();
|
||||||
|
if (imgui_cursor == ImGuiMouseCursor_None || io.MouseDrawCursor)
|
||||||
|
{
|
||||||
|
// Hide OS mouse cursor if imgui is drawing it or if it wants no cursor
|
||||||
|
::SetCursor(NULL);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Show OS mouse cursor
|
||||||
|
LPTSTR win32_cursor = IDC_ARROW;
|
||||||
|
switch (imgui_cursor)
|
||||||
|
{
|
||||||
|
case ImGuiMouseCursor_Arrow: win32_cursor = IDC_ARROW; break;
|
||||||
|
case ImGuiMouseCursor_TextInput: win32_cursor = IDC_IBEAM; break;
|
||||||
|
case ImGuiMouseCursor_ResizeAll: win32_cursor = IDC_SIZEALL; break;
|
||||||
|
case ImGuiMouseCursor_ResizeEW: win32_cursor = IDC_SIZEWE; break;
|
||||||
|
case ImGuiMouseCursor_ResizeNS: win32_cursor = IDC_SIZENS; break;
|
||||||
|
case ImGuiMouseCursor_ResizeNESW: win32_cursor = IDC_SIZENESW; break;
|
||||||
|
case ImGuiMouseCursor_ResizeNWSE: win32_cursor = IDC_SIZENWSE; break;
|
||||||
|
case ImGuiMouseCursor_Hand: win32_cursor = IDC_HAND; break;
|
||||||
|
case ImGuiMouseCursor_NotAllowed: win32_cursor = IDC_NO; break;
|
||||||
|
}
|
||||||
|
::SetCursor(::LoadCursor(NULL, win32_cursor));
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ImGui_ImplWin32_UpdateMousePos()
|
||||||
|
{
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
IM_ASSERT(g_hWnd != 0);
|
||||||
|
|
||||||
|
// Set OS mouse position if requested (rarely used, only when ImGuiConfigFlags_NavEnableSetMousePos is enabled by user)
|
||||||
|
if (io.WantSetMousePos)
|
||||||
|
{
|
||||||
|
POINT pos = { (int)io.MousePos.x, (int)io.MousePos.y };
|
||||||
|
if (::ClientToScreen(g_hWnd, &pos))
|
||||||
|
::SetCursorPos(pos.x, pos.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set mouse position
|
||||||
|
io.MousePos = ImVec2(-FLT_MAX, -FLT_MAX);
|
||||||
|
POINT pos;
|
||||||
|
if (HWND active_window = ::GetForegroundWindow())
|
||||||
|
if (active_window == g_hWnd || ::IsChild(active_window, g_hWnd))
|
||||||
|
if (::GetCursorPos(&pos) && ::ScreenToClient(g_hWnd, &pos))
|
||||||
|
io.MousePos = ImVec2((float)pos.x, (float)pos.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Gamepad navigation mapping
|
||||||
|
static void ImGui_ImplWin32_UpdateGamepads()
|
||||||
|
{
|
||||||
|
#ifndef IMGUI_IMPL_WIN32_DISABLE_GAMEPAD
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
memset(io.NavInputs, 0, sizeof(io.NavInputs));
|
||||||
|
if ((io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Calling XInputGetState() every frame on disconnected gamepads is unfortunately too slow.
|
||||||
|
// Instead we refresh gamepad availability by calling XInputGetCapabilities() _only_ after receiving WM_DEVICECHANGE.
|
||||||
|
if (g_WantUpdateHasGamepad)
|
||||||
|
{
|
||||||
|
XINPUT_CAPABILITIES caps;
|
||||||
|
g_HasGamepad = g_XInputGetCapabilities ? (g_XInputGetCapabilities(0, XINPUT_FLAG_GAMEPAD, &caps) == ERROR_SUCCESS) : false;
|
||||||
|
g_WantUpdateHasGamepad = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
io.BackendFlags &= ~ImGuiBackendFlags_HasGamepad;
|
||||||
|
XINPUT_STATE xinput_state;
|
||||||
|
if (g_HasGamepad && g_XInputGetState && g_XInputGetState(0, &xinput_state) == ERROR_SUCCESS)
|
||||||
|
{
|
||||||
|
const XINPUT_GAMEPAD& gamepad = xinput_state.Gamepad;
|
||||||
|
io.BackendFlags |= ImGuiBackendFlags_HasGamepad;
|
||||||
|
|
||||||
|
#define MAP_BUTTON(NAV_NO, BUTTON_ENUM) { io.NavInputs[NAV_NO] = (gamepad.wButtons & BUTTON_ENUM) ? 1.0f : 0.0f; }
|
||||||
|
#define MAP_ANALOG(NAV_NO, VALUE, V0, V1) { float vn = (float)(VALUE - V0) / (float)(V1 - V0); if (vn > 1.0f) vn = 1.0f; if (vn > 0.0f && io.NavInputs[NAV_NO] < vn) io.NavInputs[NAV_NO] = vn; }
|
||||||
|
MAP_BUTTON(ImGuiNavInput_Activate, XINPUT_GAMEPAD_A); // Cross / A
|
||||||
|
MAP_BUTTON(ImGuiNavInput_Cancel, XINPUT_GAMEPAD_B); // Circle / B
|
||||||
|
MAP_BUTTON(ImGuiNavInput_Menu, XINPUT_GAMEPAD_X); // Square / X
|
||||||
|
MAP_BUTTON(ImGuiNavInput_Input, XINPUT_GAMEPAD_Y); // Triangle / Y
|
||||||
|
MAP_BUTTON(ImGuiNavInput_DpadLeft, XINPUT_GAMEPAD_DPAD_LEFT); // D-Pad Left
|
||||||
|
MAP_BUTTON(ImGuiNavInput_DpadRight, XINPUT_GAMEPAD_DPAD_RIGHT); // D-Pad Right
|
||||||
|
MAP_BUTTON(ImGuiNavInput_DpadUp, XINPUT_GAMEPAD_DPAD_UP); // D-Pad Up
|
||||||
|
MAP_BUTTON(ImGuiNavInput_DpadDown, XINPUT_GAMEPAD_DPAD_DOWN); // D-Pad Down
|
||||||
|
MAP_BUTTON(ImGuiNavInput_FocusPrev, XINPUT_GAMEPAD_LEFT_SHOULDER); // L1 / LB
|
||||||
|
MAP_BUTTON(ImGuiNavInput_FocusNext, XINPUT_GAMEPAD_RIGHT_SHOULDER); // R1 / RB
|
||||||
|
MAP_BUTTON(ImGuiNavInput_TweakSlow, XINPUT_GAMEPAD_LEFT_SHOULDER); // L1 / LB
|
||||||
|
MAP_BUTTON(ImGuiNavInput_TweakFast, XINPUT_GAMEPAD_RIGHT_SHOULDER); // R1 / RB
|
||||||
|
MAP_ANALOG(ImGuiNavInput_LStickLeft, gamepad.sThumbLX, -XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, -32768);
|
||||||
|
MAP_ANALOG(ImGuiNavInput_LStickRight, gamepad.sThumbLX, +XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, +32767);
|
||||||
|
MAP_ANALOG(ImGuiNavInput_LStickUp, gamepad.sThumbLY, +XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, +32767);
|
||||||
|
MAP_ANALOG(ImGuiNavInput_LStickDown, gamepad.sThumbLY, -XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, -32767);
|
||||||
|
#undef MAP_BUTTON
|
||||||
|
#undef MAP_ANALOG
|
||||||
|
}
|
||||||
|
#endif // #ifndef IMGUI_IMPL_WIN32_DISABLE_GAMEPAD
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGui_ImplWin32_NewFrame()
|
||||||
|
{
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
IM_ASSERT(io.Fonts->IsBuilt() && "Font atlas not built! It is generally built by the renderer backend. Missing call to renderer _NewFrame() function? e.g. ImGui_ImplOpenGL3_NewFrame().");
|
||||||
|
|
||||||
|
// Setup display size (every frame to accommodate for window resizing)
|
||||||
|
RECT rect = { 0, 0, 0, 0 };
|
||||||
|
::GetClientRect(g_hWnd, &rect);
|
||||||
|
io.DisplaySize = ImVec2((float)(rect.right - rect.left), (float)(rect.bottom - rect.top));
|
||||||
|
|
||||||
|
// Setup time step
|
||||||
|
INT64 current_time = 0;
|
||||||
|
::QueryPerformanceCounter((LARGE_INTEGER*)¤t_time);
|
||||||
|
io.DeltaTime = (float)(current_time - g_Time) / g_TicksPerSecond;
|
||||||
|
g_Time = current_time;
|
||||||
|
|
||||||
|
// Read keyboard modifiers inputs
|
||||||
|
io.KeyCtrl = (::GetKeyState(VK_CONTROL) & 0x8000) != 0;
|
||||||
|
io.KeyShift = (::GetKeyState(VK_SHIFT) & 0x8000) != 0;
|
||||||
|
io.KeyAlt = (::GetKeyState(VK_MENU) & 0x8000) != 0;
|
||||||
|
io.KeySuper = false;
|
||||||
|
// io.KeysDown[], io.MousePos, io.MouseDown[], io.MouseWheel: filled by the WndProc handler below.
|
||||||
|
|
||||||
|
// Update OS mouse position
|
||||||
|
ImGui_ImplWin32_UpdateMousePos();
|
||||||
|
|
||||||
|
// Update OS mouse cursor with the cursor requested by imgui
|
||||||
|
ImGuiMouseCursor mouse_cursor = io.MouseDrawCursor ? ImGuiMouseCursor_None : ImGui::GetMouseCursor();
|
||||||
|
if (g_LastMouseCursor != mouse_cursor)
|
||||||
|
{
|
||||||
|
g_LastMouseCursor = mouse_cursor;
|
||||||
|
ImGui_ImplWin32_UpdateMouseCursor();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update game controllers (if enabled and available)
|
||||||
|
ImGui_ImplWin32_UpdateGamepads();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allow compilation with old Windows SDK. MinGW doesn't have default _WIN32_WINNT/WINVER versions.
|
||||||
|
#ifndef WM_MOUSEHWHEEL
|
||||||
|
#define WM_MOUSEHWHEEL 0x020E
|
||||||
|
#endif
|
||||||
|
#ifndef DBT_DEVNODES_CHANGED
|
||||||
|
#define DBT_DEVNODES_CHANGED 0x0007
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Win32 message handler (process Win32 mouse/keyboard inputs, etc.)
|
||||||
|
// Call from your application's message handler.
|
||||||
|
// When implementing your own backend, you can read the io.WantCaptureMouse, io.WantCaptureKeyboard flags to tell if Dear ImGui wants to use your inputs.
|
||||||
|
// - When io.WantCaptureMouse is true, do not dispatch mouse input data to your main application.
|
||||||
|
// - When io.WantCaptureKeyboard is true, do not dispatch keyboard input data to your main application.
|
||||||
|
// Generally you may always pass all inputs to Dear ImGui, and hide them from your application based on those two flags.
|
||||||
|
// PS: In this Win32 handler, we use the capture API (GetCapture/SetCapture/ReleaseCapture) to be able to read mouse coordinates when dragging mouse outside of our window bounds.
|
||||||
|
// PS: We treat DBLCLK messages as regular mouse down messages, so this code will work on windows classes that have the CS_DBLCLKS flag set. Our own example app code doesn't set this flag.
|
||||||
|
#if 0
|
||||||
|
// Copy this line into your .cpp file to forward declare the function.
|
||||||
|
extern IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
|
||||||
|
#endif
|
||||||
|
IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
||||||
|
{
|
||||||
|
if (ImGui::GetCurrentContext() == NULL)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
switch (msg)
|
||||||
|
{
|
||||||
|
case WM_LBUTTONDOWN: case WM_LBUTTONDBLCLK:
|
||||||
|
case WM_RBUTTONDOWN: case WM_RBUTTONDBLCLK:
|
||||||
|
case WM_MBUTTONDOWN: case WM_MBUTTONDBLCLK:
|
||||||
|
case WM_XBUTTONDOWN: case WM_XBUTTONDBLCLK:
|
||||||
|
{
|
||||||
|
int button = 0;
|
||||||
|
if (msg == WM_LBUTTONDOWN || msg == WM_LBUTTONDBLCLK) { button = 0; }
|
||||||
|
if (msg == WM_RBUTTONDOWN || msg == WM_RBUTTONDBLCLK) { button = 1; }
|
||||||
|
if (msg == WM_MBUTTONDOWN || msg == WM_MBUTTONDBLCLK) { button = 2; }
|
||||||
|
if (msg == WM_XBUTTONDOWN || msg == WM_XBUTTONDBLCLK) { button = (GET_XBUTTON_WPARAM(wParam) == XBUTTON1) ? 3 : 4; }
|
||||||
|
if (!ImGui::IsAnyMouseDown() && ::GetCapture() == NULL)
|
||||||
|
::SetCapture(hwnd);
|
||||||
|
io.MouseDown[button] = true;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
case WM_LBUTTONUP:
|
||||||
|
case WM_RBUTTONUP:
|
||||||
|
case WM_MBUTTONUP:
|
||||||
|
case WM_XBUTTONUP:
|
||||||
|
{
|
||||||
|
int button = 0;
|
||||||
|
if (msg == WM_LBUTTONUP) { button = 0; }
|
||||||
|
if (msg == WM_RBUTTONUP) { button = 1; }
|
||||||
|
if (msg == WM_MBUTTONUP) { button = 2; }
|
||||||
|
if (msg == WM_XBUTTONUP) { button = (GET_XBUTTON_WPARAM(wParam) == XBUTTON1) ? 3 : 4; }
|
||||||
|
io.MouseDown[button] = false;
|
||||||
|
if (!ImGui::IsAnyMouseDown() && ::GetCapture() == hwnd)
|
||||||
|
::ReleaseCapture();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
case WM_MOUSEWHEEL:
|
||||||
|
io.MouseWheel += (float)GET_WHEEL_DELTA_WPARAM(wParam) / (float)WHEEL_DELTA;
|
||||||
|
return 0;
|
||||||
|
case WM_MOUSEHWHEEL:
|
||||||
|
io.MouseWheelH += (float)GET_WHEEL_DELTA_WPARAM(wParam) / (float)WHEEL_DELTA;
|
||||||
|
return 0;
|
||||||
|
case WM_KEYDOWN:
|
||||||
|
case WM_SYSKEYDOWN:
|
||||||
|
if (wParam < 256)
|
||||||
|
io.KeysDown[wParam] = 1;
|
||||||
|
return 0;
|
||||||
|
case WM_KEYUP:
|
||||||
|
case WM_SYSKEYUP:
|
||||||
|
if (wParam < 256)
|
||||||
|
io.KeysDown[wParam] = 0;
|
||||||
|
return 0;
|
||||||
|
case WM_KILLFOCUS:
|
||||||
|
memset(io.KeysDown, 0, sizeof(io.KeysDown));
|
||||||
|
return 0;
|
||||||
|
case WM_CHAR:
|
||||||
|
// You can also use ToAscii()+GetKeyboardState() to retrieve characters.
|
||||||
|
if (wParam > 0 && wParam < 0x10000)
|
||||||
|
io.AddInputCharacterUTF16((unsigned short)wParam);
|
||||||
|
return 0;
|
||||||
|
case WM_SETCURSOR:
|
||||||
|
if (LOWORD(lParam) == HTCLIENT && ImGui_ImplWin32_UpdateMouseCursor())
|
||||||
|
return 1;
|
||||||
|
return 0;
|
||||||
|
case WM_DEVICECHANGE:
|
||||||
|
if ((UINT)wParam == DBT_DEVNODES_CHANGED)
|
||||||
|
g_WantUpdateHasGamepad = true;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------------
|
||||||
|
// DPI-related helpers (optional)
|
||||||
|
//--------------------------------------------------------------------------------------------------------
|
||||||
|
// - Use to enable DPI awareness without having to create an application manifest.
|
||||||
|
// - Your own app may already do this via a manifest or explicit calls. This is mostly useful for our examples/ apps.
|
||||||
|
// - In theory we could call simple functions from Windows SDK such as SetProcessDPIAware(), SetProcessDpiAwareness(), etc.
|
||||||
|
// but most of the functions provided by Microsoft require Windows 8.1/10+ SDK at compile time and Windows 8/10+ at runtime,
|
||||||
|
// neither we want to require the user to have. So we dynamically select and load those functions to avoid dependencies.
|
||||||
|
//---------------------------------------------------------------------------------------------------------
|
||||||
|
// This is the scheme successfully used by GLFW (from which we borrowed some of the code) and other apps aiming to be highly portable.
|
||||||
|
// ImGui_ImplWin32_EnableDpiAwareness() is just a helper called by main.cpp, we don't call it automatically.
|
||||||
|
// If you are trying to implement your own backend for your own engine, you may ignore that noise.
|
||||||
|
//---------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// Implement some of the functions and types normally declared in recent Windows SDK.
|
||||||
|
#if !defined(_versionhelpers_H_INCLUDED_) && !defined(_INC_VERSIONHELPERS)
|
||||||
|
static BOOL IsWindowsVersionOrGreater(WORD major, WORD minor, WORD sp)
|
||||||
|
{
|
||||||
|
OSVERSIONINFOEXW osvi = { sizeof(osvi), major, minor, 0, 0, { 0 }, sp, 0, 0, 0, 0 };
|
||||||
|
DWORD mask = VER_MAJORVERSION | VER_MINORVERSION | VER_SERVICEPACKMAJOR;
|
||||||
|
ULONGLONG cond = ::VerSetConditionMask(0, VER_MAJORVERSION, VER_GREATER_EQUAL);
|
||||||
|
cond = ::VerSetConditionMask(cond, VER_MINORVERSION, VER_GREATER_EQUAL);
|
||||||
|
cond = ::VerSetConditionMask(cond, VER_SERVICEPACKMAJOR, VER_GREATER_EQUAL);
|
||||||
|
return ::VerifyVersionInfoW(&osvi, mask, cond);
|
||||||
|
}
|
||||||
|
#define IsWindowsVistaOrGreater() IsWindowsVersionOrGreater(HIBYTE(0x0600), LOBYTE(0x0600), 0) // _WIN32_WINNT_VISTA
|
||||||
|
#define IsWindows8OrGreater() IsWindowsVersionOrGreater(HIBYTE(0x0602), LOBYTE(0x0602), 0) // _WIN32_WINNT_WIN8
|
||||||
|
#define IsWindows8Point1OrGreater() IsWindowsVersionOrGreater(HIBYTE(0x0603), LOBYTE(0x0603), 0) // _WIN32_WINNT_WINBLUE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef DPI_ENUMS_DECLARED
|
||||||
|
typedef enum { PROCESS_DPI_UNAWARE = 0, PROCESS_SYSTEM_DPI_AWARE = 1, PROCESS_PER_MONITOR_DPI_AWARE = 2 } PROCESS_DPI_AWARENESS;
|
||||||
|
typedef enum { MDT_EFFECTIVE_DPI = 0, MDT_ANGULAR_DPI = 1, MDT_RAW_DPI = 2, MDT_DEFAULT = MDT_EFFECTIVE_DPI } MONITOR_DPI_TYPE;
|
||||||
|
#endif
|
||||||
|
#ifndef _DPI_AWARENESS_CONTEXTS_
|
||||||
|
DECLARE_HANDLE(DPI_AWARENESS_CONTEXT);
|
||||||
|
#define DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE (DPI_AWARENESS_CONTEXT)-3
|
||||||
|
#endif
|
||||||
|
#ifndef DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2
|
||||||
|
#define DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 (DPI_AWARENESS_CONTEXT)-4
|
||||||
|
#endif
|
||||||
|
typedef HRESULT(WINAPI* PFN_SetProcessDpiAwareness)(PROCESS_DPI_AWARENESS); // Shcore.lib + dll, Windows 8.1+
|
||||||
|
typedef HRESULT(WINAPI* PFN_GetDpiForMonitor)(HMONITOR, MONITOR_DPI_TYPE, UINT*, UINT*); // Shcore.lib + dll, Windows 8.1+
|
||||||
|
typedef DPI_AWARENESS_CONTEXT(WINAPI* PFN_SetThreadDpiAwarenessContext)(DPI_AWARENESS_CONTEXT); // User32.lib + dll, Windows 10 v1607+ (Creators Update)
|
||||||
|
|
||||||
|
// Helper function to enable DPI awareness without setting up a manifest
|
||||||
|
void ImGui_ImplWin32_EnableDpiAwareness()
|
||||||
|
{
|
||||||
|
// if (IsWindows10OrGreater()) // This needs a manifest to succeed. Instead we try to grab the function pointer!
|
||||||
|
{
|
||||||
|
static HINSTANCE user32_dll = ::LoadLibraryA("user32.dll"); // Reference counted per-process
|
||||||
|
if (PFN_SetThreadDpiAwarenessContext SetThreadDpiAwarenessContextFn = (PFN_SetThreadDpiAwarenessContext)::GetProcAddress(user32_dll, "SetThreadDpiAwarenessContext"))
|
||||||
|
{
|
||||||
|
SetThreadDpiAwarenessContextFn(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (IsWindows8Point1OrGreater())
|
||||||
|
{
|
||||||
|
static HINSTANCE shcore_dll = ::LoadLibraryA("shcore.dll"); // Reference counted per-process
|
||||||
|
if (PFN_SetProcessDpiAwareness SetProcessDpiAwarenessFn = (PFN_SetProcessDpiAwareness)::GetProcAddress(shcore_dll, "SetProcessDpiAwareness"))
|
||||||
|
{
|
||||||
|
SetProcessDpiAwarenessFn(PROCESS_PER_MONITOR_DPI_AWARE);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#if _WIN32_WINNT >= 0x0600
|
||||||
|
::SetProcessDPIAware();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(_MSC_VER) && !defined(NOGDI)
|
||||||
|
#pragma comment(lib, "gdi32") // Link with gdi32.lib for GetDeviceCaps(). MinGW will require linking with '-lgdi32'
|
||||||
|
#endif
|
||||||
|
|
||||||
|
float ImGui_ImplWin32_GetDpiScaleForMonitor(void* monitor)
|
||||||
|
{
|
||||||
|
UINT xdpi = 96, ydpi = 96;
|
||||||
|
static BOOL bIsWindows8Point1OrGreater = IsWindows8Point1OrGreater();
|
||||||
|
if (bIsWindows8Point1OrGreater)
|
||||||
|
{
|
||||||
|
static HINSTANCE shcore_dll = ::LoadLibraryA("shcore.dll"); // Reference counted per-process
|
||||||
|
if (PFN_GetDpiForMonitor GetDpiForMonitorFn = (PFN_GetDpiForMonitor)::GetProcAddress(shcore_dll, "GetDpiForMonitor"))
|
||||||
|
GetDpiForMonitorFn((HMONITOR)monitor, MDT_EFFECTIVE_DPI, &xdpi, &ydpi);
|
||||||
|
}
|
||||||
|
#ifndef NOGDI
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const HDC dc = ::GetDC(NULL);
|
||||||
|
xdpi = ::GetDeviceCaps(dc, LOGPIXELSX);
|
||||||
|
ydpi = ::GetDeviceCaps(dc, LOGPIXELSY);
|
||||||
|
::ReleaseDC(NULL, dc);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
IM_ASSERT(xdpi == ydpi); // Please contact me if you hit this assert!
|
||||||
|
return xdpi / 96.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
float ImGui_ImplWin32_GetDpiScaleForHwnd(void* hwnd)
|
||||||
|
{
|
||||||
|
HMONITOR monitor = ::MonitorFromWindow((HWND)hwnd, MONITOR_DEFAULTTONEAREST);
|
||||||
|
return ImGui_ImplWin32_GetDpiScaleForMonitor(monitor);
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------------------------------------
|
||||||
|
// Transparency related helpers (optional)
|
||||||
|
//--------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#if defined(_MSC_VER)
|
||||||
|
#pragma comment(lib, "dwmapi") // Link with dwmapi.lib. MinGW will require linking with '-ldwmapi'
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// [experimental]
|
||||||
|
// Borrowed from GLFW's function updateFramebufferTransparency() in src/win32_window.c
|
||||||
|
// (the Dwm* functions are Vista era functions but we are borrowing logic from GLFW)
|
||||||
|
void ImGui_ImplWin32_EnableAlphaCompositing(void* hwnd)
|
||||||
|
{
|
||||||
|
if (!IsWindowsVistaOrGreater())
|
||||||
|
return;
|
||||||
|
|
||||||
|
BOOL composition;
|
||||||
|
if (FAILED(::DwmIsCompositionEnabled(&composition)) || !composition)
|
||||||
|
return;
|
||||||
|
|
||||||
|
BOOL opaque;
|
||||||
|
DWORD color;
|
||||||
|
if (IsWindows8OrGreater() || (SUCCEEDED(::DwmGetColorizationColor(&color, &opaque)) && !opaque))
|
||||||
|
{
|
||||||
|
HRGN region = ::CreateRectRgn(0, 0, -1, -1);
|
||||||
|
DWM_BLURBEHIND bb = {};
|
||||||
|
bb.dwFlags = DWM_BB_ENABLE | DWM_BB_BLURREGION;
|
||||||
|
bb.hRgnBlur = region;
|
||||||
|
bb.fEnable = TRUE;
|
||||||
|
::DwmEnableBlurBehindWindow((HWND)hwnd, &bb);
|
||||||
|
::DeleteObject(region);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DWM_BLURBEHIND bb = {};
|
||||||
|
bb.dwFlags = DWM_BB_ENABLE;
|
||||||
|
::DwmEnableBlurBehindWindow((HWND)hwnd, &bb);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------------------------------------
|
41
backend/imgui_impl_win32.h
Normal file
41
backend/imgui_impl_win32.h
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
// dear imgui: Platform Backend for Windows (standard windows API for 32 and 64 bits applications)
|
||||||
|
// This needs to be used along with a Renderer (e.g. DirectX11, OpenGL3, Vulkan..)
|
||||||
|
|
||||||
|
// Implemented features:
|
||||||
|
// [X] Platform: Clipboard support (for Win32 this is actually part of core dear imgui)
|
||||||
|
// [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'.
|
||||||
|
// [X] Platform: Keyboard arrays indexed using VK_* Virtual Key Codes, e.g. ImGui::IsKeyPressed(VK_SPACE).
|
||||||
|
// [X] Platform: Gamepad support. Enabled with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'.
|
||||||
|
|
||||||
|
// You can copy and use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
||||||
|
// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
|
||||||
|
// Read online: https://github.com/ocornut/imgui/tree/master/docs
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include "imgui.h" // IMGUI_IMPL_API
|
||||||
|
|
||||||
|
IMGUI_IMPL_API bool ImGui_ImplWin32_Init(void* hwnd);
|
||||||
|
IMGUI_IMPL_API void ImGui_ImplWin32_Shutdown();
|
||||||
|
IMGUI_IMPL_API void ImGui_ImplWin32_NewFrame();
|
||||||
|
|
||||||
|
// Win32 message handler your application need to call.
|
||||||
|
// - Intentionally commented out in a '#if 0' block to avoid dragging dependencies on <windows.h> from this helper.
|
||||||
|
// - You should COPY the line below into your .cpp code to forward declare the function and then you can call it.
|
||||||
|
#if 0
|
||||||
|
extern IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// DPI-related helpers (optional)
|
||||||
|
// - Use to enable DPI awareness without having to create an application manifest.
|
||||||
|
// - Your own app may already do this via a manifest or explicit calls. This is mostly useful for our examples/ apps.
|
||||||
|
// - In theory we could call simple functions from Windows SDK such as SetProcessDPIAware(), SetProcessDpiAwareness(), etc.
|
||||||
|
// but most of the functions provided by Microsoft require Windows 8.1/10+ SDK at compile time and Windows 8/10+ at runtime,
|
||||||
|
// neither we want to require the user to have. So we dynamically select and load those functions to avoid dependencies.
|
||||||
|
IMGUI_IMPL_API void ImGui_ImplWin32_EnableDpiAwareness();
|
||||||
|
IMGUI_IMPL_API float ImGui_ImplWin32_GetDpiScaleForHwnd(void* hwnd); // HWND hwnd
|
||||||
|
IMGUI_IMPL_API float ImGui_ImplWin32_GetDpiScaleForMonitor(void* monitor); // HMONITOR monitor
|
||||||
|
|
||||||
|
// Transparency related helpers (optional) [experimental]
|
||||||
|
// - Use to enable alpha compositing transparency with the desktop.
|
||||||
|
// - Use together with e.g. clearing your framebuffer with zero-alpha.
|
||||||
|
IMGUI_IMPL_API void ImGui_ImplWin32_EnableAlphaCompositing(void* hwnd); // HWND hwnd
|
Loading…
x
Reference in New Issue
Block a user