Update imgui to latest.
parent
ba877b6e78
commit
df94c38b0f
|
@ -0,0 +1,581 @@
|
||||||
|
// 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: Keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy ALLEGRO_KEY_* values will also be supported unless IMGUI_DISABLE_OBSOLETE_KEYIO is set]
|
||||||
|
// [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 use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
||||||
|
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
|
||||||
|
// 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)
|
||||||
|
// 2022-01-26: Inputs: replaced short-lived io.AddKeyModsEvent() (added two weeks ago)with io.AddKeyEvent() using ImGuiKey_ModXXX flags. Sorry for the confusion.
|
||||||
|
// 2022-01-17: Inputs: calling new io.AddMousePosEvent(), io.AddMouseButtonEvent(), io.AddMouseWheelEvent() API (1.87+).
|
||||||
|
// 2022-01-17: Inputs: always calling io.AddKeyModsEvent() next and before key event (not in NewFrame) to fix input queue with very low framerates.
|
||||||
|
// 2022-01-10: Inputs: calling new io.AddKeyEvent(), io.AddKeyModsEvent() + io.SetKeyEventNativeData() API (1.87+). Support for full ImGuiKey range.
|
||||||
|
// 2021-12-08: Renderer: Fixed mishandling of the the ImDrawCmd::IdxOffset field! This is an old bug but it never had an effect until some internal rendering changes in 1.86.
|
||||||
|
// 2021-08-17: Calling io.AddFocusEvent() on ALLEGRO_EVENT_DISPLAY_SWITCH_OUT/ALLEGRO_EVENT_DISPLAY_SWITCH_IN events.
|
||||||
|
// 2021-06-29: Reorganized backend to pull data from a single structure to facilitate usage with multiple-contexts (all g_XXXX access changed to bd->XXXX).
|
||||||
|
// 2021-05-19: Renderer: Replaced direct access to ImDrawCmd::TextureId with a call to ImDrawCmd::GetTexID(). (will become a requirement)
|
||||||
|
// 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
|
||||||
|
|
||||||
|
// Allegro Data
|
||||||
|
struct ImGui_ImplAllegro5_Data
|
||||||
|
{
|
||||||
|
ALLEGRO_DISPLAY* Display;
|
||||||
|
ALLEGRO_BITMAP* Texture;
|
||||||
|
double Time;
|
||||||
|
ALLEGRO_MOUSE_CURSOR* MouseCursorInvisible;
|
||||||
|
ALLEGRO_VERTEX_DECL* VertexDecl;
|
||||||
|
char* ClipboardTextData;
|
||||||
|
|
||||||
|
ImGui_ImplAllegro5_Data() { memset((void*)this, 0, sizeof(*this)); }
|
||||||
|
};
|
||||||
|
|
||||||
|
// Backend data stored in io.BackendPlatformUserData to allow support for multiple Dear ImGui contexts
|
||||||
|
// It is STRONGLY preferred that you use docking branch with multi-viewports (== single Dear ImGui context + multiple windows) instead of multiple Dear ImGui contexts.
|
||||||
|
// FIXME: multi-context support is not well tested and probably dysfunctional in this backend.
|
||||||
|
static ImGui_ImplAllegro5_Data* ImGui_ImplAllegro5_GetBackendData() { return ImGui::GetCurrentContext() ? (ImGui_ImplAllegro5_Data*)ImGui::GetIO().BackendPlatformUserData : 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
|
||||||
|
ImGui_ImplAllegro5_Data* bd = ImGui_ImplAllegro5_GetBackendData();
|
||||||
|
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
|
||||||
|
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
|
||||||
|
{
|
||||||
|
// Project scissor/clipping rectangles into framebuffer space
|
||||||
|
ImVec2 clip_min(pcmd->ClipRect.x - clip_off.x, pcmd->ClipRect.y - clip_off.y);
|
||||||
|
ImVec2 clip_max(pcmd->ClipRect.z - clip_off.x, pcmd->ClipRect.w - clip_off.y);
|
||||||
|
if (clip_max.x <= clip_min.x || clip_max.y <= clip_min.y)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Apply scissor/clipping rectangle, Draw
|
||||||
|
ALLEGRO_BITMAP* texture = (ALLEGRO_BITMAP*)pcmd->GetTexID();
|
||||||
|
al_set_clipping_rectangle(clip_min.x, clip_min.y, clip_max.x - clip_min.x, clip_max.y - clip_min.y);
|
||||||
|
al_draw_prim(&vertices[0], bd->VertexDecl, texture, pcmd->IdxOffset, pcmd->IdxOffset + pcmd->ElemCount, ALLEGRO_PRIM_TRIANGLE_LIST);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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
|
||||||
|
ImGui_ImplAllegro5_Data* bd = ImGui_ImplAllegro5_GetBackendData();
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
unsigned char* pixels;
|
||||||
|
int width, height;
|
||||||
|
io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height);
|
||||||
|
|
||||||
|
// Create texture
|
||||||
|
// (Bilinear sampling is required by default. Set 'io.Fonts->Flags |= ImFontAtlasFlags_NoBakedLines' or 'style.AntiAliasedLinesUseTex = false' to allow point/nearest sampling)
|
||||||
|
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((ImTextureID)(intptr_t)cloned_img);
|
||||||
|
bd->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);
|
||||||
|
bd->MouseCursorInvisible = al_create_mouse_cursor(mouse_cursor, 0, 0);
|
||||||
|
al_destroy_bitmap(mouse_cursor);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGui_ImplAllegro5_InvalidateDeviceObjects()
|
||||||
|
{
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
ImGui_ImplAllegro5_Data* bd = ImGui_ImplAllegro5_GetBackendData();
|
||||||
|
if (bd->Texture)
|
||||||
|
{
|
||||||
|
io.Fonts->SetTexID(NULL);
|
||||||
|
al_destroy_bitmap(bd->Texture);
|
||||||
|
bd->Texture = NULL;
|
||||||
|
}
|
||||||
|
if (bd->MouseCursorInvisible)
|
||||||
|
{
|
||||||
|
al_destroy_mouse_cursor(bd->MouseCursorInvisible);
|
||||||
|
bd->MouseCursorInvisible = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#if ALLEGRO_HAS_CLIPBOARD
|
||||||
|
static const char* ImGui_ImplAllegro5_GetClipboardText(void*)
|
||||||
|
{
|
||||||
|
ImGui_ImplAllegro5_Data* bd = ImGui_ImplAllegro5_GetBackendData();
|
||||||
|
if (bd->ClipboardTextData)
|
||||||
|
al_free(bd->ClipboardTextData);
|
||||||
|
bd->ClipboardTextData = al_get_clipboard_text(bd->Display);
|
||||||
|
return bd->ClipboardTextData;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ImGui_ImplAllegro5_SetClipboardText(void*, const char* text)
|
||||||
|
{
|
||||||
|
ImGui_ImplAllegro5_Data* bd = ImGui_ImplAllegro5_GetBackendData();
|
||||||
|
al_set_clipboard_text(bd->Display, text);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static ImGuiKey ImGui_ImplAllegro5_KeyCodeToImGuiKey(int key_code)
|
||||||
|
{
|
||||||
|
switch (key_code)
|
||||||
|
{
|
||||||
|
case ALLEGRO_KEY_TAB: return ImGuiKey_Tab;
|
||||||
|
case ALLEGRO_KEY_LEFT: return ImGuiKey_LeftArrow;
|
||||||
|
case ALLEGRO_KEY_RIGHT: return ImGuiKey_RightArrow;
|
||||||
|
case ALLEGRO_KEY_UP: return ImGuiKey_UpArrow;
|
||||||
|
case ALLEGRO_KEY_DOWN: return ImGuiKey_DownArrow;
|
||||||
|
case ALLEGRO_KEY_PGUP: return ImGuiKey_PageUp;
|
||||||
|
case ALLEGRO_KEY_PGDN: return ImGuiKey_PageDown;
|
||||||
|
case ALLEGRO_KEY_HOME: return ImGuiKey_Home;
|
||||||
|
case ALLEGRO_KEY_END: return ImGuiKey_End;
|
||||||
|
case ALLEGRO_KEY_INSERT: return ImGuiKey_Insert;
|
||||||
|
case ALLEGRO_KEY_DELETE: return ImGuiKey_Delete;
|
||||||
|
case ALLEGRO_KEY_BACKSPACE: return ImGuiKey_Backspace;
|
||||||
|
case ALLEGRO_KEY_SPACE: return ImGuiKey_Space;
|
||||||
|
case ALLEGRO_KEY_ENTER: return ImGuiKey_Enter;
|
||||||
|
case ALLEGRO_KEY_ESCAPE: return ImGuiKey_Escape;
|
||||||
|
case ALLEGRO_KEY_QUOTE: return ImGuiKey_Apostrophe;
|
||||||
|
case ALLEGRO_KEY_COMMA: return ImGuiKey_Comma;
|
||||||
|
case ALLEGRO_KEY_MINUS: return ImGuiKey_Minus;
|
||||||
|
case ALLEGRO_KEY_FULLSTOP: return ImGuiKey_Period;
|
||||||
|
case ALLEGRO_KEY_SLASH: return ImGuiKey_Slash;
|
||||||
|
case ALLEGRO_KEY_SEMICOLON: return ImGuiKey_Semicolon;
|
||||||
|
case ALLEGRO_KEY_EQUALS: return ImGuiKey_Equal;
|
||||||
|
case ALLEGRO_KEY_OPENBRACE: return ImGuiKey_LeftBracket;
|
||||||
|
case ALLEGRO_KEY_BACKSLASH: return ImGuiKey_Backslash;
|
||||||
|
case ALLEGRO_KEY_CLOSEBRACE: return ImGuiKey_RightBracket;
|
||||||
|
case ALLEGRO_KEY_TILDE: return ImGuiKey_GraveAccent;
|
||||||
|
case ALLEGRO_KEY_CAPSLOCK: return ImGuiKey_CapsLock;
|
||||||
|
case ALLEGRO_KEY_SCROLLLOCK: return ImGuiKey_ScrollLock;
|
||||||
|
case ALLEGRO_KEY_NUMLOCK: return ImGuiKey_NumLock;
|
||||||
|
case ALLEGRO_KEY_PRINTSCREEN: return ImGuiKey_PrintScreen;
|
||||||
|
case ALLEGRO_KEY_PAUSE: return ImGuiKey_Pause;
|
||||||
|
case ALLEGRO_KEY_PAD_0: return ImGuiKey_Keypad0;
|
||||||
|
case ALLEGRO_KEY_PAD_1: return ImGuiKey_Keypad1;
|
||||||
|
case ALLEGRO_KEY_PAD_2: return ImGuiKey_Keypad2;
|
||||||
|
case ALLEGRO_KEY_PAD_3: return ImGuiKey_Keypad3;
|
||||||
|
case ALLEGRO_KEY_PAD_4: return ImGuiKey_Keypad4;
|
||||||
|
case ALLEGRO_KEY_PAD_5: return ImGuiKey_Keypad5;
|
||||||
|
case ALLEGRO_KEY_PAD_6: return ImGuiKey_Keypad6;
|
||||||
|
case ALLEGRO_KEY_PAD_7: return ImGuiKey_Keypad7;
|
||||||
|
case ALLEGRO_KEY_PAD_8: return ImGuiKey_Keypad8;
|
||||||
|
case ALLEGRO_KEY_PAD_9: return ImGuiKey_Keypad9;
|
||||||
|
case ALLEGRO_KEY_PAD_DELETE: return ImGuiKey_KeypadDecimal;
|
||||||
|
case ALLEGRO_KEY_PAD_SLASH: return ImGuiKey_KeypadDivide;
|
||||||
|
case ALLEGRO_KEY_PAD_ASTERISK: return ImGuiKey_KeypadMultiply;
|
||||||
|
case ALLEGRO_KEY_PAD_MINUS: return ImGuiKey_KeypadSubtract;
|
||||||
|
case ALLEGRO_KEY_PAD_PLUS: return ImGuiKey_KeypadAdd;
|
||||||
|
case ALLEGRO_KEY_PAD_ENTER: return ImGuiKey_KeypadEnter;
|
||||||
|
case ALLEGRO_KEY_PAD_EQUALS: return ImGuiKey_KeypadEqual;
|
||||||
|
case ALLEGRO_KEY_LCTRL: return ImGuiKey_LeftCtrl;
|
||||||
|
case ALLEGRO_KEY_LSHIFT: return ImGuiKey_LeftShift;
|
||||||
|
case ALLEGRO_KEY_ALT: return ImGuiKey_LeftAlt;
|
||||||
|
case ALLEGRO_KEY_LWIN: return ImGuiKey_LeftSuper;
|
||||||
|
case ALLEGRO_KEY_RCTRL: return ImGuiKey_RightCtrl;
|
||||||
|
case ALLEGRO_KEY_RSHIFT: return ImGuiKey_RightShift;
|
||||||
|
case ALLEGRO_KEY_ALTGR: return ImGuiKey_RightAlt;
|
||||||
|
case ALLEGRO_KEY_RWIN: return ImGuiKey_RightSuper;
|
||||||
|
case ALLEGRO_KEY_MENU: return ImGuiKey_Menu;
|
||||||
|
case ALLEGRO_KEY_0: return ImGuiKey_0;
|
||||||
|
case ALLEGRO_KEY_1: return ImGuiKey_1;
|
||||||
|
case ALLEGRO_KEY_2: return ImGuiKey_2;
|
||||||
|
case ALLEGRO_KEY_3: return ImGuiKey_3;
|
||||||
|
case ALLEGRO_KEY_4: return ImGuiKey_4;
|
||||||
|
case ALLEGRO_KEY_5: return ImGuiKey_5;
|
||||||
|
case ALLEGRO_KEY_6: return ImGuiKey_6;
|
||||||
|
case ALLEGRO_KEY_7: return ImGuiKey_7;
|
||||||
|
case ALLEGRO_KEY_8: return ImGuiKey_8;
|
||||||
|
case ALLEGRO_KEY_9: return ImGuiKey_9;
|
||||||
|
case ALLEGRO_KEY_A: return ImGuiKey_A;
|
||||||
|
case ALLEGRO_KEY_B: return ImGuiKey_B;
|
||||||
|
case ALLEGRO_KEY_C: return ImGuiKey_C;
|
||||||
|
case ALLEGRO_KEY_D: return ImGuiKey_D;
|
||||||
|
case ALLEGRO_KEY_E: return ImGuiKey_E;
|
||||||
|
case ALLEGRO_KEY_F: return ImGuiKey_F;
|
||||||
|
case ALLEGRO_KEY_G: return ImGuiKey_G;
|
||||||
|
case ALLEGRO_KEY_H: return ImGuiKey_H;
|
||||||
|
case ALLEGRO_KEY_I: return ImGuiKey_I;
|
||||||
|
case ALLEGRO_KEY_J: return ImGuiKey_J;
|
||||||
|
case ALLEGRO_KEY_K: return ImGuiKey_K;
|
||||||
|
case ALLEGRO_KEY_L: return ImGuiKey_L;
|
||||||
|
case ALLEGRO_KEY_M: return ImGuiKey_M;
|
||||||
|
case ALLEGRO_KEY_N: return ImGuiKey_N;
|
||||||
|
case ALLEGRO_KEY_O: return ImGuiKey_O;
|
||||||
|
case ALLEGRO_KEY_P: return ImGuiKey_P;
|
||||||
|
case ALLEGRO_KEY_Q: return ImGuiKey_Q;
|
||||||
|
case ALLEGRO_KEY_R: return ImGuiKey_R;
|
||||||
|
case ALLEGRO_KEY_S: return ImGuiKey_S;
|
||||||
|
case ALLEGRO_KEY_T: return ImGuiKey_T;
|
||||||
|
case ALLEGRO_KEY_U: return ImGuiKey_U;
|
||||||
|
case ALLEGRO_KEY_V: return ImGuiKey_V;
|
||||||
|
case ALLEGRO_KEY_W: return ImGuiKey_W;
|
||||||
|
case ALLEGRO_KEY_X: return ImGuiKey_X;
|
||||||
|
case ALLEGRO_KEY_Y: return ImGuiKey_Y;
|
||||||
|
case ALLEGRO_KEY_Z: return ImGuiKey_Z;
|
||||||
|
case ALLEGRO_KEY_F1: return ImGuiKey_F1;
|
||||||
|
case ALLEGRO_KEY_F2: return ImGuiKey_F2;
|
||||||
|
case ALLEGRO_KEY_F3: return ImGuiKey_F3;
|
||||||
|
case ALLEGRO_KEY_F4: return ImGuiKey_F4;
|
||||||
|
case ALLEGRO_KEY_F5: return ImGuiKey_F5;
|
||||||
|
case ALLEGRO_KEY_F6: return ImGuiKey_F6;
|
||||||
|
case ALLEGRO_KEY_F7: return ImGuiKey_F7;
|
||||||
|
case ALLEGRO_KEY_F8: return ImGuiKey_F8;
|
||||||
|
case ALLEGRO_KEY_F9: return ImGuiKey_F9;
|
||||||
|
case ALLEGRO_KEY_F10: return ImGuiKey_F10;
|
||||||
|
case ALLEGRO_KEY_F11: return ImGuiKey_F11;
|
||||||
|
case ALLEGRO_KEY_F12: return ImGuiKey_F12;
|
||||||
|
default: return ImGuiKey_None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ImGui_ImplAllegro5_Init(ALLEGRO_DISPLAY* display)
|
||||||
|
{
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
IM_ASSERT(io.BackendPlatformUserData == NULL && "Already initialized a platform backend!");
|
||||||
|
|
||||||
|
// Setup backend capabilities flags
|
||||||
|
ImGui_ImplAllegro5_Data* bd = IM_NEW(ImGui_ImplAllegro5_Data)();
|
||||||
|
io.BackendPlatformUserData = (void*)bd;
|
||||||
|
io.BackendPlatformName = io.BackendRendererName = "imgui_impl_allegro5";
|
||||||
|
io.BackendFlags |= ImGuiBackendFlags_HasMouseCursors; // We can honor GetMouseCursor() values (optional)
|
||||||
|
|
||||||
|
bd->Display = display;
|
||||||
|
|
||||||
|
// 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 }
|
||||||
|
};
|
||||||
|
bd->VertexDecl = al_create_vertex_decl(elems, sizeof(ImDrawVertAllegro));
|
||||||
|
|
||||||
|
#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_Data* bd = ImGui_ImplAllegro5_GetBackendData();
|
||||||
|
IM_ASSERT(bd != NULL && "No platform backend to shutdown, or already shutdown?");
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
|
||||||
|
ImGui_ImplAllegro5_InvalidateDeviceObjects();
|
||||||
|
if (bd->VertexDecl)
|
||||||
|
al_destroy_vertex_decl(bd->VertexDecl);
|
||||||
|
if (bd->ClipboardTextData)
|
||||||
|
al_free(bd->ClipboardTextData);
|
||||||
|
|
||||||
|
io.BackendPlatformUserData = NULL;
|
||||||
|
io.BackendPlatformName = io.BackendRendererName = NULL;
|
||||||
|
IM_DELETE(bd);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ev->keyboard.modifiers seems always zero so using that...
|
||||||
|
static void ImGui_ImplAllegro5_UpdateKeyModifiers()
|
||||||
|
{
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
ALLEGRO_KEYBOARD_STATE keys;
|
||||||
|
al_get_keyboard_state(&keys);
|
||||||
|
io.AddKeyEvent(ImGuiKey_ModCtrl, al_key_down(&keys, ALLEGRO_KEY_LCTRL) || al_key_down(&keys, ALLEGRO_KEY_RCTRL));
|
||||||
|
io.AddKeyEvent(ImGuiKey_ModShift, al_key_down(&keys, ALLEGRO_KEY_LSHIFT) || al_key_down(&keys, ALLEGRO_KEY_RSHIFT));
|
||||||
|
io.AddKeyEvent(ImGuiKey_ModAlt, al_key_down(&keys, ALLEGRO_KEY_ALT) || al_key_down(&keys, ALLEGRO_KEY_ALTGR));
|
||||||
|
io.AddKeyEvent(ImGuiKey_ModSuper, al_key_down(&keys, ALLEGRO_KEY_LWIN) || al_key_down(&keys, ALLEGRO_KEY_RWIN));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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, or clear/overwrite your copy of the mouse data.
|
||||||
|
// - When io.WantCaptureKeyboard is true, do not dispatch keyboard input data to your main application, or clear/overwrite your copy of the keyboard data.
|
||||||
|
// 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();
|
||||||
|
ImGui_ImplAllegro5_Data* bd = ImGui_ImplAllegro5_GetBackendData();
|
||||||
|
|
||||||
|
switch (ev->type)
|
||||||
|
{
|
||||||
|
case ALLEGRO_EVENT_MOUSE_AXES:
|
||||||
|
if (ev->mouse.display == bd->Display)
|
||||||
|
{
|
||||||
|
io.AddMousePosEvent(ev->mouse.x, ev->mouse.y);
|
||||||
|
io.AddMouseWheelEvent(-ev->mouse.dw, ev->mouse.dz);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
case ALLEGRO_EVENT_MOUSE_BUTTON_DOWN:
|
||||||
|
case ALLEGRO_EVENT_MOUSE_BUTTON_UP:
|
||||||
|
if (ev->mouse.display == bd->Display && ev->mouse.button > 0 && ev->mouse.button <= 5)
|
||||||
|
io.AddMouseButtonEvent(ev->mouse.button - 1, ev->type == ALLEGRO_EVENT_MOUSE_BUTTON_DOWN);
|
||||||
|
return true;
|
||||||
|
case ALLEGRO_EVENT_TOUCH_MOVE:
|
||||||
|
if (ev->touch.display == bd->Display)
|
||||||
|
io.AddMousePosEvent(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 == bd->Display && ev->touch.primary)
|
||||||
|
io.AddMouseButtonEvent(0, ev->type == ALLEGRO_EVENT_TOUCH_BEGIN);
|
||||||
|
return true;
|
||||||
|
case ALLEGRO_EVENT_MOUSE_LEAVE_DISPLAY:
|
||||||
|
if (ev->mouse.display == bd->Display)
|
||||||
|
io.AddMousePosEvent(-FLT_MAX, -FLT_MAX);
|
||||||
|
return true;
|
||||||
|
case ALLEGRO_EVENT_KEY_CHAR:
|
||||||
|
if (ev->keyboard.display == bd->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 == bd->Display)
|
||||||
|
{
|
||||||
|
ImGui_ImplAllegro5_UpdateKeyModifiers();
|
||||||
|
ImGuiKey key = ImGui_ImplAllegro5_KeyCodeToImGuiKey(ev->keyboard.keycode);
|
||||||
|
io.AddKeyEvent(key, (ev->type == ALLEGRO_EVENT_KEY_DOWN));
|
||||||
|
io.SetKeyEventNativeData(key, ev->keyboard.keycode, -1); // To support legacy indexing (<1.87 user code)
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
case ALLEGRO_EVENT_DISPLAY_SWITCH_OUT:
|
||||||
|
if (ev->display.source == bd->Display)
|
||||||
|
io.AddFocusEvent(false);
|
||||||
|
return true;
|
||||||
|
case ALLEGRO_EVENT_DISPLAY_SWITCH_IN:
|
||||||
|
if (ev->display.source == bd->Display)
|
||||||
|
{
|
||||||
|
io.AddFocusEvent(true);
|
||||||
|
#if defined(ALLEGRO_UNSTABLE)
|
||||||
|
al_clear_keyboard_state(bd->Display);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ImGui_ImplAllegro5_UpdateMouseCursor()
|
||||||
|
{
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
if (io.ConfigFlags & ImGuiConfigFlags_NoMouseCursorChange)
|
||||||
|
return;
|
||||||
|
|
||||||
|
ImGui_ImplAllegro5_Data* bd = ImGui_ImplAllegro5_GetBackendData();
|
||||||
|
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(bd->Display, bd->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(bd->Display, cursor_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGui_ImplAllegro5_NewFrame()
|
||||||
|
{
|
||||||
|
ImGui_ImplAllegro5_Data* bd = ImGui_ImplAllegro5_GetBackendData();
|
||||||
|
IM_ASSERT(bd != NULL && "Did you call ImGui_ImplAllegro5_Init()?");
|
||||||
|
|
||||||
|
if (!bd->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(bd->Display);
|
||||||
|
h = al_get_display_height(bd->Display);
|
||||||
|
io.DisplaySize = ImVec2((float)w, (float)h);
|
||||||
|
|
||||||
|
// Setup time step
|
||||||
|
double current_time = al_get_time();
|
||||||
|
io.DeltaTime = bd->Time > 0.0 ? (float)(current_time - bd->Time) : (float)(1.0f / 60.0f);
|
||||||
|
bd->Time = current_time;
|
||||||
|
|
||||||
|
// Setup mouse cursor shape
|
||||||
|
ImGui_ImplAllegro5_UpdateMouseCursor();
|
||||||
|
}
|
|
@ -0,0 +1,32 @@
|
||||||
|
// 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: Keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy ALLEGRO_KEY_* values will also be supported unless IMGUI_DISABLE_OBSOLETE_KEYIO is set]
|
||||||
|
// [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 use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
||||||
|
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
|
||||||
|
// 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();
|
|
@ -0,0 +1,276 @@
|
||||||
|
// 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 support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy AKEYCODE_* values will also be supported unless IMGUI_DISABLE_OBSOLETE_KEYIO is set]
|
||||||
|
// 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:
|
||||||
|
// - Consider using SDL or GLFW backend on Android, which will be more full-featured than this.
|
||||||
|
// - 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 use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
||||||
|
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
|
||||||
|
// 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)
|
||||||
|
// 2022-01-26: Inputs: replaced short-lived io.AddKeyModsEvent() (added two weeks ago)with io.AddKeyEvent() using ImGuiKey_ModXXX flags. Sorry for the confusion.
|
||||||
|
// 2022-01-17: Inputs: calling new io.AddMousePosEvent(), io.AddMouseButtonEvent(), io.AddMouseWheelEvent() API (1.87+).
|
||||||
|
// 2022-01-10: Inputs: calling new io.AddKeyEvent(), io.AddKeyModsEvent() + io.SetKeyEventNativeData() API (1.87+). Support for full ImGuiKey range.
|
||||||
|
// 2021-03-04: Initial version.
|
||||||
|
|
||||||
|
#include "imgui.h"
|
||||||
|
#include "imgui_impl_android.h"
|
||||||
|
#include <time.h>
|
||||||
|
#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 ImGuiKey ImGui_ImplAndroid_KeyCodeToImGuiKey(int32_t key_code)
|
||||||
|
{
|
||||||
|
switch (key_code)
|
||||||
|
{
|
||||||
|
case AKEYCODE_TAB: return ImGuiKey_Tab;
|
||||||
|
case AKEYCODE_DPAD_LEFT: return ImGuiKey_LeftArrow;
|
||||||
|
case AKEYCODE_DPAD_RIGHT: return ImGuiKey_RightArrow;
|
||||||
|
case AKEYCODE_DPAD_UP: return ImGuiKey_UpArrow;
|
||||||
|
case AKEYCODE_DPAD_DOWN: return ImGuiKey_DownArrow;
|
||||||
|
case AKEYCODE_PAGE_UP: return ImGuiKey_PageUp;
|
||||||
|
case AKEYCODE_PAGE_DOWN: return ImGuiKey_PageDown;
|
||||||
|
case AKEYCODE_MOVE_HOME: return ImGuiKey_Home;
|
||||||
|
case AKEYCODE_MOVE_END: return ImGuiKey_End;
|
||||||
|
case AKEYCODE_INSERT: return ImGuiKey_Insert;
|
||||||
|
case AKEYCODE_FORWARD_DEL: return ImGuiKey_Delete;
|
||||||
|
case AKEYCODE_DEL: return ImGuiKey_Backspace;
|
||||||
|
case AKEYCODE_SPACE: return ImGuiKey_Space;
|
||||||
|
case AKEYCODE_ENTER: return ImGuiKey_Enter;
|
||||||
|
case AKEYCODE_ESCAPE: return ImGuiKey_Escape;
|
||||||
|
case AKEYCODE_APOSTROPHE: return ImGuiKey_Apostrophe;
|
||||||
|
case AKEYCODE_COMMA: return ImGuiKey_Comma;
|
||||||
|
case AKEYCODE_MINUS: return ImGuiKey_Minus;
|
||||||
|
case AKEYCODE_PERIOD: return ImGuiKey_Period;
|
||||||
|
case AKEYCODE_SLASH: return ImGuiKey_Slash;
|
||||||
|
case AKEYCODE_SEMICOLON: return ImGuiKey_Semicolon;
|
||||||
|
case AKEYCODE_EQUALS: return ImGuiKey_Equal;
|
||||||
|
case AKEYCODE_LEFT_BRACKET: return ImGuiKey_LeftBracket;
|
||||||
|
case AKEYCODE_BACKSLASH: return ImGuiKey_Backslash;
|
||||||
|
case AKEYCODE_RIGHT_BRACKET: return ImGuiKey_RightBracket;
|
||||||
|
case AKEYCODE_GRAVE: return ImGuiKey_GraveAccent;
|
||||||
|
case AKEYCODE_CAPS_LOCK: return ImGuiKey_CapsLock;
|
||||||
|
case AKEYCODE_SCROLL_LOCK: return ImGuiKey_ScrollLock;
|
||||||
|
case AKEYCODE_NUM_LOCK: return ImGuiKey_NumLock;
|
||||||
|
case AKEYCODE_SYSRQ: return ImGuiKey_PrintScreen;
|
||||||
|
case AKEYCODE_BREAK: return ImGuiKey_Pause;
|
||||||
|
case AKEYCODE_NUMPAD_0: return ImGuiKey_Keypad0;
|
||||||
|
case AKEYCODE_NUMPAD_1: return ImGuiKey_Keypad1;
|
||||||
|
case AKEYCODE_NUMPAD_2: return ImGuiKey_Keypad2;
|
||||||
|
case AKEYCODE_NUMPAD_3: return ImGuiKey_Keypad3;
|
||||||
|
case AKEYCODE_NUMPAD_4: return ImGuiKey_Keypad4;
|
||||||
|
case AKEYCODE_NUMPAD_5: return ImGuiKey_Keypad5;
|
||||||
|
case AKEYCODE_NUMPAD_6: return ImGuiKey_Keypad6;
|
||||||
|
case AKEYCODE_NUMPAD_7: return ImGuiKey_Keypad7;
|
||||||
|
case AKEYCODE_NUMPAD_8: return ImGuiKey_Keypad8;
|
||||||
|
case AKEYCODE_NUMPAD_9: return ImGuiKey_Keypad9;
|
||||||
|
case AKEYCODE_NUMPAD_DOT: return ImGuiKey_KeypadDecimal;
|
||||||
|
case AKEYCODE_NUMPAD_DIVIDE: return ImGuiKey_KeypadDivide;
|
||||||
|
case AKEYCODE_NUMPAD_MULTIPLY: return ImGuiKey_KeypadMultiply;
|
||||||
|
case AKEYCODE_NUMPAD_SUBTRACT: return ImGuiKey_KeypadSubtract;
|
||||||
|
case AKEYCODE_NUMPAD_ADD: return ImGuiKey_KeypadAdd;
|
||||||
|
case AKEYCODE_NUMPAD_ENTER: return ImGuiKey_KeypadEnter;
|
||||||
|
case AKEYCODE_NUMPAD_EQUALS: return ImGuiKey_KeypadEqual;
|
||||||
|
case AKEYCODE_CTRL_LEFT: return ImGuiKey_LeftCtrl;
|
||||||
|
case AKEYCODE_SHIFT_LEFT: return ImGuiKey_LeftShift;
|
||||||
|
case AKEYCODE_ALT_LEFT: return ImGuiKey_LeftAlt;
|
||||||
|
case AKEYCODE_META_LEFT: return ImGuiKey_LeftSuper;
|
||||||
|
case AKEYCODE_CTRL_RIGHT: return ImGuiKey_RightCtrl;
|
||||||
|
case AKEYCODE_SHIFT_RIGHT: return ImGuiKey_RightShift;
|
||||||
|
case AKEYCODE_ALT_RIGHT: return ImGuiKey_RightAlt;
|
||||||
|
case AKEYCODE_META_RIGHT: return ImGuiKey_RightSuper;
|
||||||
|
case AKEYCODE_MENU: return ImGuiKey_Menu;
|
||||||
|
case AKEYCODE_0: return ImGuiKey_0;
|
||||||
|
case AKEYCODE_1: return ImGuiKey_1;
|
||||||
|
case AKEYCODE_2: return ImGuiKey_2;
|
||||||
|
case AKEYCODE_3: return ImGuiKey_3;
|
||||||
|
case AKEYCODE_4: return ImGuiKey_4;
|
||||||
|
case AKEYCODE_5: return ImGuiKey_5;
|
||||||
|
case AKEYCODE_6: return ImGuiKey_6;
|
||||||
|
case AKEYCODE_7: return ImGuiKey_7;
|
||||||
|
case AKEYCODE_8: return ImGuiKey_8;
|
||||||
|
case AKEYCODE_9: return ImGuiKey_9;
|
||||||
|
case AKEYCODE_A: return ImGuiKey_A;
|
||||||
|
case AKEYCODE_B: return ImGuiKey_B;
|
||||||
|
case AKEYCODE_C: return ImGuiKey_C;
|
||||||
|
case AKEYCODE_D: return ImGuiKey_D;
|
||||||
|
case AKEYCODE_E: return ImGuiKey_E;
|
||||||
|
case AKEYCODE_F: return ImGuiKey_F;
|
||||||
|
case AKEYCODE_G: return ImGuiKey_G;
|
||||||
|
case AKEYCODE_H: return ImGuiKey_H;
|
||||||
|
case AKEYCODE_I: return ImGuiKey_I;
|
||||||
|
case AKEYCODE_J: return ImGuiKey_J;
|
||||||
|
case AKEYCODE_K: return ImGuiKey_K;
|
||||||
|
case AKEYCODE_L: return ImGuiKey_L;
|
||||||
|
case AKEYCODE_M: return ImGuiKey_M;
|
||||||
|
case AKEYCODE_N: return ImGuiKey_N;
|
||||||
|
case AKEYCODE_O: return ImGuiKey_O;
|
||||||
|
case AKEYCODE_P: return ImGuiKey_P;
|
||||||
|
case AKEYCODE_Q: return ImGuiKey_Q;
|
||||||
|
case AKEYCODE_R: return ImGuiKey_R;
|
||||||
|
case AKEYCODE_S: return ImGuiKey_S;
|
||||||
|
case AKEYCODE_T: return ImGuiKey_T;
|
||||||
|
case AKEYCODE_U: return ImGuiKey_U;
|
||||||
|
case AKEYCODE_V: return ImGuiKey_V;
|
||||||
|
case AKEYCODE_W: return ImGuiKey_W;
|
||||||
|
case AKEYCODE_X: return ImGuiKey_X;
|
||||||
|
case AKEYCODE_Y: return ImGuiKey_Y;
|
||||||
|
case AKEYCODE_Z: return ImGuiKey_Z;
|
||||||
|
case AKEYCODE_F1: return ImGuiKey_F1;
|
||||||
|
case AKEYCODE_F2: return ImGuiKey_F2;
|
||||||
|
case AKEYCODE_F3: return ImGuiKey_F3;
|
||||||
|
case AKEYCODE_F4: return ImGuiKey_F4;
|
||||||
|
case AKEYCODE_F5: return ImGuiKey_F5;
|
||||||
|
case AKEYCODE_F6: return ImGuiKey_F6;
|
||||||
|
case AKEYCODE_F7: return ImGuiKey_F7;
|
||||||
|
case AKEYCODE_F8: return ImGuiKey_F8;
|
||||||
|
case AKEYCODE_F9: return ImGuiKey_F9;
|
||||||
|
case AKEYCODE_F10: return ImGuiKey_F10;
|
||||||
|
case AKEYCODE_F11: return ImGuiKey_F11;
|
||||||
|
case AKEYCODE_F12: return ImGuiKey_F12;
|
||||||
|
default: return ImGuiKey_None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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_scan_code = AKeyEvent_getScanCode(input_event);
|
||||||
|
int32_t event_action = AKeyEvent_getAction(input_event);
|
||||||
|
int32_t event_meta_state = AKeyEvent_getMetaState(input_event);
|
||||||
|
|
||||||
|
io.AddKeyEvent(ImGuiKey_ModCtrl, (event_meta_state & AMETA_CTRL_ON) != 0);
|
||||||
|
io.AddKeyEvent(ImGuiKey_ModShift, (event_meta_state & AMETA_SHIFT_ON) != 0);
|
||||||
|
io.AddKeyEvent(ImGuiKey_ModAlt, (event_meta_state & AMETA_ALT_ON) != 0);
|
||||||
|
io.AddKeyEvent(ImGuiKey_ModSuper, (event_meta_state & AMETA_META_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:
|
||||||
|
{
|
||||||
|
ImGuiKey key = ImGui_ImplAndroid_KeyCodeToImGuiKey(event_key_code);
|
||||||
|
if (key != ImGuiKey_None && (event_action == AKEY_EVENT_ACTION_DOWN || event_action == AKEY_EVENT_ACTION_UP))
|
||||||
|
{
|
||||||
|
io.AddKeyEvent(key, event_action == AKEY_EVENT_ACTION_DOWN);
|
||||||
|
io.SetKeyEventNativeData(key, event_key_code, event_scan_code);
|
||||||
|
}
|
||||||
|
|
||||||
|
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.AddMousePosEvent(AMotionEvent_getX(input_event, event_pointer_index), AMotionEvent_getY(input_event, event_pointer_index));
|
||||||
|
io.AddMouseButtonEvent(0, event_action == AMOTION_EVENT_ACTION_DOWN);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case AMOTION_EVENT_ACTION_BUTTON_PRESS:
|
||||||
|
case AMOTION_EVENT_ACTION_BUTTON_RELEASE:
|
||||||
|
{
|
||||||
|
int32_t button_state = AMotionEvent_getButtonState(input_event);
|
||||||
|
io.AddMouseButtonEvent(0, (button_state & AMOTION_EVENT_BUTTON_PRIMARY) != 0);
|
||||||
|
io.AddMouseButtonEvent(1, (button_state & AMOTION_EVENT_BUTTON_SECONDARY) != 0);
|
||||||
|
io.AddMouseButtonEvent(2, (button_state & AMOTION_EVENT_BUTTON_TERTIARY) != 0);
|
||||||
|
}
|
||||||
|
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.AddMousePosEvent(AMotionEvent_getX(input_event, event_pointer_index), AMotionEvent_getY(input_event, event_pointer_index));
|
||||||
|
break;
|
||||||
|
case AMOTION_EVENT_ACTION_SCROLL:
|
||||||
|
io.AddMouseWheelEvent(AMotionEvent_getAxisValue(input_event, AMOTION_EVENT_AXIS_HSCROLL, event_pointer_index), AMotionEvent_getAxisValue(input_event, AMOTION_EVENT_AXIS_VSCROLL, 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";
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGui_ImplAndroid_Shutdown()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGui_ImplAndroid_NewFrame()
|
||||||
|
{
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
}
|
|
@ -0,0 +1,28 @@
|
||||||
|
// 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 support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy AKEYCODE_* values will also be supported unless IMGUI_DISABLE_OBSOLETE_KEYIO is set]
|
||||||
|
// 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:
|
||||||
|
// - Consider using SDL or GLFW backend on Android, which will be more full-featured than this.
|
||||||
|
// - 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 use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
||||||
|
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
|
||||||
|
// 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
|
||||||
|
|
||||||
|
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();
|
|
@ -12,6 +12,7 @@
|
||||||
|
|
||||||
// CHANGELOG
|
// CHANGELOG
|
||||||
// (minor and older changes stripped away, please see git history for details)
|
// (minor and older changes stripped away, please see git history for details)
|
||||||
|
// 2021-06-29: Reorganized backend to pull data from a single structure to facilitate usage with multiple-contexts (all g_XXXX access changed to bd->XXXX).
|
||||||
// 2021-05-19: DirectX10: Replaced direct access to ImDrawCmd::TextureId with a call to ImDrawCmd::GetTexID(). (will become a requirement)
|
// 2021-05-19: DirectX10: Replaced direct access to ImDrawCmd::TextureId with a call to ImDrawCmd::GetTexID(). (will become a requirement)
|
||||||
// 2021-02-18: DirectX10: Change blending equation to preserve alpha in output buffer.
|
// 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-07-21: DirectX10: Backup, clear and restore Geometry Shader is any is bound when calling ImGui_ImplDX10_RenderDrawData().
|
||||||
|
@ -35,31 +36,47 @@
|
||||||
#include <d3d10_1.h>
|
#include <d3d10_1.h>
|
||||||
#include <d3d10.h>
|
#include <d3d10.h>
|
||||||
|
|
||||||
#include "imgui_shaderblobs.h"
|
#include "imgui_win_shader_blobs.h"
|
||||||
|
|
||||||
// DirectX data
|
// DirectX data
|
||||||
static ID3D10Device* g_pd3dDevice = NULL;
|
struct ImGui_ImplDX10_Data
|
||||||
static IDXGIFactory* g_pFactory = NULL;
|
{
|
||||||
static ID3D10Buffer* g_pVB = NULL;
|
ID3D10Device* pd3dDevice;
|
||||||
static ID3D10Buffer* g_pIB = NULL;
|
IDXGIFactory* pFactory;
|
||||||
static ID3D10VertexShader* g_pVertexShader = NULL;
|
ID3D10Buffer* pVB;
|
||||||
static ID3D10InputLayout* g_pInputLayout = NULL;
|
ID3D10Buffer* pIB;
|
||||||
static ID3D10Buffer* g_pVertexConstantBuffer = NULL;
|
ID3D10VertexShader* pVertexShader;
|
||||||
static ID3D10PixelShader* g_pPixelShader = NULL;
|
ID3D10InputLayout* pInputLayout;
|
||||||
static ID3D10SamplerState* g_pFontSampler = NULL;
|
ID3D10Buffer* pVertexConstantBuffer;
|
||||||
static ID3D10ShaderResourceView*g_pFontTextureView = NULL;
|
ID3D10PixelShader* pPixelShader;
|
||||||
static ID3D10RasterizerState* g_pRasterizerState = NULL;
|
ID3D10SamplerState* pFontSampler;
|
||||||
static ID3D10BlendState* g_pBlendState = NULL;
|
ID3D10ShaderResourceView* pFontTextureView;
|
||||||
static ID3D10DepthStencilState* g_pDepthStencilState = NULL;
|
ID3D10RasterizerState* pRasterizerState;
|
||||||
static int g_VertexBufferSize = 5000, g_IndexBufferSize = 10000;
|
ID3D10BlendState* pBlendState;
|
||||||
|
ID3D10DepthStencilState* pDepthStencilState;
|
||||||
|
int VertexBufferSize;
|
||||||
|
int IndexBufferSize;
|
||||||
|
|
||||||
struct VERTEX_CONSTANT_BUFFER
|
ImGui_ImplDX10_Data() { memset((void*)this, 0, sizeof(*this)); VertexBufferSize = 5000; IndexBufferSize = 10000; }
|
||||||
|
};
|
||||||
|
|
||||||
|
struct VERTEX_CONSTANT_BUFFER_DX10
|
||||||
{
|
{
|
||||||
float mvp[4][4];
|
float mvp[4][4];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Backend data stored in io.BackendRendererUserData to allow support for multiple Dear ImGui contexts
|
||||||
|
// It is STRONGLY preferred that you use docking branch with multi-viewports (== single Dear ImGui context + multiple windows) instead of multiple Dear ImGui contexts.
|
||||||
|
static ImGui_ImplDX10_Data* ImGui_ImplDX10_GetBackendData()
|
||||||
|
{
|
||||||
|
return ImGui::GetCurrentContext() ? (ImGui_ImplDX10_Data*)ImGui::GetIO().BackendRendererUserData : NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Functions
|
||||||
static void ImGui_ImplDX10_SetupRenderState(ImDrawData* draw_data, ID3D10Device* ctx)
|
static void ImGui_ImplDX10_SetupRenderState(ImDrawData* draw_data, ID3D10Device* ctx)
|
||||||
{
|
{
|
||||||
|
ImGui_ImplDX10_Data* bd = ImGui_ImplDX10_GetBackendData();
|
||||||
|
|
||||||
// Setup viewport
|
// Setup viewport
|
||||||
D3D10_VIEWPORT vp;
|
D3D10_VIEWPORT vp;
|
||||||
memset(&vp, 0, sizeof(D3D10_VIEWPORT));
|
memset(&vp, 0, sizeof(D3D10_VIEWPORT));
|
||||||
|
@ -73,21 +90,21 @@ static void ImGui_ImplDX10_SetupRenderState(ImDrawData* draw_data, ID3D10Device*
|
||||||
// Bind shader and vertex buffers
|
// Bind shader and vertex buffers
|
||||||
unsigned int stride = sizeof(ImDrawVert);
|
unsigned int stride = sizeof(ImDrawVert);
|
||||||
unsigned int offset = 0;
|
unsigned int offset = 0;
|
||||||
ctx->IASetInputLayout(g_pInputLayout);
|
ctx->IASetInputLayout(bd->pInputLayout);
|
||||||
ctx->IASetVertexBuffers(0, 1, &g_pVB, &stride, &offset);
|
ctx->IASetVertexBuffers(0, 1, &bd->pVB, &stride, &offset);
|
||||||
ctx->IASetIndexBuffer(g_pIB, sizeof(ImDrawIdx) == 2 ? DXGI_FORMAT_R16_UINT : DXGI_FORMAT_R32_UINT, 0);
|
ctx->IASetIndexBuffer(bd->pIB, sizeof(ImDrawIdx) == 2 ? DXGI_FORMAT_R16_UINT : DXGI_FORMAT_R32_UINT, 0);
|
||||||
ctx->IASetPrimitiveTopology(D3D10_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
|
ctx->IASetPrimitiveTopology(D3D10_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
|
||||||
ctx->VSSetShader(g_pVertexShader);
|
ctx->VSSetShader(bd->pVertexShader);
|
||||||
ctx->VSSetConstantBuffers(0, 1, &g_pVertexConstantBuffer);
|
ctx->VSSetConstantBuffers(0, 1, &bd->pVertexConstantBuffer);
|
||||||
ctx->PSSetShader(g_pPixelShader);
|
ctx->PSSetShader(bd->pPixelShader);
|
||||||
ctx->PSSetSamplers(0, 1, &g_pFontSampler);
|
ctx->PSSetSamplers(0, 1, &bd->pFontSampler);
|
||||||
ctx->GSSetShader(NULL);
|
ctx->GSSetShader(NULL);
|
||||||
|
|
||||||
// Setup render state
|
// Setup render state
|
||||||
const float blend_factor[4] = { 0.f, 0.f, 0.f, 0.f };
|
const float blend_factor[4] = { 0.f, 0.f, 0.f, 0.f };
|
||||||
ctx->OMSetBlendState(g_pBlendState, blend_factor, 0xffffffff);
|
ctx->OMSetBlendState(bd->pBlendState, blend_factor, 0xffffffff);
|
||||||
ctx->OMSetDepthStencilState(g_pDepthStencilState, 0);
|
ctx->OMSetDepthStencilState(bd->pDepthStencilState, 0);
|
||||||
ctx->RSSetState(g_pRasterizerState);
|
ctx->RSSetState(bd->pRasterizerState);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Render function
|
// Render function
|
||||||
|
@ -97,43 +114,44 @@ void ImGui_ImplDX10_RenderDrawData(ImDrawData* draw_data)
|
||||||
if (draw_data->DisplaySize.x <= 0.0f || draw_data->DisplaySize.y <= 0.0f)
|
if (draw_data->DisplaySize.x <= 0.0f || draw_data->DisplaySize.y <= 0.0f)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
ID3D10Device* ctx = g_pd3dDevice;
|
ImGui_ImplDX10_Data* bd = ImGui_ImplDX10_GetBackendData();
|
||||||
|
ID3D10Device* ctx = bd->pd3dDevice;
|
||||||
|
|
||||||
// Create and grow vertex/index buffers if needed
|
// Create and grow vertex/index buffers if needed
|
||||||
if (!g_pVB || g_VertexBufferSize < draw_data->TotalVtxCount)
|
if (!bd->pVB || bd->VertexBufferSize < draw_data->TotalVtxCount)
|
||||||
{
|
{
|
||||||
if (g_pVB) { g_pVB->Release(); g_pVB = NULL; }
|
if (bd->pVB) { bd->pVB->Release(); bd->pVB = NULL; }
|
||||||
g_VertexBufferSize = draw_data->TotalVtxCount + 5000;
|
bd->VertexBufferSize = draw_data->TotalVtxCount + 5000;
|
||||||
D3D10_BUFFER_DESC desc;
|
D3D10_BUFFER_DESC desc;
|
||||||
memset(&desc, 0, sizeof(D3D10_BUFFER_DESC));
|
memset(&desc, 0, sizeof(D3D10_BUFFER_DESC));
|
||||||
desc.Usage = D3D10_USAGE_DYNAMIC;
|
desc.Usage = D3D10_USAGE_DYNAMIC;
|
||||||
desc.ByteWidth = g_VertexBufferSize * sizeof(ImDrawVert);
|
desc.ByteWidth = bd->VertexBufferSize * sizeof(ImDrawVert);
|
||||||
desc.BindFlags = D3D10_BIND_VERTEX_BUFFER;
|
desc.BindFlags = D3D10_BIND_VERTEX_BUFFER;
|
||||||
desc.CPUAccessFlags = D3D10_CPU_ACCESS_WRITE;
|
desc.CPUAccessFlags = D3D10_CPU_ACCESS_WRITE;
|
||||||
desc.MiscFlags = 0;
|
desc.MiscFlags = 0;
|
||||||
if (ctx->CreateBuffer(&desc, NULL, &g_pVB) < 0)
|
if (ctx->CreateBuffer(&desc, NULL, &bd->pVB) < 0)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!g_pIB || g_IndexBufferSize < draw_data->TotalIdxCount)
|
if (!bd->pIB || bd->IndexBufferSize < draw_data->TotalIdxCount)
|
||||||
{
|
{
|
||||||
if (g_pIB) { g_pIB->Release(); g_pIB = NULL; }
|
if (bd->pIB) { bd->pIB->Release(); bd->pIB = NULL; }
|
||||||
g_IndexBufferSize = draw_data->TotalIdxCount + 10000;
|
bd->IndexBufferSize = draw_data->TotalIdxCount + 10000;
|
||||||
D3D10_BUFFER_DESC desc;
|
D3D10_BUFFER_DESC desc;
|
||||||
memset(&desc, 0, sizeof(D3D10_BUFFER_DESC));
|
memset(&desc, 0, sizeof(D3D10_BUFFER_DESC));
|
||||||
desc.Usage = D3D10_USAGE_DYNAMIC;
|
desc.Usage = D3D10_USAGE_DYNAMIC;
|
||||||
desc.ByteWidth = g_IndexBufferSize * sizeof(ImDrawIdx);
|
desc.ByteWidth = bd->IndexBufferSize * sizeof(ImDrawIdx);
|
||||||
desc.BindFlags = D3D10_BIND_INDEX_BUFFER;
|
desc.BindFlags = D3D10_BIND_INDEX_BUFFER;
|
||||||
desc.CPUAccessFlags = D3D10_CPU_ACCESS_WRITE;
|
desc.CPUAccessFlags = D3D10_CPU_ACCESS_WRITE;
|
||||||
if (ctx->CreateBuffer(&desc, NULL, &g_pIB) < 0)
|
if (ctx->CreateBuffer(&desc, NULL, &bd->pIB) < 0)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copy and convert all vertices into a single contiguous buffer
|
// Copy and convert all vertices into a single contiguous buffer
|
||||||
ImDrawVert* vtx_dst = NULL;
|
ImDrawVert* vtx_dst = NULL;
|
||||||
ImDrawIdx* idx_dst = NULL;
|
ImDrawIdx* idx_dst = NULL;
|
||||||
g_pVB->Map(D3D10_MAP_WRITE_DISCARD, 0, (void**)&vtx_dst);
|
bd->pVB->Map(D3D10_MAP_WRITE_DISCARD, 0, (void**)&vtx_dst);
|
||||||
g_pIB->Map(D3D10_MAP_WRITE_DISCARD, 0, (void**)&idx_dst);
|
bd->pIB->Map(D3D10_MAP_WRITE_DISCARD, 0, (void**)&idx_dst);
|
||||||
for (int n = 0; n < draw_data->CmdListsCount; n++)
|
for (int n = 0; n < draw_data->CmdListsCount; n++)
|
||||||
{
|
{
|
||||||
const ImDrawList* cmd_list = draw_data->CmdLists[n];
|
const ImDrawList* cmd_list = draw_data->CmdLists[n];
|
||||||
|
@ -142,16 +160,16 @@ void ImGui_ImplDX10_RenderDrawData(ImDrawData* draw_data)
|
||||||
vtx_dst += cmd_list->VtxBuffer.Size;
|
vtx_dst += cmd_list->VtxBuffer.Size;
|
||||||
idx_dst += cmd_list->IdxBuffer.Size;
|
idx_dst += cmd_list->IdxBuffer.Size;
|
||||||
}
|
}
|
||||||
g_pVB->Unmap();
|
bd->pVB->Unmap();
|
||||||
g_pIB->Unmap();
|
bd->pIB->Unmap();
|
||||||
|
|
||||||
// Setup orthographic projection matrix into our constant buffer
|
// 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.
|
// 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;
|
void* mapped_resource;
|
||||||
if (g_pVertexConstantBuffer->Map(D3D10_MAP_WRITE_DISCARD, 0, &mapped_resource) != S_OK)
|
if (bd->pVertexConstantBuffer->Map(D3D10_MAP_WRITE_DISCARD, 0, &mapped_resource) != S_OK)
|
||||||
return;
|
return;
|
||||||
VERTEX_CONSTANT_BUFFER* constant_buffer = (VERTEX_CONSTANT_BUFFER*)mapped_resource;
|
VERTEX_CONSTANT_BUFFER_DX10* constant_buffer = (VERTEX_CONSTANT_BUFFER_DX10*)mapped_resource;
|
||||||
float L = draw_data->DisplayPos.x;
|
float L = draw_data->DisplayPos.x;
|
||||||
float R = draw_data->DisplayPos.x + draw_data->DisplaySize.x;
|
float R = draw_data->DisplayPos.x + draw_data->DisplaySize.x;
|
||||||
float T = draw_data->DisplayPos.y;
|
float T = draw_data->DisplayPos.y;
|
||||||
|
@ -164,7 +182,7 @@ void ImGui_ImplDX10_RenderDrawData(ImDrawData* draw_data)
|
||||||
{ (R+L)/(L-R), (T+B)/(B-T), 0.5f, 1.0f },
|
{ (R+L)/(L-R), (T+B)/(B-T), 0.5f, 1.0f },
|
||||||
};
|
};
|
||||||
memcpy(&constant_buffer->mvp, mvp, sizeof(mvp));
|
memcpy(&constant_buffer->mvp, mvp, sizeof(mvp));
|
||||||
g_pVertexConstantBuffer->Unmap();
|
bd->pVertexConstantBuffer->Unmap();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Backup DX state that will be modified to restore it afterwards (unfortunately this is very ugly looking and verbose. Close your eyes!)
|
// Backup DX state that will be modified to restore it afterwards (unfortunately this is very ugly looking and verbose. Close your eyes!)
|
||||||
|
@ -233,8 +251,14 @@ void ImGui_ImplDX10_RenderDrawData(ImDrawData* draw_data)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
// Project scissor/clipping rectangles into framebuffer space
|
||||||
|
ImVec2 clip_min(pcmd->ClipRect.x - clip_off.x, pcmd->ClipRect.y - clip_off.y);
|
||||||
|
ImVec2 clip_max(pcmd->ClipRect.z - clip_off.x, pcmd->ClipRect.w - clip_off.y);
|
||||||
|
if (clip_max.x <= clip_min.x || clip_max.y <= clip_min.y)
|
||||||
|
continue;
|
||||||
|
|
||||||
// Apply scissor/clipping rectangle
|
// 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)};
|
const D3D10_RECT r = { (LONG)clip_min.x, (LONG)clip_min.y, (LONG)clip_max.x, (LONG)clip_max.y };
|
||||||
ctx->RSSetScissorRects(1, &r);
|
ctx->RSSetScissorRects(1, &r);
|
||||||
|
|
||||||
// Bind texture, Draw
|
// Bind texture, Draw
|
||||||
|
@ -268,6 +292,7 @@ void ImGui_ImplDX10_RenderDrawData(ImDrawData* draw_data)
|
||||||
static void ImGui_ImplDX10_CreateFontsTexture()
|
static void ImGui_ImplDX10_CreateFontsTexture()
|
||||||
{
|
{
|
||||||
// Build texture atlas
|
// Build texture atlas
|
||||||
|
ImGui_ImplDX10_Data* bd = ImGui_ImplDX10_GetBackendData();
|
||||||
ImGuiIO& io = ImGui::GetIO();
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
unsigned char* pixels;
|
unsigned char* pixels;
|
||||||
int width, height;
|
int width, height;
|
||||||
|
@ -292,7 +317,7 @@ static void ImGui_ImplDX10_CreateFontsTexture()
|
||||||
subResource.pSysMem = pixels;
|
subResource.pSysMem = pixels;
|
||||||
subResource.SysMemPitch = desc.Width * 4;
|
subResource.SysMemPitch = desc.Width * 4;
|
||||||
subResource.SysMemSlicePitch = 0;
|
subResource.SysMemSlicePitch = 0;
|
||||||
g_pd3dDevice->CreateTexture2D(&desc, &subResource, &pTexture);
|
bd->pd3dDevice->CreateTexture2D(&desc, &subResource, &pTexture);
|
||||||
IM_ASSERT(pTexture != NULL);
|
IM_ASSERT(pTexture != NULL);
|
||||||
|
|
||||||
// Create texture view
|
// Create texture view
|
||||||
|
@ -302,14 +327,15 @@ static void ImGui_ImplDX10_CreateFontsTexture()
|
||||||
srv_desc.ViewDimension = D3D10_SRV_DIMENSION_TEXTURE2D;
|
srv_desc.ViewDimension = D3D10_SRV_DIMENSION_TEXTURE2D;
|
||||||
srv_desc.Texture2D.MipLevels = desc.MipLevels;
|
srv_desc.Texture2D.MipLevels = desc.MipLevels;
|
||||||
srv_desc.Texture2D.MostDetailedMip = 0;
|
srv_desc.Texture2D.MostDetailedMip = 0;
|
||||||
g_pd3dDevice->CreateShaderResourceView(pTexture, &srv_desc, &g_pFontTextureView);
|
bd->pd3dDevice->CreateShaderResourceView(pTexture, &srv_desc, &bd->pFontTextureView);
|
||||||
pTexture->Release();
|
pTexture->Release();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Store our identifier
|
// Store our identifier
|
||||||
io.Fonts->SetTexID((ImTextureID)g_pFontTextureView);
|
io.Fonts->SetTexID((ImTextureID)bd->pFontTextureView);
|
||||||
|
|
||||||
// Create texture sampler
|
// Create texture sampler
|
||||||
|
// (Bilinear sampling is required by default. Set 'io.Fonts->Flags |= ImFontAtlasFlags_NoBakedLines' or 'style.AntiAliasedLinesUseTex = false' to allow point/nearest sampling)
|
||||||
{
|
{
|
||||||
D3D10_SAMPLER_DESC desc;
|
D3D10_SAMPLER_DESC desc;
|
||||||
ZeroMemory(&desc, sizeof(desc));
|
ZeroMemory(&desc, sizeof(desc));
|
||||||
|
@ -321,15 +347,16 @@ static void ImGui_ImplDX10_CreateFontsTexture()
|
||||||
desc.ComparisonFunc = D3D10_COMPARISON_ALWAYS;
|
desc.ComparisonFunc = D3D10_COMPARISON_ALWAYS;
|
||||||
desc.MinLOD = 0.f;
|
desc.MinLOD = 0.f;
|
||||||
desc.MaxLOD = 0.f;
|
desc.MaxLOD = 0.f;
|
||||||
g_pd3dDevice->CreateSamplerState(&desc, &g_pFontSampler);
|
bd->pd3dDevice->CreateSamplerState(&desc, &bd->pFontSampler);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ImGui_ImplDX10_CreateDeviceObjects()
|
bool ImGui_ImplDX10_CreateDeviceObjects()
|
||||||
{
|
{
|
||||||
if (!g_pd3dDevice)
|
ImGui_ImplDX10_Data* bd = ImGui_ImplDX10_GetBackendData();
|
||||||
|
if (!bd->pd3dDevice)
|
||||||
return false;
|
return false;
|
||||||
if (g_pFontSampler)
|
if (bd->pFontSampler)
|
||||||
ImGui_ImplDX10_InvalidateDeviceObjects();
|
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)
|
// By using D3DCompile() from <d3dcompiler.h> / d3dcompiler.lib, we introduce a dependency to a given version of d3dcompiler_XX.dll (see D3DCOMPILER_DLL_A)
|
||||||
|
@ -340,7 +367,8 @@ bool ImGui_ImplDX10_CreateDeviceObjects()
|
||||||
|
|
||||||
// Create the vertex shader
|
// Create the vertex shader
|
||||||
{
|
{
|
||||||
if (g_pd3dDevice->CreateVertexShader(ImGui_vertexShaderDX10, ImGui_vertexShaderDX10_len, &g_pVertexShader) != S_OK)
|
shader_t shader = getDX10VertexShader();
|
||||||
|
if (bd->pd3dDevice->CreateVertexShader(shader.shaderBlob, shader.shaderBlobSize, &bd->pVertexShader) != S_OK)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Create the input layout
|
// Create the input layout
|
||||||
|
@ -351,24 +379,25 @@ bool ImGui_ImplDX10_CreateDeviceObjects()
|
||||||
{ "COLOR", 0, DXGI_FORMAT_R8G8B8A8_UNORM, 0, (UINT)IM_OFFSETOF(ImDrawVert, col), 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, ImGui_vertexShaderDX10, ImGui_vertexShaderDX10_len, &g_pInputLayout) != S_OK)
|
if (bd->pd3dDevice->CreateInputLayout(local_layout, 3, shader.shaderBlob, shader.shaderBlobSize, &bd->pInputLayout) != S_OK)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Create the constant buffer
|
// Create the constant buffer
|
||||||
{
|
{
|
||||||
D3D10_BUFFER_DESC desc;
|
D3D10_BUFFER_DESC desc;
|
||||||
desc.ByteWidth = sizeof(VERTEX_CONSTANT_BUFFER);
|
desc.ByteWidth = sizeof(VERTEX_CONSTANT_BUFFER_DX10);
|
||||||
desc.Usage = D3D10_USAGE_DYNAMIC;
|
desc.Usage = D3D10_USAGE_DYNAMIC;
|
||||||
desc.BindFlags = D3D10_BIND_CONSTANT_BUFFER;
|
desc.BindFlags = D3D10_BIND_CONSTANT_BUFFER;
|
||||||
desc.CPUAccessFlags = D3D10_CPU_ACCESS_WRITE;
|
desc.CPUAccessFlags = D3D10_CPU_ACCESS_WRITE;
|
||||||
desc.MiscFlags = 0;
|
desc.MiscFlags = 0;
|
||||||
g_pd3dDevice->CreateBuffer(&desc, NULL, &g_pVertexConstantBuffer);
|
bd->pd3dDevice->CreateBuffer(&desc, NULL, &bd->pVertexConstantBuffer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create the pixel shader
|
// Create the pixel shader
|
||||||
{
|
{
|
||||||
if (g_pd3dDevice->CreatePixelShader(ImGui_pixelShaderDX10, ImGui_pixelShaderDX10_len, &g_pPixelShader) != S_OK)
|
shader_t shader = getDX10PixelShader();
|
||||||
|
if (bd->pd3dDevice->CreatePixelShader(shader.shaderBlob, shader.shaderBlobSize, &bd->pPixelShader) != S_OK)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -385,7 +414,7 @@ bool ImGui_ImplDX10_CreateDeviceObjects()
|
||||||
desc.DestBlendAlpha = D3D10_BLEND_INV_SRC_ALPHA;
|
desc.DestBlendAlpha = D3D10_BLEND_INV_SRC_ALPHA;
|
||||||
desc.BlendOpAlpha = D3D10_BLEND_OP_ADD;
|
desc.BlendOpAlpha = D3D10_BLEND_OP_ADD;
|
||||||
desc.RenderTargetWriteMask[0] = D3D10_COLOR_WRITE_ENABLE_ALL;
|
desc.RenderTargetWriteMask[0] = D3D10_COLOR_WRITE_ENABLE_ALL;
|
||||||
g_pd3dDevice->CreateBlendState(&desc, &g_pBlendState);
|
bd->pd3dDevice->CreateBlendState(&desc, &bd->pBlendState);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create the rasterizer state
|
// Create the rasterizer state
|
||||||
|
@ -396,7 +425,7 @@ bool ImGui_ImplDX10_CreateDeviceObjects()
|
||||||
desc.CullMode = D3D10_CULL_NONE;
|
desc.CullMode = D3D10_CULL_NONE;
|
||||||
desc.ScissorEnable = true;
|
desc.ScissorEnable = true;
|
||||||
desc.DepthClipEnable = true;
|
desc.DepthClipEnable = true;
|
||||||
g_pd3dDevice->CreateRasterizerState(&desc, &g_pRasterizerState);
|
bd->pd3dDevice->CreateRasterizerState(&desc, &bd->pRasterizerState);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create depth-stencil State
|
// Create depth-stencil State
|
||||||
|
@ -410,7 +439,7 @@ bool ImGui_ImplDX10_CreateDeviceObjects()
|
||||||
desc.FrontFace.StencilFailOp = desc.FrontFace.StencilDepthFailOp = desc.FrontFace.StencilPassOp = D3D10_STENCIL_OP_KEEP;
|
desc.FrontFace.StencilFailOp = desc.FrontFace.StencilDepthFailOp = desc.FrontFace.StencilPassOp = D3D10_STENCIL_OP_KEEP;
|
||||||
desc.FrontFace.StencilFunc = D3D10_COMPARISON_ALWAYS;
|
desc.FrontFace.StencilFunc = D3D10_COMPARISON_ALWAYS;
|
||||||
desc.BackFace = desc.FrontFace;
|
desc.BackFace = desc.FrontFace;
|
||||||
g_pd3dDevice->CreateDepthStencilState(&desc, &g_pDepthStencilState);
|
bd->pd3dDevice->CreateDepthStencilState(&desc, &bd->pDepthStencilState);
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui_ImplDX10_CreateFontsTexture();
|
ImGui_ImplDX10_CreateFontsTexture();
|
||||||
|
@ -420,27 +449,31 @@ bool ImGui_ImplDX10_CreateDeviceObjects()
|
||||||
|
|
||||||
void ImGui_ImplDX10_InvalidateDeviceObjects()
|
void ImGui_ImplDX10_InvalidateDeviceObjects()
|
||||||
{
|
{
|
||||||
if (!g_pd3dDevice)
|
ImGui_ImplDX10_Data* bd = ImGui_ImplDX10_GetBackendData();
|
||||||
|
if (!bd->pd3dDevice)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (g_pFontSampler) { g_pFontSampler->Release(); g_pFontSampler = NULL; }
|
if (bd->pFontSampler) { bd->pFontSampler->Release(); bd->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 (bd->pFontTextureView) { bd->pFontTextureView->Release(); bd->pFontTextureView = NULL; ImGui::GetIO().Fonts->SetTexID(NULL); } // We copied bd->pFontTextureView to io.Fonts->TexID so let's clear that as well.
|
||||||
if (g_pIB) { g_pIB->Release(); g_pIB = NULL; }
|
if (bd->pIB) { bd->pIB->Release(); bd->pIB = NULL; }
|
||||||
if (g_pVB) { g_pVB->Release(); g_pVB = NULL; }
|
if (bd->pVB) { bd->pVB->Release(); bd->pVB = NULL; }
|
||||||
|
if (bd->pBlendState) { bd->pBlendState->Release(); bd->pBlendState = NULL; }
|
||||||
if (g_pBlendState) { g_pBlendState->Release(); g_pBlendState = NULL; }
|
if (bd->pDepthStencilState) { bd->pDepthStencilState->Release(); bd->pDepthStencilState = NULL; }
|
||||||
if (g_pDepthStencilState) { g_pDepthStencilState->Release(); g_pDepthStencilState = NULL; }
|
if (bd->pRasterizerState) { bd->pRasterizerState->Release(); bd->pRasterizerState = NULL; }
|
||||||
if (g_pRasterizerState) { g_pRasterizerState->Release(); g_pRasterizerState = NULL; }
|
if (bd->pPixelShader) { bd->pPixelShader->Release(); bd->pPixelShader = NULL; }
|
||||||
if (g_pPixelShader) { g_pPixelShader->Release(); g_pPixelShader = NULL; }
|
if (bd->pVertexConstantBuffer) { bd->pVertexConstantBuffer->Release(); bd->pVertexConstantBuffer = NULL; }
|
||||||
if (g_pVertexConstantBuffer) { g_pVertexConstantBuffer->Release(); g_pVertexConstantBuffer = NULL; }
|
if (bd->pInputLayout) { bd->pInputLayout->Release(); bd->pInputLayout = NULL; }
|
||||||
if (g_pInputLayout) { g_pInputLayout->Release(); g_pInputLayout = NULL; }
|
if (bd->pVertexShader) { bd->pVertexShader->Release(); bd->pVertexShader = NULL; }
|
||||||
if (g_pVertexShader) { g_pVertexShader->Release(); g_pVertexShader = NULL; }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ImGui_ImplDX10_Init(ID3D10Device* device)
|
bool ImGui_ImplDX10_Init(ID3D10Device* device)
|
||||||
{
|
{
|
||||||
// Setup backend capabilities flags
|
|
||||||
ImGuiIO& io = ImGui::GetIO();
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
IM_ASSERT(io.BackendRendererUserData == NULL && "Already initialized a renderer backend!");
|
||||||
|
|
||||||
|
// Setup backend capabilities flags
|
||||||
|
ImGui_ImplDX10_Data* bd = IM_NEW(ImGui_ImplDX10_Data)();
|
||||||
|
io.BackendRendererUserData = (void*)bd;
|
||||||
io.BackendRendererName = "imgui_impl_dx10";
|
io.BackendRendererName = "imgui_impl_dx10";
|
||||||
io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes.
|
io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes.
|
||||||
|
|
||||||
|
@ -448,31 +481,40 @@ bool ImGui_ImplDX10_Init(ID3D10Device* device)
|
||||||
IDXGIDevice* pDXGIDevice = NULL;
|
IDXGIDevice* pDXGIDevice = NULL;
|
||||||
IDXGIAdapter* pDXGIAdapter = NULL;
|
IDXGIAdapter* pDXGIAdapter = NULL;
|
||||||
IDXGIFactory* pFactory = NULL;
|
IDXGIFactory* pFactory = NULL;
|
||||||
|
|
||||||
if (device->QueryInterface(IID_PPV_ARGS(&pDXGIDevice)) == S_OK)
|
if (device->QueryInterface(IID_PPV_ARGS(&pDXGIDevice)) == S_OK)
|
||||||
if (pDXGIDevice->GetParent(IID_PPV_ARGS(&pDXGIAdapter)) == S_OK)
|
if (pDXGIDevice->GetParent(IID_PPV_ARGS(&pDXGIAdapter)) == S_OK)
|
||||||
if (pDXGIAdapter->GetParent(IID_PPV_ARGS(&pFactory)) == S_OK)
|
if (pDXGIAdapter->GetParent(IID_PPV_ARGS(&pFactory)) == S_OK)
|
||||||
{
|
{
|
||||||
g_pd3dDevice = device;
|
bd->pd3dDevice = device;
|
||||||
g_pFactory = pFactory;
|
bd->pFactory = pFactory;
|
||||||
}
|
}
|
||||||
if (pDXGIDevice) pDXGIDevice->Release();
|
if (pDXGIDevice) pDXGIDevice->Release();
|
||||||
if (pDXGIAdapter) pDXGIAdapter->Release();
|
if (pDXGIAdapter) pDXGIAdapter->Release();
|
||||||
g_pd3dDevice->AddRef();
|
bd->pd3dDevice->AddRef();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ImGui_ImplDX10_Shutdown()
|
void ImGui_ImplDX10_Shutdown()
|
||||||
{
|
{
|
||||||
|
ImGui_ImplDX10_Data* bd = ImGui_ImplDX10_GetBackendData();
|
||||||
|
IM_ASSERT(bd != NULL && "No renderer backend to shutdown, or already shutdown?");
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
|
||||||
ImGui_ImplDX10_InvalidateDeviceObjects();
|
ImGui_ImplDX10_InvalidateDeviceObjects();
|
||||||
if (g_pFactory) { g_pFactory->Release(); g_pFactory = NULL; }
|
if (bd->pFactory) { bd->pFactory->Release(); }
|
||||||
if (g_pd3dDevice) { g_pd3dDevice->Release(); g_pd3dDevice = NULL; }
|
if (bd->pd3dDevice) { bd->pd3dDevice->Release(); }
|
||||||
|
io.BackendRendererName = NULL;
|
||||||
|
io.BackendRendererUserData = NULL;
|
||||||
|
IM_DELETE(bd);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ImGui_ImplDX10_NewFrame()
|
bool ImGui_ImplDX10_NewFrame()
|
||||||
{
|
{
|
||||||
if (!g_pFontSampler)
|
ImGui_ImplDX10_Data* bd = ImGui_ImplDX10_GetBackendData();
|
||||||
|
IM_ASSERT(bd != NULL && "Did you call ImGui_ImplDX10_Init()?");
|
||||||
|
|
||||||
|
if (!bd->pFontSampler)
|
||||||
return ImGui_ImplDX10_CreateDeviceObjects();
|
return ImGui_ImplDX10_CreateDeviceObjects();
|
||||||
|
|
||||||
return true;
|
return true;
|
|
@ -12,6 +12,7 @@
|
||||||
|
|
||||||
// CHANGELOG
|
// CHANGELOG
|
||||||
// (minor and older changes stripped away, please see git history for details)
|
// (minor and older changes stripped away, please see git history for details)
|
||||||
|
// 2021-06-29: Reorganized backend to pull data from a single structure to facilitate usage with multiple-contexts (all g_XXXX access changed to bd->XXXX).
|
||||||
// 2021-05-19: DirectX11: Replaced direct access to ImDrawCmd::TextureId with a call to ImDrawCmd::GetTexID(). (will become a requirement)
|
// 2021-05-19: DirectX11: Replaced direct access to ImDrawCmd::TextureId with a call to ImDrawCmd::GetTexID(). (will become a requirement)
|
||||||
// 2021-02-18: DirectX11: Change blending equation to preserve alpha in output buffer.
|
// 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-08-01: DirectX11: Fixed code querying the Geometry Shader state (would generally error with Debug layer enabled).
|
||||||
|
@ -35,32 +36,48 @@
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <d3d11.h>
|
#include <d3d11.h>
|
||||||
|
|
||||||
#include "imgui_shaderblobs.h"
|
#include "imgui_win_shader_blobs.h"
|
||||||
|
|
||||||
// DirectX data
|
// DirectX11 data
|
||||||
static ID3D11Device* g_pd3dDevice = NULL;
|
struct ImGui_ImplDX11_Data
|
||||||
static ID3D11DeviceContext* g_pd3dDeviceContext = NULL;
|
{
|
||||||
static IDXGIFactory* g_pFactory = NULL;
|
ID3D11Device* pd3dDevice;
|
||||||
static ID3D11Buffer* g_pVB = NULL;
|
ID3D11DeviceContext* pd3dDeviceContext;
|
||||||
static ID3D11Buffer* g_pIB = NULL;
|
IDXGIFactory* pFactory;
|
||||||
static ID3D11VertexShader* g_pVertexShader = NULL;
|
ID3D11Buffer* pVB;
|
||||||
static ID3D11InputLayout* g_pInputLayout = NULL;
|
ID3D11Buffer* pIB;
|
||||||
static ID3D11Buffer* g_pVertexConstantBuffer = NULL;
|
ID3D11VertexShader* pVertexShader;
|
||||||
static ID3D11PixelShader* g_pPixelShader = NULL;
|
ID3D11InputLayout* pInputLayout;
|
||||||
static ID3D11SamplerState* g_pFontSampler = NULL;
|
ID3D11Buffer* pVertexConstantBuffer;
|
||||||
static ID3D11ShaderResourceView*g_pFontTextureView = NULL;
|
ID3D11PixelShader* pPixelShader;
|
||||||
static ID3D11RasterizerState* g_pRasterizerState = NULL;
|
ID3D11SamplerState* pFontSampler;
|
||||||
static ID3D11BlendState* g_pBlendState = NULL;
|
ID3D11ShaderResourceView* pFontTextureView;
|
||||||
static ID3D11DepthStencilState* g_pDepthStencilState = NULL;
|
ID3D11RasterizerState* pRasterizerState;
|
||||||
static int g_VertexBufferSize = 5000, g_IndexBufferSize = 10000;
|
ID3D11BlendState* pBlendState;
|
||||||
|
ID3D11DepthStencilState* pDepthStencilState;
|
||||||
|
int VertexBufferSize;
|
||||||
|
int IndexBufferSize;
|
||||||
|
|
||||||
struct VERTEX_CONSTANT_BUFFER
|
ImGui_ImplDX11_Data() { memset((void*)this, 0, sizeof(*this)); VertexBufferSize = 5000; IndexBufferSize = 10000; }
|
||||||
|
};
|
||||||
|
|
||||||
|
struct VERTEX_CONSTANT_BUFFER_DX11
|
||||||
{
|
{
|
||||||
float mvp[4][4];
|
float mvp[4][4];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Backend data stored in io.BackendRendererUserData to allow support for multiple Dear ImGui contexts
|
||||||
|
// It is STRONGLY preferred that you use docking branch with multi-viewports (== single Dear ImGui context + multiple windows) instead of multiple Dear ImGui contexts.
|
||||||
|
static ImGui_ImplDX11_Data* ImGui_ImplDX11_GetBackendData()
|
||||||
|
{
|
||||||
|
return ImGui::GetCurrentContext() ? (ImGui_ImplDX11_Data*)ImGui::GetIO().BackendRendererUserData : NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Functions
|
||||||
static void ImGui_ImplDX11_SetupRenderState(ImDrawData* draw_data, ID3D11DeviceContext* ctx)
|
static void ImGui_ImplDX11_SetupRenderState(ImDrawData* draw_data, ID3D11DeviceContext* ctx)
|
||||||
{
|
{
|
||||||
|
ImGui_ImplDX11_Data* bd = ImGui_ImplDX11_GetBackendData();
|
||||||
|
|
||||||
// Setup viewport
|
// Setup viewport
|
||||||
D3D11_VIEWPORT vp;
|
D3D11_VIEWPORT vp;
|
||||||
memset(&vp, 0, sizeof(D3D11_VIEWPORT));
|
memset(&vp, 0, sizeof(D3D11_VIEWPORT));
|
||||||
|
@ -74,14 +91,14 @@ static void ImGui_ImplDX11_SetupRenderState(ImDrawData* draw_data, ID3D11DeviceC
|
||||||
// Setup shader and vertex buffers
|
// Setup shader and vertex buffers
|
||||||
unsigned int stride = sizeof(ImDrawVert);
|
unsigned int stride = sizeof(ImDrawVert);
|
||||||
unsigned int offset = 0;
|
unsigned int offset = 0;
|
||||||
ctx->IASetInputLayout(g_pInputLayout);
|
ctx->IASetInputLayout(bd->pInputLayout);
|
||||||
ctx->IASetVertexBuffers(0, 1, &g_pVB, &stride, &offset);
|
ctx->IASetVertexBuffers(0, 1, &bd->pVB, &stride, &offset);
|
||||||
ctx->IASetIndexBuffer(g_pIB, sizeof(ImDrawIdx) == 2 ? DXGI_FORMAT_R16_UINT : DXGI_FORMAT_R32_UINT, 0);
|
ctx->IASetIndexBuffer(bd->pIB, sizeof(ImDrawIdx) == 2 ? DXGI_FORMAT_R16_UINT : DXGI_FORMAT_R32_UINT, 0);
|
||||||
ctx->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
|
ctx->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
|
||||||
ctx->VSSetShader(g_pVertexShader, NULL, 0);
|
ctx->VSSetShader(bd->pVertexShader, NULL, 0);
|
||||||
ctx->VSSetConstantBuffers(0, 1, &g_pVertexConstantBuffer);
|
ctx->VSSetConstantBuffers(0, 1, &bd->pVertexConstantBuffer);
|
||||||
ctx->PSSetShader(g_pPixelShader, NULL, 0);
|
ctx->PSSetShader(bd->pPixelShader, NULL, 0);
|
||||||
ctx->PSSetSamplers(0, 1, &g_pFontSampler);
|
ctx->PSSetSamplers(0, 1, &bd->pFontSampler);
|
||||||
ctx->GSSetShader(NULL, NULL, 0);
|
ctx->GSSetShader(NULL, NULL, 0);
|
||||||
ctx->HSSetShader(NULL, NULL, 0); // In theory we should backup and restore this as well.. very infrequently used..
|
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->DSSetShader(NULL, NULL, 0); // In theory we should backup and restore this as well.. very infrequently used..
|
||||||
|
@ -89,9 +106,9 @@ static void ImGui_ImplDX11_SetupRenderState(ImDrawData* draw_data, ID3D11DeviceC
|
||||||
|
|
||||||
// Setup blend state
|
// Setup blend state
|
||||||
const float blend_factor[4] = { 0.f, 0.f, 0.f, 0.f };
|
const float blend_factor[4] = { 0.f, 0.f, 0.f, 0.f };
|
||||||
ctx->OMSetBlendState(g_pBlendState, blend_factor, 0xffffffff);
|
ctx->OMSetBlendState(bd->pBlendState, blend_factor, 0xffffffff);
|
||||||
ctx->OMSetDepthStencilState(g_pDepthStencilState, 0);
|
ctx->OMSetDepthStencilState(bd->pDepthStencilState, 0);
|
||||||
ctx->RSSetState(g_pRasterizerState);
|
ctx->RSSetState(bd->pRasterizerState);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Render function
|
// Render function
|
||||||
|
@ -101,42 +118,43 @@ void ImGui_ImplDX11_RenderDrawData(ImDrawData* draw_data)
|
||||||
if (draw_data->DisplaySize.x <= 0.0f || draw_data->DisplaySize.y <= 0.0f)
|
if (draw_data->DisplaySize.x <= 0.0f || draw_data->DisplaySize.y <= 0.0f)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
ID3D11DeviceContext* ctx = g_pd3dDeviceContext;
|
ImGui_ImplDX11_Data* bd = ImGui_ImplDX11_GetBackendData();
|
||||||
|
ID3D11DeviceContext* ctx = bd->pd3dDeviceContext;
|
||||||
|
|
||||||
// Create and grow vertex/index buffers if needed
|
// Create and grow vertex/index buffers if needed
|
||||||
if (!g_pVB || g_VertexBufferSize < draw_data->TotalVtxCount)
|
if (!bd->pVB || bd->VertexBufferSize < draw_data->TotalVtxCount)
|
||||||
{
|
{
|
||||||
if (g_pVB) { g_pVB->Release(); g_pVB = NULL; }
|
if (bd->pVB) { bd->pVB->Release(); bd->pVB = NULL; }
|
||||||
g_VertexBufferSize = draw_data->TotalVtxCount + 5000;
|
bd->VertexBufferSize = draw_data->TotalVtxCount + 5000;
|
||||||
D3D11_BUFFER_DESC desc;
|
D3D11_BUFFER_DESC desc;
|
||||||
memset(&desc, 0, sizeof(D3D11_BUFFER_DESC));
|
memset(&desc, 0, sizeof(D3D11_BUFFER_DESC));
|
||||||
desc.Usage = D3D11_USAGE_DYNAMIC;
|
desc.Usage = D3D11_USAGE_DYNAMIC;
|
||||||
desc.ByteWidth = g_VertexBufferSize * sizeof(ImDrawVert);
|
desc.ByteWidth = bd->VertexBufferSize * sizeof(ImDrawVert);
|
||||||
desc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
|
desc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
|
||||||
desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
|
desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
|
||||||
desc.MiscFlags = 0;
|
desc.MiscFlags = 0;
|
||||||
if (g_pd3dDevice->CreateBuffer(&desc, NULL, &g_pVB) < 0)
|
if (bd->pd3dDevice->CreateBuffer(&desc, NULL, &bd->pVB) < 0)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!g_pIB || g_IndexBufferSize < draw_data->TotalIdxCount)
|
if (!bd->pIB || bd->IndexBufferSize < draw_data->TotalIdxCount)
|
||||||
{
|
{
|
||||||
if (g_pIB) { g_pIB->Release(); g_pIB = NULL; }
|
if (bd->pIB) { bd->pIB->Release(); bd->pIB = NULL; }
|
||||||
g_IndexBufferSize = draw_data->TotalIdxCount + 10000;
|
bd->IndexBufferSize = draw_data->TotalIdxCount + 10000;
|
||||||
D3D11_BUFFER_DESC desc;
|
D3D11_BUFFER_DESC desc;
|
||||||
memset(&desc, 0, sizeof(D3D11_BUFFER_DESC));
|
memset(&desc, 0, sizeof(D3D11_BUFFER_DESC));
|
||||||
desc.Usage = D3D11_USAGE_DYNAMIC;
|
desc.Usage = D3D11_USAGE_DYNAMIC;
|
||||||
desc.ByteWidth = g_IndexBufferSize * sizeof(ImDrawIdx);
|
desc.ByteWidth = bd->IndexBufferSize * sizeof(ImDrawIdx);
|
||||||
desc.BindFlags = D3D11_BIND_INDEX_BUFFER;
|
desc.BindFlags = D3D11_BIND_INDEX_BUFFER;
|
||||||
desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
|
desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
|
||||||
if (g_pd3dDevice->CreateBuffer(&desc, NULL, &g_pIB) < 0)
|
if (bd->pd3dDevice->CreateBuffer(&desc, NULL, &bd->pIB) < 0)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Upload vertex/index data into a single contiguous GPU buffer
|
// Upload vertex/index data into a single contiguous GPU buffer
|
||||||
D3D11_MAPPED_SUBRESOURCE vtx_resource, idx_resource;
|
D3D11_MAPPED_SUBRESOURCE vtx_resource, idx_resource;
|
||||||
if (ctx->Map(g_pVB, 0, D3D11_MAP_WRITE_DISCARD, 0, &vtx_resource) != S_OK)
|
if (ctx->Map(bd->pVB, 0, D3D11_MAP_WRITE_DISCARD, 0, &vtx_resource) != S_OK)
|
||||||
return;
|
return;
|
||||||
if (ctx->Map(g_pIB, 0, D3D11_MAP_WRITE_DISCARD, 0, &idx_resource) != S_OK)
|
if (ctx->Map(bd->pIB, 0, D3D11_MAP_WRITE_DISCARD, 0, &idx_resource) != S_OK)
|
||||||
return;
|
return;
|
||||||
ImDrawVert* vtx_dst = (ImDrawVert*)vtx_resource.pData;
|
ImDrawVert* vtx_dst = (ImDrawVert*)vtx_resource.pData;
|
||||||
ImDrawIdx* idx_dst = (ImDrawIdx*)idx_resource.pData;
|
ImDrawIdx* idx_dst = (ImDrawIdx*)idx_resource.pData;
|
||||||
|
@ -148,16 +166,16 @@ void ImGui_ImplDX11_RenderDrawData(ImDrawData* draw_data)
|
||||||
vtx_dst += cmd_list->VtxBuffer.Size;
|
vtx_dst += cmd_list->VtxBuffer.Size;
|
||||||
idx_dst += cmd_list->IdxBuffer.Size;
|
idx_dst += cmd_list->IdxBuffer.Size;
|
||||||
}
|
}
|
||||||
ctx->Unmap(g_pVB, 0);
|
ctx->Unmap(bd->pVB, 0);
|
||||||
ctx->Unmap(g_pIB, 0);
|
ctx->Unmap(bd->pIB, 0);
|
||||||
|
|
||||||
// Setup orthographic projection matrix into our constant buffer
|
// 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.
|
// 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;
|
D3D11_MAPPED_SUBRESOURCE mapped_resource;
|
||||||
if (ctx->Map(g_pVertexConstantBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mapped_resource) != S_OK)
|
if (ctx->Map(bd->pVertexConstantBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mapped_resource) != S_OK)
|
||||||
return;
|
return;
|
||||||
VERTEX_CONSTANT_BUFFER* constant_buffer = (VERTEX_CONSTANT_BUFFER*)mapped_resource.pData;
|
VERTEX_CONSTANT_BUFFER_DX11* constant_buffer = (VERTEX_CONSTANT_BUFFER_DX11*)mapped_resource.pData;
|
||||||
float L = draw_data->DisplayPos.x;
|
float L = draw_data->DisplayPos.x;
|
||||||
float R = draw_data->DisplayPos.x + draw_data->DisplaySize.x;
|
float R = draw_data->DisplayPos.x + draw_data->DisplaySize.x;
|
||||||
float T = draw_data->DisplayPos.y;
|
float T = draw_data->DisplayPos.y;
|
||||||
|
@ -170,7 +188,7 @@ void ImGui_ImplDX11_RenderDrawData(ImDrawData* draw_data)
|
||||||
{ (R+L)/(L-R), (T+B)/(B-T), 0.5f, 1.0f },
|
{ (R+L)/(L-R), (T+B)/(B-T), 0.5f, 1.0f },
|
||||||
};
|
};
|
||||||
memcpy(&constant_buffer->mvp, mvp, sizeof(mvp));
|
memcpy(&constant_buffer->mvp, mvp, sizeof(mvp));
|
||||||
ctx->Unmap(g_pVertexConstantBuffer, 0);
|
ctx->Unmap(bd->pVertexConstantBuffer, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Backup DX state that will be modified to restore it afterwards (unfortunately this is very ugly looking and verbose. Close your eyes!)
|
// Backup DX state that will be modified to restore it afterwards (unfortunately this is very ugly looking and verbose. Close your eyes!)
|
||||||
|
@ -243,8 +261,14 @@ void ImGui_ImplDX11_RenderDrawData(ImDrawData* draw_data)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
// Project scissor/clipping rectangles into framebuffer space
|
||||||
|
ImVec2 clip_min(pcmd->ClipRect.x - clip_off.x, pcmd->ClipRect.y - clip_off.y);
|
||||||
|
ImVec2 clip_max(pcmd->ClipRect.z - clip_off.x, pcmd->ClipRect.w - clip_off.y);
|
||||||
|
if (clip_max.x <= clip_min.x || clip_max.y <= clip_min.y)
|
||||||
|
continue;
|
||||||
|
|
||||||
// Apply scissor/clipping rectangle
|
// 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) };
|
const D3D11_RECT r = { (LONG)clip_min.x, (LONG)clip_min.y, (LONG)clip_max.x, (LONG)clip_max.y };
|
||||||
ctx->RSSetScissorRects(1, &r);
|
ctx->RSSetScissorRects(1, &r);
|
||||||
|
|
||||||
// Bind texture, Draw
|
// Bind texture, Draw
|
||||||
|
@ -281,6 +305,7 @@ static void ImGui_ImplDX11_CreateFontsTexture()
|
||||||
{
|
{
|
||||||
// Build texture atlas
|
// Build texture atlas
|
||||||
ImGuiIO& io = ImGui::GetIO();
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
ImGui_ImplDX11_Data* bd = ImGui_ImplDX11_GetBackendData();
|
||||||
unsigned char* pixels;
|
unsigned char* pixels;
|
||||||
int width, height;
|
int width, height;
|
||||||
io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height);
|
io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height);
|
||||||
|
@ -304,7 +329,7 @@ static void ImGui_ImplDX11_CreateFontsTexture()
|
||||||
subResource.pSysMem = pixels;
|
subResource.pSysMem = pixels;
|
||||||
subResource.SysMemPitch = desc.Width * 4;
|
subResource.SysMemPitch = desc.Width * 4;
|
||||||
subResource.SysMemSlicePitch = 0;
|
subResource.SysMemSlicePitch = 0;
|
||||||
g_pd3dDevice->CreateTexture2D(&desc, &subResource, &pTexture);
|
bd->pd3dDevice->CreateTexture2D(&desc, &subResource, &pTexture);
|
||||||
IM_ASSERT(pTexture != NULL);
|
IM_ASSERT(pTexture != NULL);
|
||||||
|
|
||||||
// Create texture view
|
// Create texture view
|
||||||
|
@ -314,14 +339,15 @@ static void ImGui_ImplDX11_CreateFontsTexture()
|
||||||
srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
|
srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
|
||||||
srvDesc.Texture2D.MipLevels = desc.MipLevels;
|
srvDesc.Texture2D.MipLevels = desc.MipLevels;
|
||||||
srvDesc.Texture2D.MostDetailedMip = 0;
|
srvDesc.Texture2D.MostDetailedMip = 0;
|
||||||
g_pd3dDevice->CreateShaderResourceView(pTexture, &srvDesc, &g_pFontTextureView);
|
bd->pd3dDevice->CreateShaderResourceView(pTexture, &srvDesc, &bd->pFontTextureView);
|
||||||
pTexture->Release();
|
pTexture->Release();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Store our identifier
|
// Store our identifier
|
||||||
io.Fonts->SetTexID((ImTextureID)g_pFontTextureView);
|
io.Fonts->SetTexID((ImTextureID)bd->pFontTextureView);
|
||||||
|
|
||||||
// Create texture sampler
|
// Create texture sampler
|
||||||
|
// (Bilinear sampling is required by default. Set 'io.Fonts->Flags |= ImFontAtlasFlags_NoBakedLines' or 'style.AntiAliasedLinesUseTex = false' to allow point/nearest sampling)
|
||||||
{
|
{
|
||||||
D3D11_SAMPLER_DESC desc;
|
D3D11_SAMPLER_DESC desc;
|
||||||
ZeroMemory(&desc, sizeof(desc));
|
ZeroMemory(&desc, sizeof(desc));
|
||||||
|
@ -333,15 +359,16 @@ static void ImGui_ImplDX11_CreateFontsTexture()
|
||||||
desc.ComparisonFunc = D3D11_COMPARISON_ALWAYS;
|
desc.ComparisonFunc = D3D11_COMPARISON_ALWAYS;
|
||||||
desc.MinLOD = 0.f;
|
desc.MinLOD = 0.f;
|
||||||
desc.MaxLOD = 0.f;
|
desc.MaxLOD = 0.f;
|
||||||
g_pd3dDevice->CreateSamplerState(&desc, &g_pFontSampler);
|
bd->pd3dDevice->CreateSamplerState(&desc, &bd->pFontSampler);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ImGui_ImplDX11_CreateDeviceObjects()
|
bool ImGui_ImplDX11_CreateDeviceObjects()
|
||||||
{
|
{
|
||||||
if (!g_pd3dDevice)
|
ImGui_ImplDX11_Data* bd = ImGui_ImplDX11_GetBackendData();
|
||||||
|
if (!bd->pd3dDevice)
|
||||||
return false;
|
return false;
|
||||||
if (g_pFontSampler)
|
if (bd->pFontSampler)
|
||||||
ImGui_ImplDX11_InvalidateDeviceObjects();
|
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)
|
// By using D3DCompile() from <d3dcompiler.h> / d3dcompiler.lib, we introduce a dependency to a given version of d3dcompiler_XX.dll (see D3DCOMPILER_DLL_A)
|
||||||
|
@ -352,62 +379,9 @@ bool ImGui_ImplDX11_CreateDeviceObjects()
|
||||||
|
|
||||||
// Create the vertex shader
|
// Create the vertex shader
|
||||||
{
|
{
|
||||||
unsigned char* byteCode;
|
shader_t shader = getDX11VertexShader(bd->pd3dDevice->GetFeatureLevel());
|
||||||
SIZE_T byteCodeSize;
|
|
||||||
|
|
||||||
switch (g_pd3dDevice->GetFeatureLevel())
|
auto x = bd->pd3dDevice->CreateVertexShader(shader.shaderBlob, shader.shaderBlobSize, NULL, &bd->pVertexShader);
|
||||||
{
|
|
||||||
case D3D_FEATURE_LEVEL_9_1:
|
|
||||||
byteCode = ImGui_vertexShaderDX11_9_1;
|
|
||||||
byteCodeSize = ImGui_vertexShaderDX11_9_1_len;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case D3D_FEATURE_LEVEL_9_2:
|
|
||||||
byteCode = ImGui_vertexShaderDX11_9_2;
|
|
||||||
byteCodeSize = ImGui_vertexShaderDX11_9_2_len;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case D3D_FEATURE_LEVEL_9_3:
|
|
||||||
byteCode = ImGui_vertexShaderDX11_9_3;
|
|
||||||
byteCodeSize = ImGui_vertexShaderDX11_9_3_len;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case D3D_FEATURE_LEVEL_10_0:
|
|
||||||
byteCode = ImGui_vertexShaderDX11_10_0;
|
|
||||||
byteCodeSize = ImGui_vertexShaderDX11_10_0_len;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case D3D_FEATURE_LEVEL_10_1:
|
|
||||||
byteCode = ImGui_vertexShaderDX11_10_1;
|
|
||||||
byteCodeSize = ImGui_vertexShaderDX11_10_1_len;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case D3D_FEATURE_LEVEL_11_0:
|
|
||||||
byteCode = ImGui_vertexShaderDX11_11_0;
|
|
||||||
byteCodeSize = ImGui_vertexShaderDX11_11_0_len;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case D3D_FEATURE_LEVEL_11_1:
|
|
||||||
byteCode = ImGui_vertexShaderDX11_11_1;
|
|
||||||
byteCodeSize = ImGui_vertexShaderDX11_11_1_len;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case D3D_FEATURE_LEVEL_12_0:
|
|
||||||
byteCode = ImGui_vertexShaderDX11_12_0;
|
|
||||||
byteCodeSize = ImGui_vertexShaderDX11_12_0_len;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case D3D_FEATURE_LEVEL_12_1:
|
|
||||||
byteCode = ImGui_vertexShaderDX11_12_1;
|
|
||||||
byteCodeSize = ImGui_vertexShaderDX11_12_1_len;
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
byteCode = ImGui_vertexShaderDX11;
|
|
||||||
byteCodeSize = ImGui_vertexShaderDX11_len;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto x = g_pd3dDevice->CreateVertexShader(byteCode, byteCodeSize, NULL, &g_pVertexShader);
|
|
||||||
if (x != S_OK)
|
if (x != S_OK)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
@ -419,79 +393,26 @@ bool ImGui_ImplDX11_CreateDeviceObjects()
|
||||||
{ "COLOR", 0, DXGI_FORMAT_R8G8B8A8_UNORM, 0, (UINT)IM_OFFSETOF(ImDrawVert, col), 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, ImGui_vertexShaderDX11, ImGui_vertexShaderDX11_len, &g_pInputLayout) != S_OK)
|
if (bd->pd3dDevice->CreateInputLayout(local_layout, 3, shader.shaderBlob, shader.shaderBlobSize, &bd->pInputLayout) != S_OK)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Create the constant buffer
|
// Create the constant buffer
|
||||||
{
|
{
|
||||||
D3D11_BUFFER_DESC desc;
|
D3D11_BUFFER_DESC desc;
|
||||||
desc.ByteWidth = sizeof(VERTEX_CONSTANT_BUFFER);
|
desc.ByteWidth = sizeof(VERTEX_CONSTANT_BUFFER_DX11);
|
||||||
desc.Usage = D3D11_USAGE_DYNAMIC;
|
desc.Usage = D3D11_USAGE_DYNAMIC;
|
||||||
desc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
|
desc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
|
||||||
desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
|
desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
|
||||||
desc.MiscFlags = 0;
|
desc.MiscFlags = 0;
|
||||||
g_pd3dDevice->CreateBuffer(&desc, NULL, &g_pVertexConstantBuffer);
|
bd->pd3dDevice->CreateBuffer(&desc, NULL, &bd->pVertexConstantBuffer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create the pixel shader
|
// Create the pixel shader
|
||||||
{
|
{
|
||||||
unsigned char* byteCode;
|
shader_t shader = getDX11PixelShader(bd->pd3dDevice->GetFeatureLevel());
|
||||||
SIZE_T byteCodeSize;
|
|
||||||
|
|
||||||
switch (g_pd3dDevice->GetFeatureLevel())
|
if (bd->pd3dDevice->CreatePixelShader(shader.shaderBlob, shader.shaderBlobSize, NULL, &bd->pPixelShader) != S_OK)
|
||||||
{
|
|
||||||
case D3D_FEATURE_LEVEL_9_1:
|
|
||||||
byteCode = ImGui_pixelShaderDX11_9_1;
|
|
||||||
byteCodeSize = ImGui_pixelShaderDX11_9_1_len;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case D3D_FEATURE_LEVEL_9_2:
|
|
||||||
byteCode = ImGui_pixelShaderDX11_9_2;
|
|
||||||
byteCodeSize = ImGui_pixelShaderDX11_9_2_len;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case D3D_FEATURE_LEVEL_9_3:
|
|
||||||
byteCode = ImGui_pixelShaderDX11_9_3;
|
|
||||||
byteCodeSize = ImGui_pixelShaderDX11_9_3_len;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case D3D_FEATURE_LEVEL_10_0:
|
|
||||||
byteCode = ImGui_pixelShaderDX11_10_0;
|
|
||||||
byteCodeSize = ImGui_pixelShaderDX11_10_0_len;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case D3D_FEATURE_LEVEL_10_1:
|
|
||||||
byteCode = ImGui_pixelShaderDX11_10_1;
|
|
||||||
byteCodeSize = ImGui_pixelShaderDX11_10_1_len;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case D3D_FEATURE_LEVEL_11_0:
|
|
||||||
byteCode = ImGui_pixelShaderDX11_11_0;
|
|
||||||
byteCodeSize = ImGui_pixelShaderDX11_11_0_len;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case D3D_FEATURE_LEVEL_11_1:
|
|
||||||
byteCode = ImGui_pixelShaderDX11_11_1;
|
|
||||||
byteCodeSize = ImGui_pixelShaderDX11_11_1_len;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case D3D_FEATURE_LEVEL_12_0:
|
|
||||||
byteCode = ImGui_pixelShaderDX11_12_0;
|
|
||||||
byteCodeSize = ImGui_pixelShaderDX11_12_0_len;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case D3D_FEATURE_LEVEL_12_1:
|
|
||||||
byteCode = ImGui_pixelShaderDX11_12_1;
|
|
||||||
byteCodeSize = ImGui_pixelShaderDX11_12_1_len;
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
byteCode = ImGui_pixelShaderDX11;
|
|
||||||
byteCodeSize = ImGui_pixelShaderDX11_len;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (g_pd3dDevice->CreatePixelShader(byteCode, byteCodeSize, NULL, &g_pPixelShader) != S_OK)
|
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -510,7 +431,7 @@ bool ImGui_ImplDX11_CreateDeviceObjects()
|
||||||
desc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_INV_SRC_ALPHA;
|
desc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_INV_SRC_ALPHA;
|
||||||
desc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD;
|
desc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD;
|
||||||
desc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL;
|
desc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL;
|
||||||
g_pd3dDevice->CreateBlendState(&desc, &g_pBlendState);
|
bd->pd3dDevice->CreateBlendState(&desc, &bd->pBlendState);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create the rasterizer state
|
// Create the rasterizer state
|
||||||
|
@ -521,7 +442,7 @@ bool ImGui_ImplDX11_CreateDeviceObjects()
|
||||||
desc.CullMode = D3D11_CULL_NONE;
|
desc.CullMode = D3D11_CULL_NONE;
|
||||||
desc.ScissorEnable = true;
|
desc.ScissorEnable = true;
|
||||||
desc.DepthClipEnable = true;
|
desc.DepthClipEnable = true;
|
||||||
g_pd3dDevice->CreateRasterizerState(&desc, &g_pRasterizerState);
|
bd->pd3dDevice->CreateRasterizerState(&desc, &bd->pRasterizerState);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create depth-stencil State
|
// Create depth-stencil State
|
||||||
|
@ -535,7 +456,7 @@ bool ImGui_ImplDX11_CreateDeviceObjects()
|
||||||
desc.FrontFace.StencilFailOp = desc.FrontFace.StencilDepthFailOp = desc.FrontFace.StencilPassOp = D3D11_STENCIL_OP_KEEP;
|
desc.FrontFace.StencilFailOp = desc.FrontFace.StencilDepthFailOp = desc.FrontFace.StencilPassOp = D3D11_STENCIL_OP_KEEP;
|
||||||
desc.FrontFace.StencilFunc = D3D11_COMPARISON_ALWAYS;
|
desc.FrontFace.StencilFunc = D3D11_COMPARISON_ALWAYS;
|
||||||
desc.BackFace = desc.FrontFace;
|
desc.BackFace = desc.FrontFace;
|
||||||
g_pd3dDevice->CreateDepthStencilState(&desc, &g_pDepthStencilState);
|
bd->pd3dDevice->CreateDepthStencilState(&desc, &bd->pDepthStencilState);
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui_ImplDX11_CreateFontsTexture();
|
ImGui_ImplDX11_CreateFontsTexture();
|
||||||
|
@ -545,27 +466,31 @@ bool ImGui_ImplDX11_CreateDeviceObjects()
|
||||||
|
|
||||||
void ImGui_ImplDX11_InvalidateDeviceObjects()
|
void ImGui_ImplDX11_InvalidateDeviceObjects()
|
||||||
{
|
{
|
||||||
if (!g_pd3dDevice)
|
ImGui_ImplDX11_Data* bd = ImGui_ImplDX11_GetBackendData();
|
||||||
|
if (!bd->pd3dDevice)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (g_pFontSampler) { g_pFontSampler->Release(); g_pFontSampler = NULL; }
|
if (bd->pFontSampler) { bd->pFontSampler->Release(); bd->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 (bd->pFontTextureView) { bd->pFontTextureView->Release(); bd->pFontTextureView = NULL; ImGui::GetIO().Fonts->SetTexID(NULL); } // We copied data->pFontTextureView to io.Fonts->TexID so let's clear that as well.
|
||||||
if (g_pIB) { g_pIB->Release(); g_pIB = NULL; }
|
if (bd->pIB) { bd->pIB->Release(); bd->pIB = NULL; }
|
||||||
if (g_pVB) { g_pVB->Release(); g_pVB = NULL; }
|
if (bd->pVB) { bd->pVB->Release(); bd->pVB = NULL; }
|
||||||
|
if (bd->pBlendState) { bd->pBlendState->Release(); bd->pBlendState = NULL; }
|
||||||
if (g_pBlendState) { g_pBlendState->Release(); g_pBlendState = NULL; }
|
if (bd->pDepthStencilState) { bd->pDepthStencilState->Release(); bd->pDepthStencilState = NULL; }
|
||||||
if (g_pDepthStencilState) { g_pDepthStencilState->Release(); g_pDepthStencilState = NULL; }
|
if (bd->pRasterizerState) { bd->pRasterizerState->Release(); bd->pRasterizerState = NULL; }
|
||||||
if (g_pRasterizerState) { g_pRasterizerState->Release(); g_pRasterizerState = NULL; }
|
if (bd->pPixelShader) { bd->pPixelShader->Release(); bd->pPixelShader = NULL; }
|
||||||
if (g_pPixelShader) { g_pPixelShader->Release(); g_pPixelShader = NULL; }
|
if (bd->pVertexConstantBuffer) { bd->pVertexConstantBuffer->Release(); bd->pVertexConstantBuffer = NULL; }
|
||||||
if (g_pVertexConstantBuffer) { g_pVertexConstantBuffer->Release(); g_pVertexConstantBuffer = NULL; }
|
if (bd->pInputLayout) { bd->pInputLayout->Release(); bd->pInputLayout = NULL; }
|
||||||
if (g_pInputLayout) { g_pInputLayout->Release(); g_pInputLayout = NULL; }
|
if (bd->pVertexShader) { bd->pVertexShader->Release(); bd->pVertexShader = NULL; }
|
||||||
if (g_pVertexShader) { g_pVertexShader->Release(); g_pVertexShader = NULL; }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ImGui_ImplDX11_Init(ID3D11Device* device, ID3D11DeviceContext* device_context)
|
bool ImGui_ImplDX11_Init(ID3D11Device* device, ID3D11DeviceContext* device_context)
|
||||||
{
|
{
|
||||||
// Setup backend capabilities flags
|
|
||||||
ImGuiIO& io = ImGui::GetIO();
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
IM_ASSERT(io.BackendRendererUserData == NULL && "Already initialized a renderer backend!");
|
||||||
|
|
||||||
|
// Setup backend capabilities flags
|
||||||
|
ImGui_ImplDX11_Data* bd = IM_NEW(ImGui_ImplDX11_Data)();
|
||||||
|
io.BackendRendererUserData = (void*)bd;
|
||||||
io.BackendRendererName = "imgui_impl_dx11";
|
io.BackendRendererName = "imgui_impl_dx11";
|
||||||
io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes.
|
io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes.
|
||||||
|
|
||||||
|
@ -578,29 +503,40 @@ bool ImGui_ImplDX11_Init(ID3D11Device* device, ID3D11DeviceContext* device_co
|
||||||
if (pDXGIDevice->GetParent(IID_PPV_ARGS(&pDXGIAdapter)) == S_OK)
|
if (pDXGIDevice->GetParent(IID_PPV_ARGS(&pDXGIAdapter)) == S_OK)
|
||||||
if (pDXGIAdapter->GetParent(IID_PPV_ARGS(&pFactory)) == S_OK)
|
if (pDXGIAdapter->GetParent(IID_PPV_ARGS(&pFactory)) == S_OK)
|
||||||
{
|
{
|
||||||
g_pd3dDevice = device;
|
bd->pd3dDevice = device;
|
||||||
g_pd3dDeviceContext = device_context;
|
bd->pd3dDeviceContext = device_context;
|
||||||
g_pFactory = pFactory;
|
bd->pFactory = pFactory;
|
||||||
}
|
}
|
||||||
if (pDXGIDevice) pDXGIDevice->Release();
|
if (pDXGIDevice) pDXGIDevice->Release();
|
||||||
if (pDXGIAdapter) pDXGIAdapter->Release();
|
if (pDXGIAdapter) pDXGIAdapter->Release();
|
||||||
g_pd3dDevice->AddRef();
|
bd->pd3dDevice->AddRef();
|
||||||
g_pd3dDeviceContext->AddRef();
|
bd->pd3dDeviceContext->AddRef();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ImGui_ImplDX11_Shutdown()
|
void ImGui_ImplDX11_Shutdown()
|
||||||
{
|
{
|
||||||
|
ImGui_ImplDX11_Data* bd = ImGui_ImplDX11_GetBackendData();
|
||||||
|
IM_ASSERT(bd != NULL && "No renderer backend to shutdown, or already shutdown?");
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
|
||||||
ImGui_ImplDX11_InvalidateDeviceObjects();
|
ImGui_ImplDX11_InvalidateDeviceObjects();
|
||||||
if (g_pFactory) { g_pFactory->Release(); g_pFactory = NULL; }
|
if (bd->pFactory) { bd->pFactory->Release(); }
|
||||||
if (g_pd3dDevice) { g_pd3dDevice->Release(); g_pd3dDevice = NULL; }
|
if (bd->pd3dDevice) { bd->pd3dDevice->Release(); }
|
||||||
if (g_pd3dDeviceContext) { g_pd3dDeviceContext->Release(); g_pd3dDeviceContext = NULL; }
|
if (bd->pd3dDeviceContext) { bd->pd3dDeviceContext->Release(); }
|
||||||
|
io.BackendRendererName = NULL;
|
||||||
|
io.BackendRendererUserData = NULL;
|
||||||
|
IM_DELETE(bd);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ImGui_ImplDX11_NewFrame()
|
bool ImGui_ImplDX11_NewFrame()
|
||||||
{
|
{
|
||||||
if (!g_pFontSampler)
|
ImGui_ImplDX11_Data* bd = ImGui_ImplDX11_GetBackendData();
|
||||||
|
IM_ASSERT(bd != NULL && "Did you call ImGui_ImplDX11_Init()?");
|
||||||
|
|
||||||
|
if (!bd->pFontSampler)
|
||||||
return ImGui_ImplDX11_CreateDeviceObjects();
|
return ImGui_ImplDX11_CreateDeviceObjects();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
|
@ -7,7 +7,11 @@
|
||||||
|
|
||||||
// Important: to compile on 32-bit systems, this backend requires code to be compiled with '#define ImTextureID ImU64'.
|
// 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 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.
|
// To build this on 32-bit systems:
|
||||||
|
// - [Solution 1] IDE/msbuild: in "Properties/C++/Preprocessor Definitions" add 'ImTextureID=ImU64' (this is what we do in the 'example_win32_direct12/example_win32_direct12.vcxproj' project file)
|
||||||
|
// - [Solution 2] IDE/msbuild: in "Properties/C++/Preprocessor Definitions" add 'IMGUI_USER_CONFIG="my_imgui_config.h"' and inside 'my_imgui_config.h' add '#define ImTextureID ImU64' and as many other options as you like.
|
||||||
|
// - [Solution 3] IDE/msbuild: edit imconfig.h and add '#define ImTextureID ImU64' (prefer solution 2 to create your own config file!)
|
||||||
|
// - [Solution 4] command-line: add '/D ImTextureID=ImU64' to your cl.exe command-line (this is what we do in the example_win32_direct12/build_win32.bat file)
|
||||||
|
|
||||||
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
||||||
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
|
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
|
||||||
|
@ -16,6 +20,7 @@
|
||||||
|
|
||||||
// CHANGELOG
|
// CHANGELOG
|
||||||
// (minor and older changes stripped away, please see git history for details)
|
// (minor and older changes stripped away, please see git history for details)
|
||||||
|
// 2021-06-29: Reorganized backend to pull data from a single structure to facilitate usage with multiple-contexts (all g_XXXX access changed to bd->XXXX).
|
||||||
// 2021-05-19: DirectX12: Replaced direct access to ImDrawCmd::TextureId with a call to ImDrawCmd::GetTexID(). (will become a requirement)
|
// 2021-05-19: DirectX12: Replaced direct access to ImDrawCmd::TextureId with a call to ImDrawCmd::GetTexID(). (will become a requirement)
|
||||||
// 2021-02-18: DirectX12: Change blending equation to preserve alpha in output buffer.
|
// 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.
|
// 2021-01-11: DirectX12: Improve Windows 7 compatibility (for D3D12On7) by loading d3d12.dll dynamically.
|
||||||
|
@ -39,46 +44,54 @@
|
||||||
#include <d3d12.h>
|
#include <d3d12.h>
|
||||||
#include <dxgi1_4.h>
|
#include <dxgi1_4.h>
|
||||||
|
|
||||||
#include "imgui_shaderblobs.h"
|
#include "imgui_win_shader_blobs.h"
|
||||||
|
|
||||||
// DirectX data
|
// DirectX data
|
||||||
static ID3D12Device* g_pd3dDevice = NULL;
|
struct ImGui_ImplDX12_RenderBuffers
|
||||||
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* IndexBuffer;
|
||||||
ID3D12Resource* VertexBuffer;
|
ID3D12Resource* VertexBuffer;
|
||||||
int IndexBufferSize;
|
int IndexBufferSize;
|
||||||
int VertexBufferSize;
|
int VertexBufferSize;
|
||||||
};
|
};
|
||||||
static FrameResources* g_pFrameResources = NULL;
|
|
||||||
static UINT g_numFramesInFlight = 0;
|
|
||||||
static UINT g_frameIndex = UINT_MAX;
|
|
||||||
|
|
||||||
template<typename T>
|
struct ImGui_ImplDX12_Data
|
||||||
static void SafeRelease(T*& res)
|
|
||||||
{
|
{
|
||||||
if (res)
|
ID3D12Device* pd3dDevice;
|
||||||
res->Release();
|
ID3D12RootSignature* pRootSignature;
|
||||||
res = NULL;
|
ID3D12PipelineState* pPipelineState;
|
||||||
}
|
DXGI_FORMAT RTVFormat;
|
||||||
|
ID3D12Resource* pFontTextureResource;
|
||||||
|
D3D12_CPU_DESCRIPTOR_HANDLE hFontSrvCpuDescHandle;
|
||||||
|
D3D12_GPU_DESCRIPTOR_HANDLE hFontSrvGpuDescHandle;
|
||||||
|
|
||||||
struct VERTEX_CONSTANT_BUFFER
|
ImGui_ImplDX12_RenderBuffers* pFrameResources;
|
||||||
|
UINT numFramesInFlight;
|
||||||
|
UINT frameIndex;
|
||||||
|
|
||||||
|
ImGui_ImplDX12_Data() { memset((void*)this, 0, sizeof(*this)); frameIndex = UINT_MAX; }
|
||||||
|
};
|
||||||
|
|
||||||
|
struct VERTEX_CONSTANT_BUFFER_DX12
|
||||||
{
|
{
|
||||||
float mvp[4][4];
|
float mvp[4][4];
|
||||||
};
|
};
|
||||||
|
|
||||||
static void ImGui_ImplDX12_SetupRenderState(ImDrawData* draw_data, ID3D12GraphicsCommandList* ctx, FrameResources* fr)
|
// Backend data stored in io.BackendRendererUserData to allow support for multiple Dear ImGui contexts
|
||||||
|
// It is STRONGLY preferred that you use docking branch with multi-viewports (== single Dear ImGui context + multiple windows) instead of multiple Dear ImGui contexts.
|
||||||
|
static ImGui_ImplDX12_Data* ImGui_ImplDX12_GetBackendData()
|
||||||
{
|
{
|
||||||
|
return ImGui::GetCurrentContext() ? (ImGui_ImplDX12_Data*)ImGui::GetIO().BackendRendererUserData : NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Functions
|
||||||
|
static void ImGui_ImplDX12_SetupRenderState(ImDrawData* draw_data, ID3D12GraphicsCommandList* ctx, ImGui_ImplDX12_RenderBuffers* fr)
|
||||||
|
{
|
||||||
|
ImGui_ImplDX12_Data* bd = ImGui_ImplDX12_GetBackendData();
|
||||||
|
|
||||||
// Setup orthographic projection matrix into our constant buffer
|
// 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).
|
// 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;
|
VERTEX_CONSTANT_BUFFER_DX12 vertex_constant_buffer;
|
||||||
{
|
{
|
||||||
float L = draw_data->DisplayPos.x;
|
float L = draw_data->DisplayPos.x;
|
||||||
float R = draw_data->DisplayPos.x + draw_data->DisplaySize.x;
|
float R = draw_data->DisplayPos.x + draw_data->DisplaySize.x;
|
||||||
|
@ -120,8 +133,8 @@ static void ImGui_ImplDX12_SetupRenderState(ImDrawData* draw_data, ID3D12Graphic
|
||||||
ibv.Format = sizeof(ImDrawIdx) == 2 ? DXGI_FORMAT_R16_UINT : DXGI_FORMAT_R32_UINT;
|
ibv.Format = sizeof(ImDrawIdx) == 2 ? DXGI_FORMAT_R16_UINT : DXGI_FORMAT_R32_UINT;
|
||||||
ctx->IASetIndexBuffer(&ibv);
|
ctx->IASetIndexBuffer(&ibv);
|
||||||
ctx->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
|
ctx->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
|
||||||
ctx->SetPipelineState(g_pPipelineState);
|
ctx->SetPipelineState(bd->pPipelineState);
|
||||||
ctx->SetGraphicsRootSignature(g_pRootSignature);
|
ctx->SetGraphicsRootSignature(bd->pRootSignature);
|
||||||
ctx->SetGraphicsRoot32BitConstants(0, 16, &vertex_constant_buffer, 0);
|
ctx->SetGraphicsRoot32BitConstants(0, 16, &vertex_constant_buffer, 0);
|
||||||
|
|
||||||
// Setup blend factor
|
// Setup blend factor
|
||||||
|
@ -129,6 +142,14 @@ static void ImGui_ImplDX12_SetupRenderState(ImDrawData* draw_data, ID3D12Graphic
|
||||||
ctx->OMSetBlendFactor(blend_factor);
|
ctx->OMSetBlendFactor(blend_factor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
static inline void SafeRelease(T*& res)
|
||||||
|
{
|
||||||
|
if (res)
|
||||||
|
res->Release();
|
||||||
|
res = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
// Render function
|
// Render function
|
||||||
void ImGui_ImplDX12_RenderDrawData(ImDrawData* draw_data, ID3D12GraphicsCommandList* ctx)
|
void ImGui_ImplDX12_RenderDrawData(ImDrawData* draw_data, ID3D12GraphicsCommandList* ctx)
|
||||||
{
|
{
|
||||||
|
@ -138,8 +159,9 @@ void ImGui_ImplDX12_RenderDrawData(ImDrawData* draw_data, ID3D12GraphicsCommandL
|
||||||
|
|
||||||
// FIXME: I'm assuming that this only gets called once per frame!
|
// 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.
|
// 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;
|
ImGui_ImplDX12_Data* bd = ImGui_ImplDX12_GetBackendData();
|
||||||
FrameResources* fr = &g_pFrameResources[g_frameIndex % g_numFramesInFlight];
|
bd->frameIndex = bd->frameIndex + 1;
|
||||||
|
ImGui_ImplDX12_RenderBuffers* fr = &bd->pFrameResources[bd->frameIndex % bd->numFramesInFlight];
|
||||||
|
|
||||||
// Create and grow vertex/index buffers if needed
|
// Create and grow vertex/index buffers if needed
|
||||||
if (fr->VertexBuffer == NULL || fr->VertexBufferSize < draw_data->TotalVtxCount)
|
if (fr->VertexBuffer == NULL || fr->VertexBufferSize < draw_data->TotalVtxCount)
|
||||||
|
@ -162,7 +184,7 @@ void ImGui_ImplDX12_RenderDrawData(ImDrawData* draw_data, ID3D12GraphicsCommandL
|
||||||
desc.SampleDesc.Count = 1;
|
desc.SampleDesc.Count = 1;
|
||||||
desc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
|
desc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
|
||||||
desc.Flags = D3D12_RESOURCE_FLAG_NONE;
|
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)
|
if (bd->pd3dDevice->CreateCommittedResource(&props, D3D12_HEAP_FLAG_NONE, &desc, D3D12_RESOURCE_STATE_GENERIC_READ, NULL, IID_PPV_ARGS(&fr->VertexBuffer)) < 0)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (fr->IndexBuffer == NULL || fr->IndexBufferSize < draw_data->TotalIdxCount)
|
if (fr->IndexBuffer == NULL || fr->IndexBufferSize < draw_data->TotalIdxCount)
|
||||||
|
@ -185,7 +207,7 @@ void ImGui_ImplDX12_RenderDrawData(ImDrawData* draw_data, ID3D12GraphicsCommandL
|
||||||
desc.SampleDesc.Count = 1;
|
desc.SampleDesc.Count = 1;
|
||||||
desc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
|
desc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
|
||||||
desc.Flags = D3D12_RESOURCE_FLAG_NONE;
|
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)
|
if (bd->pd3dDevice->CreateCommittedResource(&props, D3D12_HEAP_FLAG_NONE, &desc, D3D12_RESOURCE_STATE_GENERIC_READ, NULL, IID_PPV_ARGS(&fr->IndexBuffer)) < 0)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -235,18 +257,21 @@ void ImGui_ImplDX12_RenderDrawData(ImDrawData* draw_data, ID3D12GraphicsCommandL
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Apply Scissor, Bind texture, Draw
|
// Project scissor/clipping rectangles into framebuffer space
|
||||||
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) };
|
ImVec2 clip_min(pcmd->ClipRect.x - clip_off.x, pcmd->ClipRect.y - clip_off.y);
|
||||||
if (r.right > r.left && r.bottom > r.top)
|
ImVec2 clip_max(pcmd->ClipRect.z - clip_off.x, pcmd->ClipRect.w - clip_off.y);
|
||||||
{
|
if (clip_max.x <= clip_min.x || clip_max.y <= clip_min.y)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Apply Scissor/clipping rectangle, Bind texture, Draw
|
||||||
|
const D3D12_RECT r = { (LONG)clip_min.x, (LONG)clip_min.y, (LONG)clip_max.x, (LONG)clip_max.y };
|
||||||
D3D12_GPU_DESCRIPTOR_HANDLE texture_handle = {};
|
D3D12_GPU_DESCRIPTOR_HANDLE texture_handle = {};
|
||||||
texture_handle.ptr = (UINT64)(intptr_t)pcmd->GetTexID();
|
texture_handle.ptr = (UINT64)pcmd->GetTexID();
|
||||||
ctx->SetGraphicsRootDescriptorTable(1, texture_handle);
|
ctx->SetGraphicsRootDescriptorTable(1, texture_handle);
|
||||||
ctx->RSSetScissorRects(1, &r);
|
ctx->RSSetScissorRects(1, &r);
|
||||||
ctx->DrawIndexedInstanced(pcmd->ElemCount, 1, pcmd->IdxOffset + global_idx_offset, pcmd->VtxOffset + global_vtx_offset, 0);
|
ctx->DrawIndexedInstanced(pcmd->ElemCount, 1, pcmd->IdxOffset + global_idx_offset, pcmd->VtxOffset + global_vtx_offset, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
global_idx_offset += cmd_list->IdxBuffer.Size;
|
global_idx_offset += cmd_list->IdxBuffer.Size;
|
||||||
global_vtx_offset += cmd_list->VtxBuffer.Size;
|
global_vtx_offset += cmd_list->VtxBuffer.Size;
|
||||||
}
|
}
|
||||||
|
@ -256,6 +281,7 @@ static void ImGui_ImplDX12_CreateFontsTexture()
|
||||||
{
|
{
|
||||||
// Build texture atlas
|
// Build texture atlas
|
||||||
ImGuiIO& io = ImGui::GetIO();
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
ImGui_ImplDX12_Data* bd = ImGui_ImplDX12_GetBackendData();
|
||||||
unsigned char* pixels;
|
unsigned char* pixels;
|
||||||
int width, height;
|
int width, height;
|
||||||
io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height);
|
io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height);
|
||||||
|
@ -283,7 +309,7 @@ static void ImGui_ImplDX12_CreateFontsTexture()
|
||||||
desc.Flags = D3D12_RESOURCE_FLAG_NONE;
|
desc.Flags = D3D12_RESOURCE_FLAG_NONE;
|
||||||
|
|
||||||
ID3D12Resource* pTexture = NULL;
|
ID3D12Resource* pTexture = NULL;
|
||||||
g_pd3dDevice->CreateCommittedResource(&props, D3D12_HEAP_FLAG_NONE, &desc,
|
bd->pd3dDevice->CreateCommittedResource(&props, D3D12_HEAP_FLAG_NONE, &desc,
|
||||||
D3D12_RESOURCE_STATE_COPY_DEST, NULL, IID_PPV_ARGS(&pTexture));
|
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 uploadPitch = (width * 4 + D3D12_TEXTURE_DATA_PITCH_ALIGNMENT - 1u) & ~(D3D12_TEXTURE_DATA_PITCH_ALIGNMENT - 1u);
|
||||||
|
@ -305,7 +331,7 @@ static void ImGui_ImplDX12_CreateFontsTexture()
|
||||||
props.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
|
props.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
|
||||||
|
|
||||||
ID3D12Resource* uploadBuffer = NULL;
|
ID3D12Resource* uploadBuffer = NULL;
|
||||||
HRESULT hr = g_pd3dDevice->CreateCommittedResource(&props, D3D12_HEAP_FLAG_NONE, &desc,
|
HRESULT hr = bd->pd3dDevice->CreateCommittedResource(&props, D3D12_HEAP_FLAG_NONE, &desc,
|
||||||
D3D12_RESOURCE_STATE_GENERIC_READ, NULL, IID_PPV_ARGS(&uploadBuffer));
|
D3D12_RESOURCE_STATE_GENERIC_READ, NULL, IID_PPV_ARGS(&uploadBuffer));
|
||||||
IM_ASSERT(SUCCEEDED(hr));
|
IM_ASSERT(SUCCEEDED(hr));
|
||||||
|
|
||||||
|
@ -340,7 +366,7 @@ static void ImGui_ImplDX12_CreateFontsTexture()
|
||||||
barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE;
|
barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE;
|
||||||
|
|
||||||
ID3D12Fence* fence = NULL;
|
ID3D12Fence* fence = NULL;
|
||||||
hr = g_pd3dDevice->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&fence));
|
hr = bd->pd3dDevice->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&fence));
|
||||||
IM_ASSERT(SUCCEEDED(hr));
|
IM_ASSERT(SUCCEEDED(hr));
|
||||||
|
|
||||||
HANDLE event = CreateEvent(0, 0, 0, 0);
|
HANDLE event = CreateEvent(0, 0, 0, 0);
|
||||||
|
@ -352,15 +378,15 @@ static void ImGui_ImplDX12_CreateFontsTexture()
|
||||||
queueDesc.NodeMask = 1;
|
queueDesc.NodeMask = 1;
|
||||||
|
|
||||||
ID3D12CommandQueue* cmdQueue = NULL;
|
ID3D12CommandQueue* cmdQueue = NULL;
|
||||||
hr = g_pd3dDevice->CreateCommandQueue(&queueDesc, IID_PPV_ARGS(&cmdQueue));
|
hr = bd->pd3dDevice->CreateCommandQueue(&queueDesc, IID_PPV_ARGS(&cmdQueue));
|
||||||
IM_ASSERT(SUCCEEDED(hr));
|
IM_ASSERT(SUCCEEDED(hr));
|
||||||
|
|
||||||
ID3D12CommandAllocator* cmdAlloc = NULL;
|
ID3D12CommandAllocator* cmdAlloc = NULL;
|
||||||
hr = g_pd3dDevice->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&cmdAlloc));
|
hr = bd->pd3dDevice->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&cmdAlloc));
|
||||||
IM_ASSERT(SUCCEEDED(hr));
|
IM_ASSERT(SUCCEEDED(hr));
|
||||||
|
|
||||||
ID3D12GraphicsCommandList* cmdList = NULL;
|
ID3D12GraphicsCommandList* cmdList = NULL;
|
||||||
hr = g_pd3dDevice->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, cmdAlloc, NULL, IID_PPV_ARGS(&cmdList));
|
hr = bd->pd3dDevice->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, cmdAlloc, NULL, IID_PPV_ARGS(&cmdList));
|
||||||
IM_ASSERT(SUCCEEDED(hr));
|
IM_ASSERT(SUCCEEDED(hr));
|
||||||
|
|
||||||
cmdList->CopyTextureRegion(&dstLocation, 0, 0, 0, &srcLocation, NULL);
|
cmdList->CopyTextureRegion(&dstLocation, 0, 0, 0, &srcLocation, NULL);
|
||||||
|
@ -391,21 +417,29 @@ static void ImGui_ImplDX12_CreateFontsTexture()
|
||||||
srvDesc.Texture2D.MipLevels = desc.MipLevels;
|
srvDesc.Texture2D.MipLevels = desc.MipLevels;
|
||||||
srvDesc.Texture2D.MostDetailedMip = 0;
|
srvDesc.Texture2D.MostDetailedMip = 0;
|
||||||
srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
|
srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
|
||||||
g_pd3dDevice->CreateShaderResourceView(pTexture, &srvDesc, g_hFontSrvCpuDescHandle);
|
bd->pd3dDevice->CreateShaderResourceView(pTexture, &srvDesc, bd->hFontSrvCpuDescHandle);
|
||||||
SafeRelease(g_pFontTextureResource);
|
SafeRelease(bd->pFontTextureResource);
|
||||||
g_pFontTextureResource = pTexture;
|
bd->pFontTextureResource = pTexture;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Store our identifier
|
// Store our identifier
|
||||||
static_assert(sizeof(ImTextureID) >= sizeof(g_hFontSrvGpuDescHandle.ptr), "Can't pack descriptor handle into TexID, 32-bit not supported yet.");
|
// READ THIS IF THE STATIC_ASSERT() TRIGGERS:
|
||||||
io.Fonts->SetTexID((ImTextureID)g_hFontSrvGpuDescHandle.ptr);
|
// - 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*.
|
||||||
|
// [Solution 1] IDE/msbuild: in "Properties/C++/Preprocessor Definitions" add 'ImTextureID=ImU64' (this is what we do in the 'example_win32_direct12/example_win32_direct12.vcxproj' project file)
|
||||||
|
// [Solution 2] IDE/msbuild: in "Properties/C++/Preprocessor Definitions" add 'IMGUI_USER_CONFIG="my_imgui_config.h"' and inside 'my_imgui_config.h' add '#define ImTextureID ImU64' and as many other options as you like.
|
||||||
|
// [Solution 3] IDE/msbuild: edit imconfig.h and add '#define ImTextureID ImU64' (prefer solution 2 to create your own config file!)
|
||||||
|
// [Solution 4] command-line: add '/D ImTextureID=ImU64' to your cl.exe command-line (this is what we do in the example_win32_direct12/build_win32.bat file)
|
||||||
|
static_assert(sizeof(ImTextureID) >= sizeof(bd->hFontSrvGpuDescHandle.ptr), "Can't pack descriptor handle into TexID, 32-bit not supported yet.");
|
||||||
|
io.Fonts->SetTexID((ImTextureID)bd->hFontSrvGpuDescHandle.ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ImGui_ImplDX12_CreateDeviceObjects()
|
bool ImGui_ImplDX12_CreateDeviceObjects()
|
||||||
{
|
{
|
||||||
if (!g_pd3dDevice)
|
ImGui_ImplDX12_Data* bd = ImGui_ImplDX12_GetBackendData();
|
||||||
|
if (!bd || !bd->pd3dDevice)
|
||||||
return false;
|
return false;
|
||||||
if (g_pPipelineState)
|
if (bd->pPipelineState)
|
||||||
ImGui_ImplDX12_InvalidateDeviceObjects();
|
ImGui_ImplDX12_InvalidateDeviceObjects();
|
||||||
|
|
||||||
// Create the root signature
|
// Create the root signature
|
||||||
|
@ -430,6 +464,7 @@ bool ImGui_ImplDX12_CreateDeviceObjects()
|
||||||
param[1].DescriptorTable.pDescriptorRanges = &descRange;
|
param[1].DescriptorTable.pDescriptorRanges = &descRange;
|
||||||
param[1].ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL;
|
param[1].ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL;
|
||||||
|
|
||||||
|
// Bilinear sampling is required by default. Set 'io.Fonts->Flags |= ImFontAtlasFlags_NoBakedLines' or 'style.AntiAliasedLinesUseTex = false' to allow point/nearest sampling.
|
||||||
D3D12_STATIC_SAMPLER_DESC staticSampler = {};
|
D3D12_STATIC_SAMPLER_DESC staticSampler = {};
|
||||||
staticSampler.Filter = D3D12_FILTER_MIN_MAG_MIP_LINEAR;
|
staticSampler.Filter = D3D12_FILTER_MIN_MAG_MIP_LINEAR;
|
||||||
staticSampler.AddressU = D3D12_TEXTURE_ADDRESS_MODE_WRAP;
|
staticSampler.AddressU = D3D12_TEXTURE_ADDRESS_MODE_WRAP;
|
||||||
|
@ -486,7 +521,7 @@ bool ImGui_ImplDX12_CreateDeviceObjects()
|
||||||
if (D3D12SerializeRootSignatureFn(&desc, D3D_ROOT_SIGNATURE_VERSION_1, &blob, NULL) != S_OK)
|
if (D3D12SerializeRootSignatureFn(&desc, D3D_ROOT_SIGNATURE_VERSION_1, &blob, NULL) != S_OK)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
g_pd3dDevice->CreateRootSignature(0, blob->GetBufferPointer(), blob->GetBufferSize(), IID_PPV_ARGS(&g_pRootSignature));
|
bd->pd3dDevice->CreateRootSignature(0, blob->GetBufferPointer(), blob->GetBufferSize(), IID_PPV_ARGS(&bd->pRootSignature));
|
||||||
blob->Release();
|
blob->Release();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -500,16 +535,17 @@ bool ImGui_ImplDX12_CreateDeviceObjects()
|
||||||
memset(&psoDesc, 0, sizeof(D3D12_GRAPHICS_PIPELINE_STATE_DESC));
|
memset(&psoDesc, 0, sizeof(D3D12_GRAPHICS_PIPELINE_STATE_DESC));
|
||||||
psoDesc.NodeMask = 1;
|
psoDesc.NodeMask = 1;
|
||||||
psoDesc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
|
psoDesc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
|
||||||
psoDesc.pRootSignature = g_pRootSignature;
|
psoDesc.pRootSignature = bd->pRootSignature;
|
||||||
psoDesc.SampleMask = UINT_MAX;
|
psoDesc.SampleMask = UINT_MAX;
|
||||||
psoDesc.NumRenderTargets = 1;
|
psoDesc.NumRenderTargets = 1;
|
||||||
psoDesc.RTVFormats[0] = g_RTVFormat;
|
psoDesc.RTVFormats[0] = bd->RTVFormat;
|
||||||
psoDesc.SampleDesc.Count = 1;
|
psoDesc.SampleDesc.Count = 1;
|
||||||
psoDesc.Flags = D3D12_PIPELINE_STATE_FLAG_NONE;
|
psoDesc.Flags = D3D12_PIPELINE_STATE_FLAG_NONE;
|
||||||
|
|
||||||
// Create the vertex shader
|
// Create the vertex shader
|
||||||
{
|
{
|
||||||
psoDesc.VS = { ImGui_vertexShaderDX12, ImGui_vertexShaderDX12_len };
|
shader_t shader = getDX12VertexShader();
|
||||||
|
psoDesc.VS = { shader.shaderBlob, shader.shaderBlobSize };
|
||||||
|
|
||||||
// Create the input layout
|
// Create the input layout
|
||||||
static D3D12_INPUT_ELEMENT_DESC local_layout[] =
|
static D3D12_INPUT_ELEMENT_DESC local_layout[] =
|
||||||
|
@ -523,7 +559,8 @@ bool ImGui_ImplDX12_CreateDeviceObjects()
|
||||||
|
|
||||||
// Create the pixel shader
|
// Create the pixel shader
|
||||||
{
|
{
|
||||||
psoDesc.PS = { ImGui_pixelShaderDX12, ImGui_pixelShaderDX12_len };
|
shader_t shader = getDX12PixelShader();
|
||||||
|
psoDesc.PS = { shader.shaderBlob, shader.shaderBlobSize };
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create the blending setup
|
// Create the blending setup
|
||||||
|
@ -568,7 +605,8 @@ bool ImGui_ImplDX12_CreateDeviceObjects()
|
||||||
desc.BackFace = desc.FrontFace;
|
desc.BackFace = desc.FrontFace;
|
||||||
}
|
}
|
||||||
|
|
||||||
HRESULT result_pipeline_state = g_pd3dDevice->CreateGraphicsPipelineState(&psoDesc, IID_PPV_ARGS(&g_pPipelineState));
|
HRESULT result_pipeline_state = bd->pd3dDevice->CreateGraphicsPipelineState(&psoDesc, IID_PPV_ARGS(&bd->pPipelineState));
|
||||||
|
|
||||||
if (result_pipeline_state != S_OK)
|
if (result_pipeline_state != S_OK)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
@ -579,19 +617,19 @@ bool ImGui_ImplDX12_CreateDeviceObjects()
|
||||||
|
|
||||||
void ImGui_ImplDX12_InvalidateDeviceObjects()
|
void ImGui_ImplDX12_InvalidateDeviceObjects()
|
||||||
{
|
{
|
||||||
if (!g_pd3dDevice)
|
ImGui_ImplDX12_Data* bd = ImGui_ImplDX12_GetBackendData();
|
||||||
|
if (!bd || !bd->pd3dDevice)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
SafeRelease(g_pRootSignature);
|
|
||||||
SafeRelease(g_pPipelineState);
|
|
||||||
SafeRelease(g_pFontTextureResource);
|
|
||||||
|
|
||||||
ImGuiIO& io = ImGui::GetIO();
|
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++)
|
SafeRelease(bd->pRootSignature);
|
||||||
|
SafeRelease(bd->pPipelineState);
|
||||||
|
SafeRelease(bd->pFontTextureResource);
|
||||||
|
io.Fonts->SetTexID(NULL); // We copied bd->pFontTextureView to io.Fonts->TexID so let's clear that as well.
|
||||||
|
|
||||||
|
for (UINT i = 0; i < bd->numFramesInFlight; i++)
|
||||||
{
|
{
|
||||||
FrameResources* fr = &g_pFrameResources[i];
|
ImGui_ImplDX12_RenderBuffers* fr = &bd->pFrameResources[i];
|
||||||
SafeRelease(fr->IndexBuffer);
|
SafeRelease(fr->IndexBuffer);
|
||||||
SafeRelease(fr->VertexBuffer);
|
SafeRelease(fr->VertexBuffer);
|
||||||
}
|
}
|
||||||
|
@ -600,24 +638,28 @@ void ImGui_ImplDX12_InvalidateDeviceObjects()
|
||||||
bool ImGui_ImplDX12_Init(ID3D12Device* device, int num_frames_in_flight, DXGI_FORMAT rtv_format, ID3D12DescriptorHeap* cbv_srv_heap,
|
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)
|
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();
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
IM_ASSERT(io.BackendRendererUserData == NULL && "Already initialized a renderer backend!");
|
||||||
|
|
||||||
|
// Setup backend capabilities flags
|
||||||
|
ImGui_ImplDX12_Data* bd = IM_NEW(ImGui_ImplDX12_Data)();
|
||||||
|
io.BackendRendererUserData = (void*)bd;
|
||||||
io.BackendRendererName = "imgui_impl_dx12";
|
io.BackendRendererName = "imgui_impl_dx12";
|
||||||
io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes.
|
io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes.
|
||||||
|
|
||||||
g_pd3dDevice = device;
|
bd->pd3dDevice = device;
|
||||||
g_RTVFormat = rtv_format;
|
bd->RTVFormat = rtv_format;
|
||||||
g_hFontSrvCpuDescHandle = font_srv_cpu_desc_handle;
|
bd->hFontSrvCpuDescHandle = font_srv_cpu_desc_handle;
|
||||||
g_hFontSrvGpuDescHandle = font_srv_gpu_desc_handle;
|
bd->hFontSrvGpuDescHandle = font_srv_gpu_desc_handle;
|
||||||
g_pFrameResources = new FrameResources[num_frames_in_flight];
|
bd->pFrameResources = new ImGui_ImplDX12_RenderBuffers[num_frames_in_flight];
|
||||||
g_numFramesInFlight = num_frames_in_flight;
|
bd->numFramesInFlight = num_frames_in_flight;
|
||||||
g_frameIndex = UINT_MAX;
|
bd->frameIndex = UINT_MAX;
|
||||||
IM_UNUSED(cbv_srv_heap); // Unused in master branch (will be used by multi-viewports)
|
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)
|
// Create buffers with a default size (they will later be grown as needed)
|
||||||
for (int i = 0; i < num_frames_in_flight; i++)
|
for (int i = 0; i < num_frames_in_flight; i++)
|
||||||
{
|
{
|
||||||
FrameResources* fr = &g_pFrameResources[i];
|
ImGui_ImplDX12_RenderBuffers* fr = &bd->pFrameResources[i];
|
||||||
fr->IndexBuffer = NULL;
|
fr->IndexBuffer = NULL;
|
||||||
fr->VertexBuffer = NULL;
|
fr->VertexBuffer = NULL;
|
||||||
fr->IndexBufferSize = 10000;
|
fr->IndexBufferSize = 10000;
|
||||||
|
@ -629,19 +671,24 @@ bool ImGui_ImplDX12_Init(ID3D12Device* device, int num_frames_in_flight, DXGI_FO
|
||||||
|
|
||||||
void ImGui_ImplDX12_Shutdown()
|
void ImGui_ImplDX12_Shutdown()
|
||||||
{
|
{
|
||||||
|
ImGui_ImplDX12_Data* bd = ImGui_ImplDX12_GetBackendData();
|
||||||
|
IM_ASSERT(bd != NULL && "No renderer backend to shutdown, or already shutdown?");
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
|
||||||
ImGui_ImplDX12_InvalidateDeviceObjects();
|
ImGui_ImplDX12_InvalidateDeviceObjects();
|
||||||
delete[] g_pFrameResources;
|
delete[] bd->pFrameResources;
|
||||||
g_pFrameResources = NULL;
|
io.BackendRendererName = NULL;
|
||||||
g_pd3dDevice = NULL;
|
io.BackendRendererUserData = NULL;
|
||||||
g_hFontSrvCpuDescHandle.ptr = 0;
|
IM_DELETE(bd);
|
||||||
g_hFontSrvGpuDescHandle.ptr = 0;
|
|
||||||
g_numFramesInFlight = 0;
|
|
||||||
g_frameIndex = UINT_MAX;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ImGui_ImplDX12_NewFrame()
|
bool ImGui_ImplDX12_NewFrame()
|
||||||
{
|
{
|
||||||
if (!g_pPipelineState)
|
ImGui_ImplDX12_Data* bd = ImGui_ImplDX12_GetBackendData();
|
||||||
|
IM_ASSERT(bd != NULL && "Did you call ImGui_ImplDX12_Init()?");
|
||||||
|
|
||||||
|
if (!bd->pPipelineState)
|
||||||
return ImGui_ImplDX12_CreateDeviceObjects();
|
return ImGui_ImplDX12_CreateDeviceObjects();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
|
@ -6,8 +6,7 @@
|
||||||
// [X] Renderer: Support for large meshes (64k+ vertices) with 16-bit indices.
|
// [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'.
|
// 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*.
|
// See imgui_impl_dx12.cpp file for details.
|
||||||
// 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 use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
||||||
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
|
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
|
||||||
|
@ -16,13 +15,8 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include "imgui.h" // IMGUI_IMPL_API
|
#include "imgui.h" // IMGUI_IMPL_API
|
||||||
|
#include <dxgiformat.h> // DXGI_FORMAT
|
||||||
|
|
||||||
#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 ID3D12Device;
|
||||||
struct ID3D12DescriptorHeap;
|
struct ID3D12DescriptorHeap;
|
||||||
struct ID3D12GraphicsCommandList;
|
struct ID3D12GraphicsCommandList;
|
||||||
|
@ -42,8 +36,3 @@ IMGUI_IMPL_API void ImGui_ImplDX12_RenderDrawData(ImDrawData* draw_data, ID3
|
||||||
// Use if you want to reset your rendering device without losing Dear ImGui state.
|
// Use if you want to reset your rendering device without losing Dear ImGui state.
|
||||||
IMGUI_IMPL_API void ImGui_ImplDX12_InvalidateDeviceObjects();
|
IMGUI_IMPL_API void ImGui_ImplDX12_InvalidateDeviceObjects();
|
||||||
IMGUI_IMPL_API bool ImGui_ImplDX12_CreateDeviceObjects();
|
IMGUI_IMPL_API bool ImGui_ImplDX12_CreateDeviceObjects();
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
|
||||||
#pragma warning (pop)
|
|
||||||
#endif
|
|
||||||
|
|
|
@ -12,6 +12,8 @@
|
||||||
|
|
||||||
// CHANGELOG
|
// CHANGELOG
|
||||||
// (minor and older changes stripped away, please see git history for details)
|
// (minor and older changes stripped away, please see git history for details)
|
||||||
|
// 2021-06-29: Reorganized backend to pull data from a single structure to facilitate usage with multiple-contexts (all g_XXXX access changed to bd->XXXX).
|
||||||
|
// 2021-06-25: DirectX9: Explicitly disable texture state stages after >= 1.
|
||||||
// 2021-05-19: DirectX9: Replaced direct access to ImDrawCmd::TextureId with a call to ImDrawCmd::GetTexID(). (will become a requirement)
|
// 2021-05-19: DirectX9: Replaced direct access to ImDrawCmd::TextureId with a call to ImDrawCmd::GetTexID(). (will become a requirement)
|
||||||
// 2021-04-23: DirectX9: Explicitly setting up more graphics states to increase compatibility with unusual non-default states.
|
// 2021-04-23: DirectX9: Explicitly setting up more graphics states to increase compatibility with unusual non-default states.
|
||||||
// 2021-03-18: DirectX9: Calling IDirect3DStateBlock9::Capture() after CreateStateBlock() as a workaround for state restoring issues (see #3857).
|
// 2021-03-18: DirectX9: Calling IDirect3DStateBlock9::Capture() after CreateStateBlock() as a workaround for state restoring issues (see #3857).
|
||||||
|
@ -35,11 +37,17 @@
|
||||||
#include <d3d9.h>
|
#include <d3d9.h>
|
||||||
|
|
||||||
// DirectX data
|
// DirectX data
|
||||||
static LPDIRECT3DDEVICE9 g_pd3dDevice = NULL;
|
struct ImGui_ImplDX9_Data
|
||||||
static LPDIRECT3DVERTEXBUFFER9 g_pVB = NULL;
|
{
|
||||||
static LPDIRECT3DINDEXBUFFER9 g_pIB = NULL;
|
LPDIRECT3DDEVICE9 pd3dDevice;
|
||||||
static LPDIRECT3DTEXTURE9 g_FontTexture = NULL;
|
LPDIRECT3DVERTEXBUFFER9 pVB;
|
||||||
static int g_VertexBufferSize = 5000, g_IndexBufferSize = 10000;
|
LPDIRECT3DINDEXBUFFER9 pIB;
|
||||||
|
LPDIRECT3DTEXTURE9 FontTexture;
|
||||||
|
int VertexBufferSize;
|
||||||
|
int IndexBufferSize;
|
||||||
|
|
||||||
|
ImGui_ImplDX9_Data() { memset((void*)this, 0, sizeof(*this)); VertexBufferSize = 5000; IndexBufferSize = 10000; }
|
||||||
|
};
|
||||||
|
|
||||||
struct CUSTOMVERTEX
|
struct CUSTOMVERTEX
|
||||||
{
|
{
|
||||||
|
@ -55,8 +63,18 @@ struct CUSTOMVERTEX
|
||||||
#define IMGUI_COL_TO_DX9_ARGB(_COL) (((_COL) & 0xFF00FF00) | (((_COL) & 0xFF0000) >> 16) | (((_COL) & 0xFF) << 16))
|
#define IMGUI_COL_TO_DX9_ARGB(_COL) (((_COL) & 0xFF00FF00) | (((_COL) & 0xFF0000) >> 16) | (((_COL) & 0xFF) << 16))
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// Backend data stored in io.BackendRendererUserData to allow support for multiple Dear ImGui contexts
|
||||||
|
// It is STRONGLY preferred that you use docking branch with multi-viewports (== single Dear ImGui context + multiple windows) instead of multiple Dear ImGui contexts.
|
||||||
|
static ImGui_ImplDX9_Data* ImGui_ImplDX9_GetBackendData()
|
||||||
|
{
|
||||||
|
return ImGui::GetCurrentContext() ? (ImGui_ImplDX9_Data*)ImGui::GetIO().BackendRendererUserData : NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Functions
|
||||||
static void ImGui_ImplDX9_SetupRenderState(ImDrawData* draw_data)
|
static void ImGui_ImplDX9_SetupRenderState(ImDrawData* draw_data)
|
||||||
{
|
{
|
||||||
|
ImGui_ImplDX9_Data* bd = ImGui_ImplDX9_GetBackendData();
|
||||||
|
|
||||||
// Setup viewport
|
// Setup viewport
|
||||||
D3DVIEWPORT9 vp;
|
D3DVIEWPORT9 vp;
|
||||||
vp.X = vp.Y = 0;
|
vp.X = vp.Y = 0;
|
||||||
|
@ -64,39 +82,41 @@ static void ImGui_ImplDX9_SetupRenderState(ImDrawData* draw_data)
|
||||||
vp.Height = (DWORD)draw_data->DisplaySize.y;
|
vp.Height = (DWORD)draw_data->DisplaySize.y;
|
||||||
vp.MinZ = 0.0f;
|
vp.MinZ = 0.0f;
|
||||||
vp.MaxZ = 1.0f;
|
vp.MaxZ = 1.0f;
|
||||||
g_pd3dDevice->SetViewport(&vp);
|
bd->pd3dDevice->SetViewport(&vp);
|
||||||
|
|
||||||
// Setup render state: fixed-pipeline, alpha-blending, no face culling, no depth testing, shade mode (for gradient)
|
// Setup render state: fixed-pipeline, alpha-blending, no face culling, no depth testing, shade mode (for gradient), bilinear sampling.
|
||||||
g_pd3dDevice->SetPixelShader(NULL);
|
bd->pd3dDevice->SetPixelShader(NULL);
|
||||||
g_pd3dDevice->SetVertexShader(NULL);
|
bd->pd3dDevice->SetVertexShader(NULL);
|
||||||
g_pd3dDevice->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID);
|
bd->pd3dDevice->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID);
|
||||||
g_pd3dDevice->SetRenderState(D3DRS_SHADEMODE, D3DSHADE_GOURAUD);
|
bd->pd3dDevice->SetRenderState(D3DRS_SHADEMODE, D3DSHADE_GOURAUD);
|
||||||
g_pd3dDevice->SetRenderState(D3DRS_ZWRITEENABLE, FALSE);
|
bd->pd3dDevice->SetRenderState(D3DRS_ZWRITEENABLE, FALSE);
|
||||||
g_pd3dDevice->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE);
|
bd->pd3dDevice->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE);
|
||||||
g_pd3dDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
|
bd->pd3dDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
|
||||||
g_pd3dDevice->SetRenderState(D3DRS_ZENABLE, FALSE);
|
bd->pd3dDevice->SetRenderState(D3DRS_ZENABLE, FALSE);
|
||||||
g_pd3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
|
bd->pd3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
|
||||||
g_pd3dDevice->SetRenderState(D3DRS_BLENDOP, D3DBLENDOP_ADD);
|
bd->pd3dDevice->SetRenderState(D3DRS_BLENDOP, D3DBLENDOP_ADD);
|
||||||
g_pd3dDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
|
bd->pd3dDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
|
||||||
g_pd3dDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
|
bd->pd3dDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
|
||||||
g_pd3dDevice->SetRenderState(D3DRS_SEPARATEALPHABLENDENABLE, TRUE);
|
bd->pd3dDevice->SetRenderState(D3DRS_SEPARATEALPHABLENDENABLE, TRUE);
|
||||||
g_pd3dDevice->SetRenderState(D3DRS_SRCBLENDALPHA, D3DBLEND_ONE);
|
bd->pd3dDevice->SetRenderState(D3DRS_SRCBLENDALPHA, D3DBLEND_ONE);
|
||||||
g_pd3dDevice->SetRenderState(D3DRS_DESTBLENDALPHA, D3DBLEND_INVSRCALPHA);
|
bd->pd3dDevice->SetRenderState(D3DRS_DESTBLENDALPHA, D3DBLEND_INVSRCALPHA);
|
||||||
g_pd3dDevice->SetRenderState(D3DRS_SCISSORTESTENABLE, TRUE);
|
bd->pd3dDevice->SetRenderState(D3DRS_SCISSORTESTENABLE, TRUE);
|
||||||
g_pd3dDevice->SetRenderState(D3DRS_FOGENABLE, FALSE);
|
bd->pd3dDevice->SetRenderState(D3DRS_FOGENABLE, FALSE);
|
||||||
g_pd3dDevice->SetRenderState(D3DRS_RANGEFOGENABLE, FALSE);
|
bd->pd3dDevice->SetRenderState(D3DRS_RANGEFOGENABLE, FALSE);
|
||||||
g_pd3dDevice->SetRenderState(D3DRS_SPECULARENABLE, FALSE);
|
bd->pd3dDevice->SetRenderState(D3DRS_SPECULARENABLE, FALSE);
|
||||||
g_pd3dDevice->SetRenderState(D3DRS_STENCILENABLE, FALSE);
|
bd->pd3dDevice->SetRenderState(D3DRS_STENCILENABLE, FALSE);
|
||||||
g_pd3dDevice->SetRenderState(D3DRS_CLIPPING, TRUE);
|
bd->pd3dDevice->SetRenderState(D3DRS_CLIPPING, TRUE);
|
||||||
g_pd3dDevice->SetRenderState(D3DRS_LIGHTING, FALSE);
|
bd->pd3dDevice->SetRenderState(D3DRS_LIGHTING, FALSE);
|
||||||
g_pd3dDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE);
|
bd->pd3dDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE);
|
||||||
g_pd3dDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
|
bd->pd3dDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
|
||||||
g_pd3dDevice->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE);
|
bd->pd3dDevice->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE);
|
||||||
g_pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_MODULATE);
|
bd->pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_MODULATE);
|
||||||
g_pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
|
bd->pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
|
||||||
g_pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE);
|
bd->pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE);
|
||||||
g_pd3dDevice->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
|
bd->pd3dDevice->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_DISABLE);
|
||||||
g_pd3dDevice->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
|
bd->pd3dDevice->SetTextureStageState(1, D3DTSS_ALPHAOP, D3DTOP_DISABLE);
|
||||||
|
bd->pd3dDevice->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
|
||||||
|
bd->pd3dDevice->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
|
||||||
|
|
||||||
// Setup orthographic projection matrix
|
// 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.
|
// 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.
|
||||||
|
@ -114,9 +134,9 @@ static void ImGui_ImplDX9_SetupRenderState(ImDrawData* draw_data)
|
||||||
0.0f, 0.0f, 0.5f, 0.0f,
|
0.0f, 0.0f, 0.5f, 0.0f,
|
||||||
(L+R)/(L-R), (T+B)/(B-T), 0.5f, 1.0f
|
(L+R)/(L-R), (T+B)/(B-T), 0.5f, 1.0f
|
||||||
} } };
|
} } };
|
||||||
g_pd3dDevice->SetTransform(D3DTS_WORLD, &mat_identity);
|
bd->pd3dDevice->SetTransform(D3DTS_WORLD, &mat_identity);
|
||||||
g_pd3dDevice->SetTransform(D3DTS_VIEW, &mat_identity);
|
bd->pd3dDevice->SetTransform(D3DTS_VIEW, &mat_identity);
|
||||||
g_pd3dDevice->SetTransform(D3DTS_PROJECTION, &mat_projection);
|
bd->pd3dDevice->SetTransform(D3DTS_PROJECTION, &mat_projection);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -128,24 +148,25 @@ void ImGui_ImplDX9_RenderDrawData(ImDrawData* draw_data)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Create and grow buffers if needed
|
// Create and grow buffers if needed
|
||||||
if (!g_pVB || g_VertexBufferSize < draw_data->TotalVtxCount)
|
ImGui_ImplDX9_Data* bd = ImGui_ImplDX9_GetBackendData();
|
||||||
|
if (!bd->pVB || bd->VertexBufferSize < draw_data->TotalVtxCount)
|
||||||
{
|
{
|
||||||
if (g_pVB) { g_pVB->Release(); g_pVB = NULL; }
|
if (bd->pVB) { bd->pVB->Release(); bd->pVB = NULL; }
|
||||||
g_VertexBufferSize = draw_data->TotalVtxCount + 5000;
|
bd->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)
|
if (bd->pd3dDevice->CreateVertexBuffer(bd->VertexBufferSize * sizeof(CUSTOMVERTEX), D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY, D3DFVF_CUSTOMVERTEX, D3DPOOL_DEFAULT, &bd->pVB, NULL) < 0)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!g_pIB || g_IndexBufferSize < draw_data->TotalIdxCount)
|
if (!bd->pIB || bd->IndexBufferSize < draw_data->TotalIdxCount)
|
||||||
{
|
{
|
||||||
if (g_pIB) { g_pIB->Release(); g_pIB = NULL; }
|
if (bd->pIB) { bd->pIB->Release(); bd->pIB = NULL; }
|
||||||
g_IndexBufferSize = draw_data->TotalIdxCount + 10000;
|
bd->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)
|
if (bd->pd3dDevice->CreateIndexBuffer(bd->IndexBufferSize * sizeof(ImDrawIdx), D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY, sizeof(ImDrawIdx) == 2 ? D3DFMT_INDEX16 : D3DFMT_INDEX32, D3DPOOL_DEFAULT, &bd->pIB, NULL) < 0)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Backup the DX9 state
|
// Backup the DX9 state
|
||||||
IDirect3DStateBlock9* d3d9_state_block = NULL;
|
IDirect3DStateBlock9* d3d9_state_block = NULL;
|
||||||
if (g_pd3dDevice->CreateStateBlock(D3DSBT_ALL, &d3d9_state_block) < 0)
|
if (bd->pd3dDevice->CreateStateBlock(D3DSBT_ALL, &d3d9_state_block) < 0)
|
||||||
return;
|
return;
|
||||||
if (d3d9_state_block->Capture() < 0)
|
if (d3d9_state_block->Capture() < 0)
|
||||||
{
|
{
|
||||||
|
@ -155,21 +176,21 @@ void ImGui_ImplDX9_RenderDrawData(ImDrawData* draw_data)
|
||||||
|
|
||||||
// Backup the DX9 transform (DX9 documentation suggests that it is included in the StateBlock but it doesn't appear to)
|
// 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;
|
D3DMATRIX last_world, last_view, last_projection;
|
||||||
g_pd3dDevice->GetTransform(D3DTS_WORLD, &last_world);
|
bd->pd3dDevice->GetTransform(D3DTS_WORLD, &last_world);
|
||||||
g_pd3dDevice->GetTransform(D3DTS_VIEW, &last_view);
|
bd->pd3dDevice->GetTransform(D3DTS_VIEW, &last_view);
|
||||||
g_pd3dDevice->GetTransform(D3DTS_PROJECTION, &last_projection);
|
bd->pd3dDevice->GetTransform(D3DTS_PROJECTION, &last_projection);
|
||||||
|
|
||||||
// Allocate buffers
|
// Allocate buffers
|
||||||
CUSTOMVERTEX* vtx_dst;
|
CUSTOMVERTEX* vtx_dst;
|
||||||
ImDrawIdx* idx_dst;
|
ImDrawIdx* idx_dst;
|
||||||
if (g_pVB->Lock(0, (UINT)(draw_data->TotalVtxCount * sizeof(CUSTOMVERTEX)), (void**)&vtx_dst, D3DLOCK_DISCARD) < 0)
|
if (bd->pVB->Lock(0, (UINT)(draw_data->TotalVtxCount * sizeof(CUSTOMVERTEX)), (void**)&vtx_dst, D3DLOCK_DISCARD) < 0)
|
||||||
{
|
{
|
||||||
d3d9_state_block->Release();
|
d3d9_state_block->Release();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (g_pIB->Lock(0, (UINT)(draw_data->TotalIdxCount * sizeof(ImDrawIdx)), (void**)&idx_dst, D3DLOCK_DISCARD) < 0)
|
if (bd->pIB->Lock(0, (UINT)(draw_data->TotalIdxCount * sizeof(ImDrawIdx)), (void**)&idx_dst, D3DLOCK_DISCARD) < 0)
|
||||||
{
|
{
|
||||||
g_pVB->Unlock();
|
bd->pVB->Unlock();
|
||||||
d3d9_state_block->Release();
|
d3d9_state_block->Release();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -196,11 +217,11 @@ void ImGui_ImplDX9_RenderDrawData(ImDrawData* draw_data)
|
||||||
memcpy(idx_dst, cmd_list->IdxBuffer.Data, cmd_list->IdxBuffer.Size * sizeof(ImDrawIdx));
|
memcpy(idx_dst, cmd_list->IdxBuffer.Data, cmd_list->IdxBuffer.Size * sizeof(ImDrawIdx));
|
||||||
idx_dst += cmd_list->IdxBuffer.Size;
|
idx_dst += cmd_list->IdxBuffer.Size;
|
||||||
}
|
}
|
||||||
g_pVB->Unlock();
|
bd->pVB->Unlock();
|
||||||
g_pIB->Unlock();
|
bd->pIB->Unlock();
|
||||||
g_pd3dDevice->SetStreamSource(0, g_pVB, 0, sizeof(CUSTOMVERTEX));
|
bd->pd3dDevice->SetStreamSource(0, bd->pVB, 0, sizeof(CUSTOMVERTEX));
|
||||||
g_pd3dDevice->SetIndices(g_pIB);
|
bd->pd3dDevice->SetIndices(bd->pIB);
|
||||||
g_pd3dDevice->SetFVF(D3DFVF_CUSTOMVERTEX);
|
bd->pd3dDevice->SetFVF(D3DFVF_CUSTOMVERTEX);
|
||||||
|
|
||||||
// Setup desired DX state
|
// Setup desired DX state
|
||||||
ImGui_ImplDX9_SetupRenderState(draw_data);
|
ImGui_ImplDX9_SetupRenderState(draw_data);
|
||||||
|
@ -227,11 +248,18 @@ void ImGui_ImplDX9_RenderDrawData(ImDrawData* draw_data)
|
||||||
}
|
}
|
||||||
else
|
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) };
|
// Project scissor/clipping rectangles into framebuffer space
|
||||||
|
ImVec2 clip_min(pcmd->ClipRect.x - clip_off.x, pcmd->ClipRect.y - clip_off.y);
|
||||||
|
ImVec2 clip_max(pcmd->ClipRect.z - clip_off.x, pcmd->ClipRect.w - clip_off.y);
|
||||||
|
if (clip_max.x <= clip_min.x || clip_max.y <= clip_min.y)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Apply Scissor/clipping rectangle, Bind texture, Draw
|
||||||
|
const RECT r = { (LONG)clip_min.x, (LONG)clip_min.y, (LONG)clip_max.x, (LONG)clip_max.y };
|
||||||
const LPDIRECT3DTEXTURE9 texture = (LPDIRECT3DTEXTURE9)pcmd->GetTexID();
|
const LPDIRECT3DTEXTURE9 texture = (LPDIRECT3DTEXTURE9)pcmd->GetTexID();
|
||||||
g_pd3dDevice->SetTexture(0, texture);
|
bd->pd3dDevice->SetTexture(0, texture);
|
||||||
g_pd3dDevice->SetScissorRect(&r);
|
bd->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);
|
bd->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_idx_offset += cmd_list->IdxBuffer.Size;
|
||||||
|
@ -239,9 +267,9 @@ void ImGui_ImplDX9_RenderDrawData(ImDrawData* draw_data)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Restore the DX9 transform
|
// Restore the DX9 transform
|
||||||
g_pd3dDevice->SetTransform(D3DTS_WORLD, &last_world);
|
bd->pd3dDevice->SetTransform(D3DTS_WORLD, &last_world);
|
||||||
g_pd3dDevice->SetTransform(D3DTS_VIEW, &last_view);
|
bd->pd3dDevice->SetTransform(D3DTS_VIEW, &last_view);
|
||||||
g_pd3dDevice->SetTransform(D3DTS_PROJECTION, &last_projection);
|
bd->pd3dDevice->SetTransform(D3DTS_PROJECTION, &last_projection);
|
||||||
|
|
||||||
// Restore the DX9 state
|
// Restore the DX9 state
|
||||||
d3d9_state_block->Apply();
|
d3d9_state_block->Apply();
|
||||||
|
@ -250,26 +278,39 @@ void ImGui_ImplDX9_RenderDrawData(ImDrawData* draw_data)
|
||||||
|
|
||||||
bool ImGui_ImplDX9_Init(IDirect3DDevice9* device)
|
bool ImGui_ImplDX9_Init(IDirect3DDevice9* device)
|
||||||
{
|
{
|
||||||
// Setup backend capabilities flags
|
|
||||||
ImGuiIO& io = ImGui::GetIO();
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
IM_ASSERT(io.BackendRendererUserData == NULL && "Already initialized a renderer backend!");
|
||||||
|
|
||||||
|
// Setup backend capabilities flags
|
||||||
|
ImGui_ImplDX9_Data* bd = IM_NEW(ImGui_ImplDX9_Data)();
|
||||||
|
io.BackendRendererUserData = (void*)bd;
|
||||||
io.BackendRendererName = "imgui_impl_dx9";
|
io.BackendRendererName = "imgui_impl_dx9";
|
||||||
io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes.
|
io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes.
|
||||||
|
|
||||||
g_pd3dDevice = device;
|
bd->pd3dDevice = device;
|
||||||
g_pd3dDevice->AddRef();
|
bd->pd3dDevice->AddRef();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ImGui_ImplDX9_Shutdown()
|
void ImGui_ImplDX9_Shutdown()
|
||||||
{
|
{
|
||||||
|
ImGui_ImplDX9_Data* bd = ImGui_ImplDX9_GetBackendData();
|
||||||
|
IM_ASSERT(bd != NULL && "No renderer backend to shutdown, or already shutdown?");
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
|
||||||
ImGui_ImplDX9_InvalidateDeviceObjects();
|
ImGui_ImplDX9_InvalidateDeviceObjects();
|
||||||
if (g_pd3dDevice) { g_pd3dDevice->Release(); g_pd3dDevice = NULL; }
|
if (bd->pd3dDevice) { bd->pd3dDevice->Release(); }
|
||||||
|
io.BackendRendererName = NULL;
|
||||||
|
io.BackendRendererUserData = NULL;
|
||||||
|
IM_DELETE(bd);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool ImGui_ImplDX9_CreateFontsTexture()
|
static bool ImGui_ImplDX9_CreateFontsTexture()
|
||||||
{
|
{
|
||||||
// Build texture atlas
|
// Build texture atlas
|
||||||
ImGuiIO& io = ImGui::GetIO();
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
ImGui_ImplDX9_Data* bd = ImGui_ImplDX9_GetBackendData();
|
||||||
unsigned char* pixels;
|
unsigned char* pixels;
|
||||||
int width, height, bytes_per_pixel;
|
int width, height, bytes_per_pixel;
|
||||||
io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height, &bytes_per_pixel);
|
io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height, &bytes_per_pixel);
|
||||||
|
@ -278,26 +319,26 @@ static bool ImGui_ImplDX9_CreateFontsTexture()
|
||||||
#ifndef IMGUI_USE_BGRA_PACKED_COLOR
|
#ifndef IMGUI_USE_BGRA_PACKED_COLOR
|
||||||
if (io.Fonts->TexPixelsUseColors)
|
if (io.Fonts->TexPixelsUseColors)
|
||||||
{
|
{
|
||||||
ImU32* dst_start = (ImU32*)ImGui::MemAlloc(width * height * bytes_per_pixel);
|
ImU32* dst_start = (ImU32*)ImGui::MemAlloc((size_t)width * height * bytes_per_pixel);
|
||||||
for (ImU32* src = (ImU32*)pixels, *dst = dst_start, *dst_end = dst_start + width * height; dst < dst_end; src++, dst++)
|
for (ImU32* src = (ImU32*)pixels, *dst = dst_start, *dst_end = dst_start + (size_t)width * height; dst < dst_end; src++, dst++)
|
||||||
*dst = IMGUI_COL_TO_DX9_ARGB(*src);
|
*dst = IMGUI_COL_TO_DX9_ARGB(*src);
|
||||||
pixels = (unsigned char*)dst_start;
|
pixels = (unsigned char*)dst_start;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Upload texture to graphics system
|
// Upload texture to graphics system
|
||||||
g_FontTexture = NULL;
|
bd->FontTexture = NULL;
|
||||||
if (g_pd3dDevice->CreateTexture(width, height, 1, D3DUSAGE_DYNAMIC, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &g_FontTexture, NULL) < 0)
|
if (bd->pd3dDevice->CreateTexture(width, height, 1, D3DUSAGE_DYNAMIC, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &bd->FontTexture, NULL) < 0)
|
||||||
return false;
|
return false;
|
||||||
D3DLOCKED_RECT tex_locked_rect;
|
D3DLOCKED_RECT tex_locked_rect;
|
||||||
if (g_FontTexture->LockRect(0, &tex_locked_rect, NULL, 0) != D3D_OK)
|
if (bd->FontTexture->LockRect(0, &tex_locked_rect, NULL, 0) != D3D_OK)
|
||||||
return false;
|
return false;
|
||||||
for (int y = 0; y < height; y++)
|
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));
|
memcpy((unsigned char*)tex_locked_rect.pBits + (size_t)tex_locked_rect.Pitch * y, pixels + (size_t)width * bytes_per_pixel * y, (size_t)width * bytes_per_pixel);
|
||||||
g_FontTexture->UnlockRect(0);
|
bd->FontTexture->UnlockRect(0);
|
||||||
|
|
||||||
// Store our identifier
|
// Store our identifier
|
||||||
io.Fonts->SetTexID((ImTextureID)g_FontTexture);
|
io.Fonts->SetTexID((ImTextureID)bd->FontTexture);
|
||||||
|
|
||||||
#ifndef IMGUI_USE_BGRA_PACKED_COLOR
|
#ifndef IMGUI_USE_BGRA_PACKED_COLOR
|
||||||
if (io.Fonts->TexPixelsUseColors)
|
if (io.Fonts->TexPixelsUseColors)
|
||||||
|
@ -309,7 +350,8 @@ static bool ImGui_ImplDX9_CreateFontsTexture()
|
||||||
|
|
||||||
bool ImGui_ImplDX9_CreateDeviceObjects()
|
bool ImGui_ImplDX9_CreateDeviceObjects()
|
||||||
{
|
{
|
||||||
if (!g_pd3dDevice)
|
ImGui_ImplDX9_Data* bd = ImGui_ImplDX9_GetBackendData();
|
||||||
|
if (!bd || !bd->pd3dDevice)
|
||||||
return false;
|
return false;
|
||||||
if (!ImGui_ImplDX9_CreateFontsTexture())
|
if (!ImGui_ImplDX9_CreateFontsTexture())
|
||||||
return false;
|
return false;
|
||||||
|
@ -318,16 +360,21 @@ bool ImGui_ImplDX9_CreateDeviceObjects()
|
||||||
|
|
||||||
void ImGui_ImplDX9_InvalidateDeviceObjects()
|
void ImGui_ImplDX9_InvalidateDeviceObjects()
|
||||||
{
|
{
|
||||||
if (!g_pd3dDevice)
|
ImGui_ImplDX9_Data* bd = ImGui_ImplDX9_GetBackendData();
|
||||||
|
if (!bd || !bd->pd3dDevice)
|
||||||
return;
|
return;
|
||||||
if (g_pVB) { g_pVB->Release(); g_pVB = NULL; }
|
if (bd->pVB) { bd->pVB->Release(); bd->pVB = NULL; }
|
||||||
if (g_pIB) { g_pIB->Release(); g_pIB = NULL; }
|
if (bd->pIB) { bd->pIB->Release(); bd->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.
|
if (bd->FontTexture) { bd->FontTexture->Release(); bd->FontTexture = NULL; ImGui::GetIO().Fonts->SetTexID(NULL); } // We copied bd->pFontTextureView to io.Fonts->TexID so let's clear that as well.
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ImGui_ImplDX9_NewFrame()
|
bool ImGui_ImplDX9_NewFrame()
|
||||||
{
|
{
|
||||||
if (!g_FontTexture)
|
ImGui_ImplDX9_Data* bd = ImGui_ImplDX9_GetBackendData();
|
||||||
|
IM_ASSERT(bd != NULL && "Did you call ImGui_ImplDX9_Init()?");
|
||||||
|
|
||||||
|
if (!bd->FontTexture)
|
||||||
return ImGui_ImplDX9_CreateDeviceObjects();
|
return ImGui_ImplDX9_CreateDeviceObjects();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
|
@ -0,0 +1,662 @@
|
||||||
|
// 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: Keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy GLFW_KEY_* values will also be supported unless IMGUI_DISABLE_OBSOLETE_KEYIO is set]
|
||||||
|
// [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+).
|
||||||
|
|
||||||
|
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
||||||
|
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
|
||||||
|
// 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)
|
||||||
|
// 2022-04-30: Inputs: Fixed ImGui_ImplGlfw_TranslateUntranslatedKey() for lower case letters on OSX.
|
||||||
|
// 2022-03-23: Inputs: Fixed a regression in 1.87 which resulted in keyboard modifiers events being reported incorrectly on Linux/X11.
|
||||||
|
// 2022-02-07: Added ImGui_ImplGlfw_InstallCallbacks()/ImGui_ImplGlfw_RestoreCallbacks() helpers to facilitate user installing callbacks after initializing backend.
|
||||||
|
// 2022-01-26: Inputs: replaced short-lived io.AddKeyModsEvent() (added two weeks ago)with io.AddKeyEvent() using ImGuiKey_ModXXX flags. Sorry for the confusion.
|
||||||
|
// 2021-01-20: Inputs: calling new io.AddKeyAnalogEvent() for gamepad support, instead of writing directly to io.NavInputs[].
|
||||||
|
// 2022-01-17: Inputs: calling new io.AddMousePosEvent(), io.AddMouseButtonEvent(), io.AddMouseWheelEvent() API (1.87+).
|
||||||
|
// 2022-01-17: Inputs: always update key mods next and before key event (not in NewFrame) to fix input queue with very low framerates.
|
||||||
|
// 2022-01-12: *BREAKING CHANGE*: Now using glfwSetCursorPosCallback(). If you called ImGui_ImplGlfw_InitXXX() with install_callbacks = false, you MUST install glfwSetCursorPosCallback() and forward it to the backend via ImGui_ImplGlfw_CursorPosCallback().
|
||||||
|
// 2022-01-10: Inputs: calling new io.AddKeyEvent(), io.AddKeyModsEvent() + io.SetKeyEventNativeData() API (1.87+). Support for full ImGuiKey range.
|
||||||
|
// 2022-01-05: Inputs: Converting GLFW untranslated keycodes back to translated keycodes (in the ImGui_ImplGlfw_KeyCallback() function) in order to match the behavior of every other backend, and facilitate the use of GLFW with lettered-shortcuts API.
|
||||||
|
// 2021-08-17: *BREAKING CHANGE*: Now using glfwSetWindowFocusCallback() to calling io.AddFocusEvent(). If you called ImGui_ImplGlfw_InitXXX() with install_callbacks = false, you MUST install glfwSetWindowFocusCallback() and forward it to the backend via ImGui_ImplGlfw_WindowFocusCallback().
|
||||||
|
// 2021-07-29: *BREAKING CHANGE*: Now using glfwSetCursorEnterCallback(). MousePos is correctly reported when the host platform window is hovered but not focused. If you called ImGui_ImplGlfw_InitXXX() with install_callbacks = false, you MUST install glfwSetWindowFocusCallback() callback and forward it to the backend via ImGui_ImplGlfw_CursorEnterCallback().
|
||||||
|
// 2021-06-29: Reorganized backend to pull data from a single structure to facilitate usage with multiple-contexts (all g_XXXX access changed to bd->XXXX).
|
||||||
|
// 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"
|
||||||
|
|
||||||
|
// Clang warnings with -Weverything
|
||||||
|
#if defined(__clang__)
|
||||||
|
#pragma clang diagnostic push
|
||||||
|
#pragma clang diagnostic ignored "-Wold-style-cast" // warning: use of old-style cast
|
||||||
|
#pragma clang diagnostic ignored "-Wsign-conversion" // warning: implicit conversion changes signedness
|
||||||
|
#if __has_warning("-Wzero-as-null-pointer-constant")
|
||||||
|
#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant"
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// GLFW
|
||||||
|
#include <GLFW/glfw3.h>
|
||||||
|
#ifdef _WIN32
|
||||||
|
#undef APIENTRY
|
||||||
|
#define GLFW_EXPOSE_NATIVE_WIN32
|
||||||
|
#include <GLFW/glfw3native.h> // for glfwGetWin32Window
|
||||||
|
#endif
|
||||||
|
#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
|
||||||
|
#define GLFW_HAS_GAMEPAD_API (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3300) // 3.3+ glfwGetGamepadState() new api
|
||||||
|
#define GLFW_HAS_GET_KEY_NAME (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3200) // 3.2+ glfwGetKeyName()
|
||||||
|
|
||||||
|
// GLFW data
|
||||||
|
enum GlfwClientApi
|
||||||
|
{
|
||||||
|
GlfwClientApi_Unknown,
|
||||||
|
GlfwClientApi_OpenGL,
|
||||||
|
GlfwClientApi_Vulkan
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ImGui_ImplGlfw_Data
|
||||||
|
{
|
||||||
|
GLFWwindow* Window;
|
||||||
|
GlfwClientApi ClientApi;
|
||||||
|
double Time;
|
||||||
|
GLFWwindow* MouseWindow;
|
||||||
|
GLFWcursor* MouseCursors[ImGuiMouseCursor_COUNT];
|
||||||
|
ImVec2 LastValidMousePos;
|
||||||
|
bool InstalledCallbacks;
|
||||||
|
|
||||||
|
// Chain GLFW callbacks: our callbacks will call the user's previously installed callbacks, if any.
|
||||||
|
GLFWwindowfocusfun PrevUserCallbackWindowFocus;
|
||||||
|
GLFWcursorposfun PrevUserCallbackCursorPos;
|
||||||
|
GLFWcursorenterfun PrevUserCallbackCursorEnter;
|
||||||
|
GLFWmousebuttonfun PrevUserCallbackMousebutton;
|
||||||
|
GLFWscrollfun PrevUserCallbackScroll;
|
||||||
|
GLFWkeyfun PrevUserCallbackKey;
|
||||||
|
GLFWcharfun PrevUserCallbackChar;
|
||||||
|
GLFWmonitorfun PrevUserCallbackMonitor;
|
||||||
|
|
||||||
|
ImGui_ImplGlfw_Data() { memset((void*)this, 0, sizeof(*this)); }
|
||||||
|
};
|
||||||
|
|
||||||
|
// Backend data stored in io.BackendPlatformUserData to allow support for multiple Dear ImGui contexts
|
||||||
|
// It is STRONGLY preferred that you use docking branch with multi-viewports (== single Dear ImGui context + multiple windows) instead of multiple Dear ImGui contexts.
|
||||||
|
// FIXME: multi-context support is not well tested and probably dysfunctional in this backend.
|
||||||
|
// - Because glfwPollEvents() process all windows and some events may be called outside of it, you will need to register your own callbacks
|
||||||
|
// (passing install_callbacks=false in ImGui_ImplGlfw_InitXXX functions), set the current dear imgui context and then call our callbacks.
|
||||||
|
// - Otherwise we may need to store a GLFWWindow* -> ImGuiContext* map and handle this in the backend, adding a little bit of extra complexity to it.
|
||||||
|
// FIXME: some shared resources (mouse cursor shape, gamepad) are mishandled when using multi-context.
|
||||||
|
static ImGui_ImplGlfw_Data* ImGui_ImplGlfw_GetBackendData()
|
||||||
|
{
|
||||||
|
return ImGui::GetCurrentContext() ? (ImGui_ImplGlfw_Data*)ImGui::GetIO().BackendPlatformUserData : NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Functions
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
static ImGuiKey ImGui_ImplGlfw_KeyToImGuiKey(int key)
|
||||||
|
{
|
||||||
|
switch (key)
|
||||||
|
{
|
||||||
|
case GLFW_KEY_TAB: return ImGuiKey_Tab;
|
||||||
|
case GLFW_KEY_LEFT: return ImGuiKey_LeftArrow;
|
||||||
|
case GLFW_KEY_RIGHT: return ImGuiKey_RightArrow;
|
||||||
|
case GLFW_KEY_UP: return ImGuiKey_UpArrow;
|
||||||
|
case GLFW_KEY_DOWN: return ImGuiKey_DownArrow;
|
||||||
|
case GLFW_KEY_PAGE_UP: return ImGuiKey_PageUp;
|
||||||
|
case GLFW_KEY_PAGE_DOWN: return ImGuiKey_PageDown;
|
||||||
|
case GLFW_KEY_HOME: return ImGuiKey_Home;
|
||||||
|
case GLFW_KEY_END: return ImGuiKey_End;
|
||||||
|
case GLFW_KEY_INSERT: return ImGuiKey_Insert;
|
||||||
|
case GLFW_KEY_DELETE: return ImGuiKey_Delete;
|
||||||
|
case GLFW_KEY_BACKSPACE: return ImGuiKey_Backspace;
|
||||||
|
case GLFW_KEY_SPACE: return ImGuiKey_Space;
|
||||||
|
case GLFW_KEY_ENTER: return ImGuiKey_Enter;
|
||||||
|
case GLFW_KEY_ESCAPE: return ImGuiKey_Escape;
|
||||||
|
case GLFW_KEY_APOSTROPHE: return ImGuiKey_Apostrophe;
|
||||||
|
case GLFW_KEY_COMMA: return ImGuiKey_Comma;
|
||||||
|
case GLFW_KEY_MINUS: return ImGuiKey_Minus;
|
||||||
|
case GLFW_KEY_PERIOD: return ImGuiKey_Period;
|
||||||
|
case GLFW_KEY_SLASH: return ImGuiKey_Slash;
|
||||||
|
case GLFW_KEY_SEMICOLON: return ImGuiKey_Semicolon;
|
||||||
|
case GLFW_KEY_EQUAL: return ImGuiKey_Equal;
|
||||||
|
case GLFW_KEY_LEFT_BRACKET: return ImGuiKey_LeftBracket;
|
||||||
|
case GLFW_KEY_BACKSLASH: return ImGuiKey_Backslash;
|
||||||
|
case GLFW_KEY_RIGHT_BRACKET: return ImGuiKey_RightBracket;
|
||||||
|
case GLFW_KEY_GRAVE_ACCENT: return ImGuiKey_GraveAccent;
|
||||||
|
case GLFW_KEY_CAPS_LOCK: return ImGuiKey_CapsLock;
|
||||||
|
case GLFW_KEY_SCROLL_LOCK: return ImGuiKey_ScrollLock;
|
||||||
|
case GLFW_KEY_NUM_LOCK: return ImGuiKey_NumLock;
|
||||||
|
case GLFW_KEY_PRINT_SCREEN: return ImGuiKey_PrintScreen;
|
||||||
|
case GLFW_KEY_PAUSE: return ImGuiKey_Pause;
|
||||||
|
case GLFW_KEY_KP_0: return ImGuiKey_Keypad0;
|
||||||
|
case GLFW_KEY_KP_1: return ImGuiKey_Keypad1;
|
||||||
|
case GLFW_KEY_KP_2: return ImGuiKey_Keypad2;
|
||||||
|
case GLFW_KEY_KP_3: return ImGuiKey_Keypad3;
|
||||||
|
case GLFW_KEY_KP_4: return ImGuiKey_Keypad4;
|
||||||
|
case GLFW_KEY_KP_5: return ImGuiKey_Keypad5;
|
||||||
|
case GLFW_KEY_KP_6: return ImGuiKey_Keypad6;
|
||||||
|
case GLFW_KEY_KP_7: return ImGuiKey_Keypad7;
|
||||||
|
case GLFW_KEY_KP_8: return ImGuiKey_Keypad8;
|
||||||
|
case GLFW_KEY_KP_9: return ImGuiKey_Keypad9;
|
||||||
|
case GLFW_KEY_KP_DECIMAL: return ImGuiKey_KeypadDecimal;
|
||||||
|
case GLFW_KEY_KP_DIVIDE: return ImGuiKey_KeypadDivide;
|
||||||
|
case GLFW_KEY_KP_MULTIPLY: return ImGuiKey_KeypadMultiply;
|
||||||
|
case GLFW_KEY_KP_SUBTRACT: return ImGuiKey_KeypadSubtract;
|
||||||
|
case GLFW_KEY_KP_ADD: return ImGuiKey_KeypadAdd;
|
||||||
|
case GLFW_KEY_KP_ENTER: return ImGuiKey_KeypadEnter;
|
||||||
|
case GLFW_KEY_KP_EQUAL: return ImGuiKey_KeypadEqual;
|
||||||
|
case GLFW_KEY_LEFT_SHIFT: return ImGuiKey_LeftShift;
|
||||||
|
case GLFW_KEY_LEFT_CONTROL: return ImGuiKey_LeftCtrl;
|
||||||
|
case GLFW_KEY_LEFT_ALT: return ImGuiKey_LeftAlt;
|
||||||
|
case GLFW_KEY_LEFT_SUPER: return ImGuiKey_LeftSuper;
|
||||||
|
case GLFW_KEY_RIGHT_SHIFT: return ImGuiKey_RightShift;
|
||||||
|
case GLFW_KEY_RIGHT_CONTROL: return ImGuiKey_RightCtrl;
|
||||||
|
case GLFW_KEY_RIGHT_ALT: return ImGuiKey_RightAlt;
|
||||||
|
case GLFW_KEY_RIGHT_SUPER: return ImGuiKey_RightSuper;
|
||||||
|
case GLFW_KEY_MENU: return ImGuiKey_Menu;
|
||||||
|
case GLFW_KEY_0: return ImGuiKey_0;
|
||||||
|
case GLFW_KEY_1: return ImGuiKey_1;
|
||||||
|
case GLFW_KEY_2: return ImGuiKey_2;
|
||||||
|
case GLFW_KEY_3: return ImGuiKey_3;
|
||||||
|
case GLFW_KEY_4: return ImGuiKey_4;
|
||||||
|
case GLFW_KEY_5: return ImGuiKey_5;
|
||||||
|
case GLFW_KEY_6: return ImGuiKey_6;
|
||||||
|
case GLFW_KEY_7: return ImGuiKey_7;
|
||||||
|
case GLFW_KEY_8: return ImGuiKey_8;
|
||||||
|
case GLFW_KEY_9: return ImGuiKey_9;
|
||||||
|
case GLFW_KEY_A: return ImGuiKey_A;
|
||||||
|
case GLFW_KEY_B: return ImGuiKey_B;
|
||||||
|
case GLFW_KEY_C: return ImGuiKey_C;
|
||||||
|
case GLFW_KEY_D: return ImGuiKey_D;
|
||||||
|
case GLFW_KEY_E: return ImGuiKey_E;
|
||||||
|
case GLFW_KEY_F: return ImGuiKey_F;
|
||||||
|
case GLFW_KEY_G: return ImGuiKey_G;
|
||||||
|
case GLFW_KEY_H: return ImGuiKey_H;
|
||||||
|
case GLFW_KEY_I: return ImGuiKey_I;
|
||||||
|
case GLFW_KEY_J: return ImGuiKey_J;
|
||||||
|
case GLFW_KEY_K: return ImGuiKey_K;
|
||||||
|
case GLFW_KEY_L: return ImGuiKey_L;
|
||||||
|
case GLFW_KEY_M: return ImGuiKey_M;
|
||||||
|
case GLFW_KEY_N: return ImGuiKey_N;
|
||||||
|
case GLFW_KEY_O: return ImGuiKey_O;
|
||||||
|
case GLFW_KEY_P: return ImGuiKey_P;
|
||||||
|
case GLFW_KEY_Q: return ImGuiKey_Q;
|
||||||
|
case GLFW_KEY_R: return ImGuiKey_R;
|
||||||
|
case GLFW_KEY_S: return ImGuiKey_S;
|
||||||
|
case GLFW_KEY_T: return ImGuiKey_T;
|
||||||
|
case GLFW_KEY_U: return ImGuiKey_U;
|
||||||
|
case GLFW_KEY_V: return ImGuiKey_V;
|
||||||
|
case GLFW_KEY_W: return ImGuiKey_W;
|
||||||
|
case GLFW_KEY_X: return ImGuiKey_X;
|
||||||
|
case GLFW_KEY_Y: return ImGuiKey_Y;
|
||||||
|
case GLFW_KEY_Z: return ImGuiKey_Z;
|
||||||
|
case GLFW_KEY_F1: return ImGuiKey_F1;
|
||||||
|
case GLFW_KEY_F2: return ImGuiKey_F2;
|
||||||
|
case GLFW_KEY_F3: return ImGuiKey_F3;
|
||||||
|
case GLFW_KEY_F4: return ImGuiKey_F4;
|
||||||
|
case GLFW_KEY_F5: return ImGuiKey_F5;
|
||||||
|
case GLFW_KEY_F6: return ImGuiKey_F6;
|
||||||
|
case GLFW_KEY_F7: return ImGuiKey_F7;
|
||||||
|
case GLFW_KEY_F8: return ImGuiKey_F8;
|
||||||
|
case GLFW_KEY_F9: return ImGuiKey_F9;
|
||||||
|
case GLFW_KEY_F10: return ImGuiKey_F10;
|
||||||
|
case GLFW_KEY_F11: return ImGuiKey_F11;
|
||||||
|
case GLFW_KEY_F12: return ImGuiKey_F12;
|
||||||
|
default: return ImGuiKey_None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ImGui_ImplGlfw_KeyToModifier(int key)
|
||||||
|
{
|
||||||
|
if (key == GLFW_KEY_LEFT_CONTROL || key == GLFW_KEY_RIGHT_CONTROL)
|
||||||
|
return GLFW_MOD_CONTROL;
|
||||||
|
if (key == GLFW_KEY_LEFT_SHIFT || key == GLFW_KEY_RIGHT_SHIFT)
|
||||||
|
return GLFW_MOD_SHIFT;
|
||||||
|
if (key == GLFW_KEY_LEFT_ALT || key == GLFW_KEY_RIGHT_ALT)
|
||||||
|
return GLFW_MOD_ALT;
|
||||||
|
if (key == GLFW_KEY_LEFT_SUPER || key == GLFW_KEY_RIGHT_SUPER)
|
||||||
|
return GLFW_MOD_SUPER;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ImGui_ImplGlfw_UpdateKeyModifiers(int mods)
|
||||||
|
{
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
io.AddKeyEvent(ImGuiKey_ModCtrl, (mods & GLFW_MOD_CONTROL) != 0);
|
||||||
|
io.AddKeyEvent(ImGuiKey_ModShift, (mods & GLFW_MOD_SHIFT) != 0);
|
||||||
|
io.AddKeyEvent(ImGuiKey_ModAlt, (mods & GLFW_MOD_ALT) != 0);
|
||||||
|
io.AddKeyEvent(ImGuiKey_ModSuper, (mods & GLFW_MOD_SUPER) != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGui_ImplGlfw_MouseButtonCallback(GLFWwindow* window, int button, int action, int mods)
|
||||||
|
{
|
||||||
|
ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
|
||||||
|
if (bd->PrevUserCallbackMousebutton != NULL && window == bd->Window)
|
||||||
|
bd->PrevUserCallbackMousebutton(window, button, action, mods);
|
||||||
|
|
||||||
|
ImGui_ImplGlfw_UpdateKeyModifiers(mods);
|
||||||
|
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
if (button >= 0 && button < ImGuiMouseButton_COUNT)
|
||||||
|
io.AddMouseButtonEvent(button, action == GLFW_PRESS);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGui_ImplGlfw_ScrollCallback(GLFWwindow* window, double xoffset, double yoffset)
|
||||||
|
{
|
||||||
|
ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
|
||||||
|
if (bd->PrevUserCallbackScroll != NULL && window == bd->Window)
|
||||||
|
bd->PrevUserCallbackScroll(window, xoffset, yoffset);
|
||||||
|
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
io.AddMouseWheelEvent((float)xoffset, (float)yoffset);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ImGui_ImplGlfw_TranslateUntranslatedKey(int key, int scancode)
|
||||||
|
{
|
||||||
|
#if GLFW_HAS_GET_KEY_NAME && !defined(__EMSCRIPTEN__)
|
||||||
|
// GLFW 3.1+ attempts to "untranslate" keys, which goes the opposite of what every other framework does, making using lettered shortcuts difficult.
|
||||||
|
// (It had reasons to do so: namely GLFW is/was more likely to be used for WASD-type game controls rather than lettered shortcuts, but IHMO the 3.1 change could have been done differently)
|
||||||
|
// See https://github.com/glfw/glfw/issues/1502 for details.
|
||||||
|
// Adding a workaround to undo this (so our keys are translated->untranslated->translated, likely a lossy process).
|
||||||
|
// This won't cover edge cases but this is at least going to cover common cases.
|
||||||
|
if (key >= GLFW_KEY_KP_0 && key <= GLFW_KEY_KP_EQUAL)
|
||||||
|
return key;
|
||||||
|
const char* key_name = glfwGetKeyName(key, scancode);
|
||||||
|
if (key_name && key_name[0] != 0 && key_name[1] == 0)
|
||||||
|
{
|
||||||
|
const char char_names[] = "`-=[]\\,;\'./";
|
||||||
|
const int char_keys[] = { GLFW_KEY_GRAVE_ACCENT, GLFW_KEY_MINUS, GLFW_KEY_EQUAL, GLFW_KEY_LEFT_BRACKET, GLFW_KEY_RIGHT_BRACKET, GLFW_KEY_BACKSLASH, GLFW_KEY_COMMA, GLFW_KEY_SEMICOLON, GLFW_KEY_APOSTROPHE, GLFW_KEY_PERIOD, GLFW_KEY_SLASH, 0 };
|
||||||
|
IM_ASSERT(IM_ARRAYSIZE(char_names) == IM_ARRAYSIZE(char_keys));
|
||||||
|
if (key_name[0] >= '0' && key_name[0] <= '9') { key = GLFW_KEY_0 + (key_name[0] - '0'); }
|
||||||
|
else if (key_name[0] >= 'A' && key_name[0] <= 'Z') { key = GLFW_KEY_A + (key_name[0] - 'A'); }
|
||||||
|
else if (key_name[0] >= 'a' && key_name[0] <= 'z') { key = GLFW_KEY_A + (key_name[0] - 'a'); }
|
||||||
|
else if (const char* p = strchr(char_names, key_name[0])) { key = char_keys[p - char_names]; }
|
||||||
|
}
|
||||||
|
// if (action == GLFW_PRESS) printf("key %d scancode %d name '%s'\n", key, scancode, key_name);
|
||||||
|
#else
|
||||||
|
IM_UNUSED(scancode);
|
||||||
|
#endif
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGui_ImplGlfw_KeyCallback(GLFWwindow* window, int keycode, int scancode, int action, int mods)
|
||||||
|
{
|
||||||
|
ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
|
||||||
|
if (bd->PrevUserCallbackKey != NULL && window == bd->Window)
|
||||||
|
bd->PrevUserCallbackKey(window, keycode, scancode, action, mods);
|
||||||
|
|
||||||
|
if (action != GLFW_PRESS && action != GLFW_RELEASE)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Workaround: X11 does not include current pressed/released modifier key in 'mods' flags. https://github.com/glfw/glfw/issues/1630
|
||||||
|
if (int keycode_to_mod = ImGui_ImplGlfw_KeyToModifier(keycode))
|
||||||
|
mods = (action == GLFW_PRESS) ? (mods | keycode_to_mod) : (mods & ~keycode_to_mod);
|
||||||
|
ImGui_ImplGlfw_UpdateKeyModifiers(mods);
|
||||||
|
|
||||||
|
keycode = ImGui_ImplGlfw_TranslateUntranslatedKey(keycode, scancode);
|
||||||
|
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
ImGuiKey imgui_key = ImGui_ImplGlfw_KeyToImGuiKey(keycode);
|
||||||
|
io.AddKeyEvent(imgui_key, (action == GLFW_PRESS));
|
||||||
|
io.SetKeyEventNativeData(imgui_key, keycode, scancode); // To support legacy indexing (<1.87 user code)
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGui_ImplGlfw_WindowFocusCallback(GLFWwindow* window, int focused)
|
||||||
|
{
|
||||||
|
ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
|
||||||
|
if (bd->PrevUserCallbackWindowFocus != NULL && window == bd->Window)
|
||||||
|
bd->PrevUserCallbackWindowFocus(window, focused);
|
||||||
|
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
io.AddFocusEvent(focused != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGui_ImplGlfw_CursorPosCallback(GLFWwindow* window, double x, double y)
|
||||||
|
{
|
||||||
|
ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
|
||||||
|
if (bd->PrevUserCallbackCursorPos != NULL && window == bd->Window)
|
||||||
|
bd->PrevUserCallbackCursorPos(window, x, y);
|
||||||
|
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
io.AddMousePosEvent((float)x, (float)y);
|
||||||
|
bd->LastValidMousePos = ImVec2((float)x, (float)y);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Workaround: X11 seems to send spurious Leave/Enter events which would make us lose our position,
|
||||||
|
// so we back it up and restore on Leave/Enter (see https://github.com/ocornut/imgui/issues/4984)
|
||||||
|
void ImGui_ImplGlfw_CursorEnterCallback(GLFWwindow* window, int entered)
|
||||||
|
{
|
||||||
|
ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
|
||||||
|
if (bd->PrevUserCallbackCursorEnter != NULL && window == bd->Window)
|
||||||
|
bd->PrevUserCallbackCursorEnter(window, entered);
|
||||||
|
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
if (entered)
|
||||||
|
{
|
||||||
|
bd->MouseWindow = window;
|
||||||
|
io.AddMousePosEvent(bd->LastValidMousePos.x, bd->LastValidMousePos.y);
|
||||||
|
}
|
||||||
|
else if (!entered && bd->MouseWindow == window)
|
||||||
|
{
|
||||||
|
bd->LastValidMousePos = io.MousePos;
|
||||||
|
bd->MouseWindow = NULL;
|
||||||
|
io.AddMousePosEvent(-FLT_MAX, -FLT_MAX);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGui_ImplGlfw_CharCallback(GLFWwindow* window, unsigned int c)
|
||||||
|
{
|
||||||
|
ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
|
||||||
|
if (bd->PrevUserCallbackChar != NULL && window == bd->Window)
|
||||||
|
bd->PrevUserCallbackChar(window, c);
|
||||||
|
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
io.AddInputCharacter(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGui_ImplGlfw_MonitorCallback(GLFWmonitor*, int)
|
||||||
|
{
|
||||||
|
// Unused in 'master' branch but 'docking' branch will use this, so we declare it ahead of it so if you have to install callbacks you can install this one too.
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGui_ImplGlfw_InstallCallbacks(GLFWwindow* window)
|
||||||
|
{
|
||||||
|
ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
|
||||||
|
IM_ASSERT(bd->InstalledCallbacks == false && "Callbacks already installed!");
|
||||||
|
IM_ASSERT(bd->Window == window);
|
||||||
|
|
||||||
|
bd->PrevUserCallbackWindowFocus = glfwSetWindowFocusCallback(window, ImGui_ImplGlfw_WindowFocusCallback);
|
||||||
|
bd->PrevUserCallbackCursorEnter = glfwSetCursorEnterCallback(window, ImGui_ImplGlfw_CursorEnterCallback);
|
||||||
|
bd->PrevUserCallbackCursorPos = glfwSetCursorPosCallback(window, ImGui_ImplGlfw_CursorPosCallback);
|
||||||
|
bd->PrevUserCallbackMousebutton = glfwSetMouseButtonCallback(window, ImGui_ImplGlfw_MouseButtonCallback);
|
||||||
|
bd->PrevUserCallbackScroll = glfwSetScrollCallback(window, ImGui_ImplGlfw_ScrollCallback);
|
||||||
|
bd->PrevUserCallbackKey = glfwSetKeyCallback(window, ImGui_ImplGlfw_KeyCallback);
|
||||||
|
bd->PrevUserCallbackChar = glfwSetCharCallback(window, ImGui_ImplGlfw_CharCallback);
|
||||||
|
bd->PrevUserCallbackMonitor = glfwSetMonitorCallback(ImGui_ImplGlfw_MonitorCallback);
|
||||||
|
bd->InstalledCallbacks = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGui_ImplGlfw_RestoreCallbacks(GLFWwindow* window)
|
||||||
|
{
|
||||||
|
ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
|
||||||
|
IM_ASSERT(bd->InstalledCallbacks == true && "Callbacks not installed!");
|
||||||
|
IM_ASSERT(bd->Window == window);
|
||||||
|
|
||||||
|
glfwSetWindowFocusCallback(window, bd->PrevUserCallbackWindowFocus);
|
||||||
|
glfwSetCursorEnterCallback(window, bd->PrevUserCallbackCursorEnter);
|
||||||
|
glfwSetCursorPosCallback(window, bd->PrevUserCallbackCursorPos);
|
||||||
|
glfwSetMouseButtonCallback(window, bd->PrevUserCallbackMousebutton);
|
||||||
|
glfwSetScrollCallback(window, bd->PrevUserCallbackScroll);
|
||||||
|
glfwSetKeyCallback(window, bd->PrevUserCallbackKey);
|
||||||
|
glfwSetCharCallback(window, bd->PrevUserCallbackChar);
|
||||||
|
glfwSetMonitorCallback(bd->PrevUserCallbackMonitor);
|
||||||
|
bd->InstalledCallbacks = false;
|
||||||
|
bd->PrevUserCallbackWindowFocus = NULL;
|
||||||
|
bd->PrevUserCallbackCursorEnter = NULL;
|
||||||
|
bd->PrevUserCallbackCursorPos = NULL;
|
||||||
|
bd->PrevUserCallbackMousebutton = NULL;
|
||||||
|
bd->PrevUserCallbackScroll = NULL;
|
||||||
|
bd->PrevUserCallbackKey = NULL;
|
||||||
|
bd->PrevUserCallbackChar = NULL;
|
||||||
|
bd->PrevUserCallbackMonitor = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool ImGui_ImplGlfw_Init(GLFWwindow* window, bool install_callbacks, GlfwClientApi client_api)
|
||||||
|
{
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
IM_ASSERT(io.BackendPlatformUserData == NULL && "Already initialized a platform backend!");
|
||||||
|
|
||||||
|
// Setup backend capabilities flags
|
||||||
|
ImGui_ImplGlfw_Data* bd = IM_NEW(ImGui_ImplGlfw_Data)();
|
||||||
|
io.BackendPlatformUserData = (void*)bd;
|
||||||
|
io.BackendPlatformName = "imgui_impl_glfw";
|
||||||
|
io.BackendFlags |= ImGuiBackendFlags_HasMouseCursors; // We can honor GetMouseCursor() values (optional)
|
||||||
|
io.BackendFlags |= ImGuiBackendFlags_HasSetMousePos; // We can honor io.WantSetMousePos requests (optional, rarely used)
|
||||||
|
|
||||||
|
bd->Window = window;
|
||||||
|
bd->Time = 0.0;
|
||||||
|
|
||||||
|
io.SetClipboardTextFn = ImGui_ImplGlfw_SetClipboardText;
|
||||||
|
io.GetClipboardTextFn = ImGui_ImplGlfw_GetClipboardText;
|
||||||
|
io.ClipboardUserData = bd->Window;
|
||||||
|
|
||||||
|
// Set platform dependent data in viewport
|
||||||
|
#if defined(_WIN32)
|
||||||
|
ImGui::GetMainViewport()->PlatformHandleRaw = (void*)glfwGetWin32Window(bd->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);
|
||||||
|
bd->MouseCursors[ImGuiMouseCursor_Arrow] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR);
|
||||||
|
bd->MouseCursors[ImGuiMouseCursor_TextInput] = glfwCreateStandardCursor(GLFW_IBEAM_CURSOR);
|
||||||
|
bd->MouseCursors[ImGuiMouseCursor_ResizeNS] = glfwCreateStandardCursor(GLFW_VRESIZE_CURSOR);
|
||||||
|
bd->MouseCursors[ImGuiMouseCursor_ResizeEW] = glfwCreateStandardCursor(GLFW_HRESIZE_CURSOR);
|
||||||
|
bd->MouseCursors[ImGuiMouseCursor_Hand] = glfwCreateStandardCursor(GLFW_HAND_CURSOR);
|
||||||
|
#if GLFW_HAS_NEW_CURSORS
|
||||||
|
bd->MouseCursors[ImGuiMouseCursor_ResizeAll] = glfwCreateStandardCursor(GLFW_RESIZE_ALL_CURSOR);
|
||||||
|
bd->MouseCursors[ImGuiMouseCursor_ResizeNESW] = glfwCreateStandardCursor(GLFW_RESIZE_NESW_CURSOR);
|
||||||
|
bd->MouseCursors[ImGuiMouseCursor_ResizeNWSE] = glfwCreateStandardCursor(GLFW_RESIZE_NWSE_CURSOR);
|
||||||
|
bd->MouseCursors[ImGuiMouseCursor_NotAllowed] = glfwCreateStandardCursor(GLFW_NOT_ALLOWED_CURSOR);
|
||||||
|
#else
|
||||||
|
bd->MouseCursors[ImGuiMouseCursor_ResizeAll] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR);
|
||||||
|
bd->MouseCursors[ImGuiMouseCursor_ResizeNESW] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR);
|
||||||
|
bd->MouseCursors[ImGuiMouseCursor_ResizeNWSE] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR);
|
||||||
|
bd->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.
|
||||||
|
if (install_callbacks)
|
||||||
|
ImGui_ImplGlfw_InstallCallbacks(window);
|
||||||
|
|
||||||
|
bd->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()
|
||||||
|
{
|
||||||
|
ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
|
||||||
|
IM_ASSERT(bd != NULL && "No platform backend to shutdown, or already shutdown?");
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
|
||||||
|
if (bd->InstalledCallbacks)
|
||||||
|
ImGui_ImplGlfw_RestoreCallbacks(bd->Window);
|
||||||
|
|
||||||
|
for (ImGuiMouseCursor cursor_n = 0; cursor_n < ImGuiMouseCursor_COUNT; cursor_n++)
|
||||||
|
glfwDestroyCursor(bd->MouseCursors[cursor_n]);
|
||||||
|
|
||||||
|
io.BackendPlatformName = NULL;
|
||||||
|
io.BackendPlatformUserData = NULL;
|
||||||
|
IM_DELETE(bd);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ImGui_ImplGlfw_UpdateMouseData()
|
||||||
|
{
|
||||||
|
ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
|
||||||
|
#ifdef __EMSCRIPTEN__
|
||||||
|
const bool is_app_focused = true;
|
||||||
|
#else
|
||||||
|
const bool is_app_focused = glfwGetWindowAttrib(bd->Window, GLFW_FOCUSED) != 0;
|
||||||
|
#endif
|
||||||
|
if (is_app_focused)
|
||||||
|
{
|
||||||
|
// (Optional) Set OS mouse position from Dear ImGui if requested (rarely used, only when ImGuiConfigFlags_NavEnableSetMousePos is enabled by user)
|
||||||
|
if (io.WantSetMousePos)
|
||||||
|
glfwSetCursorPos(bd->Window, (double)io.MousePos.x, (double)io.MousePos.y);
|
||||||
|
|
||||||
|
// (Optional) Fallback to provide mouse position when focused (ImGui_ImplGlfw_CursorPosCallback already provides this when hovered or captured)
|
||||||
|
if (is_app_focused && bd->MouseWindow == NULL)
|
||||||
|
{
|
||||||
|
double mouse_x, mouse_y;
|
||||||
|
glfwGetCursorPos(bd->Window, &mouse_x, &mouse_y);
|
||||||
|
io.AddMousePosEvent((float)mouse_x, (float)mouse_y);
|
||||||
|
bd->LastValidMousePos = ImVec2((float)mouse_x, (float)mouse_y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ImGui_ImplGlfw_UpdateMouseCursor()
|
||||||
|
{
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
|
||||||
|
if ((io.ConfigFlags & ImGuiConfigFlags_NoMouseCursorChange) || glfwGetInputMode(bd->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(bd->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(bd->Window, bd->MouseCursors[imgui_cursor] ? bd->MouseCursors[imgui_cursor] : bd->MouseCursors[ImGuiMouseCursor_Arrow]);
|
||||||
|
glfwSetInputMode(bd->Window, GLFW_CURSOR, GLFW_CURSOR_NORMAL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update gamepad inputs
|
||||||
|
static inline float Saturate(float v) { return v < 0.0f ? 0.0f : v > 1.0f ? 1.0f : v; }
|
||||||
|
static void ImGui_ImplGlfw_UpdateGamepads()
|
||||||
|
{
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
if ((io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) == 0) // FIXME: Technically feeding gamepad shouldn't depend on this now that they are regular inputs.
|
||||||
|
return;
|
||||||
|
|
||||||
|
io.BackendFlags &= ~ImGuiBackendFlags_HasGamepad;
|
||||||
|
#if GLFW_HAS_GAMEPAD_API
|
||||||
|
GLFWgamepadstate gamepad;
|
||||||
|
if (!glfwGetGamepadState(GLFW_JOYSTICK_1, &gamepad))
|
||||||
|
return;
|
||||||
|
#define MAP_BUTTON(KEY_NO, BUTTON_NO, _UNUSED) do { io.AddKeyEvent(KEY_NO, gamepad.buttons[BUTTON_NO] != 0); } while (0)
|
||||||
|
#define MAP_ANALOG(KEY_NO, AXIS_NO, _UNUSED, V0, V1) do { float v = gamepad.axes[AXIS_NO]; v = (v - V0) / (V1 - V0); io.AddKeyAnalogEvent(KEY_NO, v > 0.10f, Saturate(v)); } while (0)
|
||||||
|
#else
|
||||||
|
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);
|
||||||
|
if (axes_count == 0 || buttons_count == 0)
|
||||||
|
return;
|
||||||
|
#define MAP_BUTTON(KEY_NO, _UNUSED, BUTTON_NO) do { io.AddKeyEvent(KEY_NO, (buttons_count > BUTTON_NO && buttons[BUTTON_NO] == GLFW_PRESS)); } while (0)
|
||||||
|
#define MAP_ANALOG(KEY_NO, _UNUSED, AXIS_NO, V0, V1) do { float v = (axes_count > AXIS_NO) ? axes[AXIS_NO] : V0; v = (v - V0) / (V1 - V0); io.AddKeyAnalogEvent(KEY_NO, v > 0.10f, Saturate(v)); } while (0)
|
||||||
|
#endif
|
||||||
|
io.BackendFlags |= ImGuiBackendFlags_HasGamepad;
|
||||||
|
MAP_BUTTON(ImGuiKey_GamepadStart, GLFW_GAMEPAD_BUTTON_START, 7);
|
||||||
|
MAP_BUTTON(ImGuiKey_GamepadBack, GLFW_GAMEPAD_BUTTON_BACK, 6);
|
||||||
|
MAP_BUTTON(ImGuiKey_GamepadFaceLeft, GLFW_GAMEPAD_BUTTON_X, 2); // Xbox X, PS Square
|
||||||
|
MAP_BUTTON(ImGuiKey_GamepadFaceRight, GLFW_GAMEPAD_BUTTON_B, 1); // Xbox B, PS Circle
|
||||||
|
MAP_BUTTON(ImGuiKey_GamepadFaceUp, GLFW_GAMEPAD_BUTTON_Y, 3); // Xbox Y, PS Triangle
|
||||||
|
MAP_BUTTON(ImGuiKey_GamepadFaceDown, GLFW_GAMEPAD_BUTTON_A, 0); // Xbox A, PS Cross
|
||||||
|
MAP_BUTTON(ImGuiKey_GamepadDpadLeft, GLFW_GAMEPAD_BUTTON_DPAD_LEFT, 13);
|
||||||
|
MAP_BUTTON(ImGuiKey_GamepadDpadRight, GLFW_GAMEPAD_BUTTON_DPAD_RIGHT, 11);
|
||||||
|
MAP_BUTTON(ImGuiKey_GamepadDpadUp, GLFW_GAMEPAD_BUTTON_DPAD_UP, 10);
|
||||||
|
MAP_BUTTON(ImGuiKey_GamepadDpadDown, GLFW_GAMEPAD_BUTTON_DPAD_DOWN, 12);
|
||||||
|
MAP_BUTTON(ImGuiKey_GamepadL1, GLFW_GAMEPAD_BUTTON_LEFT_BUMPER, 4);
|
||||||
|
MAP_BUTTON(ImGuiKey_GamepadR1, GLFW_GAMEPAD_BUTTON_RIGHT_BUMPER, 5);
|
||||||
|
MAP_ANALOG(ImGuiKey_GamepadL2, GLFW_GAMEPAD_AXIS_LEFT_TRIGGER, 4, -0.75f, +1.0f);
|
||||||
|
MAP_ANALOG(ImGuiKey_GamepadR2, GLFW_GAMEPAD_AXIS_RIGHT_TRIGGER, 5, -0.75f, +1.0f);
|
||||||
|
MAP_BUTTON(ImGuiKey_GamepadL3, GLFW_GAMEPAD_BUTTON_LEFT_THUMB, 8);
|
||||||
|
MAP_BUTTON(ImGuiKey_GamepadR3, GLFW_GAMEPAD_BUTTON_RIGHT_THUMB, 9);
|
||||||
|
MAP_ANALOG(ImGuiKey_GamepadLStickLeft, GLFW_GAMEPAD_AXIS_LEFT_X, 0, -0.25f, -1.0f);
|
||||||
|
MAP_ANALOG(ImGuiKey_GamepadLStickRight, GLFW_GAMEPAD_AXIS_LEFT_X, 0, +0.25f, +1.0f);
|
||||||
|
MAP_ANALOG(ImGuiKey_GamepadLStickUp, GLFW_GAMEPAD_AXIS_LEFT_Y, 1, -0.25f, -1.0f);
|
||||||
|
MAP_ANALOG(ImGuiKey_GamepadLStickDown, GLFW_GAMEPAD_AXIS_LEFT_Y, 1, +0.25f, +1.0f);
|
||||||
|
MAP_ANALOG(ImGuiKey_GamepadRStickLeft, GLFW_GAMEPAD_AXIS_RIGHT_X, 2, -0.25f, -1.0f);
|
||||||
|
MAP_ANALOG(ImGuiKey_GamepadRStickRight, GLFW_GAMEPAD_AXIS_RIGHT_X, 2, +0.25f, +1.0f);
|
||||||
|
MAP_ANALOG(ImGuiKey_GamepadRStickUp, GLFW_GAMEPAD_AXIS_RIGHT_Y, 3, -0.25f, -1.0f);
|
||||||
|
MAP_ANALOG(ImGuiKey_GamepadRStickDown, GLFW_GAMEPAD_AXIS_RIGHT_Y, 3, +0.25f, +1.0f);
|
||||||
|
#undef MAP_BUTTON
|
||||||
|
#undef MAP_ANALOG
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGui_ImplGlfw_NewFrame()
|
||||||
|
{
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
|
||||||
|
IM_ASSERT(bd != NULL && "Did you call ImGui_ImplGlfw_InitForXXX()?");
|
||||||
|
|
||||||
|
// Setup display size (every frame to accommodate for window resizing)
|
||||||
|
int w, h;
|
||||||
|
int display_w, display_h;
|
||||||
|
glfwGetWindowSize(bd->Window, &w, &h);
|
||||||
|
glfwGetFramebufferSize(bd->Window, &display_w, &display_h);
|
||||||
|
io.DisplaySize = ImVec2((float)w, (float)h);
|
||||||
|
if (w > 0 && h > 0)
|
||||||
|
io.DisplayFramebufferScale = ImVec2((float)display_w / (float)w, (float)display_h / (float)h);
|
||||||
|
|
||||||
|
// Setup time step
|
||||||
|
double current_time = glfwGetTime();
|
||||||
|
io.DeltaTime = bd->Time > 0.0 ? (float)(current_time - bd->Time) : (float)(1.0f / 60.0f);
|
||||||
|
bd->Time = current_time;
|
||||||
|
|
||||||
|
ImGui_ImplGlfw_UpdateMouseData();
|
||||||
|
ImGui_ImplGlfw_UpdateMouseCursor();
|
||||||
|
|
||||||
|
// Update game controllers (if enabled and available)
|
||||||
|
ImGui_ImplGlfw_UpdateGamepads();
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(__clang__)
|
||||||
|
#pragma clang diagnostic pop
|
||||||
|
#endif
|
|
@ -0,0 +1,46 @@
|
||||||
|
// 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: Keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy GLFW_KEY_* values will also be supported unless IMGUI_DISABLE_OBSOLETE_KEYIO is set]
|
||||||
|
// [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+).
|
||||||
|
|
||||||
|
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
||||||
|
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
|
||||||
|
// 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;
|
||||||
|
struct GLFWmonitor;
|
||||||
|
|
||||||
|
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 (installer)
|
||||||
|
// - When calling Init with 'install_callbacks=true': ImGui_ImplGlfw_InstallCallbacks() is called. GLFW callbacks will be installed for you. They will chain-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 individual function yourself from your own GLFW callbacks.
|
||||||
|
IMGUI_IMPL_API void ImGui_ImplGlfw_InstallCallbacks(GLFWwindow* window);
|
||||||
|
IMGUI_IMPL_API void ImGui_ImplGlfw_RestoreCallbacks(GLFWwindow* window);
|
||||||
|
|
||||||
|
// GLFW callbacks (individual callbacks to call if you didn't install callbacks)
|
||||||
|
IMGUI_IMPL_API void ImGui_ImplGlfw_WindowFocusCallback(GLFWwindow* window, int focused); // Since 1.84
|
||||||
|
IMGUI_IMPL_API void ImGui_ImplGlfw_CursorEnterCallback(GLFWwindow* window, int entered); // Since 1.84
|
||||||
|
IMGUI_IMPL_API void ImGui_ImplGlfw_CursorPosCallback(GLFWwindow* window, double x, double y); // Since 1.87
|
||||||
|
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);
|
||||||
|
IMGUI_IMPL_API void ImGui_ImplGlfw_MonitorCallback(GLFWmonitor* monitor, int event);
|
|
@ -0,0 +1,297 @@
|
||||||
|
// 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!
|
||||||
|
|
||||||
|
// Implemented features:
|
||||||
|
// [X] Platform: Partial keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy GLUT values will also be supported unless IMGUI_DISABLE_OBSOLETE_KEYIO is set]
|
||||||
|
// 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 use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
||||||
|
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
|
||||||
|
// 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)
|
||||||
|
// 2022-01-26: Inputs: replaced short-lived io.AddKeyModsEvent() (added two weeks ago) with io.AddKeyEvent() using ImGuiKey_ModXXX flags. Sorry for the confusion.
|
||||||
|
// 2022-01-17: Inputs: calling new io.AddMousePosEvent(), io.AddMouseButtonEvent(), io.AddMouseWheelEvent() API (1.87+).
|
||||||
|
// 2022-01-10: Inputs: calling new io.AddKeyEvent(), io.AddKeyModsEvent() + io.SetKeyEventNativeData() API (1.87+). Support for full ImGuiKey range.
|
||||||
|
// 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
|
||||||
|
|
||||||
|
// Glut has 1 function for characters and one for "special keys". We map the characters in the 0..255 range and the keys above.
|
||||||
|
static ImGuiKey ImGui_ImplGLUT_KeyToImGuiKey(int key)
|
||||||
|
{
|
||||||
|
switch (key)
|
||||||
|
{
|
||||||
|
case '\t': return ImGuiKey_Tab;
|
||||||
|
case 256 + GLUT_KEY_LEFT: return ImGuiKey_LeftArrow;
|
||||||
|
case 256 + GLUT_KEY_RIGHT: return ImGuiKey_RightArrow;
|
||||||
|
case 256 + GLUT_KEY_UP: return ImGuiKey_UpArrow;
|
||||||
|
case 256 + GLUT_KEY_DOWN: return ImGuiKey_DownArrow;
|
||||||
|
case 256 + GLUT_KEY_PAGE_UP: return ImGuiKey_PageUp;
|
||||||
|
case 256 + GLUT_KEY_PAGE_DOWN: return ImGuiKey_PageDown;
|
||||||
|
case 256 + GLUT_KEY_HOME: return ImGuiKey_Home;
|
||||||
|
case 256 + GLUT_KEY_END: return ImGuiKey_End;
|
||||||
|
case 256 + GLUT_KEY_INSERT: return ImGuiKey_Insert;
|
||||||
|
case 127: return ImGuiKey_Delete;
|
||||||
|
case 8: return ImGuiKey_Backspace;
|
||||||
|
case ' ': return ImGuiKey_Space;
|
||||||
|
case 13: return ImGuiKey_Enter;
|
||||||
|
case 27: return ImGuiKey_Escape;
|
||||||
|
case 39: return ImGuiKey_Apostrophe;
|
||||||
|
case 44: return ImGuiKey_Comma;
|
||||||
|
case 45: return ImGuiKey_Minus;
|
||||||
|
case 46: return ImGuiKey_Period;
|
||||||
|
case 47: return ImGuiKey_Slash;
|
||||||
|
case 59: return ImGuiKey_Semicolon;
|
||||||
|
case 61: return ImGuiKey_Equal;
|
||||||
|
case 91: return ImGuiKey_LeftBracket;
|
||||||
|
case 92: return ImGuiKey_Backslash;
|
||||||
|
case 93: return ImGuiKey_RightBracket;
|
||||||
|
case 96: return ImGuiKey_GraveAccent;
|
||||||
|
//case 0: return ImGuiKey_CapsLock;
|
||||||
|
//case 0: return ImGuiKey_ScrollLock;
|
||||||
|
case 256 + 0x006D: return ImGuiKey_NumLock;
|
||||||
|
//case 0: return ImGuiKey_PrintScreen;
|
||||||
|
//case 0: return ImGuiKey_Pause;
|
||||||
|
//case '0': return ImGuiKey_Keypad0;
|
||||||
|
//case '1': return ImGuiKey_Keypad1;
|
||||||
|
//case '2': return ImGuiKey_Keypad2;
|
||||||
|
//case '3': return ImGuiKey_Keypad3;
|
||||||
|
//case '4': return ImGuiKey_Keypad4;
|
||||||
|
//case '5': return ImGuiKey_Keypad5;
|
||||||
|
//case '6': return ImGuiKey_Keypad6;
|
||||||
|
//case '7': return ImGuiKey_Keypad7;
|
||||||
|
//case '8': return ImGuiKey_Keypad8;
|
||||||
|
//case '9': return ImGuiKey_Keypad9;
|
||||||
|
//case 46: return ImGuiKey_KeypadDecimal;
|
||||||
|
//case 47: return ImGuiKey_KeypadDivide;
|
||||||
|
case 42: return ImGuiKey_KeypadMultiply;
|
||||||
|
//case 45: return ImGuiKey_KeypadSubtract;
|
||||||
|
case 43: return ImGuiKey_KeypadAdd;
|
||||||
|
//case 13: return ImGuiKey_KeypadEnter;
|
||||||
|
//case 0: return ImGuiKey_KeypadEqual;
|
||||||
|
case 256 + 0x0072: return ImGuiKey_LeftCtrl;
|
||||||
|
case 256 + 0x0070: return ImGuiKey_LeftShift;
|
||||||
|
case 256 + 0x0074: return ImGuiKey_LeftAlt;
|
||||||
|
//case 0: return ImGuiKey_LeftSuper;
|
||||||
|
case 256 + 0x0073: return ImGuiKey_RightCtrl;
|
||||||
|
case 256 + 0x0071: return ImGuiKey_RightShift;
|
||||||
|
case 256 + 0x0075: return ImGuiKey_RightAlt;
|
||||||
|
//case 0: return ImGuiKey_RightSuper;
|
||||||
|
//case 0: return ImGuiKey_Menu;
|
||||||
|
case '0': return ImGuiKey_0;
|
||||||
|
case '1': return ImGuiKey_1;
|
||||||
|
case '2': return ImGuiKey_2;
|
||||||
|
case '3': return ImGuiKey_3;
|
||||||
|
case '4': return ImGuiKey_4;
|
||||||
|
case '5': return ImGuiKey_5;
|
||||||
|
case '6': return ImGuiKey_6;
|
||||||
|
case '7': return ImGuiKey_7;
|
||||||
|
case '8': return ImGuiKey_8;
|
||||||
|
case '9': return ImGuiKey_9;
|
||||||
|
case 'A': case 'a': return ImGuiKey_A;
|
||||||
|
case 'B': case 'b': return ImGuiKey_B;
|
||||||
|
case 'C': case 'c': return ImGuiKey_C;
|
||||||
|
case 'D': case 'd': return ImGuiKey_D;
|
||||||
|
case 'E': case 'e': return ImGuiKey_E;
|
||||||
|
case 'F': case 'f': return ImGuiKey_F;
|
||||||
|
case 'G': case 'g': return ImGuiKey_G;
|
||||||
|
case 'H': case 'h': return ImGuiKey_H;
|
||||||
|
case 'I': case 'i': return ImGuiKey_I;
|
||||||
|
case 'J': case 'j': return ImGuiKey_J;
|
||||||
|
case 'K': case 'k': return ImGuiKey_K;
|
||||||
|
case 'L': case 'l': return ImGuiKey_L;
|
||||||
|
case 'M': case 'm': return ImGuiKey_M;
|
||||||
|
case 'N': case 'n': return ImGuiKey_N;
|
||||||
|
case 'O': case 'o': return ImGuiKey_O;
|
||||||
|
case 'P': case 'p': return ImGuiKey_P;
|
||||||
|
case 'Q': case 'q': return ImGuiKey_Q;
|
||||||
|
case 'R': case 'r': return ImGuiKey_R;
|
||||||
|
case 'S': case 's': return ImGuiKey_S;
|
||||||
|
case 'T': case 't': return ImGuiKey_T;
|
||||||
|
case 'U': case 'u': return ImGuiKey_U;
|
||||||
|
case 'V': case 'v': return ImGuiKey_V;
|
||||||
|
case 'W': case 'w': return ImGuiKey_W;
|
||||||
|
case 'X': case 'x': return ImGuiKey_X;
|
||||||
|
case 'Y': case 'y': return ImGuiKey_Y;
|
||||||
|
case 'Z': case 'z': return ImGuiKey_Z;
|
||||||
|
case 256 + GLUT_KEY_F1: return ImGuiKey_F1;
|
||||||
|
case 256 + GLUT_KEY_F2: return ImGuiKey_F2;
|
||||||
|
case 256 + GLUT_KEY_F3: return ImGuiKey_F3;
|
||||||
|
case 256 + GLUT_KEY_F4: return ImGuiKey_F4;
|
||||||
|
case 256 + GLUT_KEY_F5: return ImGuiKey_F5;
|
||||||
|
case 256 + GLUT_KEY_F6: return ImGuiKey_F6;
|
||||||
|
case 256 + GLUT_KEY_F7: return ImGuiKey_F7;
|
||||||
|
case 256 + GLUT_KEY_F8: return ImGuiKey_F8;
|
||||||
|
case 256 + GLUT_KEY_F9: return ImGuiKey_F9;
|
||||||
|
case 256 + GLUT_KEY_F10: return ImGuiKey_F10;
|
||||||
|
case 256 + GLUT_KEY_F11: return ImGuiKey_F11;
|
||||||
|
case 256 + GLUT_KEY_F12: return ImGuiKey_F12;
|
||||||
|
default: return ImGuiKey_None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
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_UpdateKeyModifiers()
|
||||||
|
{
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
int glut_key_mods = glutGetModifiers();
|
||||||
|
io.AddKeyEvent(ImGuiKey_ModCtrl, (glut_key_mods & GLUT_ACTIVE_CTRL) != 0);
|
||||||
|
io.AddKeyEvent(ImGuiKey_ModShift, (glut_key_mods & GLUT_ACTIVE_SHIFT) != 0);
|
||||||
|
io.AddKeyEvent(ImGuiKey_ModAlt, (glut_key_mods & GLUT_ACTIVE_ALT) != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ImGui_ImplGLUT_AddKeyEvent(ImGuiKey key, bool down, int native_keycode)
|
||||||
|
{
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
io.AddKeyEvent(key, down);
|
||||||
|
io.SetKeyEventNativeData(key, native_keycode, -1); // To support legacy indexing (<1.87 user code)
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
ImGuiKey key = ImGui_ImplGLUT_KeyToImGuiKey(c);
|
||||||
|
ImGui_ImplGLUT_AddKeyEvent(key, true, c);
|
||||||
|
ImGui_ImplGLUT_UpdateKeyModifiers();
|
||||||
|
(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);
|
||||||
|
ImGuiKey key = ImGui_ImplGLUT_KeyToImGuiKey(c);
|
||||||
|
ImGui_ImplGLUT_AddKeyEvent(key, false, c);
|
||||||
|
ImGui_ImplGLUT_UpdateKeyModifiers();
|
||||||
|
(void)x; (void)y; // Unused
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGui_ImplGLUT_SpecialFunc(int key, int x, int y)
|
||||||
|
{
|
||||||
|
//printf("key_down_func %d\n", key);
|
||||||
|
ImGuiKey imgui_key = ImGui_ImplGLUT_KeyToImGuiKey(key + 256);
|
||||||
|
ImGui_ImplGLUT_AddKeyEvent(imgui_key, true, key + 256);
|
||||||
|
ImGui_ImplGLUT_UpdateKeyModifiers();
|
||||||
|
(void)x; (void)y; // Unused
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGui_ImplGLUT_SpecialUpFunc(int key, int x, int y)
|
||||||
|
{
|
||||||
|
//printf("key_up_func %d\n", key);
|
||||||
|
ImGuiKey imgui_key = ImGui_ImplGLUT_KeyToImGuiKey(key + 256);
|
||||||
|
ImGui_ImplGLUT_AddKeyEvent(imgui_key, false, key + 256);
|
||||||
|
ImGui_ImplGLUT_UpdateKeyModifiers();
|
||||||
|
(void)x; (void)y; // Unused
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGui_ImplGLUT_MouseFunc(int glut_button, int state, int x, int y)
|
||||||
|
{
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
io.AddMousePosEvent((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 || state == GLUT_UP))
|
||||||
|
io.AddMouseButtonEvent(button, state == GLUT_DOWN);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef __FREEGLUT_EXT_H__
|
||||||
|
void ImGui_ImplGLUT_MouseWheelFunc(int button, int dir, int x, int y)
|
||||||
|
{
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
io.AddMousePosEvent((float)x, (float)y);
|
||||||
|
if (dir != 0)
|
||||||
|
io.AddMouseWheelEvent(0.0f, dir > 0 ? 1.0f : -1.0f);
|
||||||
|
(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.AddMousePosEvent((float)x, (float)y);
|
||||||
|
}
|
|
@ -0,0 +1,39 @@
|
||||||
|
// 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!
|
||||||
|
|
||||||
|
// Implemented features:
|
||||||
|
// [X] Platform: Partial keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy GLUT values will also be supported unless IMGUI_DISABLE_OBSOLETE_KEYIO is set]
|
||||||
|
// 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 use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
||||||
|
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
|
||||||
|
// 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
|
|
@ -0,0 +1,317 @@
|
||||||
|
// 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)
|
||||||
|
// 2021-05-19: Renderer: Replaced direct access to ImDrawCmd::TextureId with a call to ImDrawCmd::GetTexID(). (will become a requirement)
|
||||||
|
// 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->GetTexID());
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
|
@ -0,0 +1,64 @@
|
||||||
|
// 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 use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
||||||
|
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
|
||||||
|
// 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
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// ObjC API
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#ifdef __OBJC__
|
||||||
|
|
||||||
|
@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* drawData,
|
||||||
|
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();
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// C++ API
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// Enable Metal C++ binding support with '#define IMGUI_IMPL_METAL_CPP' in your imconfig.h file
|
||||||
|
// More info about using Metal from C++: https://developer.apple.com/metal/cpp/
|
||||||
|
|
||||||
|
#ifdef IMGUI_IMPL_METAL_CPP
|
||||||
|
#include <Metal/Metal.hpp>
|
||||||
|
#ifndef __OBJC__
|
||||||
|
|
||||||
|
IMGUI_IMPL_API bool ImGui_ImplMetal_Init(MTL::Device* device);
|
||||||
|
IMGUI_IMPL_API void ImGui_ImplMetal_Shutdown();
|
||||||
|
IMGUI_IMPL_API void ImGui_ImplMetal_NewFrame(MTL::RenderPassDescriptor* renderPassDescriptor);
|
||||||
|
IMGUI_IMPL_API void ImGui_ImplMetal_RenderDrawData(ImDrawData* draw_data,
|
||||||
|
MTL::CommandBuffer* commandBuffer,
|
||||||
|
MTL::RenderCommandEncoder* commandEncoder);
|
||||||
|
|
||||||
|
// Called by Init/NewFrame/Shutdown
|
||||||
|
IMGUI_IMPL_API bool ImGui_ImplMetal_CreateFontsTexture(MTL::Device* device);
|
||||||
|
IMGUI_IMPL_API void ImGui_ImplMetal_DestroyFontsTexture();
|
||||||
|
IMGUI_IMPL_API bool ImGui_ImplMetal_CreateDeviceObjects(MTL::Device* device);
|
||||||
|
IMGUI_IMPL_API void ImGui_ImplMetal_DestroyDeviceObjects();
|
||||||
|
|
||||||
|
#endif
|
||||||
|
#endif
|
|
@ -0,0 +1,574 @@
|
||||||
|
// 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 use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
||||||
|
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
|
||||||
|
// 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)
|
||||||
|
// 2022-07-05: Metal: Add dispatch synchronization.
|
||||||
|
// 2022-06-30: Metal: Use __bridge for ARC based systems.
|
||||||
|
// 2022-06-01: Metal: Fixed null dereference on exit inside command buffer completion handler.
|
||||||
|
// 2022-04-27: Misc: Store backend data in a per-context struct, allowing to use this backend with multiple contexts.
|
||||||
|
// 2022-01-03: Metal: Ignore ImDrawCmd where ElemCount == 0 (very rare but can technically be manufactured by user code).
|
||||||
|
// 2021-12-30: Metal: Added Metal C++ support. Enable with '#define IMGUI_IMPL_METAL_CPP' in your imconfig.h file.
|
||||||
|
// 2021-08-24: Metal: Fixed a crash when clipping rect larger than framebuffer is submitted. (#4464)
|
||||||
|
// 2021-05-19: Metal: Replaced direct access to ImDrawCmd::TextureId with a call to ImDrawCmd::GetTexID(). (will become a requirement)
|
||||||
|
// 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 <time.h>
|
||||||
|
#import <Metal/Metal.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) double 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<MTLDevice> device;
|
||||||
|
@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) double lastBufferCachePurge;
|
||||||
|
- (MetalBuffer*)dequeueReusableBufferOfLength:(NSUInteger)length device:(id<MTLDevice>)device;
|
||||||
|
- (id<MTLRenderPipelineState>)renderPipelineStateForFramebufferDescriptor:(FramebufferDescriptor*)descriptor device:(id<MTLDevice>)device;
|
||||||
|
@end
|
||||||
|
|
||||||
|
struct ImGui_ImplMetal_Data
|
||||||
|
{
|
||||||
|
MetalContext* SharedMetalContext;
|
||||||
|
|
||||||
|
ImGui_ImplMetal_Data() { memset(this, 0, sizeof(*this)); }
|
||||||
|
};
|
||||||
|
|
||||||
|
static ImGui_ImplMetal_Data* ImGui_ImplMetal_CreateBackendData() { return IM_NEW(ImGui_ImplMetal_Data)(); }
|
||||||
|
static ImGui_ImplMetal_Data* ImGui_ImplMetal_GetBackendData() { return ImGui::GetCurrentContext() ? (ImGui_ImplMetal_Data*)ImGui::GetIO().BackendRendererUserData : NULL; }
|
||||||
|
static void ImGui_ImplMetal_DestroyBackendData() { IM_DELETE(ImGui_ImplMetal_GetBackendData()); }
|
||||||
|
|
||||||
|
static inline CFTimeInterval GetMachAbsoluteTimeInSeconds() { return static_cast<CFTimeInterval>(static_cast<double>(clock_gettime_nsec_np(CLOCK_UPTIME_RAW)) / 1e9); }
|
||||||
|
|
||||||
|
#ifdef IMGUI_IMPL_METAL_CPP
|
||||||
|
|
||||||
|
#pragma mark - Dear ImGui Metal C++ Backend API
|
||||||
|
|
||||||
|
bool ImGui_ImplMetal_Init(MTL::Device* device)
|
||||||
|
{
|
||||||
|
return ImGui_ImplMetal_Init((__bridge id<MTLDevice>)(device));
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGui_ImplMetal_NewFrame(MTL::RenderPassDescriptor* renderPassDescriptor)
|
||||||
|
{
|
||||||
|
ImGui_ImplMetal_NewFrame((__bridge MTLRenderPassDescriptor*)(renderPassDescriptor));
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGui_ImplMetal_RenderDrawData(ImDrawData* draw_data,
|
||||||
|
MTL::CommandBuffer* commandBuffer,
|
||||||
|
MTL::RenderCommandEncoder* commandEncoder)
|
||||||
|
{
|
||||||
|
ImGui_ImplMetal_RenderDrawData(draw_data,
|
||||||
|
(__bridge id<MTLCommandBuffer>)(commandBuffer),
|
||||||
|
(__bridge id<MTLRenderCommandEncoder>)(commandEncoder));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ImGui_ImplMetal_CreateFontsTexture(MTL::Device* device)
|
||||||
|
{
|
||||||
|
return ImGui_ImplMetal_CreateFontsTexture((__bridge id<MTLDevice>)(device));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ImGui_ImplMetal_CreateDeviceObjects(MTL::Device* device)
|
||||||
|
{
|
||||||
|
return ImGui_ImplMetal_CreateDeviceObjects((__bridge id<MTLDevice>)(device));
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // #ifdef IMGUI_IMPL_METAL_CPP
|
||||||
|
|
||||||
|
#pragma mark - Dear ImGui Metal Backend API
|
||||||
|
|
||||||
|
bool ImGui_ImplMetal_Init(id<MTLDevice> device)
|
||||||
|
{
|
||||||
|
ImGui_ImplMetal_Data* bd = ImGui_ImplMetal_CreateBackendData();
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
io.BackendRendererUserData = (void*)bd;
|
||||||
|
io.BackendRendererName = "imgui_impl_metal";
|
||||||
|
io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes.
|
||||||
|
|
||||||
|
bd->SharedMetalContext = [[MetalContext alloc] init];
|
||||||
|
bd->SharedMetalContext.device = device;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGui_ImplMetal_Shutdown()
|
||||||
|
{
|
||||||
|
ImGui_ImplMetal_DestroyDeviceObjects();
|
||||||
|
ImGui_ImplMetal_DestroyBackendData();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGui_ImplMetal_NewFrame(MTLRenderPassDescriptor* renderPassDescriptor)
|
||||||
|
{
|
||||||
|
ImGui_ImplMetal_Data* bd = ImGui_ImplMetal_GetBackendData();
|
||||||
|
IM_ASSERT(bd->SharedMetalContext != nil && "No Metal context. Did you call ImGui_ImplMetal_Init() ?");
|
||||||
|
bd->SharedMetalContext.framebufferDescriptor = [[FramebufferDescriptor alloc] initWithRenderPassDescriptor:renderPassDescriptor];
|
||||||
|
|
||||||
|
if (bd->SharedMetalContext.depthStencilState == nil)
|
||||||
|
ImGui_ImplMetal_CreateDeviceObjects(bd->SharedMetalContext.device);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ImGui_ImplMetal_SetupRenderState(ImDrawData* drawData, id<MTLCommandBuffer> commandBuffer,
|
||||||
|
id<MTLRenderCommandEncoder> commandEncoder, id<MTLRenderPipelineState> renderPipelineState,
|
||||||
|
MetalBuffer* vertexBuffer, size_t vertexBufferOffset)
|
||||||
|
{
|
||||||
|
IM_UNUSED(commandBuffer);
|
||||||
|
ImGui_ImplMetal_Data* bd = ImGui_ImplMetal_GetBackendData();
|
||||||
|
[commandEncoder setCullMode:MTLCullModeNone];
|
||||||
|
[commandEncoder setDepthStencilState:bd->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];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Metal Render function.
|
||||||
|
void ImGui_ImplMetal_RenderDrawData(ImDrawData* drawData, id<MTLCommandBuffer> commandBuffer, id<MTLRenderCommandEncoder> commandEncoder)
|
||||||
|
{
|
||||||
|
ImGui_ImplMetal_Data* bd = ImGui_ImplMetal_GetBackendData();
|
||||||
|
MetalContext* ctx = bd->SharedMetalContext;
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
|
||||||
|
// 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 = ctx.renderPipelineStateCache[ctx.framebufferDescriptor];
|
||||||
|
if (renderPipelineState == nil)
|
||||||
|
{
|
||||||
|
// No luck; make a new render pipeline state
|
||||||
|
renderPipelineState = [ctx renderPipelineStateForFramebufferDescriptor:ctx.framebufferDescriptor device:commandBuffer.device];
|
||||||
|
|
||||||
|
// Cache render pipeline state for later reuse
|
||||||
|
ctx.renderPipelineStateCache[ctx.framebufferDescriptor] = renderPipelineState;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t vertexBufferLength = (size_t)drawData->TotalVtxCount * sizeof(ImDrawVert);
|
||||||
|
size_t indexBufferLength = (size_t)drawData->TotalIdxCount * sizeof(ImDrawIdx);
|
||||||
|
MetalBuffer* vertexBuffer = [ctx dequeueReusableBufferOfLength:vertexBufferLength device:commandBuffer.device];
|
||||||
|
MetalBuffer* indexBuffer = [ctx dequeueReusableBufferOfLength:indexBufferLength device:commandBuffer.device];
|
||||||
|
|
||||||
|
ImGui_ImplMetal_SetupRenderState(drawData, commandBuffer, commandEncoder, renderPipelineState, vertexBuffer, 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)
|
||||||
|
ImGui_ImplMetal_SetupRenderState(drawData, commandBuffer, commandEncoder, renderPipelineState, vertexBuffer, vertexBufferOffset);
|
||||||
|
else
|
||||||
|
pcmd->UserCallback(cmd_list, pcmd);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Project scissor/clipping rectangles into framebuffer space
|
||||||
|
ImVec2 clip_min((pcmd->ClipRect.x - clip_off.x) * clip_scale.x, (pcmd->ClipRect.y - clip_off.y) * clip_scale.y);
|
||||||
|
ImVec2 clip_max((pcmd->ClipRect.z - clip_off.x) * clip_scale.x, (pcmd->ClipRect.w - clip_off.y) * clip_scale.y);
|
||||||
|
|
||||||
|
// Clamp to viewport as setScissorRect() won't accept values that are off bounds
|
||||||
|
if (clip_min.x < 0.0f) { clip_min.x = 0.0f; }
|
||||||
|
if (clip_min.y < 0.0f) { clip_min.y = 0.0f; }
|
||||||
|
if (clip_max.x > fb_width) { clip_max.x = (float)fb_width; }
|
||||||
|
if (clip_max.y > fb_height) { clip_max.y = (float)fb_height; }
|
||||||
|
if (clip_max.x <= clip_min.x || clip_max.y <= clip_min.y)
|
||||||
|
continue;
|
||||||
|
if (pcmd->ElemCount == 0) // drawIndexedPrimitives() validation doesn't accept this
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Apply scissor/clipping rectangle
|
||||||
|
MTLScissorRect scissorRect =
|
||||||
|
{
|
||||||
|
.x = NSUInteger(clip_min.x),
|
||||||
|
.y = NSUInteger(clip_min.y),
|
||||||
|
.width = NSUInteger(clip_max.x - clip_min.x),
|
||||||
|
.height = NSUInteger(clip_max.y - clip_min.y)
|
||||||
|
};
|
||||||
|
[commandEncoder setScissorRect:scissorRect];
|
||||||
|
|
||||||
|
// Bind texture, Draw
|
||||||
|
if (ImTextureID tex_id = pcmd->GetTexID())
|
||||||
|
[commandEncoder setFragmentTexture:(__bridge id<MTLTexture>)(tex_id) 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
[commandBuffer addCompletedHandler:^(id<MTLCommandBuffer>)
|
||||||
|
{
|
||||||
|
dispatch_async(dispatch_get_main_queue(), ^{
|
||||||
|
ImGui_ImplMetal_Data* bd = ImGui_ImplMetal_GetBackendData();
|
||||||
|
if (bd != NULL)
|
||||||
|
{
|
||||||
|
@synchronized(bd->SharedMetalContext.bufferCache)
|
||||||
|
{
|
||||||
|
[bd->SharedMetalContext.bufferCache addObject:vertexBuffer];
|
||||||
|
[bd->SharedMetalContext.bufferCache addObject:indexBuffer];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ImGui_ImplMetal_CreateFontsTexture(id<MTLDevice> device)
|
||||||
|
{
|
||||||
|
ImGui_ImplMetal_Data* bd = ImGui_ImplMetal_GetBackendData();
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
|
||||||
|
// 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.
|
||||||
|
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];
|
||||||
|
bd->SharedMetalContext.fontTexture = texture;
|
||||||
|
io.Fonts->SetTexID((__bridge void*)bd->SharedMetalContext.fontTexture); // ImTextureID == void*
|
||||||
|
|
||||||
|
return (bd->SharedMetalContext.fontTexture != nil);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGui_ImplMetal_DestroyFontsTexture()
|
||||||
|
{
|
||||||
|
ImGui_ImplMetal_Data* bd = ImGui_ImplMetal_GetBackendData();
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
bd->SharedMetalContext.fontTexture = nil;
|
||||||
|
io.Fonts->SetTexID(nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ImGui_ImplMetal_CreateDeviceObjects(id<MTLDevice> device)
|
||||||
|
{
|
||||||
|
ImGui_ImplMetal_Data* bd = ImGui_ImplMetal_GetBackendData();
|
||||||
|
MTLDepthStencilDescriptor* depthStencilDescriptor = [[MTLDepthStencilDescriptor alloc] init];
|
||||||
|
depthStencilDescriptor.depthWriteEnabled = NO;
|
||||||
|
depthStencilDescriptor.depthCompareFunction = MTLCompareFunctionAlways;
|
||||||
|
bd->SharedMetalContext.depthStencilState = [device newDepthStencilStateWithDescriptor:depthStencilDescriptor];
|
||||||
|
ImGui_ImplMetal_CreateFontsTexture(device);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGui_ImplMetal_DestroyDeviceObjects()
|
||||||
|
{
|
||||||
|
ImGui_ImplMetal_Data* bd = ImGui_ImplMetal_GetBackendData();
|
||||||
|
ImGui_ImplMetal_DestroyFontsTexture();
|
||||||
|
[bd->SharedMetalContext.renderPipelineStateCache removeAllObjects];
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark - MetalBuffer implementation
|
||||||
|
|
||||||
|
@implementation MetalBuffer
|
||||||
|
- (instancetype)initWithBuffer:(id<MTLBuffer>)buffer
|
||||||
|
{
|
||||||
|
if ((self = [super init]))
|
||||||
|
{
|
||||||
|
_buffer = buffer;
|
||||||
|
_lastReuseTime = GetMachAbsoluteTimeInSeconds();
|
||||||
|
}
|
||||||
|
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]))
|
||||||
|
{
|
||||||
|
self.renderPipelineStateCache = [NSMutableDictionary dictionary];
|
||||||
|
self.bufferCache = [NSMutableArray array];
|
||||||
|
_lastBufferCachePurge = GetMachAbsoluteTimeInSeconds();
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (MetalBuffer*)dequeueReusableBufferOfLength:(NSUInteger)length device:(id<MTLDevice>)device
|
||||||
|
{
|
||||||
|
uint64_t now = GetMachAbsoluteTimeInSeconds();
|
||||||
|
|
||||||
|
@synchronized(self.bufferCache)
|
||||||
|
{
|
||||||
|
// 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];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bilinear sampling is required by default. Set 'io.Fonts->Flags |= ImFontAtlasFlags_NoBakedLines' or 'style.AntiAliasedLinesUseTex = false' to allow point/nearest sampling.
|
||||||
|
- (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;
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
|
@ -0,0 +1,289 @@
|
||||||
|
// 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 use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
||||||
|
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
|
||||||
|
// 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-12-08: OpenGL: Fixed mishandling of the the ImDrawCmd::IdxOffset field! This is an old bug but it never had an effect until some internal rendering changes in 1.86.
|
||||||
|
// 2021-06-29: Reorganized backend to pull data from a single structure to facilitate usage with multiple-contexts (all g_XXXX access changed to bd->XXXX).
|
||||||
|
// 2021-05-19: OpenGL: Replaced direct access to ImDrawCmd::TextureId with a call to ImDrawCmd::GetTexID(). (will become a requirement)
|
||||||
|
// 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>
|
||||||
|
#include <glad/gl.h>
|
||||||
|
#else
|
||||||
|
#include <GL/gl.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct ImGui_ImplOpenGL2_Data
|
||||||
|
{
|
||||||
|
GLuint FontTexture;
|
||||||
|
|
||||||
|
ImGui_ImplOpenGL2_Data() { memset((void*)this, 0, sizeof(*this)); }
|
||||||
|
};
|
||||||
|
|
||||||
|
// Backend data stored in io.BackendRendererUserData to allow support for multiple Dear ImGui contexts
|
||||||
|
// It is STRONGLY preferred that you use docking branch with multi-viewports (== single Dear ImGui context + multiple windows) instead of multiple Dear ImGui contexts.
|
||||||
|
static ImGui_ImplOpenGL2_Data* ImGui_ImplOpenGL2_GetBackendData()
|
||||||
|
{
|
||||||
|
return ImGui::GetCurrentContext() ? (ImGui_ImplOpenGL2_Data*)ImGui::GetIO().BackendRendererUserData : NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Functions
|
||||||
|
bool ImGui_ImplOpenGL2_Init()
|
||||||
|
{
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
IM_ASSERT(io.BackendRendererUserData == NULL && "Already initialized a renderer backend!");
|
||||||
|
|
||||||
|
// Setup backend capabilities flags
|
||||||
|
ImGui_ImplOpenGL2_Data* bd = IM_NEW(ImGui_ImplOpenGL2_Data)();
|
||||||
|
io.BackendRendererUserData = (void*)bd;
|
||||||
|
io.BackendRendererName = "imgui_impl_opengl2";
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGui_ImplOpenGL2_Shutdown()
|
||||||
|
{
|
||||||
|
ImGui_ImplOpenGL2_Data* bd = ImGui_ImplOpenGL2_GetBackendData();
|
||||||
|
IM_ASSERT(bd != NULL && "No renderer backend to shutdown, or already shutdown?");
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
|
||||||
|
ImGui_ImplOpenGL2_DestroyDeviceObjects();
|
||||||
|
io.BackendRendererName = NULL;
|
||||||
|
io.BackendRendererUserData = NULL;
|
||||||
|
IM_DELETE(bd);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ImGui_ImplOpenGL2_NewFrame()
|
||||||
|
{
|
||||||
|
ImGui_ImplOpenGL2_Data* bd = ImGui_ImplOpenGL2_GetBackendData();
|
||||||
|
IM_ASSERT(bd != NULL && "Did you call ImGui_ImplOpenGL2_Init()?");
|
||||||
|
|
||||||
|
if (!bd->FontTexture)
|
||||||
|
return ImGui_ImplOpenGL2_CreateDeviceObjects();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
ImVec2 clip_min((pcmd->ClipRect.x - clip_off.x) * clip_scale.x, (pcmd->ClipRect.y - clip_off.y) * clip_scale.y);
|
||||||
|
ImVec2 clip_max((pcmd->ClipRect.z - clip_off.x) * clip_scale.x, (pcmd->ClipRect.w - clip_off.y) * clip_scale.y);
|
||||||
|
if (clip_max.x <= clip_min.x || clip_max.y <= clip_min.y)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Apply scissor/clipping rectangle (Y is inverted in OpenGL)
|
||||||
|
glScissor((int)clip_min.x, (int)(fb_height - clip_max.y), (int)(clip_max.x - clip_min.x), (int)(clip_max.y - clip_min.y));
|
||||||
|
|
||||||
|
// Bind texture, Draw
|
||||||
|
glBindTexture(GL_TEXTURE_2D, (GLuint)(intptr_t)pcmd->GetTexID());
|
||||||
|
glDrawElements(GL_TRIANGLES, (GLsizei)pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, idx_buffer + pcmd->IdxOffset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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();
|
||||||
|
ImGui_ImplOpenGL2_Data* bd = ImGui_ImplOpenGL2_GetBackendData();
|
||||||
|
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
|
||||||
|
// (Bilinear sampling is required by default. Set 'io.Fonts->Flags |= ImFontAtlasFlags_NoBakedLines' or 'style.AntiAliasedLinesUseTex = false' to allow point/nearest sampling)
|
||||||
|
GLint last_texture;
|
||||||
|
glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture);
|
||||||
|
glGenTextures(1, &bd->FontTexture);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, bd->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)bd->FontTexture);
|
||||||
|
|
||||||
|
// Restore state
|
||||||
|
glBindTexture(GL_TEXTURE_2D, last_texture);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGui_ImplOpenGL2_DestroyFontsTexture()
|
||||||
|
{
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
ImGui_ImplOpenGL2_Data* bd = ImGui_ImplOpenGL2_GetBackendData();
|
||||||
|
if (bd->FontTexture)
|
||||||
|
{
|
||||||
|
glDeleteTextures(1, &bd->FontTexture);
|
||||||
|
io.Fonts->SetTexID(0);
|
||||||
|
bd->FontTexture = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ImGui_ImplOpenGL2_CreateDeviceObjects()
|
||||||
|
{
|
||||||
|
return ImGui_ImplOpenGL2_CreateFontsTexture();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGui_ImplOpenGL2_DestroyDeviceObjects()
|
||||||
|
{
|
||||||
|
ImGui_ImplOpenGL2_DestroyFontsTexture();
|
||||||
|
}
|
|
@ -0,0 +1,32 @@
|
||||||
|
// 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 use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
||||||
|
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
|
||||||
|
// 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 bool 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();
|
|
@ -14,6 +14,14 @@
|
||||||
|
|
||||||
// CHANGELOG
|
// CHANGELOG
|
||||||
// (minor and older changes stripped away, please see git history for details)
|
// (minor and older changes stripped away, please see git history for details)
|
||||||
|
// 2022-05-23: OpenGL: Reworking 2021-12-15 "Using buffer orphaning" so it only happens on Intel GPU, seems to cause problems otherwise. (#4468, #4825, #4832, #5127).
|
||||||
|
// 2022-05-13: OpenGL: Fix state corruption on OpenGL ES 2.0 due to not preserving GL_ELEMENT_ARRAY_BUFFER_BINDING and vertex attribute states.
|
||||||
|
// 2021-12-15: OpenGL: Using buffer orphaning + glBufferSubData(), seems to fix leaks with multi-viewports with some Intel HD drivers.
|
||||||
|
// 2021-08-23: OpenGL: Fixed ES 3.0 shader ("#version 300 es") use normal precision floats to avoid wobbly rendering at HD resolutions.
|
||||||
|
// 2021-08-19: OpenGL: Embed and use our own minimal GL loader (imgui_impl_opengl3_loader.h), removing requirement and support for third-party loader.
|
||||||
|
// 2021-06-29: Reorganized backend to pull data from a single structure to facilitate usage with multiple-contexts (all g_XXXX access changed to bd->XXXX).
|
||||||
|
// 2021-06-25: OpenGL: Use OES_vertex_array extension on Emscripten + backup/restore current state.
|
||||||
|
// 2021-06-21: OpenGL: Destroy individual vertex/fragment shader objects right after they are linked into the main shader.
|
||||||
// 2021-05-24: OpenGL: Access GL_CLIP_ORIGIN when "GL_ARB_clip_control" extension is detected, inside of just OpenGL 4.5 version.
|
// 2021-05-24: OpenGL: Access GL_CLIP_ORIGIN when "GL_ARB_clip_control" extension is detected, inside of just OpenGL 4.5 version.
|
||||||
// 2021-05-19: OpenGL: Replaced direct access to ImDrawCmd::TextureId with a call to ImDrawCmd::GetTexID(). (will become a requirement)
|
// 2021-05-19: OpenGL: Replaced direct access to ImDrawCmd::TextureId with a call to ImDrawCmd::GetTexID(). (will become a requirement)
|
||||||
// 2021-04-06: OpenGL: Don't try to read GL_CLIP_ORIGIN unless we're OpenGL 4.5 or greater.
|
// 2021-04-06: OpenGL: Don't try to read GL_CLIP_ORIGIN unless we're OpenGL 4.5 or greater.
|
||||||
|
@ -89,46 +97,65 @@
|
||||||
#else
|
#else
|
||||||
#include <stdint.h> // intptr_t
|
#include <stdint.h> // intptr_t
|
||||||
#endif
|
#endif
|
||||||
|
#if defined(__APPLE__)
|
||||||
|
#include <TargetConditionals.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Clang warnings with -Weverything
|
||||||
|
#if defined(__clang__)
|
||||||
|
#pragma clang diagnostic push
|
||||||
|
#pragma clang diagnostic ignored "-Wold-style-cast" // warning: use of old-style cast
|
||||||
|
#pragma clang diagnostic ignored "-Wsign-conversion" // warning: implicit conversion changes signedness
|
||||||
|
#if __has_warning("-Wzero-as-null-pointer-constant")
|
||||||
|
#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant"
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
// GL includes
|
// GL includes
|
||||||
#if defined(IMGUI_IMPL_OPENGL_ES2)
|
#if defined(IMGUI_IMPL_OPENGL_ES2)
|
||||||
#include <GLES2/gl2.h>
|
#if (defined(__APPLE__) && (TARGET_OS_IOS || TARGET_OS_TV))
|
||||||
|
#include <OpenGLES/ES2/gl.h> // Use GL ES 2
|
||||||
|
#else
|
||||||
|
#include <GLES2/gl2.h> // Use GL ES 2
|
||||||
|
#endif
|
||||||
|
#if defined(__EMSCRIPTEN__)
|
||||||
|
#ifndef GL_GLEXT_PROTOTYPES
|
||||||
|
#define GL_GLEXT_PROTOTYPES
|
||||||
|
#endif
|
||||||
|
#include <GLES2/gl2ext.h>
|
||||||
|
#endif
|
||||||
#elif defined(IMGUI_IMPL_OPENGL_ES3)
|
#elif defined(IMGUI_IMPL_OPENGL_ES3)
|
||||||
#if (defined(__APPLE__) && (TARGET_OS_IOS || TARGET_OS_TV))
|
#if (defined(__APPLE__) && (TARGET_OS_IOS || TARGET_OS_TV))
|
||||||
#include <OpenGLES/ES3/gl.h> // Use GL ES 3
|
#include <OpenGLES/ES3/gl.h> // Use GL ES 3
|
||||||
#else
|
#else
|
||||||
#include <GLES3/gl3.h> // Use GL ES 3
|
#include <GLES3/gl3.h> // Use GL ES 3
|
||||||
#endif
|
#endif
|
||||||
#else
|
#elif !defined(IMGUI_IMPL_OPENGL_LOADER_CUSTOM)
|
||||||
// About Desktop OpenGL function loaders:
|
|
||||||
// Modern desktop OpenGL doesn't have a standard portable header file to load OpenGL function pointers.
|
// 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).
|
// Helper libraries are often used for this purpose! Here we are using our own minimal custom loader based on gl3w.
|
||||||
// You may use another loader/header of your choice (glext, glLoadGen, etc.), or chose to manually implement your own.
|
// In the rest of your app/engine, you can use another loader of your choice (gl3w, glew, glad, glbinding, glext, glLoadGen, etc.).
|
||||||
#if defined(IMGUI_IMPL_OPENGL_LOADER_GL3W)
|
// If you happen to be developing a new feature for this backend (imgui_impl_opengl3.cpp):
|
||||||
#include <GL/gl3w.h> // Needs to be initialized with gl3wInit() in user's code
|
// - You may need to regenerate imgui_impl_opengl3_loader.h to add new symbols. See https://github.com/dearimgui/gl3w_stripped
|
||||||
#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLEW)
|
// - You can temporarily use an unstripped version. See https://github.com/dearimgui/gl3w_stripped/releases
|
||||||
#include <GL/glew.h> // Needs to be initialized with glewInit() in user's code.
|
// Changes to this backend using new APIs should be accompanied by a regenerated stripped loader version.
|
||||||
#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLAD)
|
#define IMGL3W_IMPL
|
||||||
#include <glad/glad.h> // Needs to be initialized with gladLoadGL() in user's code.
|
#include "imgui_impl_opengl3_loader.h"
|
||||||
#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
|
#endif
|
||||||
#include <glbinding/Binding.h> // Needs to be initialized with glbinding::Binding::initialize() in user's code.
|
|
||||||
#include <glbinding/gl/gl.h>
|
// Vertex arrays are not supported on ES2/WebGL1 unless Emscripten which uses an extension
|
||||||
using namespace gl;
|
#ifndef IMGUI_IMPL_OPENGL_ES2
|
||||||
#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLBINDING3)
|
#define IMGUI_IMPL_OPENGL_USE_VERTEX_ARRAY
|
||||||
#ifndef GLFW_INCLUDE_NONE
|
#elif defined(__EMSCRIPTEN__)
|
||||||
#define GLFW_INCLUDE_NONE // GLFW including OpenGL headers causes ambiguity or multiple definition errors.
|
#define IMGUI_IMPL_OPENGL_USE_VERTEX_ARRAY
|
||||||
#endif
|
#define glBindVertexArray glBindVertexArrayOES
|
||||||
#include <glbinding/glbinding.h>// Needs to be initialized with glbinding::initialize() in user's code.
|
#define glGenVertexArrays glGenVertexArraysOES
|
||||||
#include <glbinding/gl/gl.h>
|
#define glDeleteVertexArrays glDeleteVertexArraysOES
|
||||||
using namespace gl;
|
#define GL_VERTEX_ARRAY_BINDING GL_VERTEX_ARRAY_BINDING_OES
|
||||||
#else
|
|
||||||
#include IMGUI_IMPL_OPENGL_LOADER_CUSTOM
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// Desktop GL 2.0+ has glPolygonMode() which GL ES and WebGL don't have.
|
||||||
|
#ifdef GL_POLYGON_MODE
|
||||||
|
#define IMGUI_IMPL_HAS_POLYGON_MODE
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Desktop GL 3.2+ has glDrawElementsBaseVertex() which GL ES and WebGL don't have.
|
// Desktop GL 3.2+ has glDrawElementsBaseVertex() which GL ES and WebGL don't have.
|
||||||
|
@ -152,18 +179,77 @@ using namespace gl;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// OpenGL Data
|
// 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)
|
struct ImGui_ImplOpenGL3_Data
|
||||||
static char g_GlslVersionString[32] = ""; // Specified by user or detected based on compile time GL settings.
|
{
|
||||||
static GLuint g_FontTexture = 0;
|
GLuint GlVersion; // Extracted at runtime using GL_MAJOR_VERSION, GL_MINOR_VERSION queries (e.g. 320 for GL 3.2)
|
||||||
static GLuint g_ShaderHandle = 0, g_VertHandle = 0, g_FragHandle = 0;
|
char GlslVersionString[32]; // Specified by user or detected based on compile time GL settings.
|
||||||
static GLint g_AttribLocationTex = 0, g_AttribLocationProjMtx = 0; // Uniforms location
|
GLuint FontTexture;
|
||||||
static GLuint g_AttribLocationVtxPos = 0, g_AttribLocationVtxUV = 0, g_AttribLocationVtxColor = 0; // Vertex attributes location
|
GLuint ShaderHandle;
|
||||||
static unsigned int g_VboHandle = 0, g_ElementsHandle = 0;
|
GLint AttribLocationTex; // Uniforms location
|
||||||
static bool g_HasClipOrigin = false;
|
GLint AttribLocationProjMtx;
|
||||||
|
GLuint AttribLocationVtxPos; // Vertex attributes location
|
||||||
|
GLuint AttribLocationVtxUV;
|
||||||
|
GLuint AttribLocationVtxColor;
|
||||||
|
unsigned int VboHandle, ElementsHandle;
|
||||||
|
GLsizeiptr VertexBufferSize;
|
||||||
|
GLsizeiptr IndexBufferSize;
|
||||||
|
bool HasClipOrigin;
|
||||||
|
bool UseBufferSubData;
|
||||||
|
|
||||||
|
ImGui_ImplOpenGL3_Data() { memset((void*)this, 0, sizeof(*this)); }
|
||||||
|
};
|
||||||
|
|
||||||
|
// Backend data stored in io.BackendRendererUserData to allow support for multiple Dear ImGui contexts
|
||||||
|
// It is STRONGLY preferred that you use docking branch with multi-viewports (== single Dear ImGui context + multiple windows) instead of multiple Dear ImGui contexts.
|
||||||
|
static ImGui_ImplOpenGL3_Data* ImGui_ImplOpenGL3_GetBackendData()
|
||||||
|
{
|
||||||
|
return ImGui::GetCurrentContext() ? (ImGui_ImplOpenGL3_Data*)ImGui::GetIO().BackendRendererUserData : NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// OpenGL vertex attribute state (for ES 1.0 and ES 2.0 only)
|
||||||
|
#ifndef IMGUI_IMPL_OPENGL_USE_VERTEX_ARRAY
|
||||||
|
struct ImGui_ImplOpenGL3_VtxAttribState
|
||||||
|
{
|
||||||
|
GLint Enabled, Size, Type, Normalized, Stride;
|
||||||
|
GLvoid* Ptr;
|
||||||
|
|
||||||
|
void GetState(GLint index)
|
||||||
|
{
|
||||||
|
glGetVertexAttribiv(index, GL_VERTEX_ATTRIB_ARRAY_ENABLED, &Enabled);
|
||||||
|
glGetVertexAttribiv(index, GL_VERTEX_ATTRIB_ARRAY_SIZE, &Size);
|
||||||
|
glGetVertexAttribiv(index, GL_VERTEX_ATTRIB_ARRAY_TYPE, &Type);
|
||||||
|
glGetVertexAttribiv(index, GL_VERTEX_ATTRIB_ARRAY_NORMALIZED, &Normalized);
|
||||||
|
glGetVertexAttribiv(index, GL_VERTEX_ATTRIB_ARRAY_STRIDE, &Stride);
|
||||||
|
glGetVertexAttribPointerv(index, GL_VERTEX_ATTRIB_ARRAY_POINTER, &Ptr);
|
||||||
|
}
|
||||||
|
void SetState(GLint index)
|
||||||
|
{
|
||||||
|
glVertexAttribPointer(index, Size, Type, (GLboolean)Normalized, Stride, Ptr);
|
||||||
|
if (Enabled) glEnableVertexAttribArray(index); else glDisableVertexAttribArray(index);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
// Functions
|
// Functions
|
||||||
bool ImGui_ImplOpenGL3_Init(const char* glsl_version)
|
bool ImGui_ImplOpenGL3_Init(const char* glsl_version)
|
||||||
{
|
{
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
IM_ASSERT(io.BackendRendererUserData == NULL && "Already initialized a renderer backend!");
|
||||||
|
|
||||||
|
// Initialize our loader
|
||||||
|
#if !defined(IMGUI_IMPL_OPENGL_ES2) && !defined(IMGUI_IMPL_OPENGL_ES3) && !defined(IMGUI_IMPL_OPENGL_LOADER_CUSTOM)
|
||||||
|
if (imgl3wInit() != 0)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Failed to initialize OpenGL loader!\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Setup backend capabilities flags
|
||||||
|
ImGui_ImplOpenGL3_Data* bd = IM_NEW(ImGui_ImplOpenGL3_Data)();
|
||||||
|
io.BackendRendererUserData = (void*)bd;
|
||||||
|
io.BackendRendererName = "imgui_impl_opengl3";
|
||||||
|
|
||||||
// Query for GL version (e.g. 320 for GL 3.2)
|
// Query for GL version (e.g. 320 for GL 3.2)
|
||||||
#if !defined(IMGUI_IMPL_OPENGL_ES2)
|
#if !defined(IMGUI_IMPL_OPENGL_ES2)
|
||||||
GLint major = 0;
|
GLint major = 0;
|
||||||
|
@ -176,71 +262,49 @@ bool ImGui_ImplOpenGL3_Init(const char* glsl_version)
|
||||||
const char* gl_version = (const char*)glGetString(GL_VERSION);
|
const char* gl_version = (const char*)glGetString(GL_VERSION);
|
||||||
sscanf(gl_version, "%d.%d", &major, &minor);
|
sscanf(gl_version, "%d.%d", &major, &minor);
|
||||||
}
|
}
|
||||||
g_GlVersion = (GLuint)(major * 100 + minor * 10);
|
bd->GlVersion = (GLuint)(major * 100 + minor * 10);
|
||||||
|
|
||||||
|
// Query vendor to enable glBufferSubData kludge
|
||||||
|
#ifdef _WIN32
|
||||||
|
if (const char* vendor = (const char*)glGetString(GL_VENDOR))
|
||||||
|
if (strncmp(vendor, "Intel", 5) == 0)
|
||||||
|
bd->UseBufferSubData = true;
|
||||||
|
#endif
|
||||||
|
//printf("GL_MAJOR_VERSION = %d\nGL_MINOR_VERSION = %d\nGL_VENDOR = '%s'\nGL_RENDERER = '%s'\n", major, minor, (const char*)glGetString(GL_VENDOR), (const char*)glGetString(GL_RENDERER)); // [DEBUG]
|
||||||
#else
|
#else
|
||||||
g_GlVersion = 200; // GLES 2
|
bd->GlVersion = 200; // GLES 2
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Setup backend capabilities flags
|
|
||||||
ImGuiIO& io = ImGui::GetIO();
|
|
||||||
io.BackendRendererName = "imgui_impl_opengl3";
|
|
||||||
#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_VTX_OFFSET
|
#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_VTX_OFFSET
|
||||||
if (g_GlVersion >= 320)
|
if (bd->GlVersion >= 320)
|
||||||
io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes.
|
io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes.
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Store GLSL version string so we can refer to it later in case we recreate shaders.
|
// 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.
|
// 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)
|
if (glsl_version == NULL)
|
||||||
|
{
|
||||||
|
#if defined(IMGUI_IMPL_OPENGL_ES2)
|
||||||
glsl_version = "#version 100";
|
glsl_version = "#version 100";
|
||||||
#elif defined(IMGUI_IMPL_OPENGL_ES3)
|
#elif defined(IMGUI_IMPL_OPENGL_ES3)
|
||||||
if (glsl_version == NULL)
|
|
||||||
glsl_version = "#version 300 es";
|
glsl_version = "#version 300 es";
|
||||||
#elif defined(__APPLE__)
|
#elif defined(__APPLE__)
|
||||||
if (glsl_version == NULL)
|
|
||||||
glsl_version = "#version 150";
|
glsl_version = "#version 150";
|
||||||
#else
|
#else
|
||||||
if (glsl_version == NULL)
|
|
||||||
glsl_version = "#version 130";
|
glsl_version = "#version 130";
|
||||||
#endif
|
#endif
|
||||||
IM_ASSERT((int)strlen(glsl_version) + 2 < IM_ARRAYSIZE(g_GlslVersionString));
|
}
|
||||||
strcpy(g_GlslVersionString, glsl_version);
|
IM_ASSERT((int)strlen(glsl_version) + 2 < IM_ARRAYSIZE(bd->GlslVersionString));
|
||||||
strcat(g_GlslVersionString, "\n");
|
strcpy(bd->GlslVersionString, glsl_version);
|
||||||
|
strcat(bd->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)
|
// 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.
|
// IF YOU GET A CRASH HERE: it probably means the OpenGL function loader didn't do its job. Let us know!
|
||||||
// Desktop OpenGL 3/4 need a function loader. See the IMGUI_IMPL_OPENGL_LOADER_xxx explanation above.
|
|
||||||
GLint current_texture;
|
GLint current_texture;
|
||||||
glGetIntegerv(GL_TEXTURE_BINDING_2D, ¤t_texture);
|
glGetIntegerv(GL_TEXTURE_BINDING_2D, ¤t_texture);
|
||||||
|
|
||||||
// Detect extensions we support
|
// Detect extensions we support
|
||||||
g_HasClipOrigin = (g_GlVersion >= 450);
|
bd->HasClipOrigin = (bd->GlVersion >= 450);
|
||||||
#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_EXTENSIONS
|
#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_EXTENSIONS
|
||||||
GLint num_extensions = 0;
|
GLint num_extensions = 0;
|
||||||
glGetIntegerv(GL_NUM_EXTENSIONS, &num_extensions);
|
glGetIntegerv(GL_NUM_EXTENSIONS, &num_extensions);
|
||||||
|
@ -248,7 +312,7 @@ bool ImGui_ImplOpenGL3_Init(const char* glsl_version)
|
||||||
{
|
{
|
||||||
const char* extension = (const char*)glGetStringi(GL_EXTENSIONS, i);
|
const char* extension = (const char*)glGetStringi(GL_EXTENSIONS, i);
|
||||||
if (extension != NULL && strcmp(extension, "GL_ARB_clip_control") == 0)
|
if (extension != NULL && strcmp(extension, "GL_ARB_clip_control") == 0)
|
||||||
g_HasClipOrigin = true;
|
bd->HasClipOrigin = true;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -257,18 +321,31 @@ bool ImGui_ImplOpenGL3_Init(const char* glsl_version)
|
||||||
|
|
||||||
void ImGui_ImplOpenGL3_Shutdown()
|
void ImGui_ImplOpenGL3_Shutdown()
|
||||||
{
|
{
|
||||||
|
ImGui_ImplOpenGL3_Data* bd = ImGui_ImplOpenGL3_GetBackendData();
|
||||||
|
IM_ASSERT(bd != NULL && "No renderer backend to shutdown, or already shutdown?");
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
|
||||||
ImGui_ImplOpenGL3_DestroyDeviceObjects();
|
ImGui_ImplOpenGL3_DestroyDeviceObjects();
|
||||||
|
io.BackendRendererName = NULL;
|
||||||
|
io.BackendRendererUserData = NULL;
|
||||||
|
IM_DELETE(bd);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ImGui_ImplOpenGL3_NewFrame()
|
bool ImGui_ImplOpenGL3_NewFrame()
|
||||||
{
|
{
|
||||||
if (!g_ShaderHandle)
|
ImGui_ImplOpenGL3_Data* bd = ImGui_ImplOpenGL3_GetBackendData();
|
||||||
|
IM_ASSERT(bd != NULL && "Did you call ImGui_ImplOpenGL3_Init()?");
|
||||||
|
|
||||||
|
if (!bd->ShaderHandle)
|
||||||
return ImGui_ImplOpenGL3_CreateDeviceObjects();
|
return ImGui_ImplOpenGL3_CreateDeviceObjects();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ImGui_ImplOpenGL3_SetupRenderState(ImDrawData* draw_data, int fb_width, int fb_height, GLuint vertex_array_object)
|
static void ImGui_ImplOpenGL3_SetupRenderState(ImDrawData* draw_data, int fb_width, int fb_height, GLuint vertex_array_object)
|
||||||
{
|
{
|
||||||
|
ImGui_ImplOpenGL3_Data* bd = ImGui_ImplOpenGL3_GetBackendData();
|
||||||
|
|
||||||
// Setup render state: alpha-blending enabled, no face culling, no depth testing, scissor enabled, polygon fill
|
// Setup render state: alpha-blending enabled, no face culling, no depth testing, scissor enabled, polygon fill
|
||||||
glEnable(GL_BLEND);
|
glEnable(GL_BLEND);
|
||||||
glBlendEquation(GL_FUNC_ADD);
|
glBlendEquation(GL_FUNC_ADD);
|
||||||
|
@ -278,17 +355,17 @@ static void ImGui_ImplOpenGL3_SetupRenderState(ImDrawData* draw_data, int fb_wid
|
||||||
glDisable(GL_STENCIL_TEST);
|
glDisable(GL_STENCIL_TEST);
|
||||||
glEnable(GL_SCISSOR_TEST);
|
glEnable(GL_SCISSOR_TEST);
|
||||||
#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_PRIMITIVE_RESTART
|
#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_PRIMITIVE_RESTART
|
||||||
if (g_GlVersion >= 310)
|
if (bd->GlVersion >= 310)
|
||||||
glDisable(GL_PRIMITIVE_RESTART);
|
glDisable(GL_PRIMITIVE_RESTART);
|
||||||
#endif
|
#endif
|
||||||
#ifdef GL_POLYGON_MODE
|
#ifdef IMGUI_IMPL_HAS_POLYGON_MODE
|
||||||
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
|
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Support for GL 4.5 rarely used glClipControl(GL_UPPER_LEFT)
|
// Support for GL 4.5 rarely used glClipControl(GL_UPPER_LEFT)
|
||||||
#if defined(GL_CLIP_ORIGIN)
|
#if defined(GL_CLIP_ORIGIN)
|
||||||
bool clip_origin_lower_left = true;
|
bool clip_origin_lower_left = true;
|
||||||
if (g_HasClipOrigin)
|
if (bd->HasClipOrigin)
|
||||||
{
|
{
|
||||||
GLenum current_clip_origin = 0; glGetIntegerv(GL_CLIP_ORIGIN, (GLint*)¤t_clip_origin);
|
GLenum current_clip_origin = 0; glGetIntegerv(GL_CLIP_ORIGIN, (GLint*)¤t_clip_origin);
|
||||||
if (current_clip_origin == GL_UPPER_LEFT)
|
if (current_clip_origin == GL_UPPER_LEFT)
|
||||||
|
@ -313,29 +390,29 @@ static void ImGui_ImplOpenGL3_SetupRenderState(ImDrawData* draw_data, int fb_wid
|
||||||
{ 0.0f, 0.0f, -1.0f, 0.0f },
|
{ 0.0f, 0.0f, -1.0f, 0.0f },
|
||||||
{ (R+L)/(L-R), (T+B)/(B-T), 0.0f, 1.0f },
|
{ (R+L)/(L-R), (T+B)/(B-T), 0.0f, 1.0f },
|
||||||
};
|
};
|
||||||
glUseProgram(g_ShaderHandle);
|
glUseProgram(bd->ShaderHandle);
|
||||||
glUniform1i(g_AttribLocationTex, 0);
|
glUniform1i(bd->AttribLocationTex, 0);
|
||||||
glUniformMatrix4fv(g_AttribLocationProjMtx, 1, GL_FALSE, &ortho_projection[0][0]);
|
glUniformMatrix4fv(bd->AttribLocationProjMtx, 1, GL_FALSE, &ortho_projection[0][0]);
|
||||||
|
|
||||||
#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_BIND_SAMPLER
|
#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_BIND_SAMPLER
|
||||||
if (g_GlVersion >= 330)
|
if (bd->GlVersion >= 330)
|
||||||
glBindSampler(0, 0); // We use combined texture/sampler state. Applications using GL 3.3 may set that otherwise.
|
glBindSampler(0, 0); // We use combined texture/sampler state. Applications using GL 3.3 may set that otherwise.
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
(void)vertex_array_object;
|
(void)vertex_array_object;
|
||||||
#ifndef IMGUI_IMPL_OPENGL_ES2
|
#ifdef IMGUI_IMPL_OPENGL_USE_VERTEX_ARRAY
|
||||||
glBindVertexArray(vertex_array_object);
|
glBindVertexArray(vertex_array_object);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Bind vertex/index buffers and setup attributes for ImDrawVert
|
// Bind vertex/index buffers and setup attributes for ImDrawVert
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, g_VboHandle);
|
glBindBuffer(GL_ARRAY_BUFFER, bd->VboHandle);
|
||||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, g_ElementsHandle);
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, bd->ElementsHandle);
|
||||||
glEnableVertexAttribArray(g_AttribLocationVtxPos);
|
glEnableVertexAttribArray(bd->AttribLocationVtxPos);
|
||||||
glEnableVertexAttribArray(g_AttribLocationVtxUV);
|
glEnableVertexAttribArray(bd->AttribLocationVtxUV);
|
||||||
glEnableVertexAttribArray(g_AttribLocationVtxColor);
|
glEnableVertexAttribArray(bd->AttribLocationVtxColor);
|
||||||
glVertexAttribPointer(g_AttribLocationVtxPos, 2, GL_FLOAT, GL_FALSE, sizeof(ImDrawVert), (GLvoid*)IM_OFFSETOF(ImDrawVert, pos));
|
glVertexAttribPointer(bd->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(bd->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));
|
glVertexAttribPointer(bd->AttribLocationVtxColor, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(ImDrawVert), (GLvoid*)IM_OFFSETOF(ImDrawVert, col));
|
||||||
}
|
}
|
||||||
|
|
||||||
// OpenGL3 Render function.
|
// OpenGL3 Render function.
|
||||||
|
@ -349,19 +426,28 @@ void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data)
|
||||||
if (fb_width <= 0 || fb_height <= 0)
|
if (fb_width <= 0 || fb_height <= 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
ImGui_ImplOpenGL3_Data* bd = ImGui_ImplOpenGL3_GetBackendData();
|
||||||
|
|
||||||
// Backup GL state
|
// Backup GL state
|
||||||
GLenum last_active_texture; glGetIntegerv(GL_ACTIVE_TEXTURE, (GLint*)&last_active_texture);
|
GLenum last_active_texture; glGetIntegerv(GL_ACTIVE_TEXTURE, (GLint*)&last_active_texture);
|
||||||
glActiveTexture(GL_TEXTURE0);
|
glActiveTexture(GL_TEXTURE0);
|
||||||
GLuint last_program; glGetIntegerv(GL_CURRENT_PROGRAM, (GLint*)&last_program);
|
GLuint last_program; glGetIntegerv(GL_CURRENT_PROGRAM, (GLint*)&last_program);
|
||||||
GLuint last_texture; glGetIntegerv(GL_TEXTURE_BINDING_2D, (GLint*)&last_texture);
|
GLuint last_texture; glGetIntegerv(GL_TEXTURE_BINDING_2D, (GLint*)&last_texture);
|
||||||
#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_BIND_SAMPLER
|
#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; }
|
GLuint last_sampler; if (bd->GlVersion >= 330) { glGetIntegerv(GL_SAMPLER_BINDING, (GLint*)&last_sampler); } else { last_sampler = 0; }
|
||||||
#endif
|
#endif
|
||||||
GLuint last_array_buffer; glGetIntegerv(GL_ARRAY_BUFFER_BINDING, (GLint*)&last_array_buffer);
|
GLuint last_array_buffer; glGetIntegerv(GL_ARRAY_BUFFER_BINDING, (GLint*)&last_array_buffer);
|
||||||
#ifndef IMGUI_IMPL_OPENGL_ES2
|
#ifndef IMGUI_IMPL_OPENGL_USE_VERTEX_ARRAY
|
||||||
|
// This is part of VAO on OpenGL 3.0+ and OpenGL ES 3.0+.
|
||||||
|
GLint last_element_array_buffer; glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, &last_element_array_buffer);
|
||||||
|
ImGui_ImplOpenGL3_VtxAttribState last_vtx_attrib_state_pos; last_vtx_attrib_state_pos.GetState(bd->AttribLocationVtxPos);
|
||||||
|
ImGui_ImplOpenGL3_VtxAttribState last_vtx_attrib_state_uv; last_vtx_attrib_state_uv.GetState(bd->AttribLocationVtxUV);
|
||||||
|
ImGui_ImplOpenGL3_VtxAttribState last_vtx_attrib_state_color; last_vtx_attrib_state_color.GetState(bd->AttribLocationVtxColor);
|
||||||
|
#endif
|
||||||
|
#ifdef IMGUI_IMPL_OPENGL_USE_VERTEX_ARRAY
|
||||||
GLuint last_vertex_array_object; glGetIntegerv(GL_VERTEX_ARRAY_BINDING, (GLint*)&last_vertex_array_object);
|
GLuint last_vertex_array_object; glGetIntegerv(GL_VERTEX_ARRAY_BINDING, (GLint*)&last_vertex_array_object);
|
||||||
#endif
|
#endif
|
||||||
#ifdef GL_POLYGON_MODE
|
#ifdef IMGUI_IMPL_HAS_POLYGON_MODE
|
||||||
GLint last_polygon_mode[2]; glGetIntegerv(GL_POLYGON_MODE, last_polygon_mode);
|
GLint last_polygon_mode[2]; glGetIntegerv(GL_POLYGON_MODE, last_polygon_mode);
|
||||||
#endif
|
#endif
|
||||||
GLint last_viewport[4]; glGetIntegerv(GL_VIEWPORT, last_viewport);
|
GLint last_viewport[4]; glGetIntegerv(GL_VIEWPORT, last_viewport);
|
||||||
|
@ -378,14 +464,14 @@ void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data)
|
||||||
GLboolean last_enable_stencil_test = glIsEnabled(GL_STENCIL_TEST);
|
GLboolean last_enable_stencil_test = glIsEnabled(GL_STENCIL_TEST);
|
||||||
GLboolean last_enable_scissor_test = glIsEnabled(GL_SCISSOR_TEST);
|
GLboolean last_enable_scissor_test = glIsEnabled(GL_SCISSOR_TEST);
|
||||||
#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_PRIMITIVE_RESTART
|
#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_PRIMITIVE_RESTART
|
||||||
GLboolean last_enable_primitive_restart = (g_GlVersion >= 310) ? glIsEnabled(GL_PRIMITIVE_RESTART) : GL_FALSE;
|
GLboolean last_enable_primitive_restart = (bd->GlVersion >= 310) ? glIsEnabled(GL_PRIMITIVE_RESTART) : GL_FALSE;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Setup desired GL state
|
// 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)
|
// 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.
|
// 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;
|
GLuint vertex_array_object = 0;
|
||||||
#ifndef IMGUI_IMPL_OPENGL_ES2
|
#ifdef IMGUI_IMPL_OPENGL_USE_VERTEX_ARRAY
|
||||||
glGenVertexArrays(1, &vertex_array_object);
|
glGenVertexArrays(1, &vertex_array_object);
|
||||||
#endif
|
#endif
|
||||||
ImGui_ImplOpenGL3_SetupRenderState(draw_data, fb_width, fb_height, vertex_array_object);
|
ImGui_ImplOpenGL3_SetupRenderState(draw_data, fb_width, fb_height, vertex_array_object);
|
||||||
|
@ -400,8 +486,31 @@ void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data)
|
||||||
const ImDrawList* cmd_list = draw_data->CmdLists[n];
|
const ImDrawList* cmd_list = draw_data->CmdLists[n];
|
||||||
|
|
||||||
// Upload vertex/index buffers
|
// 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);
|
// - On Intel windows drivers we got reports that regular glBufferData() led to accumulating leaks when using multi-viewports, so we started using orphaning + glBufferSubData(). (See https://github.com/ocornut/imgui/issues/4468)
|
||||||
glBufferData(GL_ELEMENT_ARRAY_BUFFER, (GLsizeiptr)cmd_list->IdxBuffer.Size * (int)sizeof(ImDrawIdx), (const GLvoid*)cmd_list->IdxBuffer.Data, GL_STREAM_DRAW);
|
// - On NVIDIA drivers we got reports that using orphaning + glBufferSubData() led to glitches when using multi-viewports.
|
||||||
|
// - OpenGL drivers are in a very sorry state in 2022, for now we are switching code path based on vendors.
|
||||||
|
const GLsizeiptr vtx_buffer_size = (GLsizeiptr)cmd_list->VtxBuffer.Size * (int)sizeof(ImDrawVert);
|
||||||
|
const GLsizeiptr idx_buffer_size = (GLsizeiptr)cmd_list->IdxBuffer.Size * (int)sizeof(ImDrawIdx);
|
||||||
|
if (bd->UseBufferSubData)
|
||||||
|
{
|
||||||
|
if (bd->VertexBufferSize < vtx_buffer_size)
|
||||||
|
{
|
||||||
|
bd->VertexBufferSize = vtx_buffer_size;
|
||||||
|
glBufferData(GL_ARRAY_BUFFER, bd->VertexBufferSize, NULL, GL_STREAM_DRAW);
|
||||||
|
}
|
||||||
|
if (bd->IndexBufferSize < idx_buffer_size)
|
||||||
|
{
|
||||||
|
bd->IndexBufferSize = idx_buffer_size;
|
||||||
|
glBufferData(GL_ELEMENT_ARRAY_BUFFER, bd->IndexBufferSize, NULL, GL_STREAM_DRAW);
|
||||||
|
}
|
||||||
|
glBufferSubData(GL_ARRAY_BUFFER, 0, vtx_buffer_size, (const GLvoid*)cmd_list->VtxBuffer.Data);
|
||||||
|
glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, idx_buffer_size, (const GLvoid*)cmd_list->IdxBuffer.Data);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
glBufferData(GL_ARRAY_BUFFER, vtx_buffer_size, (const GLvoid*)cmd_list->VtxBuffer.Data, GL_STREAM_DRAW);
|
||||||
|
glBufferData(GL_ELEMENT_ARRAY_BUFFER, idx_buffer_size, (const GLvoid*)cmd_list->IdxBuffer.Data, GL_STREAM_DRAW);
|
||||||
|
}
|
||||||
|
|
||||||
for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++)
|
for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++)
|
||||||
{
|
{
|
||||||
|
@ -418,21 +527,18 @@ void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data)
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Project scissor/clipping rectangles into framebuffer space
|
// Project scissor/clipping rectangles into framebuffer space
|
||||||
ImVec4 clip_rect;
|
ImVec2 clip_min((pcmd->ClipRect.x - clip_off.x) * clip_scale.x, (pcmd->ClipRect.y - clip_off.y) * clip_scale.y);
|
||||||
clip_rect.x = (pcmd->ClipRect.x - clip_off.x) * clip_scale.x;
|
ImVec2 clip_max((pcmd->ClipRect.z - clip_off.x) * clip_scale.x, (pcmd->ClipRect.w - clip_off.y) * clip_scale.y);
|
||||||
clip_rect.y = (pcmd->ClipRect.y - clip_off.y) * clip_scale.y;
|
if (clip_max.x <= clip_min.x || clip_max.y <= clip_min.y)
|
||||||
clip_rect.z = (pcmd->ClipRect.z - clip_off.x) * clip_scale.x;
|
continue;
|
||||||
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 (Y is inverted in OpenGL)
|
||||||
{
|
glScissor((int)clip_min.x, (int)((float)fb_height - clip_max.y), (int)(clip_max.x - clip_min.x), (int)(clip_max.y - clip_min.y));
|
||||||
// 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
|
// Bind texture, Draw
|
||||||
glBindTexture(GL_TEXTURE_2D, (GLuint)(intptr_t)pcmd->GetTexID());
|
glBindTexture(GL_TEXTURE_2D, (GLuint)(intptr_t)pcmd->GetTexID());
|
||||||
#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_VTX_OFFSET
|
#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_VTX_OFFSET
|
||||||
if (g_GlVersion >= 320)
|
if (bd->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);
|
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
|
else
|
||||||
#endif
|
#endif
|
||||||
|
@ -440,10 +546,9 @@ void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Destroy the temporary VAO
|
// Destroy the temporary VAO
|
||||||
#ifndef IMGUI_IMPL_OPENGL_ES2
|
#ifdef IMGUI_IMPL_OPENGL_USE_VERTEX_ARRAY
|
||||||
glDeleteVertexArrays(1, &vertex_array_object);
|
glDeleteVertexArrays(1, &vertex_array_object);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -451,14 +556,20 @@ void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data)
|
||||||
glUseProgram(last_program);
|
glUseProgram(last_program);
|
||||||
glBindTexture(GL_TEXTURE_2D, last_texture);
|
glBindTexture(GL_TEXTURE_2D, last_texture);
|
||||||
#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_BIND_SAMPLER
|
#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_BIND_SAMPLER
|
||||||
if (g_GlVersion >= 330)
|
if (bd->GlVersion >= 330)
|
||||||
glBindSampler(0, last_sampler);
|
glBindSampler(0, last_sampler);
|
||||||
#endif
|
#endif
|
||||||
glActiveTexture(last_active_texture);
|
glActiveTexture(last_active_texture);
|
||||||
#ifndef IMGUI_IMPL_OPENGL_ES2
|
#ifdef IMGUI_IMPL_OPENGL_USE_VERTEX_ARRAY
|
||||||
glBindVertexArray(last_vertex_array_object);
|
glBindVertexArray(last_vertex_array_object);
|
||||||
#endif
|
#endif
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, last_array_buffer);
|
glBindBuffer(GL_ARRAY_BUFFER, last_array_buffer);
|
||||||
|
#ifndef IMGUI_IMPL_OPENGL_USE_VERTEX_ARRAY
|
||||||
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, last_element_array_buffer);
|
||||||
|
last_vtx_attrib_state_pos.SetState(bd->AttribLocationVtxPos);
|
||||||
|
last_vtx_attrib_state_uv.SetState(bd->AttribLocationVtxUV);
|
||||||
|
last_vtx_attrib_state_color.SetState(bd->AttribLocationVtxColor);
|
||||||
|
#endif
|
||||||
glBlendEquationSeparate(last_blend_equation_rgb, last_blend_equation_alpha);
|
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);
|
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_blend) glEnable(GL_BLEND); else glDisable(GL_BLEND);
|
||||||
|
@ -467,38 +578,42 @@ void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data)
|
||||||
if (last_enable_stencil_test) glEnable(GL_STENCIL_TEST); else glDisable(GL_STENCIL_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);
|
if (last_enable_scissor_test) glEnable(GL_SCISSOR_TEST); else glDisable(GL_SCISSOR_TEST);
|
||||||
#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_PRIMITIVE_RESTART
|
#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); }
|
if (bd->GlVersion >= 310) { if (last_enable_primitive_restart) glEnable(GL_PRIMITIVE_RESTART); else glDisable(GL_PRIMITIVE_RESTART); }
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef GL_POLYGON_MODE
|
#ifdef IMGUI_IMPL_HAS_POLYGON_MODE
|
||||||
glPolygonMode(GL_FRONT_AND_BACK, (GLenum)last_polygon_mode[0]);
|
glPolygonMode(GL_FRONT_AND_BACK, (GLenum)last_polygon_mode[0]);
|
||||||
#endif
|
#endif
|
||||||
glViewport(last_viewport[0], last_viewport[1], (GLsizei)last_viewport[2], (GLsizei)last_viewport[3]);
|
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]);
|
glScissor(last_scissor_box[0], last_scissor_box[1], (GLsizei)last_scissor_box[2], (GLsizei)last_scissor_box[3]);
|
||||||
|
(void)bd; // Not all compilation paths use this
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ImGui_ImplOpenGL3_CreateFontsTexture()
|
bool ImGui_ImplOpenGL3_CreateFontsTexture()
|
||||||
{
|
{
|
||||||
// Build texture atlas
|
|
||||||
ImGuiIO& io = ImGui::GetIO();
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
ImGui_ImplOpenGL3_Data* bd = ImGui_ImplOpenGL3_GetBackendData();
|
||||||
|
|
||||||
|
// Build texture atlas
|
||||||
unsigned char* pixels;
|
unsigned char* pixels;
|
||||||
int width, height;
|
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.
|
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
|
// Upload texture to graphics system
|
||||||
|
// (Bilinear sampling is required by default. Set 'io.Fonts->Flags |= ImFontAtlasFlags_NoBakedLines' or 'style.AntiAliasedLinesUseTex = false' to allow point/nearest sampling)
|
||||||
GLint last_texture;
|
GLint last_texture;
|
||||||
glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture);
|
glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture);
|
||||||
glGenTextures(1, &g_FontTexture);
|
glGenTextures(1, &bd->FontTexture);
|
||||||
glBindTexture(GL_TEXTURE_2D, g_FontTexture);
|
glBindTexture(GL_TEXTURE_2D, bd->FontTexture);
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||||
#ifdef GL_UNPACK_ROW_LENGTH
|
#ifdef GL_UNPACK_ROW_LENGTH // Not on WebGL/ES
|
||||||
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
|
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
|
||||||
#endif
|
#endif
|
||||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
|
||||||
|
|
||||||
// Store our identifier
|
// Store our identifier
|
||||||
io.Fonts->SetTexID((ImTextureID)(intptr_t)g_FontTexture);
|
io.Fonts->SetTexID((ImTextureID)(intptr_t)bd->FontTexture);
|
||||||
|
|
||||||
// Restore state
|
// Restore state
|
||||||
glBindTexture(GL_TEXTURE_2D, last_texture);
|
glBindTexture(GL_TEXTURE_2D, last_texture);
|
||||||
|
@ -508,23 +623,25 @@ bool ImGui_ImplOpenGL3_CreateFontsTexture()
|
||||||
|
|
||||||
void ImGui_ImplOpenGL3_DestroyFontsTexture()
|
void ImGui_ImplOpenGL3_DestroyFontsTexture()
|
||||||
{
|
{
|
||||||
if (g_FontTexture)
|
|
||||||
{
|
|
||||||
ImGuiIO& io = ImGui::GetIO();
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
glDeleteTextures(1, &g_FontTexture);
|
ImGui_ImplOpenGL3_Data* bd = ImGui_ImplOpenGL3_GetBackendData();
|
||||||
|
if (bd->FontTexture)
|
||||||
|
{
|
||||||
|
glDeleteTextures(1, &bd->FontTexture);
|
||||||
io.Fonts->SetTexID(0);
|
io.Fonts->SetTexID(0);
|
||||||
g_FontTexture = 0;
|
bd->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.
|
// 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)
|
static bool CheckShader(GLuint handle, const char* desc)
|
||||||
{
|
{
|
||||||
|
ImGui_ImplOpenGL3_Data* bd = ImGui_ImplOpenGL3_GetBackendData();
|
||||||
GLint status = 0, log_length = 0;
|
GLint status = 0, log_length = 0;
|
||||||
glGetShaderiv(handle, GL_COMPILE_STATUS, &status);
|
glGetShaderiv(handle, GL_COMPILE_STATUS, &status);
|
||||||
glGetShaderiv(handle, GL_INFO_LOG_LENGTH, &log_length);
|
glGetShaderiv(handle, GL_INFO_LOG_LENGTH, &log_length);
|
||||||
if ((GLboolean)status == GL_FALSE)
|
if ((GLboolean)status == GL_FALSE)
|
||||||
fprintf(stderr, "ERROR: ImGui_ImplOpenGL3_CreateDeviceObjects: failed to compile %s!\n", desc);
|
fprintf(stderr, "ERROR: ImGui_ImplOpenGL3_CreateDeviceObjects: failed to compile %s! With GLSL: %s\n", desc, bd->GlslVersionString);
|
||||||
if (log_length > 1)
|
if (log_length > 1)
|
||||||
{
|
{
|
||||||
ImVector<char> buf;
|
ImVector<char> buf;
|
||||||
|
@ -538,11 +655,12 @@ static bool CheckShader(GLuint handle, const char* desc)
|
||||||
// If you get an error please report on GitHub. You may try different GL context version or GLSL version.
|
// 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)
|
static bool CheckProgram(GLuint handle, const char* desc)
|
||||||
{
|
{
|
||||||
|
ImGui_ImplOpenGL3_Data* bd = ImGui_ImplOpenGL3_GetBackendData();
|
||||||
GLint status = 0, log_length = 0;
|
GLint status = 0, log_length = 0;
|
||||||
glGetProgramiv(handle, GL_LINK_STATUS, &status);
|
glGetProgramiv(handle, GL_LINK_STATUS, &status);
|
||||||
glGetProgramiv(handle, GL_INFO_LOG_LENGTH, &log_length);
|
glGetProgramiv(handle, GL_INFO_LOG_LENGTH, &log_length);
|
||||||
if ((GLboolean)status == GL_FALSE)
|
if ((GLboolean)status == GL_FALSE)
|
||||||
fprintf(stderr, "ERROR: ImGui_ImplOpenGL3_CreateDeviceObjects: failed to link %s! (with GLSL '%s')\n", desc, g_GlslVersionString);
|
fprintf(stderr, "ERROR: ImGui_ImplOpenGL3_CreateDeviceObjects: failed to link %s! With GLSL %s\n", desc, bd->GlslVersionString);
|
||||||
if (log_length > 1)
|
if (log_length > 1)
|
||||||
{
|
{
|
||||||
ImVector<char> buf;
|
ImVector<char> buf;
|
||||||
|
@ -555,18 +673,20 @@ static bool CheckProgram(GLuint handle, const char* desc)
|
||||||
|
|
||||||
bool ImGui_ImplOpenGL3_CreateDeviceObjects()
|
bool ImGui_ImplOpenGL3_CreateDeviceObjects()
|
||||||
{
|
{
|
||||||
|
ImGui_ImplOpenGL3_Data* bd = ImGui_ImplOpenGL3_GetBackendData();
|
||||||
|
|
||||||
// Backup GL state
|
// Backup GL state
|
||||||
GLint last_texture, last_array_buffer;
|
GLint last_texture, last_array_buffer;
|
||||||
glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture);
|
glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture);
|
||||||
glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &last_array_buffer);
|
glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &last_array_buffer);
|
||||||
#ifndef IMGUI_IMPL_OPENGL_ES2
|
#ifdef IMGUI_IMPL_OPENGL_USE_VERTEX_ARRAY
|
||||||
GLint last_vertex_array;
|
GLint last_vertex_array;
|
||||||
glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &last_vertex_array);
|
glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &last_vertex_array);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Parse GLSL version string
|
// Parse GLSL version string
|
||||||
int glsl_version = 130;
|
int glsl_version = 130;
|
||||||
sscanf(g_GlslVersionString, "#version %d", &glsl_version);
|
sscanf(bd->GlslVersionString, "#version %d", &glsl_version);
|
||||||
|
|
||||||
const GLchar* vertex_shader_glsl_120 =
|
const GLchar* vertex_shader_glsl_120 =
|
||||||
"uniform mat4 ProjMtx;\n"
|
"uniform mat4 ProjMtx;\n"
|
||||||
|
@ -597,7 +717,7 @@ bool ImGui_ImplOpenGL3_CreateDeviceObjects()
|
||||||
"}\n";
|
"}\n";
|
||||||
|
|
||||||
const GLchar* vertex_shader_glsl_300_es =
|
const GLchar* vertex_shader_glsl_300_es =
|
||||||
"precision mediump float;\n"
|
"precision highp float;\n"
|
||||||
"layout (location = 0) in vec2 Position;\n"
|
"layout (location = 0) in vec2 Position;\n"
|
||||||
"layout (location = 1) in vec2 UV;\n"
|
"layout (location = 1) in vec2 UV;\n"
|
||||||
"layout (location = 2) in vec4 Color;\n"
|
"layout (location = 2) in vec4 Color;\n"
|
||||||
|
@ -693,40 +813,46 @@ bool ImGui_ImplOpenGL3_CreateDeviceObjects()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create shaders
|
// Create shaders
|
||||||
const GLchar* vertex_shader_with_version[2] = { g_GlslVersionString, vertex_shader };
|
const GLchar* vertex_shader_with_version[2] = { bd->GlslVersionString, vertex_shader };
|
||||||
g_VertHandle = glCreateShader(GL_VERTEX_SHADER);
|
GLuint vert_handle = glCreateShader(GL_VERTEX_SHADER);
|
||||||
glShaderSource(g_VertHandle, 2, vertex_shader_with_version, NULL);
|
glShaderSource(vert_handle, 2, vertex_shader_with_version, NULL);
|
||||||
glCompileShader(g_VertHandle);
|
glCompileShader(vert_handle);
|
||||||
CheckShader(g_VertHandle, "vertex shader");
|
CheckShader(vert_handle, "vertex shader");
|
||||||
|
|
||||||
const GLchar* fragment_shader_with_version[2] = { g_GlslVersionString, fragment_shader };
|
const GLchar* fragment_shader_with_version[2] = { bd->GlslVersionString, fragment_shader };
|
||||||
g_FragHandle = glCreateShader(GL_FRAGMENT_SHADER);
|
GLuint frag_handle = glCreateShader(GL_FRAGMENT_SHADER);
|
||||||
glShaderSource(g_FragHandle, 2, fragment_shader_with_version, NULL);
|
glShaderSource(frag_handle, 2, fragment_shader_with_version, NULL);
|
||||||
glCompileShader(g_FragHandle);
|
glCompileShader(frag_handle);
|
||||||
CheckShader(g_FragHandle, "fragment shader");
|
CheckShader(frag_handle, "fragment shader");
|
||||||
|
|
||||||
g_ShaderHandle = glCreateProgram();
|
// Link
|
||||||
glAttachShader(g_ShaderHandle, g_VertHandle);
|
bd->ShaderHandle = glCreateProgram();
|
||||||
glAttachShader(g_ShaderHandle, g_FragHandle);
|
glAttachShader(bd->ShaderHandle, vert_handle);
|
||||||
glLinkProgram(g_ShaderHandle);
|
glAttachShader(bd->ShaderHandle, frag_handle);
|
||||||
CheckProgram(g_ShaderHandle, "shader program");
|
glLinkProgram(bd->ShaderHandle);
|
||||||
|
CheckProgram(bd->ShaderHandle, "shader program");
|
||||||
|
|
||||||
g_AttribLocationTex = glGetUniformLocation(g_ShaderHandle, "Texture");
|
glDetachShader(bd->ShaderHandle, vert_handle);
|
||||||
g_AttribLocationProjMtx = glGetUniformLocation(g_ShaderHandle, "ProjMtx");
|
glDetachShader(bd->ShaderHandle, frag_handle);
|
||||||
g_AttribLocationVtxPos = (GLuint)glGetAttribLocation(g_ShaderHandle, "Position");
|
glDeleteShader(vert_handle);
|
||||||
g_AttribLocationVtxUV = (GLuint)glGetAttribLocation(g_ShaderHandle, "UV");
|
glDeleteShader(frag_handle);
|
||||||
g_AttribLocationVtxColor = (GLuint)glGetAttribLocation(g_ShaderHandle, "Color");
|
|
||||||
|
bd->AttribLocationTex = glGetUniformLocation(bd->ShaderHandle, "Texture");
|
||||||
|
bd->AttribLocationProjMtx = glGetUniformLocation(bd->ShaderHandle, "ProjMtx");
|
||||||
|
bd->AttribLocationVtxPos = (GLuint)glGetAttribLocation(bd->ShaderHandle, "Position");
|
||||||
|
bd->AttribLocationVtxUV = (GLuint)glGetAttribLocation(bd->ShaderHandle, "UV");
|
||||||
|
bd->AttribLocationVtxColor = (GLuint)glGetAttribLocation(bd->ShaderHandle, "Color");
|
||||||
|
|
||||||
// Create buffers
|
// Create buffers
|
||||||
glGenBuffers(1, &g_VboHandle);
|
glGenBuffers(1, &bd->VboHandle);
|
||||||
glGenBuffers(1, &g_ElementsHandle);
|
glGenBuffers(1, &bd->ElementsHandle);
|
||||||
|
|
||||||
ImGui_ImplOpenGL3_CreateFontsTexture();
|
ImGui_ImplOpenGL3_CreateFontsTexture();
|
||||||
|
|
||||||
// Restore modified GL state
|
// Restore modified GL state
|
||||||
glBindTexture(GL_TEXTURE_2D, last_texture);
|
glBindTexture(GL_TEXTURE_2D, last_texture);
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, last_array_buffer);
|
glBindBuffer(GL_ARRAY_BUFFER, last_array_buffer);
|
||||||
#ifndef IMGUI_IMPL_OPENGL_ES2
|
#ifdef IMGUI_IMPL_OPENGL_USE_VERTEX_ARRAY
|
||||||
glBindVertexArray(last_vertex_array);
|
glBindVertexArray(last_vertex_array);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -735,13 +861,13 @@ bool ImGui_ImplOpenGL3_CreateDeviceObjects()
|
||||||
|
|
||||||
void ImGui_ImplOpenGL3_DestroyDeviceObjects()
|
void ImGui_ImplOpenGL3_DestroyDeviceObjects()
|
||||||
{
|
{
|
||||||
if (g_VboHandle) { glDeleteBuffers(1, &g_VboHandle); g_VboHandle = 0; }
|
ImGui_ImplOpenGL3_Data* bd = ImGui_ImplOpenGL3_GetBackendData();
|
||||||
if (g_ElementsHandle) { glDeleteBuffers(1, &g_ElementsHandle); g_ElementsHandle = 0; }
|
if (bd->VboHandle) { glDeleteBuffers(1, &bd->VboHandle); bd->VboHandle = 0; }
|
||||||
if (g_ShaderHandle && g_VertHandle) { glDetachShader(g_ShaderHandle, g_VertHandle); }
|
if (bd->ElementsHandle) { glDeleteBuffers(1, &bd->ElementsHandle); bd->ElementsHandle = 0; }
|
||||||
if (g_ShaderHandle && g_FragHandle) { glDetachShader(g_ShaderHandle, g_FragHandle); }
|
if (bd->ShaderHandle) { glDeleteProgram(bd->ShaderHandle); bd->ShaderHandle = 0; }
|
||||||
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();
|
ImGui_ImplOpenGL3_DestroyFontsTexture();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined(__clang__)
|
||||||
|
#pragma clang diagnostic pop
|
||||||
|
#endif
|
|
@ -12,11 +12,6 @@
|
||||||
// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
|
// 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
|
// 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:
|
// About GLSL version:
|
||||||
// The 'glsl_version' initialization parameter should be NULL (default) or a "#version XXX" string.
|
// 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"
|
// On computer platform the GLSL version default to "#version 130". On OpenGL ES 3 platform it defaults to "#version 300 es"
|
||||||
|
@ -41,48 +36,20 @@ IMGUI_IMPL_API void ImGui_ImplOpenGL3_DestroyDeviceObjects();
|
||||||
//#define IMGUI_IMPL_OPENGL_ES2 // Auto-detected on Emscripten
|
//#define IMGUI_IMPL_OPENGL_ES2 // Auto-detected on Emscripten
|
||||||
//#define IMGUI_IMPL_OPENGL_ES3 // Auto-detected on iOS/Android
|
//#define IMGUI_IMPL_OPENGL_ES3 // Auto-detected on iOS/Android
|
||||||
|
|
||||||
// Attempt to auto-detect the default Desktop GL loader based on available header files.
|
// You can explicitly select GLES2 or GLES3 API by using one of the '#define IMGUI_IMPL_OPENGL_LOADER_XXX' in imconfig.h or compiler command-line.
|
||||||
// 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) \
|
#if !defined(IMGUI_IMPL_OPENGL_ES2) \
|
||||||
&& !defined(IMGUI_IMPL_OPENGL_ES3) \
|
&& !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
|
// Try to detect GLES on matching platforms
|
||||||
#if defined(__APPLE__)
|
#if defined(__APPLE__)
|
||||||
#include "TargetConditionals.h"
|
#include <TargetConditionals.h>
|
||||||
#endif
|
#endif
|
||||||
#if (defined(__APPLE__) && (TARGET_OS_IOS || TARGET_OS_TV)) || (defined(__ANDROID__))
|
#if (defined(__APPLE__) && (TARGET_OS_IOS || TARGET_OS_TV)) || (defined(__ANDROID__))
|
||||||
#define IMGUI_IMPL_OPENGL_ES3 // iOS, Android -> GL ES 3, "#version 300 es"
|
#define IMGUI_IMPL_OPENGL_ES3 // iOS, Android -> GL ES 3, "#version 300 es"
|
||||||
#elif defined(__EMSCRIPTEN__)
|
#elif defined(__EMSCRIPTEN__) || defined(__amigaos4__)
|
||||||
#define IMGUI_IMPL_OPENGL_ES2 // Emscripten -> GL ES 2, "#version 100"
|
#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
|
#else
|
||||||
#error "Cannot detect OpenGL loader!"
|
// Otherwise imgui_impl_opengl3_loader.h will be used.
|
||||||
#endif
|
|
||||||
#else
|
|
||||||
#define IMGUI_IMPL_OPENGL_LOADER_GL3W // Default to GL3W embedded in our repository
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
|
@ -0,0 +1,786 @@
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// About imgui_impl_opengl3_loader.h:
|
||||||
|
//
|
||||||
|
// We embed our own OpenGL loader to not require user to provide their own or to have to use ours,
|
||||||
|
// which proved to be endless problems for users.
|
||||||
|
// Our loader is custom-generated, based on gl3w but automatically filtered to only include
|
||||||
|
// enums/functions that we use in our imgui_impl_opengl3.cpp source file in order to be small.
|
||||||
|
//
|
||||||
|
// YOU SHOULD NOT NEED TO INCLUDE/USE THIS DIRECTLY. THIS IS USED BY imgui_impl_opengl3.cpp ONLY.
|
||||||
|
// THE REST OF YOUR APP SHOULD USE A DIFFERENT GL LOADER: ANY GL LOADER OF YOUR CHOICE.
|
||||||
|
//
|
||||||
|
// Regenerate with:
|
||||||
|
// python gl3w_gen.py --output ../imgui/backends/imgui_impl_opengl3_loader.h --ref ../imgui/backends/imgui_impl_opengl3.cpp ./extra_symbols.txt
|
||||||
|
//
|
||||||
|
// More info:
|
||||||
|
// https://github.com/dearimgui/gl3w_stripped
|
||||||
|
// https://github.com/ocornut/imgui/issues/4445
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file was generated with gl3w_gen.py, part of imgl3w
|
||||||
|
* (hosted at https://github.com/dearimgui/gl3w_stripped)
|
||||||
|
*
|
||||||
|
* This is free and unencumbered software released into the public domain.
|
||||||
|
*
|
||||||
|
* Anyone is free to copy, modify, publish, use, compile, sell, or
|
||||||
|
* distribute this software, either in source code form or as a compiled
|
||||||
|
* binary, for any purpose, commercial or non-commercial, and by any
|
||||||
|
* means.
|
||||||
|
*
|
||||||
|
* In jurisdictions that recognize copyright laws, the author or authors
|
||||||
|
* of this software dedicate any and all copyright interest in the
|
||||||
|
* software to the public domain. We make this dedication for the benefit
|
||||||
|
* of the public at large and to the detriment of our heirs and
|
||||||
|
* successors. We intend this dedication to be an overt act of
|
||||||
|
* relinquishment in perpetuity of all present and future rights to this
|
||||||
|
* software under copyright law.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
|
* IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||||
|
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||||
|
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||||
|
* OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __gl3w_h_
|
||||||
|
#define __gl3w_h_
|
||||||
|
|
||||||
|
// Adapted from KHR/khrplatform.h to avoid including entire file.
|
||||||
|
#ifndef __khrplatform_h_
|
||||||
|
typedef float khronos_float_t;
|
||||||
|
typedef signed char khronos_int8_t;
|
||||||
|
typedef unsigned char khronos_uint8_t;
|
||||||
|
typedef signed short int khronos_int16_t;
|
||||||
|
typedef unsigned short int khronos_uint16_t;
|
||||||
|
#ifdef _WIN64
|
||||||
|
typedef signed long long int khronos_intptr_t;
|
||||||
|
typedef signed long long int khronos_ssize_t;
|
||||||
|
#else
|
||||||
|
typedef signed long int khronos_intptr_t;
|
||||||
|
typedef signed long int khronos_ssize_t;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(_MSC_VER) && !defined(__clang__)
|
||||||
|
typedef signed __int64 khronos_int64_t;
|
||||||
|
typedef unsigned __int64 khronos_uint64_t;
|
||||||
|
#elif (defined(__clang__) || defined(__GNUC__)) && (__cplusplus < 201100)
|
||||||
|
#include <stdint.h>
|
||||||
|
typedef int64_t khronos_int64_t;
|
||||||
|
typedef uint64_t khronos_uint64_t;
|
||||||
|
#else
|
||||||
|
typedef signed long long khronos_int64_t;
|
||||||
|
typedef unsigned long long khronos_uint64_t;
|
||||||
|
#endif
|
||||||
|
#endif // __khrplatform_h_
|
||||||
|
|
||||||
|
#ifndef __gl_glcorearb_h_
|
||||||
|
#define __gl_glcorearb_h_ 1
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
/*
|
||||||
|
** Copyright 2013-2020 The Khronos Group Inc.
|
||||||
|
** SPDX-License-Identifier: MIT
|
||||||
|
**
|
||||||
|
** This header is generated from the Khronos OpenGL / OpenGL ES XML
|
||||||
|
** API Registry. The current version of the Registry, generator scripts
|
||||||
|
** used to make the header, and the header can be found at
|
||||||
|
** https://github.com/KhronosGroup/OpenGL-Registry
|
||||||
|
*/
|
||||||
|
#if defined(_WIN32) && !defined(APIENTRY) && !defined(__CYGWIN__) && !defined(__SCITECH_SNAP__)
|
||||||
|
#ifndef WIN32_LEAN_AND_MEAN
|
||||||
|
#define WIN32_LEAN_AND_MEAN 1
|
||||||
|
#endif
|
||||||
|
#include <windows.h>
|
||||||
|
#endif
|
||||||
|
#ifndef APIENTRY
|
||||||
|
#define APIENTRY
|
||||||
|
#endif
|
||||||
|
#ifndef APIENTRYP
|
||||||
|
#define APIENTRYP APIENTRY *
|
||||||
|
#endif
|
||||||
|
#ifndef GLAPI
|
||||||
|
#define GLAPI extern
|
||||||
|
#endif
|
||||||
|
/* glcorearb.h is for use with OpenGL core profile implementations.
|
||||||
|
** It should should be placed in the same directory as gl.h and
|
||||||
|
** included as <GL/glcorearb.h>.
|
||||||
|
**
|
||||||
|
** glcorearb.h includes only APIs in the latest OpenGL core profile
|
||||||
|
** implementation together with APIs in newer ARB extensions which
|
||||||
|
** can be supported by the core profile. It does not, and never will
|
||||||
|
** include functionality removed from the core profile, such as
|
||||||
|
** fixed-function vertex and fragment processing.
|
||||||
|
**
|
||||||
|
** Do not #include both <GL/glcorearb.h> and either of <GL/gl.h> or
|
||||||
|
** <GL/glext.h> in the same source file.
|
||||||
|
*/
|
||||||
|
/* Generated C header for:
|
||||||
|
* API: gl
|
||||||
|
* Profile: core
|
||||||
|
* Versions considered: .*
|
||||||
|
* Versions emitted: .*
|
||||||
|
* Default extensions included: glcore
|
||||||
|
* Additional extensions included: _nomatch_^
|
||||||
|
* Extensions removed: _nomatch_^
|
||||||
|
*/
|
||||||
|
#ifndef GL_VERSION_1_0
|
||||||
|
typedef void GLvoid;
|
||||||
|
typedef unsigned int GLenum;
|
||||||
|
|
||||||
|
typedef khronos_float_t GLfloat;
|
||||||
|
typedef int GLint;
|
||||||
|
typedef int GLsizei;
|
||||||
|
typedef unsigned int GLbitfield;
|
||||||
|
typedef double GLdouble;
|
||||||
|
typedef unsigned int GLuint;
|
||||||
|
typedef unsigned char GLboolean;
|
||||||
|
typedef khronos_uint8_t GLubyte;
|
||||||
|
#define GL_COLOR_BUFFER_BIT 0x00004000
|
||||||
|
#define GL_FALSE 0
|
||||||
|
#define GL_TRUE 1
|
||||||
|
#define GL_TRIANGLES 0x0004
|
||||||
|
#define GL_ONE 1
|
||||||
|
#define GL_SRC_ALPHA 0x0302
|
||||||
|
#define GL_ONE_MINUS_SRC_ALPHA 0x0303
|
||||||
|
#define GL_FRONT_AND_BACK 0x0408
|
||||||
|
#define GL_POLYGON_MODE 0x0B40
|
||||||
|
#define GL_CULL_FACE 0x0B44
|
||||||
|
#define GL_DEPTH_TEST 0x0B71
|
||||||
|
#define GL_STENCIL_TEST 0x0B90
|
||||||
|
#define GL_VIEWPORT 0x0BA2
|
||||||
|
#define GL_BLEND 0x0BE2
|
||||||
|
#define GL_SCISSOR_BOX 0x0C10
|
||||||
|
#define GL_SCISSOR_TEST 0x0C11
|
||||||
|
#define GL_UNPACK_ROW_LENGTH 0x0CF2
|
||||||
|
#define GL_PACK_ALIGNMENT 0x0D05
|
||||||
|
#define GL_TEXTURE_2D 0x0DE1
|
||||||
|
#define GL_UNSIGNED_BYTE 0x1401
|
||||||
|
#define GL_UNSIGNED_SHORT 0x1403
|
||||||
|
#define GL_UNSIGNED_INT 0x1405
|
||||||
|
#define GL_FLOAT 0x1406
|
||||||
|
#define GL_RGBA 0x1908
|
||||||
|
#define GL_FILL 0x1B02
|
||||||
|
#define GL_VENDOR 0x1F00
|
||||||
|
#define GL_RENDERER 0x1F01
|
||||||
|
#define GL_VERSION 0x1F02
|
||||||
|
#define GL_EXTENSIONS 0x1F03
|
||||||
|
#define GL_LINEAR 0x2601
|
||||||
|
#define GL_TEXTURE_MAG_FILTER 0x2800
|
||||||
|
#define GL_TEXTURE_MIN_FILTER 0x2801
|
||||||
|
typedef void (APIENTRYP PFNGLPOLYGONMODEPROC) (GLenum face, GLenum mode);
|
||||||
|
typedef void (APIENTRYP PFNGLSCISSORPROC) (GLint x, GLint y, GLsizei width, GLsizei height);
|
||||||
|
typedef void (APIENTRYP PFNGLTEXPARAMETERIPROC) (GLenum target, GLenum pname, GLint param);
|
||||||
|
typedef void (APIENTRYP PFNGLTEXIMAGE2DPROC) (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void *pixels);
|
||||||
|
typedef void (APIENTRYP PFNGLCLEARPROC) (GLbitfield mask);
|
||||||
|
typedef void (APIENTRYP PFNGLCLEARCOLORPROC) (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha);
|
||||||
|
typedef void (APIENTRYP PFNGLDISABLEPROC) (GLenum cap);
|
||||||
|
typedef void (APIENTRYP PFNGLENABLEPROC) (GLenum cap);
|
||||||
|
typedef void (APIENTRYP PFNGLFLUSHPROC) (void);
|
||||||
|
typedef void (APIENTRYP PFNGLPIXELSTOREIPROC) (GLenum pname, GLint param);
|
||||||
|
typedef void (APIENTRYP PFNGLREADPIXELSPROC) (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void *pixels);
|
||||||
|
typedef GLenum (APIENTRYP PFNGLGETERRORPROC) (void);
|
||||||
|
typedef void (APIENTRYP PFNGLGETINTEGERVPROC) (GLenum pname, GLint *data);
|
||||||
|
typedef const GLubyte *(APIENTRYP PFNGLGETSTRINGPROC) (GLenum name);
|
||||||
|
typedef GLboolean (APIENTRYP PFNGLISENABLEDPROC) (GLenum cap);
|
||||||
|
typedef void (APIENTRYP PFNGLVIEWPORTPROC) (GLint x, GLint y, GLsizei width, GLsizei height);
|
||||||
|
#ifdef GL_GLEXT_PROTOTYPES
|
||||||
|
GLAPI void APIENTRY glPolygonMode (GLenum face, GLenum mode);
|
||||||
|
GLAPI void APIENTRY glScissor (GLint x, GLint y, GLsizei width, GLsizei height);
|
||||||
|
GLAPI void APIENTRY glTexParameteri (GLenum target, GLenum pname, GLint param);
|
||||||
|
GLAPI void APIENTRY glTexImage2D (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void *pixels);
|
||||||
|
GLAPI void APIENTRY glClear (GLbitfield mask);
|
||||||
|
GLAPI void APIENTRY glClearColor (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha);
|
||||||
|
GLAPI void APIENTRY glDisable (GLenum cap);
|
||||||
|
GLAPI void APIENTRY glEnable (GLenum cap);
|
||||||
|
GLAPI void APIENTRY glFlush (void);
|
||||||
|
GLAPI void APIENTRY glPixelStorei (GLenum pname, GLint param);
|
||||||
|
GLAPI void APIENTRY glReadPixels (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void *pixels);
|
||||||
|
GLAPI GLenum APIENTRY glGetError (void);
|
||||||
|
GLAPI void APIENTRY glGetIntegerv (GLenum pname, GLint *data);
|
||||||
|
GLAPI const GLubyte *APIENTRY glGetString (GLenum name);
|
||||||
|
GLAPI GLboolean APIENTRY glIsEnabled (GLenum cap);
|
||||||
|
GLAPI void APIENTRY glViewport (GLint x, GLint y, GLsizei width, GLsizei height);
|
||||||
|
#endif
|
||||||
|
#endif /* GL_VERSION_1_0 */
|
||||||
|
#ifndef GL_VERSION_1_1
|
||||||
|
typedef khronos_float_t GLclampf;
|
||||||
|
typedef double GLclampd;
|
||||||
|
#define GL_TEXTURE_BINDING_2D 0x8069
|
||||||
|
typedef void (APIENTRYP PFNGLDRAWELEMENTSPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices);
|
||||||
|
typedef void (APIENTRYP PFNGLBINDTEXTUREPROC) (GLenum target, GLuint texture);
|
||||||
|
typedef void (APIENTRYP PFNGLDELETETEXTURESPROC) (GLsizei n, const GLuint *textures);
|
||||||
|
typedef void (APIENTRYP PFNGLGENTEXTURESPROC) (GLsizei n, GLuint *textures);
|
||||||
|
#ifdef GL_GLEXT_PROTOTYPES
|
||||||
|
GLAPI void APIENTRY glDrawElements (GLenum mode, GLsizei count, GLenum type, const void *indices);
|
||||||
|
GLAPI void APIENTRY glBindTexture (GLenum target, GLuint texture);
|
||||||
|
GLAPI void APIENTRY glDeleteTextures (GLsizei n, const GLuint *textures);
|
||||||
|
GLAPI void APIENTRY glGenTextures (GLsizei n, GLuint *textures);
|
||||||
|
#endif
|
||||||
|
#endif /* GL_VERSION_1_1 */
|
||||||
|
#ifndef GL_VERSION_1_3
|
||||||
|
#define GL_TEXTURE0 0x84C0
|
||||||
|
#define GL_ACTIVE_TEXTURE 0x84E0
|
||||||
|
typedef void (APIENTRYP PFNGLACTIVETEXTUREPROC) (GLenum texture);
|
||||||
|
#ifdef GL_GLEXT_PROTOTYPES
|
||||||
|
GLAPI void APIENTRY glActiveTexture (GLenum texture);
|
||||||
|
#endif
|
||||||
|
#endif /* GL_VERSION_1_3 */
|
||||||
|
#ifndef GL_VERSION_1_4
|
||||||
|
#define GL_BLEND_DST_RGB 0x80C8
|
||||||
|
#define GL_BLEND_SRC_RGB 0x80C9
|
||||||
|
#define GL_BLEND_DST_ALPHA 0x80CA
|
||||||
|
#define GL_BLEND_SRC_ALPHA 0x80CB
|
||||||
|
#define GL_FUNC_ADD 0x8006
|
||||||
|
typedef void (APIENTRYP PFNGLBLENDFUNCSEPARATEPROC) (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha);
|
||||||
|
typedef void (APIENTRYP PFNGLBLENDEQUATIONPROC) (GLenum mode);
|
||||||
|
#ifdef GL_GLEXT_PROTOTYPES
|
||||||
|
GLAPI void APIENTRY glBlendFuncSeparate (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha);
|
||||||
|
GLAPI void APIENTRY glBlendEquation (GLenum mode);
|
||||||
|
#endif
|
||||||
|
#endif /* GL_VERSION_1_4 */
|
||||||
|
#ifndef GL_VERSION_1_5
|
||||||
|
typedef khronos_ssize_t GLsizeiptr;
|
||||||
|
typedef khronos_intptr_t GLintptr;
|
||||||
|
#define GL_ARRAY_BUFFER 0x8892
|
||||||
|
#define GL_ELEMENT_ARRAY_BUFFER 0x8893
|
||||||
|
#define GL_ARRAY_BUFFER_BINDING 0x8894
|
||||||
|
#define GL_ELEMENT_ARRAY_BUFFER_BINDING 0x8895
|
||||||
|
#define GL_STREAM_DRAW 0x88E0
|
||||||
|
typedef void (APIENTRYP PFNGLBINDBUFFERPROC) (GLenum target, GLuint buffer);
|
||||||
|
typedef void (APIENTRYP PFNGLDELETEBUFFERSPROC) (GLsizei n, const GLuint *buffers);
|
||||||
|
typedef void (APIENTRYP PFNGLGENBUFFERSPROC) (GLsizei n, GLuint *buffers);
|
||||||
|
typedef void (APIENTRYP PFNGLBUFFERDATAPROC) (GLenum target, GLsizeiptr size, const void *data, GLenum usage);
|
||||||
|
typedef void (APIENTRYP PFNGLBUFFERSUBDATAPROC) (GLenum target, GLintptr offset, GLsizeiptr size, const void *data);
|
||||||
|
#ifdef GL_GLEXT_PROTOTYPES
|
||||||
|
GLAPI void APIENTRY glBindBuffer (GLenum target, GLuint buffer);
|
||||||
|
GLAPI void APIENTRY glDeleteBuffers (GLsizei n, const GLuint *buffers);
|
||||||
|
GLAPI void APIENTRY glGenBuffers (GLsizei n, GLuint *buffers);
|
||||||
|
GLAPI void APIENTRY glBufferData (GLenum target, GLsizeiptr size, const void *data, GLenum usage);
|
||||||
|
GLAPI void APIENTRY glBufferSubData (GLenum target, GLintptr offset, GLsizeiptr size, const void *data);
|
||||||
|
#endif
|
||||||
|
#endif /* GL_VERSION_1_5 */
|
||||||
|
#ifndef GL_VERSION_2_0
|
||||||
|
typedef char GLchar;
|
||||||
|
typedef khronos_int16_t GLshort;
|
||||||
|
typedef khronos_int8_t GLbyte;
|
||||||
|
typedef khronos_uint16_t GLushort;
|
||||||
|
#define GL_BLEND_EQUATION_RGB 0x8009
|
||||||
|
#define GL_VERTEX_ATTRIB_ARRAY_ENABLED 0x8622
|
||||||
|
#define GL_VERTEX_ATTRIB_ARRAY_SIZE 0x8623
|
||||||
|
#define GL_VERTEX_ATTRIB_ARRAY_STRIDE 0x8624
|
||||||
|
#define GL_VERTEX_ATTRIB_ARRAY_TYPE 0x8625
|
||||||
|
#define GL_VERTEX_ATTRIB_ARRAY_POINTER 0x8645
|
||||||
|
#define GL_BLEND_EQUATION_ALPHA 0x883D
|
||||||
|
#define GL_VERTEX_ATTRIB_ARRAY_NORMALIZED 0x886A
|
||||||
|
#define GL_FRAGMENT_SHADER 0x8B30
|
||||||
|
#define GL_VERTEX_SHADER 0x8B31
|
||||||
|
#define GL_COMPILE_STATUS 0x8B81
|
||||||
|
#define GL_LINK_STATUS 0x8B82
|
||||||
|
#define GL_INFO_LOG_LENGTH 0x8B84
|
||||||
|
#define GL_CURRENT_PROGRAM 0x8B8D
|
||||||
|
#define GL_UPPER_LEFT 0x8CA2
|
||||||
|
typedef void (APIENTRYP PFNGLBLENDEQUATIONSEPARATEPROC) (GLenum modeRGB, GLenum modeAlpha);
|
||||||
|
typedef void (APIENTRYP PFNGLATTACHSHADERPROC) (GLuint program, GLuint shader);
|
||||||
|
typedef void (APIENTRYP PFNGLCOMPILESHADERPROC) (GLuint shader);
|
||||||
|
typedef GLuint (APIENTRYP PFNGLCREATEPROGRAMPROC) (void);
|
||||||
|
typedef GLuint (APIENTRYP PFNGLCREATESHADERPROC) (GLenum type);
|
||||||
|
typedef void (APIENTRYP PFNGLDELETEPROGRAMPROC) (GLuint program);
|
||||||
|
typedef void (APIENTRYP PFNGLDELETESHADERPROC) (GLuint shader);
|
||||||
|
typedef void (APIENTRYP PFNGLDETACHSHADERPROC) (GLuint program, GLuint shader);
|
||||||
|
typedef void (APIENTRYP PFNGLDISABLEVERTEXATTRIBARRAYPROC) (GLuint index);
|
||||||
|
typedef void (APIENTRYP PFNGLENABLEVERTEXATTRIBARRAYPROC) (GLuint index);
|
||||||
|
typedef GLint (APIENTRYP PFNGLGETATTRIBLOCATIONPROC) (GLuint program, const GLchar *name);
|
||||||
|
typedef void (APIENTRYP PFNGLGETPROGRAMIVPROC) (GLuint program, GLenum pname, GLint *params);
|
||||||
|
typedef void (APIENTRYP PFNGLGETPROGRAMINFOLOGPROC) (GLuint program, GLsizei bufSize, GLsizei *length, GLchar *infoLog);
|
||||||
|
typedef void (APIENTRYP PFNGLGETSHADERIVPROC) (GLuint shader, GLenum pname, GLint *params);
|
||||||
|
typedef void (APIENTRYP PFNGLGETSHADERINFOLOGPROC) (GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *infoLog);
|
||||||
|
typedef GLint (APIENTRYP PFNGLGETUNIFORMLOCATIONPROC) (GLuint program, const GLchar *name);
|
||||||
|
typedef void (APIENTRYP PFNGLGETVERTEXATTRIBIVPROC) (GLuint index, GLenum pname, GLint *params);
|
||||||
|
typedef void (APIENTRYP PFNGLGETVERTEXATTRIBPOINTERVPROC) (GLuint index, GLenum pname, void **pointer);
|
||||||
|
typedef void (APIENTRYP PFNGLLINKPROGRAMPROC) (GLuint program);
|
||||||
|
typedef void (APIENTRYP PFNGLSHADERSOURCEPROC) (GLuint shader, GLsizei count, const GLchar *const*string, const GLint *length);
|
||||||
|
typedef void (APIENTRYP PFNGLUSEPROGRAMPROC) (GLuint program);
|
||||||
|
typedef void (APIENTRYP PFNGLUNIFORM1IPROC) (GLint location, GLint v0);
|
||||||
|
typedef void (APIENTRYP PFNGLUNIFORMMATRIX4FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
|
||||||
|
typedef void (APIENTRYP PFNGLVERTEXATTRIBPOINTERPROC) (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void *pointer);
|
||||||
|
#ifdef GL_GLEXT_PROTOTYPES
|
||||||
|
GLAPI void APIENTRY glBlendEquationSeparate (GLenum modeRGB, GLenum modeAlpha);
|
||||||
|
GLAPI void APIENTRY glAttachShader (GLuint program, GLuint shader);
|
||||||
|
GLAPI void APIENTRY glCompileShader (GLuint shader);
|
||||||
|
GLAPI GLuint APIENTRY glCreateProgram (void);
|
||||||
|
GLAPI GLuint APIENTRY glCreateShader (GLenum type);
|
||||||
|
GLAPI void APIENTRY glDeleteProgram (GLuint program);
|
||||||
|
GLAPI void APIENTRY glDeleteShader (GLuint shader);
|
||||||
|
GLAPI void APIENTRY glDetachShader (GLuint program, GLuint shader);
|
||||||
|
GLAPI void APIENTRY glDisableVertexAttribArray (GLuint index);
|
||||||
|
GLAPI void APIENTRY glEnableVertexAttribArray (GLuint index);
|
||||||
|
GLAPI GLint APIENTRY glGetAttribLocation (GLuint program, const GLchar *name);
|
||||||
|
GLAPI void APIENTRY glGetProgramiv (GLuint program, GLenum pname, GLint *params);
|
||||||
|
GLAPI void APIENTRY glGetProgramInfoLog (GLuint program, GLsizei bufSize, GLsizei *length, GLchar *infoLog);
|
||||||
|
GLAPI void APIENTRY glGetShaderiv (GLuint shader, GLenum pname, GLint *params);
|
||||||
|
GLAPI void APIENTRY glGetShaderInfoLog (GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *infoLog);
|
||||||
|
GLAPI GLint APIENTRY glGetUniformLocation (GLuint program, const GLchar *name);
|
||||||
|
GLAPI void APIENTRY glGetVertexAttribiv (GLuint index, GLenum pname, GLint *params);
|
||||||
|
GLAPI void APIENTRY glGetVertexAttribPointerv (GLuint index, GLenum pname, void **pointer);
|
||||||
|
GLAPI void APIENTRY glLinkProgram (GLuint program);
|
||||||
|
GLAPI void APIENTRY glShaderSource (GLuint shader, GLsizei count, const GLchar *const*string, const GLint *length);
|
||||||
|
GLAPI void APIENTRY glUseProgram (GLuint program);
|
||||||
|
GLAPI void APIENTRY glUniform1i (GLint location, GLint v0);
|
||||||
|
GLAPI void APIENTRY glUniformMatrix4fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
|
||||||
|
GLAPI void APIENTRY glVertexAttribPointer (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void *pointer);
|
||||||
|
#endif
|
||||||
|
#endif /* GL_VERSION_2_0 */
|
||||||
|
#ifndef GL_VERSION_3_0
|
||||||
|
typedef khronos_uint16_t GLhalf;
|
||||||
|
#define GL_MAJOR_VERSION 0x821B
|
||||||
|
#define GL_MINOR_VERSION 0x821C
|
||||||
|
#define GL_NUM_EXTENSIONS 0x821D
|
||||||
|
#define GL_FRAMEBUFFER_SRGB 0x8DB9
|
||||||
|
#define GL_VERTEX_ARRAY_BINDING 0x85B5
|
||||||
|
typedef void (APIENTRYP PFNGLGETBOOLEANI_VPROC) (GLenum target, GLuint index, GLboolean *data);
|
||||||
|
typedef void (APIENTRYP PFNGLGETINTEGERI_VPROC) (GLenum target, GLuint index, GLint *data);
|
||||||
|
typedef const GLubyte *(APIENTRYP PFNGLGETSTRINGIPROC) (GLenum name, GLuint index);
|
||||||
|
typedef void (APIENTRYP PFNGLBINDVERTEXARRAYPROC) (GLuint array);
|
||||||
|
typedef void (APIENTRYP PFNGLDELETEVERTEXARRAYSPROC) (GLsizei n, const GLuint *arrays);
|
||||||
|
typedef void (APIENTRYP PFNGLGENVERTEXARRAYSPROC) (GLsizei n, GLuint *arrays);
|
||||||
|
#ifdef GL_GLEXT_PROTOTYPES
|
||||||
|
GLAPI const GLubyte *APIENTRY glGetStringi (GLenum name, GLuint index);
|
||||||
|
GLAPI void APIENTRY glBindVertexArray (GLuint array);
|
||||||
|
GLAPI void APIENTRY glDeleteVertexArrays (GLsizei n, const GLuint *arrays);
|
||||||
|
GLAPI void APIENTRY glGenVertexArrays (GLsizei n, GLuint *arrays);
|
||||||
|
#endif
|
||||||
|
#endif /* GL_VERSION_3_0 */
|
||||||
|
#ifndef GL_VERSION_3_1
|
||||||
|
#define GL_VERSION_3_1 1
|
||||||
|
#define GL_PRIMITIVE_RESTART 0x8F9D
|
||||||
|
#endif /* GL_VERSION_3_1 */
|
||||||
|
#ifndef GL_VERSION_3_2
|
||||||
|
#define GL_VERSION_3_2 1
|
||||||
|
typedef struct __GLsync *GLsync;
|
||||||
|
typedef khronos_uint64_t GLuint64;
|
||||||
|
typedef khronos_int64_t GLint64;
|
||||||
|
typedef void (APIENTRYP PFNGLDRAWELEMENTSBASEVERTEXPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLint basevertex);
|
||||||
|
typedef void (APIENTRYP PFNGLGETINTEGER64I_VPROC) (GLenum target, GLuint index, GLint64 *data);
|
||||||
|
#ifdef GL_GLEXT_PROTOTYPES
|
||||||
|
GLAPI void APIENTRY glDrawElementsBaseVertex (GLenum mode, GLsizei count, GLenum type, const void *indices, GLint basevertex);
|
||||||
|
#endif
|
||||||
|
#endif /* GL_VERSION_3_2 */
|
||||||
|
#ifndef GL_VERSION_3_3
|
||||||
|
#define GL_VERSION_3_3 1
|
||||||
|
#define GL_SAMPLER_BINDING 0x8919
|
||||||
|
typedef void (APIENTRYP PFNGLBINDSAMPLERPROC) (GLuint unit, GLuint sampler);
|
||||||
|
#ifdef GL_GLEXT_PROTOTYPES
|
||||||
|
GLAPI void APIENTRY glBindSampler (GLuint unit, GLuint sampler);
|
||||||
|
#endif
|
||||||
|
#endif /* GL_VERSION_3_3 */
|
||||||
|
#ifndef GL_VERSION_4_1
|
||||||
|
typedef void (APIENTRYP PFNGLGETFLOATI_VPROC) (GLenum target, GLuint index, GLfloat *data);
|
||||||
|
typedef void (APIENTRYP PFNGLGETDOUBLEI_VPROC) (GLenum target, GLuint index, GLdouble *data);
|
||||||
|
#endif /* GL_VERSION_4_1 */
|
||||||
|
#ifndef GL_VERSION_4_3
|
||||||
|
typedef void (APIENTRY *GLDEBUGPROC)(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,const void *userParam);
|
||||||
|
#endif /* GL_VERSION_4_3 */
|
||||||
|
#ifndef GL_VERSION_4_5
|
||||||
|
#define GL_CLIP_ORIGIN 0x935C
|
||||||
|
typedef void (APIENTRYP PFNGLGETTRANSFORMFEEDBACKI_VPROC) (GLuint xfb, GLenum pname, GLuint index, GLint *param);
|
||||||
|
typedef void (APIENTRYP PFNGLGETTRANSFORMFEEDBACKI64_VPROC) (GLuint xfb, GLenum pname, GLuint index, GLint64 *param);
|
||||||
|
#endif /* GL_VERSION_4_5 */
|
||||||
|
#ifndef GL_ARB_bindless_texture
|
||||||
|
typedef khronos_uint64_t GLuint64EXT;
|
||||||
|
#endif /* GL_ARB_bindless_texture */
|
||||||
|
#ifndef GL_ARB_cl_event
|
||||||
|
struct _cl_context;
|
||||||
|
struct _cl_event;
|
||||||
|
#endif /* GL_ARB_cl_event */
|
||||||
|
#ifndef GL_ARB_clip_control
|
||||||
|
#define GL_ARB_clip_control 1
|
||||||
|
#endif /* GL_ARB_clip_control */
|
||||||
|
#ifndef GL_ARB_debug_output
|
||||||
|
typedef void (APIENTRY *GLDEBUGPROCARB)(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,const void *userParam);
|
||||||
|
#endif /* GL_ARB_debug_output */
|
||||||
|
#ifndef GL_EXT_EGL_image_storage
|
||||||
|
typedef void *GLeglImageOES;
|
||||||
|
#endif /* GL_EXT_EGL_image_storage */
|
||||||
|
#ifndef GL_EXT_direct_state_access
|
||||||
|
typedef void (APIENTRYP PFNGLGETFLOATI_VEXTPROC) (GLenum pname, GLuint index, GLfloat *params);
|
||||||
|
typedef void (APIENTRYP PFNGLGETDOUBLEI_VEXTPROC) (GLenum pname, GLuint index, GLdouble *params);
|
||||||
|
typedef void (APIENTRYP PFNGLGETPOINTERI_VEXTPROC) (GLenum pname, GLuint index, void **params);
|
||||||
|
typedef void (APIENTRYP PFNGLGETVERTEXARRAYINTEGERI_VEXTPROC) (GLuint vaobj, GLuint index, GLenum pname, GLint *param);
|
||||||
|
typedef void (APIENTRYP PFNGLGETVERTEXARRAYPOINTERI_VEXTPROC) (GLuint vaobj, GLuint index, GLenum pname, void **param);
|
||||||
|
#endif /* GL_EXT_direct_state_access */
|
||||||
|
#ifndef GL_NV_draw_vulkan_image
|
||||||
|
typedef void (APIENTRY *GLVULKANPROCNV)(void);
|
||||||
|
#endif /* GL_NV_draw_vulkan_image */
|
||||||
|
#ifndef GL_NV_gpu_shader5
|
||||||
|
typedef khronos_int64_t GLint64EXT;
|
||||||
|
#endif /* GL_NV_gpu_shader5 */
|
||||||
|
#ifndef GL_NV_vertex_buffer_unified_memory
|
||||||
|
typedef void (APIENTRYP PFNGLGETINTEGERUI64I_VNVPROC) (GLenum value, GLuint index, GLuint64EXT *result);
|
||||||
|
#endif /* GL_NV_vertex_buffer_unified_memory */
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef GL3W_API
|
||||||
|
#define GL3W_API
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef __gl_h_
|
||||||
|
#define __gl_h_
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define GL3W_OK 0
|
||||||
|
#define GL3W_ERROR_INIT -1
|
||||||
|
#define GL3W_ERROR_LIBRARY_OPEN -2
|
||||||
|
#define GL3W_ERROR_OPENGL_VERSION -3
|
||||||
|
|
||||||
|
typedef void (*GL3WglProc)(void);
|
||||||
|
typedef GL3WglProc (*GL3WGetProcAddressProc)(const char *proc);
|
||||||
|
|
||||||
|
/* gl3w api */
|
||||||
|
GL3W_API int imgl3wInit(void);
|
||||||
|
GL3W_API int imgl3wInit2(GL3WGetProcAddressProc proc);
|
||||||
|
GL3W_API int imgl3wIsSupported(int major, int minor);
|
||||||
|
GL3W_API GL3WglProc imgl3wGetProcAddress(const char *proc);
|
||||||
|
|
||||||
|
/* gl3w internal state */
|
||||||
|
union GL3WProcs {
|
||||||
|
GL3WglProc ptr[58];
|
||||||
|
struct {
|
||||||
|
PFNGLACTIVETEXTUREPROC ActiveTexture;
|
||||||
|
PFNGLATTACHSHADERPROC AttachShader;
|
||||||
|
PFNGLBINDBUFFERPROC BindBuffer;
|
||||||
|
PFNGLBINDSAMPLERPROC BindSampler;
|
||||||
|
PFNGLBINDTEXTUREPROC BindTexture;
|
||||||
|
PFNGLBINDVERTEXARRAYPROC BindVertexArray;
|
||||||
|
PFNGLBLENDEQUATIONPROC BlendEquation;
|
||||||
|
PFNGLBLENDEQUATIONSEPARATEPROC BlendEquationSeparate;
|
||||||
|
PFNGLBLENDFUNCSEPARATEPROC BlendFuncSeparate;
|
||||||
|
PFNGLBUFFERDATAPROC BufferData;
|
||||||
|
PFNGLBUFFERSUBDATAPROC BufferSubData;
|
||||||
|
PFNGLCLEARPROC Clear;
|
||||||
|
PFNGLCLEARCOLORPROC ClearColor;
|
||||||
|
PFNGLCOMPILESHADERPROC CompileShader;
|
||||||
|
PFNGLCREATEPROGRAMPROC CreateProgram;
|
||||||
|
PFNGLCREATESHADERPROC CreateShader;
|
||||||
|
PFNGLDELETEBUFFERSPROC DeleteBuffers;
|
||||||
|
PFNGLDELETEPROGRAMPROC DeleteProgram;
|
||||||
|
PFNGLDELETESHADERPROC DeleteShader;
|
||||||
|
PFNGLDELETETEXTURESPROC DeleteTextures;
|
||||||
|
PFNGLDELETEVERTEXARRAYSPROC DeleteVertexArrays;
|
||||||
|
PFNGLDETACHSHADERPROC DetachShader;
|
||||||
|
PFNGLDISABLEPROC Disable;
|
||||||
|
PFNGLDISABLEVERTEXATTRIBARRAYPROC DisableVertexAttribArray;
|
||||||
|
PFNGLDRAWELEMENTSPROC DrawElements;
|
||||||
|
PFNGLDRAWELEMENTSBASEVERTEXPROC DrawElementsBaseVertex;
|
||||||
|
PFNGLENABLEPROC Enable;
|
||||||
|
PFNGLENABLEVERTEXATTRIBARRAYPROC EnableVertexAttribArray;
|
||||||
|
PFNGLFLUSHPROC Flush;
|
||||||
|
PFNGLGENBUFFERSPROC GenBuffers;
|
||||||
|
PFNGLGENTEXTURESPROC GenTextures;
|
||||||
|
PFNGLGENVERTEXARRAYSPROC GenVertexArrays;
|
||||||
|
PFNGLGETATTRIBLOCATIONPROC GetAttribLocation;
|
||||||
|
PFNGLGETERRORPROC GetError;
|
||||||
|
PFNGLGETINTEGERVPROC GetIntegerv;
|
||||||
|
PFNGLGETPROGRAMINFOLOGPROC GetProgramInfoLog;
|
||||||
|
PFNGLGETPROGRAMIVPROC GetProgramiv;
|
||||||
|
PFNGLGETSHADERINFOLOGPROC GetShaderInfoLog;
|
||||||
|
PFNGLGETSHADERIVPROC GetShaderiv;
|
||||||
|
PFNGLGETSTRINGPROC GetString;
|
||||||
|
PFNGLGETSTRINGIPROC GetStringi;
|
||||||
|
PFNGLGETUNIFORMLOCATIONPROC GetUniformLocation;
|
||||||
|
PFNGLGETVERTEXATTRIBPOINTERVPROC GetVertexAttribPointerv;
|
||||||
|
PFNGLGETVERTEXATTRIBIVPROC GetVertexAttribiv;
|
||||||
|
PFNGLISENABLEDPROC IsEnabled;
|
||||||
|
PFNGLLINKPROGRAMPROC LinkProgram;
|
||||||
|
PFNGLPIXELSTOREIPROC PixelStorei;
|
||||||
|
PFNGLPOLYGONMODEPROC PolygonMode;
|
||||||
|
PFNGLREADPIXELSPROC ReadPixels;
|
||||||
|
PFNGLSCISSORPROC Scissor;
|
||||||
|
PFNGLSHADERSOURCEPROC ShaderSource;
|
||||||
|
PFNGLTEXIMAGE2DPROC TexImage2D;
|
||||||
|
PFNGLTEXPARAMETERIPROC TexParameteri;
|
||||||
|
PFNGLUNIFORM1IPROC Uniform1i;
|
||||||
|
PFNGLUNIFORMMATRIX4FVPROC UniformMatrix4fv;
|
||||||
|
PFNGLUSEPROGRAMPROC UseProgram;
|
||||||
|
PFNGLVERTEXATTRIBPOINTERPROC VertexAttribPointer;
|
||||||
|
PFNGLVIEWPORTPROC Viewport;
|
||||||
|
} gl;
|
||||||
|
};
|
||||||
|
|
||||||
|
GL3W_API extern union GL3WProcs imgl3wProcs;
|
||||||
|
|
||||||
|
/* OpenGL functions */
|
||||||
|
#define glActiveTexture imgl3wProcs.gl.ActiveTexture
|
||||||
|
#define glAttachShader imgl3wProcs.gl.AttachShader
|
||||||
|
#define glBindBuffer imgl3wProcs.gl.BindBuffer
|
||||||
|
#define glBindSampler imgl3wProcs.gl.BindSampler
|
||||||
|
#define glBindTexture imgl3wProcs.gl.BindTexture
|
||||||
|
#define glBindVertexArray imgl3wProcs.gl.BindVertexArray
|
||||||
|
#define glBlendEquation imgl3wProcs.gl.BlendEquation
|
||||||
|
#define glBlendEquationSeparate imgl3wProcs.gl.BlendEquationSeparate
|
||||||
|
#define glBlendFuncSeparate imgl3wProcs.gl.BlendFuncSeparate
|
||||||
|
#define glBufferData imgl3wProcs.gl.BufferData
|
||||||
|
#define glBufferSubData imgl3wProcs.gl.BufferSubData
|
||||||
|
#define glClear imgl3wProcs.gl.Clear
|
||||||
|
#define glClearColor imgl3wProcs.gl.ClearColor
|
||||||
|
#define glCompileShader imgl3wProcs.gl.CompileShader
|
||||||
|
#define glCreateProgram imgl3wProcs.gl.CreateProgram
|
||||||
|
#define glCreateShader imgl3wProcs.gl.CreateShader
|
||||||
|
#define glDeleteBuffers imgl3wProcs.gl.DeleteBuffers
|
||||||
|
#define glDeleteProgram imgl3wProcs.gl.DeleteProgram
|
||||||
|
#define glDeleteShader imgl3wProcs.gl.DeleteShader
|
||||||
|
#define glDeleteTextures imgl3wProcs.gl.DeleteTextures
|
||||||
|
#define glDeleteVertexArrays imgl3wProcs.gl.DeleteVertexArrays
|
||||||
|
#define glDetachShader imgl3wProcs.gl.DetachShader
|
||||||
|
#define glDisable imgl3wProcs.gl.Disable
|
||||||
|
#define glDisableVertexAttribArray imgl3wProcs.gl.DisableVertexAttribArray
|
||||||
|
#define glDrawElements imgl3wProcs.gl.DrawElements
|
||||||
|
#define glDrawElementsBaseVertex imgl3wProcs.gl.DrawElementsBaseVertex
|
||||||
|
#define glEnable imgl3wProcs.gl.Enable
|
||||||
|
#define glEnableVertexAttribArray imgl3wProcs.gl.EnableVertexAttribArray
|
||||||
|
#define glFlush imgl3wProcs.gl.Flush
|
||||||
|
#define glGenBuffers imgl3wProcs.gl.GenBuffers
|
||||||
|
#define glGenTextures imgl3wProcs.gl.GenTextures
|
||||||
|
#define glGenVertexArrays imgl3wProcs.gl.GenVertexArrays
|
||||||
|
#define glGetAttribLocation imgl3wProcs.gl.GetAttribLocation
|
||||||
|
#define glGetError imgl3wProcs.gl.GetError
|
||||||
|
#define glGetIntegerv imgl3wProcs.gl.GetIntegerv
|
||||||
|
#define glGetProgramInfoLog imgl3wProcs.gl.GetProgramInfoLog
|
||||||
|
#define glGetProgramiv imgl3wProcs.gl.GetProgramiv
|
||||||
|
#define glGetShaderInfoLog imgl3wProcs.gl.GetShaderInfoLog
|
||||||
|
#define glGetShaderiv imgl3wProcs.gl.GetShaderiv
|
||||||
|
#define glGetString imgl3wProcs.gl.GetString
|
||||||
|
#define glGetStringi imgl3wProcs.gl.GetStringi
|
||||||
|
#define glGetUniformLocation imgl3wProcs.gl.GetUniformLocation
|
||||||
|
#define glGetVertexAttribPointerv imgl3wProcs.gl.GetVertexAttribPointerv
|
||||||
|
#define glGetVertexAttribiv imgl3wProcs.gl.GetVertexAttribiv
|
||||||
|
#define glIsEnabled imgl3wProcs.gl.IsEnabled
|
||||||
|
#define glLinkProgram imgl3wProcs.gl.LinkProgram
|
||||||
|
#define glPixelStorei imgl3wProcs.gl.PixelStorei
|
||||||
|
#define glPolygonMode imgl3wProcs.gl.PolygonMode
|
||||||
|
#define glReadPixels imgl3wProcs.gl.ReadPixels
|
||||||
|
#define glScissor imgl3wProcs.gl.Scissor
|
||||||
|
#define glShaderSource imgl3wProcs.gl.ShaderSource
|
||||||
|
#define glTexImage2D imgl3wProcs.gl.TexImage2D
|
||||||
|
#define glTexParameteri imgl3wProcs.gl.TexParameteri
|
||||||
|
#define glUniform1i imgl3wProcs.gl.Uniform1i
|
||||||
|
#define glUniformMatrix4fv imgl3wProcs.gl.UniformMatrix4fv
|
||||||
|
#define glUseProgram imgl3wProcs.gl.UseProgram
|
||||||
|
#define glVertexAttribPointer imgl3wProcs.gl.VertexAttribPointer
|
||||||
|
#define glViewport imgl3wProcs.gl.Viewport
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef IMGL3W_IMPL
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
|
||||||
|
|
||||||
|
#if defined(_WIN32)
|
||||||
|
#ifndef WIN32_LEAN_AND_MEAN
|
||||||
|
#define WIN32_LEAN_AND_MEAN 1
|
||||||
|
#endif
|
||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
static HMODULE libgl;
|
||||||
|
typedef PROC(__stdcall* GL3WglGetProcAddr)(LPCSTR);
|
||||||
|
static GL3WglGetProcAddr wgl_get_proc_address;
|
||||||
|
|
||||||
|
static int open_libgl(void)
|
||||||
|
{
|
||||||
|
libgl = LoadLibraryA("opengl32.dll");
|
||||||
|
if (!libgl)
|
||||||
|
return GL3W_ERROR_LIBRARY_OPEN;
|
||||||
|
wgl_get_proc_address = (GL3WglGetProcAddr)GetProcAddress(libgl, "wglGetProcAddress");
|
||||||
|
return GL3W_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void close_libgl(void) { FreeLibrary(libgl); }
|
||||||
|
static GL3WglProc get_proc(const char *proc)
|
||||||
|
{
|
||||||
|
GL3WglProc res;
|
||||||
|
res = (GL3WglProc)wgl_get_proc_address(proc);
|
||||||
|
if (!res)
|
||||||
|
res = (GL3WglProc)GetProcAddress(libgl, proc);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
#elif defined(__APPLE__)
|
||||||
|
#include <dlfcn.h>
|
||||||
|
|
||||||
|
static void *libgl;
|
||||||
|
static int open_libgl(void)
|
||||||
|
{
|
||||||
|
libgl = dlopen("/System/Library/Frameworks/OpenGL.framework/OpenGL", RTLD_LAZY | RTLD_LOCAL);
|
||||||
|
if (!libgl)
|
||||||
|
return GL3W_ERROR_LIBRARY_OPEN;
|
||||||
|
return GL3W_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void close_libgl(void) { dlclose(libgl); }
|
||||||
|
|
||||||
|
static GL3WglProc get_proc(const char *proc)
|
||||||
|
{
|
||||||
|
GL3WglProc res;
|
||||||
|
*(void **)(&res) = dlsym(libgl, proc);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
#include <dlfcn.h>
|
||||||
|
|
||||||
|
static void *libgl;
|
||||||
|
static GL3WglProc (*glx_get_proc_address)(const GLubyte *);
|
||||||
|
|
||||||
|
static int open_libgl(void)
|
||||||
|
{
|
||||||
|
libgl = dlopen("libGL.so.1", RTLD_LAZY | RTLD_LOCAL);
|
||||||
|
if (!libgl)
|
||||||
|
return GL3W_ERROR_LIBRARY_OPEN;
|
||||||
|
*(void **)(&glx_get_proc_address) = dlsym(libgl, "glXGetProcAddressARB");
|
||||||
|
return GL3W_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void close_libgl(void) { dlclose(libgl); }
|
||||||
|
|
||||||
|
static GL3WglProc get_proc(const char *proc)
|
||||||
|
{
|
||||||
|
GL3WglProc res;
|
||||||
|
res = glx_get_proc_address((const GLubyte *)proc);
|
||||||
|
if (!res)
|
||||||
|
*(void **)(&res) = dlsym(libgl, proc);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static struct { int major, minor; } version;
|
||||||
|
|
||||||
|
static int parse_version(void)
|
||||||
|
{
|
||||||
|
if (!glGetIntegerv)
|
||||||
|
return GL3W_ERROR_INIT;
|
||||||
|
glGetIntegerv(GL_MAJOR_VERSION, &version.major);
|
||||||
|
glGetIntegerv(GL_MINOR_VERSION, &version.minor);
|
||||||
|
if (version.major < 3)
|
||||||
|
return GL3W_ERROR_OPENGL_VERSION;
|
||||||
|
return GL3W_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void load_procs(GL3WGetProcAddressProc proc);
|
||||||
|
|
||||||
|
int imgl3wInit(void)
|
||||||
|
{
|
||||||
|
int res = open_libgl();
|
||||||
|
if (res)
|
||||||
|
return res;
|
||||||
|
atexit(close_libgl);
|
||||||
|
return imgl3wInit2(get_proc);
|
||||||
|
}
|
||||||
|
|
||||||
|
int imgl3wInit2(GL3WGetProcAddressProc proc)
|
||||||
|
{
|
||||||
|
load_procs(proc);
|
||||||
|
return parse_version();
|
||||||
|
}
|
||||||
|
|
||||||
|
int imgl3wIsSupported(int major, int minor)
|
||||||
|
{
|
||||||
|
if (major < 3)
|
||||||
|
return 0;
|
||||||
|
if (version.major == major)
|
||||||
|
return version.minor >= minor;
|
||||||
|
return version.major >= major;
|
||||||
|
}
|
||||||
|
|
||||||
|
GL3WglProc imgl3wGetProcAddress(const char *proc) { return get_proc(proc); }
|
||||||
|
|
||||||
|
static const char *proc_names[] = {
|
||||||
|
"glActiveTexture",
|
||||||
|
"glAttachShader",
|
||||||
|
"glBindBuffer",
|
||||||
|
"glBindSampler",
|
||||||
|
"glBindTexture",
|
||||||
|
"glBindVertexArray",
|
||||||
|
"glBlendEquation",
|
||||||
|
"glBlendEquationSeparate",
|
||||||
|
"glBlendFuncSeparate",
|
||||||
|
"glBufferData",
|
||||||
|
"glBufferSubData",
|
||||||
|
"glClear",
|
||||||
|
"glClearColor",
|
||||||
|
"glCompileShader",
|
||||||
|
"glCreateProgram",
|
||||||
|
"glCreateShader",
|
||||||
|
"glDeleteBuffers",
|
||||||
|
"glDeleteProgram",
|
||||||
|
"glDeleteShader",
|
||||||
|
"glDeleteTextures",
|
||||||
|
"glDeleteVertexArrays",
|
||||||
|
"glDetachShader",
|
||||||
|
"glDisable",
|
||||||
|
"glDisableVertexAttribArray",
|
||||||
|
"glDrawElements",
|
||||||
|
"glDrawElementsBaseVertex",
|
||||||
|
"glEnable",
|
||||||
|
"glEnableVertexAttribArray",
|
||||||
|
"glFlush",
|
||||||
|
"glGenBuffers",
|
||||||
|
"glGenTextures",
|
||||||
|
"glGenVertexArrays",
|
||||||
|
"glGetAttribLocation",
|
||||||
|
"glGetError",
|
||||||
|
"glGetIntegerv",
|
||||||
|
"glGetProgramInfoLog",
|
||||||
|
"glGetProgramiv",
|
||||||
|
"glGetShaderInfoLog",
|
||||||
|
"glGetShaderiv",
|
||||||
|
"glGetString",
|
||||||
|
"glGetStringi",
|
||||||
|
"glGetUniformLocation",
|
||||||
|
"glGetVertexAttribPointerv",
|
||||||
|
"glGetVertexAttribiv",
|
||||||
|
"glIsEnabled",
|
||||||
|
"glLinkProgram",
|
||||||
|
"glPixelStorei",
|
||||||
|
"glPolygonMode",
|
||||||
|
"glReadPixels",
|
||||||
|
"glScissor",
|
||||||
|
"glShaderSource",
|
||||||
|
"glTexImage2D",
|
||||||
|
"glTexParameteri",
|
||||||
|
"glUniform1i",
|
||||||
|
"glUniformMatrix4fv",
|
||||||
|
"glUseProgram",
|
||||||
|
"glVertexAttribPointer",
|
||||||
|
"glViewport",
|
||||||
|
};
|
||||||
|
|
||||||
|
GL3W_API union GL3WProcs imgl3wProcs;
|
||||||
|
|
||||||
|
static void load_procs(GL3WGetProcAddressProc proc)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
for (i = 0; i < ARRAY_SIZE(proc_names); i++)
|
||||||
|
imgl3wProcs.ptr[i] = proc(proc_names[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#endif
|
|
@ -0,0 +1,43 @@
|
||||||
|
// 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: Keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy kVK_* values will also be supported unless IMGUI_DISABLE_OBSOLETE_KEYIO is set]
|
||||||
|
// [X] Platform: OSX clipboard is supported within core Dear ImGui (no specific code in this backend).
|
||||||
|
// [X] Platform: Gamepad support. Enabled with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'.
|
||||||
|
// [X] Platform: IME support.
|
||||||
|
//
|
||||||
|
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
||||||
|
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
|
||||||
|
// 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
|
||||||
|
|
||||||
|
#ifdef __OBJC__
|
||||||
|
|
||||||
|
@class NSEvent;
|
||||||
|
@class NSView;
|
||||||
|
|
||||||
|
IMGUI_IMPL_API bool ImGui_ImplOSX_Init(NSView* _Nonnull view);
|
||||||
|
IMGUI_IMPL_API void ImGui_ImplOSX_Shutdown();
|
||||||
|
IMGUI_IMPL_API void ImGui_ImplOSX_NewFrame(NSView* _Nullable view);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// C++ API
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#ifdef IMGUI_IMPL_METAL_CPP_EXTENSIONS
|
||||||
|
// #include <AppKit/AppKit.hpp>
|
||||||
|
#ifndef __OBJC__
|
||||||
|
|
||||||
|
IMGUI_IMPL_API bool ImGui_ImplOSX_Init(void* _Nonnull view);
|
||||||
|
IMGUI_IMPL_API void ImGui_ImplOSX_Shutdown();
|
||||||
|
IMGUI_IMPL_API void ImGui_ImplOSX_NewFrame(void* _Nullable view);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
#endif
|
|
@ -0,0 +1,758 @@
|
||||||
|
// 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: Keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy kVK_* values will also be supported unless IMGUI_DISABLE_OBSOLETE_KEYIO is set]
|
||||||
|
// [X] Platform: OSX clipboard is supported within core Dear ImGui (no specific code in this backend).
|
||||||
|
// [X] Platform: Gamepad support. Enabled with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'.
|
||||||
|
// [X] Platform: IME support.
|
||||||
|
|
||||||
|
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
||||||
|
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
|
||||||
|
// 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
|
||||||
|
|
||||||
|
#import "imgui.h"
|
||||||
|
#import "imgui_impl_osx.h"
|
||||||
|
#import <Cocoa/Cocoa.h>
|
||||||
|
#import <Carbon/Carbon.h>
|
||||||
|
#import <GameController/GameController.h>
|
||||||
|
#import <time.h>
|
||||||
|
|
||||||
|
// CHANGELOG
|
||||||
|
// (minor and older changes stripped away, please see git history for details)
|
||||||
|
// 2022-05-03: Inputs: Removed ImGui_ImplOSX_HandleEvent() from backend API in favor of backend automatically handling event capture.
|
||||||
|
// 2022-04-27: Misc: Store backend data in a per-context struct, allowing to use this backend with multiple contexts.
|
||||||
|
// 2022-03-22: Inputs: Monitor NSKeyUp events to catch missing keyUp for key when user press Cmd + key
|
||||||
|
// 2022-02-07: Inputs: Forward keyDown/keyUp events to OS when unused by dear imgui.
|
||||||
|
// 2022-01-31: Fix building with old Xcode versions that are missing gamepad features.
|
||||||
|
// 2022-01-26: Inputs: replaced short-lived io.AddKeyModsEvent() (added two weeks ago)with io.AddKeyEvent() using ImGuiKey_ModXXX flags. Sorry for the confusion.
|
||||||
|
// 2021-01-20: Inputs: calling new io.AddKeyAnalogEvent() for gamepad support, instead of writing directly to io.NavInputs[].
|
||||||
|
// 2022-01-17: Inputs: calling new io.AddMousePosEvent(), io.AddMouseButtonEvent(), io.AddMouseWheelEvent() API (1.87+).
|
||||||
|
// 2022-01-12: Inputs: Added basic Platform IME support, hooking the io.SetPlatformImeDataFn() function.
|
||||||
|
// 2022-01-10: Inputs: calling new io.AddKeyEvent(), io.AddKeyModsEvent() + io.SetKeyEventNativeData() API (1.87+). Support for full ImGuiKey range.
|
||||||
|
// 2021-12-13: *BREAKING CHANGE* Add NSView parameter to ImGui_ImplOSX_Init(). Generally fix keyboard support. Using kVK_* codes for keyboard keys.
|
||||||
|
// 2021-12-13: Add game controller support.
|
||||||
|
// 2021-09-21: Use mach_absolute_time as CFAbsoluteTimeGetCurrent can jump backwards.
|
||||||
|
// 2021-08-17: Calling io.AddFocusEvent() on NSApplicationDidBecomeActiveNotification/NSApplicationDidResignActiveNotification events.
|
||||||
|
// 2021-06-23: Inputs: Added a fix for shortcuts using CTRL key instead of CMD key.
|
||||||
|
// 2021-04-19: Inputs: Added a fix for keys remaining stuck in pressed state when CMD-tabbing into different application.
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
#define APPLE_HAS_BUTTON_OPTIONS (__IPHONE_OS_VERSION_MIN_REQUIRED >= 130000 || __MAC_OS_X_VERSION_MIN_REQUIRED >= 101500 || __TV_OS_VERSION_MIN_REQUIRED >= 130000)
|
||||||
|
#define APPLE_HAS_CONTROLLER (__IPHONE_OS_VERSION_MIN_REQUIRED >= 140000 || __MAC_OS_X_VERSION_MIN_REQUIRED >= 110000 || __TV_OS_VERSION_MIN_REQUIRED >= 140000)
|
||||||
|
#define APPLE_HAS_THUMBSTICKS (__IPHONE_OS_VERSION_MIN_REQUIRED >= 120100 || __MAC_OS_X_VERSION_MIN_REQUIRED >= 101401 || __TV_OS_VERSION_MIN_REQUIRED >= 120100)
|
||||||
|
|
||||||
|
@class ImGuiObserver;
|
||||||
|
@class KeyEventResponder;
|
||||||
|
|
||||||
|
// Data
|
||||||
|
struct ImGui_ImplOSX_Data
|
||||||
|
{
|
||||||
|
CFTimeInterval Time;
|
||||||
|
NSCursor* MouseCursors[ImGuiMouseCursor_COUNT];
|
||||||
|
bool MouseCursorHidden;
|
||||||
|
ImGuiObserver* Observer;
|
||||||
|
KeyEventResponder* KeyEventResponder;
|
||||||
|
NSTextInputContext* InputContext;
|
||||||
|
id Monitor;
|
||||||
|
|
||||||
|
ImGui_ImplOSX_Data() { memset(this, 0, sizeof(*this)); }
|
||||||
|
};
|
||||||
|
|
||||||
|
static ImGui_ImplOSX_Data* ImGui_ImplOSX_CreateBackendData() { return IM_NEW(ImGui_ImplOSX_Data)(); }
|
||||||
|
static ImGui_ImplOSX_Data* ImGui_ImplOSX_GetBackendData() { return (ImGui_ImplOSX_Data*)ImGui::GetIO().BackendPlatformUserData; }
|
||||||
|
static void ImGui_ImplOSX_DestroyBackendData() { IM_DELETE(ImGui_ImplOSX_GetBackendData()); }
|
||||||
|
|
||||||
|
static inline CFTimeInterval GetMachAbsoluteTimeInSeconds() { return static_cast<CFTimeInterval>(static_cast<double>(clock_gettime_nsec_np(CLOCK_UPTIME_RAW)) / 1e9); }
|
||||||
|
|
||||||
|
// Forward Declarations
|
||||||
|
static void ImGui_ImplOSX_AddTrackingArea(NSView* _Nonnull view);
|
||||||
|
static bool ImGui_ImplOSX_HandleEvent(NSEvent* event, NSView* view);
|
||||||
|
|
||||||
|
// Undocumented methods for creating cursors.
|
||||||
|
@interface NSCursor()
|
||||||
|
+ (id)_windowResizeNorthWestSouthEastCursor;
|
||||||
|
+ (id)_windowResizeNorthEastSouthWestCursor;
|
||||||
|
+ (id)_windowResizeNorthSouthCursor;
|
||||||
|
+ (id)_windowResizeEastWestCursor;
|
||||||
|
@end
|
||||||
|
|
||||||
|
/**
|
||||||
|
KeyEventResponder implements the NSTextInputClient protocol as is required by the macOS text input manager.
|
||||||
|
|
||||||
|
The macOS text input manager is invoked by calling the interpretKeyEvents method from the keyDown method.
|
||||||
|
Keyboard events are then evaluated by the macOS input manager and valid text input is passed back via the
|
||||||
|
insertText:replacementRange method.
|
||||||
|
|
||||||
|
This is the same approach employed by other cross-platform libraries such as SDL2:
|
||||||
|
https://github.com/spurious/SDL-mirror/blob/e17aacbd09e65a4fd1e166621e011e581fb017a8/src/video/cocoa/SDL_cocoakeyboard.m#L53
|
||||||
|
and GLFW:
|
||||||
|
https://github.com/glfw/glfw/blob/b55a517ae0c7b5127dffa79a64f5406021bf9076/src/cocoa_window.m#L722-L723
|
||||||
|
*/
|
||||||
|
@interface KeyEventResponder: NSView<NSTextInputClient>
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation KeyEventResponder
|
||||||
|
{
|
||||||
|
float _posX;
|
||||||
|
float _posY;
|
||||||
|
NSRect _imeRect;
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark - Public
|
||||||
|
|
||||||
|
- (void)setImePosX:(float)posX imePosY:(float)posY
|
||||||
|
{
|
||||||
|
_posX = posX;
|
||||||
|
_posY = posY;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)updateImePosWithView:(NSView *)view
|
||||||
|
{
|
||||||
|
NSWindow *window = view.window;
|
||||||
|
if (!window)
|
||||||
|
return;
|
||||||
|
NSRect contentRect = [window contentRectForFrameRect:window.frame];
|
||||||
|
NSRect rect = NSMakeRect(_posX, contentRect.size.height - _posY, 0, 0);
|
||||||
|
_imeRect = [window convertRectToScreen:rect];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)viewDidMoveToWindow
|
||||||
|
{
|
||||||
|
// Ensure self is a first responder to receive the input events.
|
||||||
|
[self.window makeFirstResponder:self];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)keyDown:(NSEvent*)event
|
||||||
|
{
|
||||||
|
if (!ImGui_ImplOSX_HandleEvent(event, self))
|
||||||
|
[super keyDown:event];
|
||||||
|
|
||||||
|
// Call to the macOS input manager system.
|
||||||
|
[self interpretKeyEvents:@[event]];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)keyUp:(NSEvent*)event
|
||||||
|
{
|
||||||
|
if (!ImGui_ImplOSX_HandleEvent(event, self))
|
||||||
|
[super keyUp:event];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)insertText:(id)aString replacementRange:(NSRange)replacementRange
|
||||||
|
{
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
|
||||||
|
NSString* characters;
|
||||||
|
if ([aString isKindOfClass:[NSAttributedString class]])
|
||||||
|
characters = [aString string];
|
||||||
|
else
|
||||||
|
characters = (NSString*)aString;
|
||||||
|
|
||||||
|
io.AddInputCharactersUTF8(characters.UTF8String);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)acceptsFirstResponder
|
||||||
|
{
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)doCommandBySelector:(SEL)myselector
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
- (nullable NSAttributedString*)attributedSubstringForProposedRange:(NSRange)range actualRange:(nullable NSRangePointer)actualRange
|
||||||
|
{
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSUInteger)characterIndexForPoint:(NSPoint)point
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSRect)firstRectForCharacterRange:(NSRange)range actualRange:(nullable NSRangePointer)actualRange
|
||||||
|
{
|
||||||
|
return _imeRect;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)hasMarkedText
|
||||||
|
{
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSRange)markedRange
|
||||||
|
{
|
||||||
|
return NSMakeRange(NSNotFound, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSRange)selectedRange
|
||||||
|
{
|
||||||
|
return NSMakeRange(NSNotFound, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setMarkedText:(nonnull id)string selectedRange:(NSRange)selectedRange replacementRange:(NSRange)replacementRange
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)unmarkText
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
- (nonnull NSArray<NSAttributedStringKey>*)validAttributesForMarkedText
|
||||||
|
{
|
||||||
|
return @[];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
@interface ImGuiObserver : NSObject
|
||||||
|
|
||||||
|
- (void)onApplicationBecomeActive:(NSNotification*)aNotification;
|
||||||
|
- (void)onApplicationBecomeInactive:(NSNotification*)aNotification;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation ImGuiObserver
|
||||||
|
|
||||||
|
- (void)onApplicationBecomeActive:(NSNotification*)aNotification
|
||||||
|
{
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
io.AddFocusEvent(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)onApplicationBecomeInactive:(NSNotification*)aNotification
|
||||||
|
{
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
io.AddFocusEvent(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
// Functions
|
||||||
|
static ImGuiKey ImGui_ImplOSX_KeyCodeToImGuiKey(int key_code)
|
||||||
|
{
|
||||||
|
switch (key_code)
|
||||||
|
{
|
||||||
|
case kVK_ANSI_A: return ImGuiKey_A;
|
||||||
|
case kVK_ANSI_S: return ImGuiKey_S;
|
||||||
|
case kVK_ANSI_D: return ImGuiKey_D;
|
||||||
|
case kVK_ANSI_F: return ImGuiKey_F;
|
||||||
|
case kVK_ANSI_H: return ImGuiKey_H;
|
||||||
|
case kVK_ANSI_G: return ImGuiKey_G;
|
||||||
|
case kVK_ANSI_Z: return ImGuiKey_Z;
|
||||||
|
case kVK_ANSI_X: return ImGuiKey_X;
|
||||||
|
case kVK_ANSI_C: return ImGuiKey_C;
|
||||||
|
case kVK_ANSI_V: return ImGuiKey_V;
|
||||||
|
case kVK_ANSI_B: return ImGuiKey_B;
|
||||||
|
case kVK_ANSI_Q: return ImGuiKey_Q;
|
||||||
|
case kVK_ANSI_W: return ImGuiKey_W;
|
||||||
|
case kVK_ANSI_E: return ImGuiKey_E;
|
||||||
|
case kVK_ANSI_R: return ImGuiKey_R;
|
||||||
|
case kVK_ANSI_Y: return ImGuiKey_Y;
|
||||||
|
case kVK_ANSI_T: return ImGuiKey_T;
|
||||||
|
case kVK_ANSI_1: return ImGuiKey_1;
|
||||||
|
case kVK_ANSI_2: return ImGuiKey_2;
|
||||||
|
case kVK_ANSI_3: return ImGuiKey_3;
|
||||||
|
case kVK_ANSI_4: return ImGuiKey_4;
|
||||||
|
case kVK_ANSI_6: return ImGuiKey_6;
|
||||||
|
case kVK_ANSI_5: return ImGuiKey_5;
|
||||||
|
case kVK_ANSI_Equal: return ImGuiKey_Equal;
|
||||||
|
case kVK_ANSI_9: return ImGuiKey_9;
|
||||||
|
case kVK_ANSI_7: return ImGuiKey_7;
|
||||||
|
case kVK_ANSI_Minus: return ImGuiKey_Minus;
|
||||||
|
case kVK_ANSI_8: return ImGuiKey_8;
|
||||||
|
case kVK_ANSI_0: return ImGuiKey_0;
|
||||||
|
case kVK_ANSI_RightBracket: return ImGuiKey_RightBracket;
|
||||||
|
case kVK_ANSI_O: return ImGuiKey_O;
|
||||||
|
case kVK_ANSI_U: return ImGuiKey_U;
|
||||||
|
case kVK_ANSI_LeftBracket: return ImGuiKey_LeftBracket;
|
||||||
|
case kVK_ANSI_I: return ImGuiKey_I;
|
||||||
|
case kVK_ANSI_P: return ImGuiKey_P;
|
||||||
|
case kVK_ANSI_L: return ImGuiKey_L;
|
||||||
|
case kVK_ANSI_J: return ImGuiKey_J;
|
||||||
|
case kVK_ANSI_Quote: return ImGuiKey_Apostrophe;
|
||||||
|
case kVK_ANSI_K: return ImGuiKey_K;
|
||||||
|
case kVK_ANSI_Semicolon: return ImGuiKey_Semicolon;
|
||||||
|
case kVK_ANSI_Backslash: return ImGuiKey_Backslash;
|
||||||
|
case kVK_ANSI_Comma: return ImGuiKey_Comma;
|
||||||
|
case kVK_ANSI_Slash: return ImGuiKey_Slash;
|
||||||
|
case kVK_ANSI_N: return ImGuiKey_N;
|
||||||
|
case kVK_ANSI_M: return ImGuiKey_M;
|
||||||
|
case kVK_ANSI_Period: return ImGuiKey_Period;
|
||||||
|
case kVK_ANSI_Grave: return ImGuiKey_GraveAccent;
|
||||||
|
case kVK_ANSI_KeypadDecimal: return ImGuiKey_KeypadDecimal;
|
||||||
|
case kVK_ANSI_KeypadMultiply: return ImGuiKey_KeypadMultiply;
|
||||||
|
case kVK_ANSI_KeypadPlus: return ImGuiKey_KeypadAdd;
|
||||||
|
case kVK_ANSI_KeypadClear: return ImGuiKey_NumLock;
|
||||||
|
case kVK_ANSI_KeypadDivide: return ImGuiKey_KeypadDivide;
|
||||||
|
case kVK_ANSI_KeypadEnter: return ImGuiKey_KeypadEnter;
|
||||||
|
case kVK_ANSI_KeypadMinus: return ImGuiKey_KeypadSubtract;
|
||||||
|
case kVK_ANSI_KeypadEquals: return ImGuiKey_KeypadEqual;
|
||||||
|
case kVK_ANSI_Keypad0: return ImGuiKey_Keypad0;
|
||||||
|
case kVK_ANSI_Keypad1: return ImGuiKey_Keypad1;
|
||||||
|
case kVK_ANSI_Keypad2: return ImGuiKey_Keypad2;
|
||||||
|
case kVK_ANSI_Keypad3: return ImGuiKey_Keypad3;
|
||||||
|
case kVK_ANSI_Keypad4: return ImGuiKey_Keypad4;
|
||||||
|
case kVK_ANSI_Keypad5: return ImGuiKey_Keypad5;
|
||||||
|
case kVK_ANSI_Keypad6: return ImGuiKey_Keypad6;
|
||||||
|
case kVK_ANSI_Keypad7: return ImGuiKey_Keypad7;
|
||||||
|
case kVK_ANSI_Keypad8: return ImGuiKey_Keypad8;
|
||||||
|
case kVK_ANSI_Keypad9: return ImGuiKey_Keypad9;
|
||||||
|
case kVK_Return: return ImGuiKey_Enter;
|
||||||
|
case kVK_Tab: return ImGuiKey_Tab;
|
||||||
|
case kVK_Space: return ImGuiKey_Space;
|
||||||
|
case kVK_Delete: return ImGuiKey_Backspace;
|
||||||
|
case kVK_Escape: return ImGuiKey_Escape;
|
||||||
|
case kVK_CapsLock: return ImGuiKey_CapsLock;
|
||||||
|
case kVK_Control: return ImGuiKey_LeftCtrl;
|
||||||
|
case kVK_Shift: return ImGuiKey_LeftShift;
|
||||||
|
case kVK_Option: return ImGuiKey_LeftAlt;
|
||||||
|
case kVK_Command: return ImGuiKey_LeftSuper;
|
||||||
|
case kVK_RightControl: return ImGuiKey_RightCtrl;
|
||||||
|
case kVK_RightShift: return ImGuiKey_RightShift;
|
||||||
|
case kVK_RightOption: return ImGuiKey_RightAlt;
|
||||||
|
case kVK_RightCommand: return ImGuiKey_RightSuper;
|
||||||
|
// case kVK_Function: return ImGuiKey_;
|
||||||
|
// case kVK_F17: return ImGuiKey_;
|
||||||
|
// case kVK_VolumeUp: return ImGuiKey_;
|
||||||
|
// case kVK_VolumeDown: return ImGuiKey_;
|
||||||
|
// case kVK_Mute: return ImGuiKey_;
|
||||||
|
// case kVK_F18: return ImGuiKey_;
|
||||||
|
// case kVK_F19: return ImGuiKey_;
|
||||||
|
// case kVK_F20: return ImGuiKey_;
|
||||||
|
case kVK_F5: return ImGuiKey_F5;
|
||||||
|
case kVK_F6: return ImGuiKey_F6;
|
||||||
|
case kVK_F7: return ImGuiKey_F7;
|
||||||
|
case kVK_F3: return ImGuiKey_F3;
|
||||||
|
case kVK_F8: return ImGuiKey_F8;
|
||||||
|
case kVK_F9: return ImGuiKey_F9;
|
||||||
|
case kVK_F11: return ImGuiKey_F11;
|
||||||
|
case kVK_F13: return ImGuiKey_PrintScreen;
|
||||||
|
// case kVK_F16: return ImGuiKey_;
|
||||||
|
// case kVK_F14: return ImGuiKey_;
|
||||||
|
case kVK_F10: return ImGuiKey_F10;
|
||||||
|
case 0x6E: return ImGuiKey_Menu;
|
||||||
|
case kVK_F12: return ImGuiKey_F12;
|
||||||
|
// case kVK_F15: return ImGuiKey_;
|
||||||
|
case kVK_Help: return ImGuiKey_Insert;
|
||||||
|
case kVK_Home: return ImGuiKey_Home;
|
||||||
|
case kVK_PageUp: return ImGuiKey_PageUp;
|
||||||
|
case kVK_ForwardDelete: return ImGuiKey_Delete;
|
||||||
|
case kVK_F4: return ImGuiKey_F4;
|
||||||
|
case kVK_End: return ImGuiKey_End;
|
||||||
|
case kVK_F2: return ImGuiKey_F2;
|
||||||
|
case kVK_PageDown: return ImGuiKey_PageDown;
|
||||||
|
case kVK_F1: return ImGuiKey_F1;
|
||||||
|
case kVK_LeftArrow: return ImGuiKey_LeftArrow;
|
||||||
|
case kVK_RightArrow: return ImGuiKey_RightArrow;
|
||||||
|
case kVK_DownArrow: return ImGuiKey_DownArrow;
|
||||||
|
case kVK_UpArrow: return ImGuiKey_UpArrow;
|
||||||
|
default: return ImGuiKey_None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef IMGUI_IMPL_METAL_CPP_EXTENSIONS
|
||||||
|
|
||||||
|
IMGUI_IMPL_API bool ImGui_ImplOSX_Init(void* _Nonnull view) {
|
||||||
|
return ImGui_ImplOSX_Init((__bridge NSView*)(view));
|
||||||
|
}
|
||||||
|
|
||||||
|
IMGUI_IMPL_API void ImGui_ImplOSX_NewFrame(void* _Nullable view) {
|
||||||
|
return ImGui_ImplOSX_NewFrame((__bridge NSView*)(view));
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
bool ImGui_ImplOSX_Init(NSView* view)
|
||||||
|
{
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
ImGui_ImplOSX_Data* bd = ImGui_ImplOSX_CreateBackendData();
|
||||||
|
io.BackendPlatformUserData = (void*)bd;
|
||||||
|
|
||||||
|
// 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";
|
||||||
|
|
||||||
|
bd->Observer = [ImGuiObserver new];
|
||||||
|
|
||||||
|
// Load cursors. Some of them are undocumented.
|
||||||
|
bd->MouseCursorHidden = false;
|
||||||
|
bd->MouseCursors[ImGuiMouseCursor_Arrow] = [NSCursor arrowCursor];
|
||||||
|
bd->MouseCursors[ImGuiMouseCursor_TextInput] = [NSCursor IBeamCursor];
|
||||||
|
bd->MouseCursors[ImGuiMouseCursor_ResizeAll] = [NSCursor closedHandCursor];
|
||||||
|
bd->MouseCursors[ImGuiMouseCursor_Hand] = [NSCursor pointingHandCursor];
|
||||||
|
bd->MouseCursors[ImGuiMouseCursor_NotAllowed] = [NSCursor operationNotAllowedCursor];
|
||||||
|
bd->MouseCursors[ImGuiMouseCursor_ResizeNS] = [NSCursor respondsToSelector:@selector(_windowResizeNorthSouthCursor)] ? [NSCursor _windowResizeNorthSouthCursor] : [NSCursor resizeUpDownCursor];
|
||||||
|
bd->MouseCursors[ImGuiMouseCursor_ResizeEW] = [NSCursor respondsToSelector:@selector(_windowResizeEastWestCursor)] ? [NSCursor _windowResizeEastWestCursor] : [NSCursor resizeLeftRightCursor];
|
||||||
|
bd->MouseCursors[ImGuiMouseCursor_ResizeNESW] = [NSCursor respondsToSelector:@selector(_windowResizeNorthEastSouthWestCursor)] ? [NSCursor _windowResizeNorthEastSouthWestCursor] : [NSCursor closedHandCursor];
|
||||||
|
bd->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;
|
||||||
|
};
|
||||||
|
|
||||||
|
[[NSNotificationCenter defaultCenter] addObserver:bd->Observer
|
||||||
|
selector:@selector(onApplicationBecomeActive:)
|
||||||
|
name:NSApplicationDidBecomeActiveNotification
|
||||||
|
object:nil];
|
||||||
|
[[NSNotificationCenter defaultCenter] addObserver:bd->Observer
|
||||||
|
selector:@selector(onApplicationBecomeInactive:)
|
||||||
|
name:NSApplicationDidResignActiveNotification
|
||||||
|
object:nil];
|
||||||
|
|
||||||
|
// Add the NSTextInputClient to the view hierarchy,
|
||||||
|
// to receive keyboard events and translate them to input text.
|
||||||
|
bd->KeyEventResponder = [[KeyEventResponder alloc] initWithFrame:NSZeroRect];
|
||||||
|
bd->InputContext = [[NSTextInputContext alloc] initWithClient:bd->KeyEventResponder];
|
||||||
|
[view addSubview:bd->KeyEventResponder];
|
||||||
|
ImGui_ImplOSX_AddTrackingArea(view);
|
||||||
|
|
||||||
|
io.SetPlatformImeDataFn = [](ImGuiViewport* viewport, ImGuiPlatformImeData* data) -> void
|
||||||
|
{
|
||||||
|
ImGui_ImplOSX_Data* bd = ImGui_ImplOSX_GetBackendData();
|
||||||
|
if (data->WantVisible)
|
||||||
|
{
|
||||||
|
[bd->InputContext activate];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
[bd->InputContext discardMarkedText];
|
||||||
|
[bd->InputContext invalidateCharacterCoordinates];
|
||||||
|
[bd->InputContext deactivate];
|
||||||
|
}
|
||||||
|
[bd->KeyEventResponder setImePosX:data->InputPos.x imePosY:data->InputPos.y + data->InputLineHeight];
|
||||||
|
};
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGui_ImplOSX_Shutdown()
|
||||||
|
{
|
||||||
|
ImGui_ImplOSX_Data* bd = ImGui_ImplOSX_GetBackendData();
|
||||||
|
bd->Observer = NULL;
|
||||||
|
if (bd->Monitor != NULL)
|
||||||
|
{
|
||||||
|
[NSEvent removeMonitor:bd->Monitor];
|
||||||
|
bd->Monitor = NULL;
|
||||||
|
}
|
||||||
|
ImGui_ImplOSX_DestroyBackendData();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ImGui_ImplOSX_UpdateMouseCursor()
|
||||||
|
{
|
||||||
|
ImGui_ImplOSX_Data* bd = ImGui_ImplOSX_GetBackendData();
|
||||||
|
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
|
||||||
|
if (!bd->MouseCursorHidden)
|
||||||
|
{
|
||||||
|
bd->MouseCursorHidden = true;
|
||||||
|
[NSCursor hide];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
NSCursor* desired = bd->MouseCursors[imgui_cursor] ?: bd->MouseCursors[ImGuiMouseCursor_Arrow];
|
||||||
|
// -[NSCursor set] generates measureable overhead if called unconditionally.
|
||||||
|
if (desired != NSCursor.currentCursor)
|
||||||
|
{
|
||||||
|
[desired set];
|
||||||
|
}
|
||||||
|
if (bd->MouseCursorHidden)
|
||||||
|
{
|
||||||
|
bd->MouseCursorHidden = false;
|
||||||
|
[NSCursor unhide];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ImGui_ImplOSX_UpdateGamepads()
|
||||||
|
{
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
memset(io.NavInputs, 0, sizeof(io.NavInputs));
|
||||||
|
if ((io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) == 0) // FIXME: Technically feeding gamepad shouldn't depend on this now that they are regular inputs.
|
||||||
|
return;
|
||||||
|
|
||||||
|
#if APPLE_HAS_CONTROLLER
|
||||||
|
GCController* controller = GCController.current;
|
||||||
|
#else
|
||||||
|
GCController* controller = GCController.controllers.firstObject;
|
||||||
|
#endif
|
||||||
|
if (controller == nil || controller.extendedGamepad == nil)
|
||||||
|
{
|
||||||
|
io.BackendFlags &= ~ImGuiBackendFlags_HasGamepad;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
GCExtendedGamepad* gp = controller.extendedGamepad;
|
||||||
|
|
||||||
|
// Update gamepad inputs
|
||||||
|
#define IM_SATURATE(V) (V < 0.0f ? 0.0f : V > 1.0f ? 1.0f : V)
|
||||||
|
#define MAP_BUTTON(KEY_NO, BUTTON_NAME) { io.AddKeyEvent(KEY_NO, gp.BUTTON_NAME.isPressed); }
|
||||||
|
#define MAP_ANALOG(KEY_NO, AXIS_NAME, V0, V1) { float vn = (float)(gp.AXIS_NAME.value - V0) / (float)(V1 - V0); vn = IM_SATURATE(vn); io.AddKeyAnalogEvent(KEY_NO, vn > 0.1f, vn); }
|
||||||
|
const float thumb_dead_zone = 0.0f;
|
||||||
|
|
||||||
|
#if APPLE_HAS_BUTTON_OPTIONS
|
||||||
|
MAP_BUTTON(ImGuiKey_GamepadBack, buttonOptions);
|
||||||
|
#endif
|
||||||
|
MAP_BUTTON(ImGuiKey_GamepadFaceLeft, buttonX); // Xbox X, PS Square
|
||||||
|
MAP_BUTTON(ImGuiKey_GamepadFaceRight, buttonB); // Xbox B, PS Circle
|
||||||
|
MAP_BUTTON(ImGuiKey_GamepadFaceUp, buttonY); // Xbox Y, PS Triangle
|
||||||
|
MAP_BUTTON(ImGuiKey_GamepadFaceDown, buttonA); // Xbox A, PS Cross
|
||||||
|
MAP_BUTTON(ImGuiKey_GamepadDpadLeft, dpad.left);
|
||||||
|
MAP_BUTTON(ImGuiKey_GamepadDpadRight, dpad.right);
|
||||||
|
MAP_BUTTON(ImGuiKey_GamepadDpadUp, dpad.up);
|
||||||
|
MAP_BUTTON(ImGuiKey_GamepadDpadDown, dpad.down);
|
||||||
|
MAP_ANALOG(ImGuiKey_GamepadL1, leftShoulder, 0.0f, 1.0f);
|
||||||
|
MAP_ANALOG(ImGuiKey_GamepadR1, rightShoulder, 0.0f, 1.0f);
|
||||||
|
MAP_ANALOG(ImGuiKey_GamepadL2, leftTrigger, 0.0f, 1.0f);
|
||||||
|
MAP_ANALOG(ImGuiKey_GamepadR2, rightTrigger, 0.0f, 1.0f);
|
||||||
|
#if APPLE_HAS_THUMBSTICKS
|
||||||
|
MAP_BUTTON(ImGuiKey_GamepadL3, leftThumbstickButton);
|
||||||
|
MAP_BUTTON(ImGuiKey_GamepadR3, rightThumbstickButton);
|
||||||
|
#endif
|
||||||
|
MAP_ANALOG(ImGuiKey_GamepadLStickLeft, leftThumbstick.xAxis, -thumb_dead_zone, -1.0f);
|
||||||
|
MAP_ANALOG(ImGuiKey_GamepadLStickRight, leftThumbstick.xAxis, +thumb_dead_zone, +1.0f);
|
||||||
|
MAP_ANALOG(ImGuiKey_GamepadLStickUp, leftThumbstick.yAxis, +thumb_dead_zone, +1.0f);
|
||||||
|
MAP_ANALOG(ImGuiKey_GamepadLStickDown, leftThumbstick.yAxis, -thumb_dead_zone, -1.0f);
|
||||||
|
MAP_ANALOG(ImGuiKey_GamepadRStickLeft, rightThumbstick.xAxis, -thumb_dead_zone, -1.0f);
|
||||||
|
MAP_ANALOG(ImGuiKey_GamepadRStickRight, rightThumbstick.xAxis, +thumb_dead_zone, +1.0f);
|
||||||
|
MAP_ANALOG(ImGuiKey_GamepadRStickUp, rightThumbstick.yAxis, +thumb_dead_zone, +1.0f);
|
||||||
|
MAP_ANALOG(ImGuiKey_GamepadRStickDown, rightThumbstick.yAxis, -thumb_dead_zone, -1.0f);
|
||||||
|
#undef MAP_BUTTON
|
||||||
|
#undef MAP_ANALOG
|
||||||
|
|
||||||
|
io.BackendFlags |= ImGuiBackendFlags_HasGamepad;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ImGui_ImplOSX_UpdateImePosWithView(NSView* view)
|
||||||
|
{
|
||||||
|
ImGui_ImplOSX_Data* bd = ImGui_ImplOSX_GetBackendData();
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
if (io.WantTextInput)
|
||||||
|
[bd->KeyEventResponder updateImePosWithView:view];
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGui_ImplOSX_NewFrame(NSView* view)
|
||||||
|
{
|
||||||
|
ImGui_ImplOSX_Data* bd = ImGui_ImplOSX_GetBackendData();
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
|
||||||
|
// Setup display size
|
||||||
|
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 (bd->Time == 0.0)
|
||||||
|
bd->Time = GetMachAbsoluteTimeInSeconds();
|
||||||
|
|
||||||
|
double current_time = GetMachAbsoluteTimeInSeconds();
|
||||||
|
io.DeltaTime = (float)(current_time - bd->Time);
|
||||||
|
bd->Time = current_time;
|
||||||
|
|
||||||
|
ImGui_ImplOSX_UpdateMouseCursor();
|
||||||
|
ImGui_ImplOSX_UpdateGamepads();
|
||||||
|
ImGui_ImplOSX_UpdateImePosWithView(view);
|
||||||
|
}
|
||||||
|
|
||||||
|
static 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 < ImGuiMouseButton_COUNT)
|
||||||
|
io.AddMouseButtonEvent(button, true);
|
||||||
|
return io.WantCaptureMouse;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event.type == NSEventTypeLeftMouseUp || event.type == NSEventTypeRightMouseUp || event.type == NSEventTypeOtherMouseUp)
|
||||||
|
{
|
||||||
|
int button = (int)[event buttonNumber];
|
||||||
|
if (button >= 0 && button < ImGuiMouseButton_COUNT)
|
||||||
|
io.AddMouseButtonEvent(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.AddMousePosEvent((float)mousePoint.x, (float)mousePoint.y);
|
||||||
|
return io.WantCaptureMouse;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event.type == NSEventTypeScrollWheel)
|
||||||
|
{
|
||||||
|
// Ignore canceled events.
|
||||||
|
//
|
||||||
|
// From macOS 12.1, scrolling with two fingers and then decelerating
|
||||||
|
// by tapping two fingers results in two events appearing:
|
||||||
|
//
|
||||||
|
// 1. A scroll wheel NSEvent, with a phase == NSEventPhaseMayBegin, when the user taps
|
||||||
|
// two fingers to decelerate or stop the scroll events.
|
||||||
|
//
|
||||||
|
// 2. A scroll wheel NSEvent, with a phase == NSEventPhaseCancelled, when the user releases the
|
||||||
|
// two-finger tap. It is this event that sometimes contains large values for scrollingDeltaX and
|
||||||
|
// scrollingDeltaY. When these are added to the current x and y positions of the scrolling view,
|
||||||
|
// it appears to jump up or down. It can be observed in Preview, various JetBrains IDEs and here.
|
||||||
|
if (event.phase == NSEventPhaseCancelled)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
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 (wheel_dx != 0.0 || wheel_dy != 0.0)
|
||||||
|
io.AddMouseWheelEvent((float)wheel_dx * 0.1f, (float)wheel_dy * 0.1f);
|
||||||
|
|
||||||
|
return io.WantCaptureMouse;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event.type == NSEventTypeKeyDown || event.type == NSEventTypeKeyUp)
|
||||||
|
{
|
||||||
|
if ([event isARepeat])
|
||||||
|
return io.WantCaptureKeyboard;
|
||||||
|
|
||||||
|
int key_code = (int)[event keyCode];
|
||||||
|
ImGuiKey key = ImGui_ImplOSX_KeyCodeToImGuiKey(key_code);
|
||||||
|
io.AddKeyEvent(key, event.type == NSEventTypeKeyDown);
|
||||||
|
io.SetKeyEventNativeData(key, key_code, -1); // To support legacy indexing (<1.87 user code)
|
||||||
|
|
||||||
|
return io.WantCaptureKeyboard;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event.type == NSEventTypeFlagsChanged)
|
||||||
|
{
|
||||||
|
unsigned short key_code = [event keyCode];
|
||||||
|
NSEventModifierFlags modifier_flags = [event modifierFlags];
|
||||||
|
|
||||||
|
io.AddKeyEvent(ImGuiKey_ModShift, (modifier_flags & NSEventModifierFlagShift) != 0);
|
||||||
|
io.AddKeyEvent(ImGuiKey_ModCtrl, (modifier_flags & NSEventModifierFlagControl) != 0);
|
||||||
|
io.AddKeyEvent(ImGuiKey_ModAlt, (modifier_flags & NSEventModifierFlagOption) != 0);
|
||||||
|
io.AddKeyEvent(ImGuiKey_ModSuper, (modifier_flags & NSEventModifierFlagCommand) != 0);
|
||||||
|
|
||||||
|
ImGuiKey key = ImGui_ImplOSX_KeyCodeToImGuiKey(key_code);
|
||||||
|
if (key != ImGuiKey_None)
|
||||||
|
{
|
||||||
|
// macOS does not generate down/up event for modifiers. We're trying
|
||||||
|
// to use hardware dependent masks to extract that information.
|
||||||
|
// 'imgui_mask' is left as a fallback.
|
||||||
|
NSEventModifierFlags mask = 0;
|
||||||
|
switch (key)
|
||||||
|
{
|
||||||
|
case ImGuiKey_LeftCtrl: mask = 0x0001; break;
|
||||||
|
case ImGuiKey_RightCtrl: mask = 0x2000; break;
|
||||||
|
case ImGuiKey_LeftShift: mask = 0x0002; break;
|
||||||
|
case ImGuiKey_RightShift: mask = 0x0004; break;
|
||||||
|
case ImGuiKey_LeftSuper: mask = 0x0008; break;
|
||||||
|
case ImGuiKey_RightSuper: mask = 0x0010; break;
|
||||||
|
case ImGuiKey_LeftAlt: mask = 0x0020; break;
|
||||||
|
case ImGuiKey_RightAlt: mask = 0x0040; break;
|
||||||
|
default:
|
||||||
|
return io.WantCaptureKeyboard;
|
||||||
|
}
|
||||||
|
|
||||||
|
NSEventModifierFlags modifier_flags = [event modifierFlags];
|
||||||
|
io.AddKeyEvent(key, (modifier_flags & mask) != 0);
|
||||||
|
io.SetKeyEventNativeData(key, key_code, -1); // To support legacy indexing (<1.87 user code)
|
||||||
|
}
|
||||||
|
|
||||||
|
return io.WantCaptureKeyboard;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ImGui_ImplOSX_AddTrackingArea(NSView* _Nonnull view)
|
||||||
|
{
|
||||||
|
// If we want to receive key events, we either need to be in the responder chain of the key view,
|
||||||
|
// or else we can install a local monitor. The consequence of this heavy-handed approach is that
|
||||||
|
// we receive events for all controls, not just Dear ImGui widgets. If we had native controls in our
|
||||||
|
// window, we'd want to be much more careful than just ingesting the complete event stream.
|
||||||
|
// To match the behavior of other backends, we pass every event down to the OS.
|
||||||
|
ImGui_ImplOSX_Data* bd = ImGui_ImplOSX_GetBackendData();
|
||||||
|
if (bd->Monitor)
|
||||||
|
return;
|
||||||
|
NSEventMask eventMask = 0;
|
||||||
|
eventMask |= NSEventMaskMouseMoved | NSEventMaskScrollWheel;
|
||||||
|
eventMask |= NSEventMaskLeftMouseDown | NSEventMaskLeftMouseUp | NSEventMaskLeftMouseDragged;
|
||||||
|
eventMask |= NSEventMaskRightMouseDown | NSEventMaskRightMouseUp | NSEventMaskRightMouseDragged;
|
||||||
|
eventMask |= NSEventMaskOtherMouseDown | NSEventMaskOtherMouseUp | NSEventMaskOtherMouseDragged;
|
||||||
|
eventMask |= NSEventMaskKeyDown | NSEventMaskKeyUp | NSEventMaskFlagsChanged;
|
||||||
|
bd->Monitor = [NSEvent addLocalMonitorForEventsMatchingMask:eventMask
|
||||||
|
handler:^NSEvent* _Nullable(NSEvent* event)
|
||||||
|
{
|
||||||
|
ImGui_ImplOSX_HandleEvent(event, view);
|
||||||
|
return event;
|
||||||
|
}];
|
||||||
|
}
|
|
@ -0,0 +1,564 @@
|
||||||
|
// 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.)
|
||||||
|
// (Prefer SDL 2.0.5+ for full feature support.)
|
||||||
|
|
||||||
|
// Implemented features:
|
||||||
|
// [X] Platform: Clipboard support.
|
||||||
|
// [X] Platform: Keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy SDL_SCANCODE_* values will also be supported unless IMGUI_DISABLE_OBSOLETE_KEYIO is set]
|
||||||
|
// [X] Platform: Gamepad support. Enabled with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'.
|
||||||
|
// [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'.
|
||||||
|
// 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 use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
||||||
|
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
|
||||||
|
// 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)
|
||||||
|
// 2022-03-22: Inputs: Fix mouse position issues when dragging outside of boundaries. SDL_CaptureMouse() erroneously still gives out LEAVE events when hovering OS decorations.
|
||||||
|
// 2022-03-22: Inputs: Added support for extra mouse buttons (SDL_BUTTON_X1/SDL_BUTTON_X2).
|
||||||
|
// 2022-02-04: Added SDL_Renderer* parameter to ImGui_ImplSDL2_InitForSDLRenderer(), so we can use SDL_GetRendererOutputSize() instead of SDL_GL_GetDrawableSize() when bound to a SDL_Renderer.
|
||||||
|
// 2022-01-26: Inputs: replaced short-lived io.AddKeyModsEvent() (added two weeks ago) with io.AddKeyEvent() using ImGuiKey_ModXXX flags. Sorry for the confusion.
|
||||||
|
// 2021-01-20: Inputs: calling new io.AddKeyAnalogEvent() for gamepad support, instead of writing directly to io.NavInputs[].
|
||||||
|
// 2022-01-17: Inputs: calling new io.AddMousePosEvent(), io.AddMouseButtonEvent(), io.AddMouseWheelEvent() API (1.87+).
|
||||||
|
// 2022-01-17: Inputs: always update key mods next and before key event (not in NewFrame) to fix input queue with very low framerates.
|
||||||
|
// 2022-01-12: Update mouse inputs using SDL_MOUSEMOTION/SDL_WINDOWEVENT_LEAVE + fallback to provide it when focused but not hovered/captured. More standard and will allow us to pass it to future input queue API.
|
||||||
|
// 2022-01-12: Maintain our own copy of MouseButtonsDown mask instead of using ImGui::IsAnyMouseDown() which will be obsoleted.
|
||||||
|
// 2022-01-10: Inputs: calling new io.AddKeyEvent(), io.AddKeyModsEvent() + io.SetKeyEventNativeData() API (1.87+). Support for full ImGuiKey range.
|
||||||
|
// 2021-08-17: Calling io.AddFocusEvent() on SDL_WINDOWEVENT_FOCUS_GAINED/SDL_WINDOWEVENT_FOCUS_LOST.
|
||||||
|
// 2021-07-29: Inputs: MousePos is correctly reported when the host platform window is hovered but not focused (using SDL_GetMouseFocus() + SDL_HINT_MOUSE_FOCUS_CLICKTHROUGH, requires SDL 2.0.5+)
|
||||||
|
// 2021-06-29: *BREAKING CHANGE* Removed 'SDL_Window* window' parameter to ImGui_ImplSDL2_NewFrame() which was unnecessary.
|
||||||
|
// 2021-06-29: Reorganized backend to pull data from a single structure to facilitate usage with multiple-contexts (all g_XXXX access changed to bd->XXXX).
|
||||||
|
// 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
|
||||||
|
|
||||||
|
#if SDL_VERSION_ATLEAST(2,0,4) && !defined(__EMSCRIPTEN__) && !defined(__ANDROID__) && !(defined(__APPLE__) && TARGET_OS_IOS) && !defined(__amigaos4__)
|
||||||
|
#define SDL_HAS_CAPTURE_AND_GLOBAL_MOUSE 1
|
||||||
|
#else
|
||||||
|
#define SDL_HAS_CAPTURE_AND_GLOBAL_MOUSE 0
|
||||||
|
#endif
|
||||||
|
#define SDL_HAS_MOUSE_FOCUS_CLICKTHROUGH SDL_VERSION_ATLEAST(2,0,5)
|
||||||
|
#define SDL_HAS_VULKAN SDL_VERSION_ATLEAST(2,0,6)
|
||||||
|
|
||||||
|
// SDL Data
|
||||||
|
struct ImGui_ImplSDL2_Data
|
||||||
|
{
|
||||||
|
SDL_Window* Window;
|
||||||
|
SDL_Renderer* Renderer;
|
||||||
|
Uint64 Time;
|
||||||
|
int MouseButtonsDown;
|
||||||
|
SDL_Cursor* MouseCursors[ImGuiMouseCursor_COUNT];
|
||||||
|
int PendingMouseLeaveFrame;
|
||||||
|
char* ClipboardTextData;
|
||||||
|
bool MouseCanUseGlobalState;
|
||||||
|
|
||||||
|
ImGui_ImplSDL2_Data() { memset((void*)this, 0, sizeof(*this)); }
|
||||||
|
};
|
||||||
|
|
||||||
|
// Backend data stored in io.BackendPlatformUserData to allow support for multiple Dear ImGui contexts
|
||||||
|
// It is STRONGLY preferred that you use docking branch with multi-viewports (== single Dear ImGui context + multiple windows) instead of multiple Dear ImGui contexts.
|
||||||
|
// FIXME: multi-context support is not well tested and probably dysfunctional in this backend.
|
||||||
|
// FIXME: some shared resources (mouse cursor shape, gamepad) are mishandled when using multi-context.
|
||||||
|
static ImGui_ImplSDL2_Data* ImGui_ImplSDL2_GetBackendData()
|
||||||
|
{
|
||||||
|
return ImGui::GetCurrentContext() ? (ImGui_ImplSDL2_Data*)ImGui::GetIO().BackendPlatformUserData : NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Functions
|
||||||
|
static const char* ImGui_ImplSDL2_GetClipboardText(void*)
|
||||||
|
{
|
||||||
|
ImGui_ImplSDL2_Data* bd = ImGui_ImplSDL2_GetBackendData();
|
||||||
|
if (bd->ClipboardTextData)
|
||||||
|
SDL_free(bd->ClipboardTextData);
|
||||||
|
bd->ClipboardTextData = SDL_GetClipboardText();
|
||||||
|
return bd->ClipboardTextData;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ImGui_ImplSDL2_SetClipboardText(void*, const char* text)
|
||||||
|
{
|
||||||
|
SDL_SetClipboardText(text);
|
||||||
|
}
|
||||||
|
|
||||||
|
static ImGuiKey ImGui_ImplSDL2_KeycodeToImGuiKey(int keycode)
|
||||||
|
{
|
||||||
|
switch (keycode)
|
||||||
|
{
|
||||||
|
case SDLK_TAB: return ImGuiKey_Tab;
|
||||||
|
case SDLK_LEFT: return ImGuiKey_LeftArrow;
|
||||||
|
case SDLK_RIGHT: return ImGuiKey_RightArrow;
|
||||||
|
case SDLK_UP: return ImGuiKey_UpArrow;
|
||||||
|
case SDLK_DOWN: return ImGuiKey_DownArrow;
|
||||||
|
case SDLK_PAGEUP: return ImGuiKey_PageUp;
|
||||||
|
case SDLK_PAGEDOWN: return ImGuiKey_PageDown;
|
||||||
|
case SDLK_HOME: return ImGuiKey_Home;
|
||||||
|
case SDLK_END: return ImGuiKey_End;
|
||||||
|
case SDLK_INSERT: return ImGuiKey_Insert;
|
||||||
|
case SDLK_DELETE: return ImGuiKey_Delete;
|
||||||
|
case SDLK_BACKSPACE: return ImGuiKey_Backspace;
|
||||||
|
case SDLK_SPACE: return ImGuiKey_Space;
|
||||||
|
case SDLK_RETURN: return ImGuiKey_Enter;
|
||||||
|
case SDLK_ESCAPE: return ImGuiKey_Escape;
|
||||||
|
case SDLK_QUOTE: return ImGuiKey_Apostrophe;
|
||||||
|
case SDLK_COMMA: return ImGuiKey_Comma;
|
||||||
|
case SDLK_MINUS: return ImGuiKey_Minus;
|
||||||
|
case SDLK_PERIOD: return ImGuiKey_Period;
|
||||||
|
case SDLK_SLASH: return ImGuiKey_Slash;
|
||||||
|
case SDLK_SEMICOLON: return ImGuiKey_Semicolon;
|
||||||
|
case SDLK_EQUALS: return ImGuiKey_Equal;
|
||||||
|
case SDLK_LEFTBRACKET: return ImGuiKey_LeftBracket;
|
||||||
|
case SDLK_BACKSLASH: return ImGuiKey_Backslash;
|
||||||
|
case SDLK_RIGHTBRACKET: return ImGuiKey_RightBracket;
|
||||||
|
case SDLK_BACKQUOTE: return ImGuiKey_GraveAccent;
|
||||||
|
case SDLK_CAPSLOCK: return ImGuiKey_CapsLock;
|
||||||
|
case SDLK_SCROLLLOCK: return ImGuiKey_ScrollLock;
|
||||||
|
case SDLK_NUMLOCKCLEAR: return ImGuiKey_NumLock;
|
||||||
|
case SDLK_PRINTSCREEN: return ImGuiKey_PrintScreen;
|
||||||
|
case SDLK_PAUSE: return ImGuiKey_Pause;
|
||||||
|
case SDLK_KP_0: return ImGuiKey_Keypad0;
|
||||||
|
case SDLK_KP_1: return ImGuiKey_Keypad1;
|
||||||
|
case SDLK_KP_2: return ImGuiKey_Keypad2;
|
||||||
|
case SDLK_KP_3: return ImGuiKey_Keypad3;
|
||||||
|
case SDLK_KP_4: return ImGuiKey_Keypad4;
|
||||||
|
case SDLK_KP_5: return ImGuiKey_Keypad5;
|
||||||
|
case SDLK_KP_6: return ImGuiKey_Keypad6;
|
||||||
|
case SDLK_KP_7: return ImGuiKey_Keypad7;
|
||||||
|
case SDLK_KP_8: return ImGuiKey_Keypad8;
|
||||||
|
case SDLK_KP_9: return ImGuiKey_Keypad9;
|
||||||
|
case SDLK_KP_PERIOD: return ImGuiKey_KeypadDecimal;
|
||||||
|
case SDLK_KP_DIVIDE: return ImGuiKey_KeypadDivide;
|
||||||
|
case SDLK_KP_MULTIPLY: return ImGuiKey_KeypadMultiply;
|
||||||
|
case SDLK_KP_MINUS: return ImGuiKey_KeypadSubtract;
|
||||||
|
case SDLK_KP_PLUS: return ImGuiKey_KeypadAdd;
|
||||||
|
case SDLK_KP_ENTER: return ImGuiKey_KeypadEnter;
|
||||||
|
case SDLK_KP_EQUALS: return ImGuiKey_KeypadEqual;
|
||||||
|
case SDLK_LCTRL: return ImGuiKey_LeftCtrl;
|
||||||
|
case SDLK_LSHIFT: return ImGuiKey_LeftShift;
|
||||||
|
case SDLK_LALT: return ImGuiKey_LeftAlt;
|
||||||
|
case SDLK_LGUI: return ImGuiKey_LeftSuper;
|
||||||
|
case SDLK_RCTRL: return ImGuiKey_RightCtrl;
|
||||||
|
case SDLK_RSHIFT: return ImGuiKey_RightShift;
|
||||||
|
case SDLK_RALT: return ImGuiKey_RightAlt;
|
||||||
|
case SDLK_RGUI: return ImGuiKey_RightSuper;
|
||||||
|
case SDLK_APPLICATION: return ImGuiKey_Menu;
|
||||||
|
case SDLK_0: return ImGuiKey_0;
|
||||||
|
case SDLK_1: return ImGuiKey_1;
|
||||||
|
case SDLK_2: return ImGuiKey_2;
|
||||||
|
case SDLK_3: return ImGuiKey_3;
|
||||||
|
case SDLK_4: return ImGuiKey_4;
|
||||||
|
case SDLK_5: return ImGuiKey_5;
|
||||||
|
case SDLK_6: return ImGuiKey_6;
|
||||||
|
case SDLK_7: return ImGuiKey_7;
|
||||||
|
case SDLK_8: return ImGuiKey_8;
|
||||||
|
case SDLK_9: return ImGuiKey_9;
|
||||||
|
case SDLK_a: return ImGuiKey_A;
|
||||||
|
case SDLK_b: return ImGuiKey_B;
|
||||||
|
case SDLK_c: return ImGuiKey_C;
|
||||||
|
case SDLK_d: return ImGuiKey_D;
|
||||||
|
case SDLK_e: return ImGuiKey_E;
|
||||||
|
case SDLK_f: return ImGuiKey_F;
|
||||||
|
case SDLK_g: return ImGuiKey_G;
|
||||||
|
case SDLK_h: return ImGuiKey_H;
|
||||||
|
case SDLK_i: return ImGuiKey_I;
|
||||||
|
case SDLK_j: return ImGuiKey_J;
|
||||||
|
case SDLK_k: return ImGuiKey_K;
|
||||||
|
case SDLK_l: return ImGuiKey_L;
|
||||||
|
case SDLK_m: return ImGuiKey_M;
|
||||||
|
case SDLK_n: return ImGuiKey_N;
|
||||||
|
case SDLK_o: return ImGuiKey_O;
|
||||||
|
case SDLK_p: return ImGuiKey_P;
|
||||||
|
case SDLK_q: return ImGuiKey_Q;
|
||||||
|
case SDLK_r: return ImGuiKey_R;
|
||||||
|
case SDLK_s: return ImGuiKey_S;
|
||||||
|
case SDLK_t: return ImGuiKey_T;
|
||||||
|
case SDLK_u: return ImGuiKey_U;
|
||||||
|
case SDLK_v: return ImGuiKey_V;
|
||||||
|
case SDLK_w: return ImGuiKey_W;
|
||||||
|
case SDLK_x: return ImGuiKey_X;
|
||||||
|
case SDLK_y: return ImGuiKey_Y;
|
||||||
|
case SDLK_z: return ImGuiKey_Z;
|
||||||
|
case SDLK_F1: return ImGuiKey_F1;
|
||||||
|
case SDLK_F2: return ImGuiKey_F2;
|
||||||
|
case SDLK_F3: return ImGuiKey_F3;
|
||||||
|
case SDLK_F4: return ImGuiKey_F4;
|
||||||
|
case SDLK_F5: return ImGuiKey_F5;
|
||||||
|
case SDLK_F6: return ImGuiKey_F6;
|
||||||
|
case SDLK_F7: return ImGuiKey_F7;
|
||||||
|
case SDLK_F8: return ImGuiKey_F8;
|
||||||
|
case SDLK_F9: return ImGuiKey_F9;
|
||||||
|
case SDLK_F10: return ImGuiKey_F10;
|
||||||
|
case SDLK_F11: return ImGuiKey_F11;
|
||||||
|
case SDLK_F12: return ImGuiKey_F12;
|
||||||
|
}
|
||||||
|
return ImGuiKey_None;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ImGui_ImplSDL2_UpdateKeyModifiers(SDL_Keymod sdl_key_mods)
|
||||||
|
{
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
io.AddKeyEvent(ImGuiKey_ModCtrl, (sdl_key_mods & KMOD_CTRL) != 0);
|
||||||
|
io.AddKeyEvent(ImGuiKey_ModShift, (sdl_key_mods & KMOD_SHIFT) != 0);
|
||||||
|
io.AddKeyEvent(ImGuiKey_ModAlt, (sdl_key_mods & KMOD_ALT) != 0);
|
||||||
|
io.AddKeyEvent(ImGuiKey_ModSuper, (sdl_key_mods & KMOD_GUI) != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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, or clear/overwrite your copy of the mouse data.
|
||||||
|
// - When io.WantCaptureKeyboard is true, do not dispatch keyboard input data to your main application, or clear/overwrite your copy of the keyboard data.
|
||||||
|
// 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();
|
||||||
|
ImGui_ImplSDL2_Data* bd = ImGui_ImplSDL2_GetBackendData();
|
||||||
|
|
||||||
|
switch (event->type)
|
||||||
|
{
|
||||||
|
case SDL_MOUSEMOTION:
|
||||||
|
{
|
||||||
|
io.AddMousePosEvent((float)event->motion.x, (float)event->motion.y);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
case SDL_MOUSEWHEEL:
|
||||||
|
{
|
||||||
|
float wheel_x = (event->wheel.x > 0) ? 1.0f : (event->wheel.x < 0) ? -1.0f : 0.0f;
|
||||||
|
float wheel_y = (event->wheel.y > 0) ? 1.0f : (event->wheel.y < 0) ? -1.0f : 0.0f;
|
||||||
|
io.AddMouseWheelEvent(wheel_x, wheel_y);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
case SDL_MOUSEBUTTONDOWN:
|
||||||
|
case SDL_MOUSEBUTTONUP:
|
||||||
|
{
|
||||||
|
int mouse_button = -1;
|
||||||
|
if (event->button.button == SDL_BUTTON_LEFT) { mouse_button = 0; }
|
||||||
|
if (event->button.button == SDL_BUTTON_RIGHT) { mouse_button = 1; }
|
||||||
|
if (event->button.button == SDL_BUTTON_MIDDLE) { mouse_button = 2; }
|
||||||
|
if (event->button.button == SDL_BUTTON_X1) { mouse_button = 3; }
|
||||||
|
if (event->button.button == SDL_BUTTON_X2) { mouse_button = 4; }
|
||||||
|
if (mouse_button == -1)
|
||||||
|
break;
|
||||||
|
io.AddMouseButtonEvent(mouse_button, (event->type == SDL_MOUSEBUTTONDOWN));
|
||||||
|
bd->MouseButtonsDown = (event->type == SDL_MOUSEBUTTONDOWN) ? (bd->MouseButtonsDown | (1 << mouse_button)) : (bd->MouseButtonsDown & ~(1 << mouse_button));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
case SDL_TEXTINPUT:
|
||||||
|
{
|
||||||
|
io.AddInputCharactersUTF8(event->text.text);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
case SDL_KEYDOWN:
|
||||||
|
case SDL_KEYUP:
|
||||||
|
{
|
||||||
|
ImGui_ImplSDL2_UpdateKeyModifiers((SDL_Keymod)event->key.keysym.mod);
|
||||||
|
ImGuiKey key = ImGui_ImplSDL2_KeycodeToImGuiKey(event->key.keysym.sym);
|
||||||
|
io.AddKeyEvent(key, (event->type == SDL_KEYDOWN));
|
||||||
|
io.SetKeyEventNativeData(key, event->key.keysym.sym, event->key.keysym.scancode, event->key.keysym.scancode); // To support legacy indexing (<1.87 user code). Legacy backend uses SDLK_*** as indices to IsKeyXXX() functions.
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
case SDL_WINDOWEVENT:
|
||||||
|
{
|
||||||
|
// - When capturing mouse, SDL will send a bunch of conflicting LEAVE/ENTER event on every mouse move, but the final ENTER tends to be right.
|
||||||
|
// - However we won't get a correct LEAVE event for a captured window.
|
||||||
|
// - In some cases, when detaching a window from main viewport SDL may send SDL_WINDOWEVENT_ENTER one frame too late,
|
||||||
|
// causing SDL_WINDOWEVENT_LEAVE on previous frame to interrupt drag operation by clear mouse position. This is why
|
||||||
|
// we delay process the SDL_WINDOWEVENT_LEAVE events by one frame. See issue #5012 for details.
|
||||||
|
Uint8 window_event = event->window.event;
|
||||||
|
if (window_event == SDL_WINDOWEVENT_ENTER)
|
||||||
|
bd->PendingMouseLeaveFrame = 0;
|
||||||
|
if (window_event == SDL_WINDOWEVENT_LEAVE)
|
||||||
|
bd->PendingMouseLeaveFrame = ImGui::GetFrameCount() + 1;
|
||||||
|
if (window_event == SDL_WINDOWEVENT_FOCUS_GAINED)
|
||||||
|
io.AddFocusEvent(true);
|
||||||
|
else if (event->window.event == SDL_WINDOWEVENT_FOCUS_LOST)
|
||||||
|
io.AddFocusEvent(false);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool ImGui_ImplSDL2_Init(SDL_Window* window, SDL_Renderer* renderer)
|
||||||
|
{
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
IM_ASSERT(io.BackendPlatformUserData == NULL && "Already initialized a platform backend!");
|
||||||
|
|
||||||
|
// 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)
|
||||||
|
bool mouse_can_use_global_state = false;
|
||||||
|
#if SDL_HAS_CAPTURE_AND_GLOBAL_MOUSE
|
||||||
|
const char* sdl_backend = SDL_GetCurrentVideoDriver();
|
||||||
|
const char* global_mouse_whitelist[] = { "windows", "cocoa", "x11", "DIVE", "VMAN" };
|
||||||
|
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)
|
||||||
|
mouse_can_use_global_state = true;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Setup backend capabilities flags
|
||||||
|
ImGui_ImplSDL2_Data* bd = IM_NEW(ImGui_ImplSDL2_Data)();
|
||||||
|
io.BackendPlatformUserData = (void*)bd;
|
||||||
|
io.BackendPlatformName = "imgui_impl_sdl";
|
||||||
|
io.BackendFlags |= ImGuiBackendFlags_HasMouseCursors; // We can honor GetMouseCursor() values (optional)
|
||||||
|
io.BackendFlags |= ImGuiBackendFlags_HasSetMousePos; // We can honor io.WantSetMousePos requests (optional, rarely used)
|
||||||
|
|
||||||
|
bd->Window = window;
|
||||||
|
bd->Renderer = renderer;
|
||||||
|
bd->MouseCanUseGlobalState = mouse_can_use_global_state;
|
||||||
|
|
||||||
|
io.SetClipboardTextFn = ImGui_ImplSDL2_SetClipboardText;
|
||||||
|
io.GetClipboardTextFn = ImGui_ImplSDL2_GetClipboardText;
|
||||||
|
io.ClipboardUserData = NULL;
|
||||||
|
|
||||||
|
// Load mouse cursors
|
||||||
|
bd->MouseCursors[ImGuiMouseCursor_Arrow] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_ARROW);
|
||||||
|
bd->MouseCursors[ImGuiMouseCursor_TextInput] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_IBEAM);
|
||||||
|
bd->MouseCursors[ImGuiMouseCursor_ResizeAll] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZEALL);
|
||||||
|
bd->MouseCursors[ImGuiMouseCursor_ResizeNS] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZENS);
|
||||||
|
bd->MouseCursors[ImGuiMouseCursor_ResizeEW] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZEWE);
|
||||||
|
bd->MouseCursors[ImGuiMouseCursor_ResizeNESW] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZENESW);
|
||||||
|
bd->MouseCursors[ImGuiMouseCursor_ResizeNWSE] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZENWSE);
|
||||||
|
bd->MouseCursors[ImGuiMouseCursor_Hand] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_HAND);
|
||||||
|
bd->MouseCursors[ImGuiMouseCursor_NotAllowed] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_NO);
|
||||||
|
|
||||||
|
// Set platform dependent data in viewport
|
||||||
|
#ifdef _WIN32
|
||||||
|
SDL_SysWMinfo info;
|
||||||
|
SDL_VERSION(&info.version);
|
||||||
|
if (SDL_GetWindowWMInfo(window, &info))
|
||||||
|
ImGui::GetMainViewport()->PlatformHandleRaw = (void*)info.info.win.window;
|
||||||
|
#else
|
||||||
|
(void)window;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Set SDL hint to receive mouse click events on window focus, otherwise SDL doesn't emit the event.
|
||||||
|
// Without this, when clicking to gain focus, our widgets wouldn't activate even though they showed as hovered.
|
||||||
|
// (This is unfortunately a global SDL setting, so enabling it might have a side-effect on your application.
|
||||||
|
// It is unlikely to make a difference, but if your app absolutely needs to ignore the initial on-focus click:
|
||||||
|
// you can ignore SDL_MOUSEBUTTONDOWN events coming right after a SDL_WINDOWEVENT_FOCUS_GAINED)
|
||||||
|
#if SDL_HAS_MOUSE_FOCUS_CLICKTHROUGH
|
||||||
|
SDL_SetHint(SDL_HINT_MOUSE_FOCUS_CLICKTHROUGH, "1");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ImGui_ImplSDL2_InitForOpenGL(SDL_Window* window, void* sdl_gl_context)
|
||||||
|
{
|
||||||
|
IM_UNUSED(sdl_gl_context); // Viewport branch will need this.
|
||||||
|
return ImGui_ImplSDL2_Init(window, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ImGui_ImplSDL2_InitForVulkan(SDL_Window* window)
|
||||||
|
{
|
||||||
|
#if !SDL_HAS_VULKAN
|
||||||
|
IM_ASSERT(0 && "Unsupported");
|
||||||
|
#endif
|
||||||
|
return ImGui_ImplSDL2_Init(window, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ImGui_ImplSDL2_InitForD3D(SDL_Window* window)
|
||||||
|
{
|
||||||
|
#if !defined(_WIN32)
|
||||||
|
IM_ASSERT(0 && "Unsupported");
|
||||||
|
#endif
|
||||||
|
return ImGui_ImplSDL2_Init(window, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ImGui_ImplSDL2_InitForMetal(SDL_Window* window)
|
||||||
|
{
|
||||||
|
return ImGui_ImplSDL2_Init(window, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ImGui_ImplSDL2_InitForSDLRenderer(SDL_Window* window, SDL_Renderer* renderer)
|
||||||
|
{
|
||||||
|
return ImGui_ImplSDL2_Init(window, renderer);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGui_ImplSDL2_Shutdown()
|
||||||
|
{
|
||||||
|
ImGui_ImplSDL2_Data* bd = ImGui_ImplSDL2_GetBackendData();
|
||||||
|
IM_ASSERT(bd != NULL && "No platform backend to shutdown, or already shutdown?");
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
|
||||||
|
if (bd->ClipboardTextData)
|
||||||
|
SDL_free(bd->ClipboardTextData);
|
||||||
|
for (ImGuiMouseCursor cursor_n = 0; cursor_n < ImGuiMouseCursor_COUNT; cursor_n++)
|
||||||
|
SDL_FreeCursor(bd->MouseCursors[cursor_n]);
|
||||||
|
|
||||||
|
io.BackendPlatformName = NULL;
|
||||||
|
io.BackendPlatformUserData = NULL;
|
||||||
|
IM_DELETE(bd);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ImGui_ImplSDL2_UpdateMouseData()
|
||||||
|
{
|
||||||
|
ImGui_ImplSDL2_Data* bd = ImGui_ImplSDL2_GetBackendData();
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
|
||||||
|
// We forward mouse input when hovered or captured (via SDL_MOUSEMOTION) or when focused (below)
|
||||||
|
#if SDL_HAS_CAPTURE_AND_GLOBAL_MOUSE
|
||||||
|
// SDL_CaptureMouse() let the OS know e.g. that our imgui drag outside the SDL window boundaries shouldn't e.g. trigger other operations outside
|
||||||
|
SDL_CaptureMouse(bd->MouseButtonsDown != 0 ? SDL_TRUE : SDL_FALSE);
|
||||||
|
SDL_Window* focused_window = SDL_GetKeyboardFocus();
|
||||||
|
const bool is_app_focused = (bd->Window == focused_window);
|
||||||
|
#else
|
||||||
|
const bool is_app_focused = (SDL_GetWindowFlags(bd->Window) & SDL_WINDOW_INPUT_FOCUS) != 0; // SDL 2.0.3 and non-windowed systems: single-viewport only
|
||||||
|
#endif
|
||||||
|
if (is_app_focused)
|
||||||
|
{
|
||||||
|
// (Optional) Set OS mouse position from Dear ImGui if requested (rarely used, only when ImGuiConfigFlags_NavEnableSetMousePos is enabled by user)
|
||||||
|
if (io.WantSetMousePos)
|
||||||
|
SDL_WarpMouseInWindow(bd->Window, (int)io.MousePos.x, (int)io.MousePos.y);
|
||||||
|
|
||||||
|
// (Optional) Fallback to provide mouse position when focused (SDL_MOUSEMOTION already provides this when hovered or captured)
|
||||||
|
if (bd->MouseCanUseGlobalState && bd->MouseButtonsDown == 0)
|
||||||
|
{
|
||||||
|
int window_x, window_y, mouse_x_global, mouse_y_global;
|
||||||
|
SDL_GetGlobalMouseState(&mouse_x_global, &mouse_y_global);
|
||||||
|
SDL_GetWindowPosition(bd->Window, &window_x, &window_y);
|
||||||
|
io.AddMousePosEvent((float)(mouse_x_global - window_x), (float)(mouse_y_global - window_y));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ImGui_ImplSDL2_UpdateMouseCursor()
|
||||||
|
{
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
if (io.ConfigFlags & ImGuiConfigFlags_NoMouseCursorChange)
|
||||||
|
return;
|
||||||
|
ImGui_ImplSDL2_Data* bd = ImGui_ImplSDL2_GetBackendData();
|
||||||
|
|
||||||
|
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(bd->MouseCursors[imgui_cursor] ? bd->MouseCursors[imgui_cursor] : bd->MouseCursors[ImGuiMouseCursor_Arrow]);
|
||||||
|
SDL_ShowCursor(SDL_TRUE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ImGui_ImplSDL2_UpdateGamepads()
|
||||||
|
{
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
if ((io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) == 0) // FIXME: Technically feeding gamepad shouldn't depend on this now that they are regular inputs.
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Get gamepad
|
||||||
|
io.BackendFlags &= ~ImGuiBackendFlags_HasGamepad;
|
||||||
|
SDL_GameController* game_controller = SDL_GameControllerOpen(0);
|
||||||
|
if (!game_controller)
|
||||||
|
return;
|
||||||
|
io.BackendFlags |= ImGuiBackendFlags_HasGamepad;
|
||||||
|
|
||||||
|
// Update gamepad inputs
|
||||||
|
#define IM_SATURATE(V) (V < 0.0f ? 0.0f : V > 1.0f ? 1.0f : V)
|
||||||
|
#define MAP_BUTTON(KEY_NO, BUTTON_NO) { io.AddKeyEvent(KEY_NO, SDL_GameControllerGetButton(game_controller, BUTTON_NO) != 0); }
|
||||||
|
#define MAP_ANALOG(KEY_NO, AXIS_NO, V0, V1) { float vn = (float)(SDL_GameControllerGetAxis(game_controller, AXIS_NO) - V0) / (float)(V1 - V0); vn = IM_SATURATE(vn); io.AddKeyAnalogEvent(KEY_NO, vn > 0.1f, vn); }
|
||||||
|
const int thumb_dead_zone = 8000; // SDL_gamecontroller.h suggests using this value.
|
||||||
|
MAP_BUTTON(ImGuiKey_GamepadStart, SDL_CONTROLLER_BUTTON_START);
|
||||||
|
MAP_BUTTON(ImGuiKey_GamepadBack, SDL_CONTROLLER_BUTTON_BACK);
|
||||||
|
MAP_BUTTON(ImGuiKey_GamepadFaceLeft, SDL_CONTROLLER_BUTTON_X); // Xbox X, PS Square
|
||||||
|
MAP_BUTTON(ImGuiKey_GamepadFaceRight, SDL_CONTROLLER_BUTTON_B); // Xbox B, PS Circle
|
||||||
|
MAP_BUTTON(ImGuiKey_GamepadFaceUp, SDL_CONTROLLER_BUTTON_Y); // Xbox Y, PS Triangle
|
||||||
|
MAP_BUTTON(ImGuiKey_GamepadFaceDown, SDL_CONTROLLER_BUTTON_A); // Xbox A, PS Cross
|
||||||
|
MAP_BUTTON(ImGuiKey_GamepadDpadLeft, SDL_CONTROLLER_BUTTON_DPAD_LEFT);
|
||||||
|
MAP_BUTTON(ImGuiKey_GamepadDpadRight, SDL_CONTROLLER_BUTTON_DPAD_RIGHT);
|
||||||
|
MAP_BUTTON(ImGuiKey_GamepadDpadUp, SDL_CONTROLLER_BUTTON_DPAD_UP);
|
||||||
|
MAP_BUTTON(ImGuiKey_GamepadDpadDown, SDL_CONTROLLER_BUTTON_DPAD_DOWN);
|
||||||
|
MAP_BUTTON(ImGuiKey_GamepadL1, SDL_CONTROLLER_BUTTON_LEFTSHOULDER);
|
||||||
|
MAP_BUTTON(ImGuiKey_GamepadR1, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER);
|
||||||
|
MAP_ANALOG(ImGuiKey_GamepadL2, SDL_CONTROLLER_AXIS_TRIGGERLEFT, 0.0f, 32767);
|
||||||
|
MAP_ANALOG(ImGuiKey_GamepadR2, SDL_CONTROLLER_AXIS_TRIGGERRIGHT, 0.0f, 32767);
|
||||||
|
MAP_BUTTON(ImGuiKey_GamepadL3, SDL_CONTROLLER_BUTTON_LEFTSTICK);
|
||||||
|
MAP_BUTTON(ImGuiKey_GamepadR3, SDL_CONTROLLER_BUTTON_RIGHTSTICK);
|
||||||
|
MAP_ANALOG(ImGuiKey_GamepadLStickLeft, SDL_CONTROLLER_AXIS_LEFTX, -thumb_dead_zone, -32768);
|
||||||
|
MAP_ANALOG(ImGuiKey_GamepadLStickRight, SDL_CONTROLLER_AXIS_LEFTX, +thumb_dead_zone, +32767);
|
||||||
|
MAP_ANALOG(ImGuiKey_GamepadLStickUp, SDL_CONTROLLER_AXIS_LEFTY, -thumb_dead_zone, -32768);
|
||||||
|
MAP_ANALOG(ImGuiKey_GamepadLStickDown, SDL_CONTROLLER_AXIS_LEFTY, +thumb_dead_zone, +32767);
|
||||||
|
MAP_ANALOG(ImGuiKey_GamepadRStickLeft, SDL_CONTROLLER_AXIS_RIGHTX, -thumb_dead_zone, -32768);
|
||||||
|
MAP_ANALOG(ImGuiKey_GamepadRStickRight, SDL_CONTROLLER_AXIS_RIGHTX, +thumb_dead_zone, +32767);
|
||||||
|
MAP_ANALOG(ImGuiKey_GamepadRStickUp, SDL_CONTROLLER_AXIS_RIGHTY, -thumb_dead_zone, -32768);
|
||||||
|
MAP_ANALOG(ImGuiKey_GamepadRStickDown, SDL_CONTROLLER_AXIS_RIGHTY, +thumb_dead_zone, +32767);
|
||||||
|
#undef MAP_BUTTON
|
||||||
|
#undef MAP_ANALOG
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGui_ImplSDL2_NewFrame()
|
||||||
|
{
|
||||||
|
ImGui_ImplSDL2_Data* bd = ImGui_ImplSDL2_GetBackendData();
|
||||||
|
IM_ASSERT(bd != NULL && "Did you call ImGui_ImplSDL2_Init()?");
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
|
||||||
|
// Setup display size (every frame to accommodate for window resizing)
|
||||||
|
int w, h;
|
||||||
|
int display_w, display_h;
|
||||||
|
SDL_GetWindowSize(bd->Window, &w, &h);
|
||||||
|
if (SDL_GetWindowFlags(bd->Window) & SDL_WINDOW_MINIMIZED)
|
||||||
|
w = h = 0;
|
||||||
|
if (bd->Renderer != NULL)
|
||||||
|
SDL_GetRendererOutputSize(bd->Renderer, &display_w, &display_h);
|
||||||
|
else
|
||||||
|
SDL_GL_GetDrawableSize(bd->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 = bd->Time > 0 ? (float)((double)(current_time - bd->Time) / frequency) : (float)(1.0f / 60.0f);
|
||||||
|
bd->Time = current_time;
|
||||||
|
|
||||||
|
if (bd->PendingMouseLeaveFrame && bd->PendingMouseLeaveFrame >= ImGui::GetFrameCount() && bd->MouseButtonsDown == 0)
|
||||||
|
{
|
||||||
|
io.AddMousePosEvent(-FLT_MAX, -FLT_MAX);
|
||||||
|
bd->PendingMouseLeaveFrame = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui_ImplSDL2_UpdateMouseData();
|
||||||
|
ImGui_ImplSDL2_UpdateMouseCursor();
|
||||||
|
|
||||||
|
// Update game controllers (if enabled and available)
|
||||||
|
ImGui_ImplSDL2_UpdateGamepads();
|
||||||
|
}
|
|
@ -0,0 +1,36 @@
|
||||||
|
// 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: Clipboard support.
|
||||||
|
// [X] Platform: Keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy SDL_SCANCODE_* values will also be supported unless IMGUI_DISABLE_OBSOLETE_KEYIO is set]
|
||||||
|
// [X] Platform: Gamepad support. Enabled with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'.
|
||||||
|
// [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'.
|
||||||
|
// 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 use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
||||||
|
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
|
||||||
|
// 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;
|
||||||
|
struct SDL_Renderer;
|
||||||
|
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 bool ImGui_ImplSDL2_InitForSDLRenderer(SDL_Window* window, SDL_Renderer* renderer);
|
||||||
|
IMGUI_IMPL_API void ImGui_ImplSDL2_Shutdown();
|
||||||
|
IMGUI_IMPL_API void ImGui_ImplSDL2_NewFrame();
|
||||||
|
IMGUI_IMPL_API bool ImGui_ImplSDL2_ProcessEvent(const SDL_Event* event);
|
||||||
|
|
||||||
|
#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
|
||||||
|
static inline void ImGui_ImplSDL2_NewFrame(SDL_Window*) { ImGui_ImplSDL2_NewFrame(); } // 1.84: removed unnecessary parameter
|
||||||
|
#endif
|
|
@ -0,0 +1,250 @@
|
||||||
|
// dear imgui: Renderer Backend for SDL_Renderer
|
||||||
|
// (Requires: SDL 2.0.17+)
|
||||||
|
|
||||||
|
// Important to understand: SDL_Renderer is an _optional_ component of SDL.
|
||||||
|
// For a multi-platform app consider using e.g. SDL+DirectX on Windows and SDL+OpenGL on Linux/OSX.
|
||||||
|
// If your application will want to render any non trivial amount of graphics other than UI,
|
||||||
|
// please be aware that SDL_Renderer offers a limited graphic API to the end-user and it might
|
||||||
|
// be difficult to step out of those boundaries.
|
||||||
|
// However, we understand it is a convenient choice to get an app started easily.
|
||||||
|
|
||||||
|
// Implemented features:
|
||||||
|
// [X] Renderer: User texture binding. Use 'SDL_Texture*' as ImTextureID. Read the FAQ about ImTextureID!
|
||||||
|
// [X] Renderer: Support for large meshes (64k+ vertices) with 16-bit indices.
|
||||||
|
// Missing features:
|
||||||
|
|
||||||
|
// 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
|
||||||
|
// 2021-12-21: Update SDL_RenderGeometryRaw() format to work with SDL 2.0.19.
|
||||||
|
// 2021-12-03: Added support for large mesh (64K+ vertices), enable ImGuiBackendFlags_RendererHasVtxOffset flag.
|
||||||
|
// 2021-10-06: Backup and restore modified ClipRect/Viewport.
|
||||||
|
// 2021-09-21: Initial version.
|
||||||
|
|
||||||
|
#include "imgui.h"
|
||||||
|
#include "imgui_impl_sdlrenderer.h"
|
||||||
|
#if defined(_MSC_VER) && _MSC_VER <= 1500 // MSVC 2008 or earlier
|
||||||
|
#include <stddef.h> // intptr_t
|
||||||
|
#else
|
||||||
|
#include <stdint.h> // intptr_t
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// SDL
|
||||||
|
#include <SDL.h>
|
||||||
|
#if !SDL_VERSION_ATLEAST(2,0,17)
|
||||||
|
#error This backend requires SDL 2.0.17+ because of SDL_RenderGeometry() function
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// SDL_Renderer data
|
||||||
|
struct ImGui_ImplSDLRenderer_Data
|
||||||
|
{
|
||||||
|
SDL_Renderer* SDLRenderer;
|
||||||
|
SDL_Texture* FontTexture;
|
||||||
|
ImGui_ImplSDLRenderer_Data() { memset((void*)this, 0, sizeof(*this)); }
|
||||||
|
};
|
||||||
|
|
||||||
|
// Backend data stored in io.BackendRendererUserData to allow support for multiple Dear ImGui contexts
|
||||||
|
// It is STRONGLY preferred that you use docking branch with multi-viewports (== single Dear ImGui context + multiple windows) instead of multiple Dear ImGui contexts.
|
||||||
|
static ImGui_ImplSDLRenderer_Data* ImGui_ImplSDLRenderer_GetBackendData()
|
||||||
|
{
|
||||||
|
return ImGui::GetCurrentContext() ? (ImGui_ImplSDLRenderer_Data*)ImGui::GetIO().BackendRendererUserData : NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Functions
|
||||||
|
bool ImGui_ImplSDLRenderer_Init(SDL_Renderer* renderer)
|
||||||
|
{
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
IM_ASSERT(io.BackendRendererUserData == NULL && "Already initialized a renderer backend!");
|
||||||
|
IM_ASSERT(renderer != NULL && "SDL_Renderer not initialized!");
|
||||||
|
|
||||||
|
// Setup backend capabilities flags
|
||||||
|
ImGui_ImplSDLRenderer_Data* bd = IM_NEW(ImGui_ImplSDLRenderer_Data)();
|
||||||
|
io.BackendRendererUserData = (void*)bd;
|
||||||
|
io.BackendRendererName = "imgui_impl_sdlrenderer";
|
||||||
|
io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes.
|
||||||
|
|
||||||
|
bd->SDLRenderer = renderer;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGui_ImplSDLRenderer_Shutdown()
|
||||||
|
{
|
||||||
|
ImGui_ImplSDLRenderer_Data* bd = ImGui_ImplSDLRenderer_GetBackendData();
|
||||||
|
IM_ASSERT(bd != NULL && "No renderer backend to shutdown, or already shutdown?");
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
|
||||||
|
ImGui_ImplSDLRenderer_DestroyDeviceObjects();
|
||||||
|
|
||||||
|
io.BackendRendererName = NULL;
|
||||||
|
io.BackendRendererUserData = NULL;
|
||||||
|
IM_DELETE(bd);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ImGui_ImplSDLRenderer_SetupRenderState()
|
||||||
|
{
|
||||||
|
ImGui_ImplSDLRenderer_Data* bd = ImGui_ImplSDLRenderer_GetBackendData();
|
||||||
|
|
||||||
|
// Clear out any viewports and cliprect set by the user
|
||||||
|
// FIXME: Technically speaking there are lots of other things we could backup/setup/restore during our render process.
|
||||||
|
SDL_RenderSetViewport(bd->SDLRenderer, NULL);
|
||||||
|
SDL_RenderSetClipRect(bd->SDLRenderer, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGui_ImplSDLRenderer_NewFrame()
|
||||||
|
{
|
||||||
|
ImGui_ImplSDLRenderer_Data* bd = ImGui_ImplSDLRenderer_GetBackendData();
|
||||||
|
IM_ASSERT(bd != NULL && "Did you call ImGui_ImplSDLRenderer_Init()?");
|
||||||
|
|
||||||
|
if (!bd->FontTexture)
|
||||||
|
ImGui_ImplSDLRenderer_CreateDeviceObjects();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGui_ImplSDLRenderer_RenderDrawData(ImDrawData* draw_data)
|
||||||
|
{
|
||||||
|
ImGui_ImplSDLRenderer_Data* bd = ImGui_ImplSDLRenderer_GetBackendData();
|
||||||
|
|
||||||
|
// If there's a scale factor set by the user, use that instead
|
||||||
|
// If the user has specified a scale factor to SDL_Renderer already via SDL_RenderSetScale(), SDL will scale whatever we pass
|
||||||
|
// to SDL_RenderGeometryRaw() by that scale factor. In that case we don't want to be also scaling it ourselves here.
|
||||||
|
float rsx = 1.0f;
|
||||||
|
float rsy = 1.0f;
|
||||||
|
SDL_RenderGetScale(bd->SDLRenderer, &rsx, &rsy);
|
||||||
|
ImVec2 render_scale;
|
||||||
|
render_scale.x = (rsx == 1.0f) ? draw_data->FramebufferScale.x : 1.0f;
|
||||||
|
render_scale.y = (rsy == 1.0f) ? draw_data->FramebufferScale.y : 1.0f;
|
||||||
|
|
||||||
|
// Avoid rendering when minimized, scale coordinates for retina displays (screen coordinates != framebuffer coordinates)
|
||||||
|
int fb_width = (int)(draw_data->DisplaySize.x * render_scale.x);
|
||||||
|
int fb_height = (int)(draw_data->DisplaySize.y * render_scale.y);
|
||||||
|
if (fb_width == 0 || fb_height == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Backup SDL_Renderer state that will be modified to restore it afterwards
|
||||||
|
struct BackupSDLRendererState
|
||||||
|
{
|
||||||
|
SDL_Rect Viewport;
|
||||||
|
bool ClipEnabled;
|
||||||
|
SDL_Rect ClipRect;
|
||||||
|
};
|
||||||
|
BackupSDLRendererState old = {};
|
||||||
|
old.ClipEnabled = SDL_RenderIsClipEnabled(bd->SDLRenderer) == SDL_TRUE;
|
||||||
|
SDL_RenderGetViewport(bd->SDLRenderer, &old.Viewport);
|
||||||
|
SDL_RenderGetClipRect(bd->SDLRenderer, &old.ClipRect);
|
||||||
|
|
||||||
|
// Will project scissor/clipping rectangles into framebuffer space
|
||||||
|
ImVec2 clip_off = draw_data->DisplayPos; // (0,0) unless using multi-viewports
|
||||||
|
ImVec2 clip_scale = render_scale;
|
||||||
|
|
||||||
|
// Render command lists
|
||||||
|
ImGui_ImplSDLRenderer_SetupRenderState();
|
||||||
|
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;
|
||||||
|
|
||||||
|
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_ImplSDLRenderer_SetupRenderState();
|
||||||
|
else
|
||||||
|
pcmd->UserCallback(cmd_list, pcmd);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Project scissor/clipping rectangles into framebuffer space
|
||||||
|
ImVec2 clip_min((pcmd->ClipRect.x - clip_off.x) * clip_scale.x, (pcmd->ClipRect.y - clip_off.y) * clip_scale.y);
|
||||||
|
ImVec2 clip_max((pcmd->ClipRect.z - clip_off.x) * clip_scale.x, (pcmd->ClipRect.w - clip_off.y) * clip_scale.y);
|
||||||
|
if (clip_min.x < 0.0f) { clip_min.x = 0.0f; }
|
||||||
|
if (clip_min.y < 0.0f) { clip_min.y = 0.0f; }
|
||||||
|
if (clip_max.x > fb_width) { clip_max.x = (float)fb_width; }
|
||||||
|
if (clip_max.y > fb_height) { clip_max.y = (float)fb_height; }
|
||||||
|
if (clip_max.x <= clip_min.x || clip_max.y <= clip_min.y)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
SDL_Rect r = { (int)(clip_min.x), (int)(clip_min.y), (int)(clip_max.x - clip_min.x), (int)(clip_max.y - clip_min.y) };
|
||||||
|
SDL_RenderSetClipRect(bd->SDLRenderer, &r);
|
||||||
|
|
||||||
|
const float* xy = (const float*)((const char*)(vtx_buffer + pcmd->VtxOffset) + IM_OFFSETOF(ImDrawVert, pos));
|
||||||
|
const float* uv = (const float*)((const char*)(vtx_buffer + pcmd->VtxOffset) + IM_OFFSETOF(ImDrawVert, uv));
|
||||||
|
#if SDL_VERSION_ATLEAST(2,0,19)
|
||||||
|
const SDL_Color* color = (const SDL_Color*)((const char*)(vtx_buffer + pcmd->VtxOffset) + IM_OFFSETOF(ImDrawVert, col)); // SDL 2.0.19+
|
||||||
|
#else
|
||||||
|
const int* color = (const int*)((const char*)(vtx_buffer + pcmd->VtxOffset) + IM_OFFSETOF(ImDrawVert, col)); // SDL 2.0.17 and 2.0.18
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Bind texture, Draw
|
||||||
|
SDL_Texture* tex = (SDL_Texture*)pcmd->GetTexID();
|
||||||
|
SDL_RenderGeometryRaw(bd->SDLRenderer, tex,
|
||||||
|
xy, (int)sizeof(ImDrawVert),
|
||||||
|
color, (int)sizeof(ImDrawVert),
|
||||||
|
uv, (int)sizeof(ImDrawVert),
|
||||||
|
cmd_list->VtxBuffer.Size - pcmd->VtxOffset,
|
||||||
|
idx_buffer + pcmd->IdxOffset, pcmd->ElemCount, sizeof(ImDrawIdx));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Restore modified SDL_Renderer state
|
||||||
|
SDL_RenderSetViewport(bd->SDLRenderer, &old.Viewport);
|
||||||
|
SDL_RenderSetClipRect(bd->SDLRenderer, old.ClipEnabled ? &old.ClipRect : NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Called by Init/NewFrame/Shutdown
|
||||||
|
bool ImGui_ImplSDLRenderer_CreateFontsTexture()
|
||||||
|
{
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
ImGui_ImplSDLRenderer_Data* bd = ImGui_ImplSDLRenderer_GetBackendData();
|
||||||
|
|
||||||
|
// Build texture atlas
|
||||||
|
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
|
||||||
|
// (Bilinear sampling is required by default. Set 'io.Fonts->Flags |= ImFontAtlasFlags_NoBakedLines' or 'style.AntiAliasedLinesUseTex = false' to allow point/nearest sampling)
|
||||||
|
bd->FontTexture = SDL_CreateTexture(bd->SDLRenderer, SDL_PIXELFORMAT_ABGR8888, SDL_TEXTUREACCESS_STATIC, width, height);
|
||||||
|
if (bd->FontTexture == NULL)
|
||||||
|
{
|
||||||
|
SDL_Log("error creating texture");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
SDL_UpdateTexture(bd->FontTexture, NULL, pixels, 4 * width);
|
||||||
|
SDL_SetTextureBlendMode(bd->FontTexture, SDL_BLENDMODE_BLEND);
|
||||||
|
SDL_SetTextureScaleMode(bd->FontTexture, SDL_ScaleModeLinear);
|
||||||
|
|
||||||
|
// Store our identifier
|
||||||
|
io.Fonts->SetTexID((ImTextureID)(intptr_t)bd->FontTexture);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGui_ImplSDLRenderer_DestroyFontsTexture()
|
||||||
|
{
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
ImGui_ImplSDLRenderer_Data* bd = ImGui_ImplSDLRenderer_GetBackendData();
|
||||||
|
if (bd->FontTexture)
|
||||||
|
{
|
||||||
|
io.Fonts->SetTexID(0);
|
||||||
|
SDL_DestroyTexture(bd->FontTexture);
|
||||||
|
bd->FontTexture = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ImGui_ImplSDLRenderer_CreateDeviceObjects()
|
||||||
|
{
|
||||||
|
return ImGui_ImplSDLRenderer_CreateFontsTexture();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGui_ImplSDLRenderer_DestroyDeviceObjects()
|
||||||
|
{
|
||||||
|
ImGui_ImplSDLRenderer_DestroyFontsTexture();
|
||||||
|
}
|
|
@ -0,0 +1,29 @@
|
||||||
|
// dear imgui: Renderer Backend for SDL_Renderer
|
||||||
|
// (Requires: SDL 2.0.17+)
|
||||||
|
|
||||||
|
// Important to understand: SDL_Renderer is an _optional_ component of SDL.
|
||||||
|
// For a multi-platform app consider using e.g. SDL+DirectX on Windows and SDL+OpenGL on Linux/OSX.
|
||||||
|
// If your application will want to render any non trivial amount of graphics other than UI,
|
||||||
|
// please be aware that SDL_Renderer offers a limited graphic API to the end-user and it might
|
||||||
|
// be difficult to step out of those boundaries.
|
||||||
|
// However, we understand it is a convenient choice to get an app started easily.
|
||||||
|
|
||||||
|
// Implemented features:
|
||||||
|
// [X] Renderer: User texture binding. Use 'SDL_Texture*' as ImTextureID. Read the FAQ about ImTextureID!
|
||||||
|
// [X] Renderer: Support for large meshes (64k+ vertices) with 16-bit indices.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include "imgui.h" // IMGUI_IMPL_API
|
||||||
|
|
||||||
|
struct SDL_Renderer;
|
||||||
|
|
||||||
|
IMGUI_IMPL_API bool ImGui_ImplSDLRenderer_Init(SDL_Renderer* renderer);
|
||||||
|
IMGUI_IMPL_API void ImGui_ImplSDLRenderer_Shutdown();
|
||||||
|
IMGUI_IMPL_API void ImGui_ImplSDLRenderer_NewFrame();
|
||||||
|
IMGUI_IMPL_API void ImGui_ImplSDLRenderer_RenderDrawData(ImDrawData* draw_data);
|
||||||
|
|
||||||
|
// Called by Init/NewFrame/Shutdown
|
||||||
|
IMGUI_IMPL_API bool ImGui_ImplSDLRenderer_CreateFontsTexture();
|
||||||
|
IMGUI_IMPL_API void ImGui_ImplSDLRenderer_DestroyFontsTexture();
|
||||||
|
IMGUI_IMPL_API bool ImGui_ImplSDLRenderer_CreateDeviceObjects();
|
||||||
|
IMGUI_IMPL_API void ImGui_ImplSDLRenderer_DestroyDeviceObjects();
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,155 @@
|
||||||
|
// 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.
|
||||||
|
// [!] Renderer: User texture binding. Use 'VkDescriptorSet' as ImTextureID. Read the FAQ about ImTextureID! See https://github.com/ocornut/imgui/pull/914 for discussions.
|
||||||
|
|
||||||
|
// Important: on 32-bit systems, user texture binding is only supported if your imconfig file has '#define ImTextureID ImU64'.
|
||||||
|
// See imgui_impl_vulkan.cpp file for details.
|
||||||
|
|
||||||
|
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
||||||
|
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
|
||||||
|
// 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 (0 -> default to 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)
|
||||||
|
|
||||||
|
// Register a texture (VkDescriptorSet == ImTextureID)
|
||||||
|
// FIXME: This is experimental in the sense that we are unsure how to best design/tackle this problem, please post to https://github.com/ocornut/imgui/pull/914 if you have suggestions.
|
||||||
|
IMGUI_IMPL_API VkDescriptorSet ImGui_ImplVulkan_AddTexture(VkSampler sampler, VkImageView image_view, VkImageLayout image_layout);
|
||||||
|
|
||||||
|
// 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((void*)this, 0, sizeof(*this));
|
||||||
|
PresentMode = (VkPresentModeKHR)~0; // Ensure we get an error if user doesn't set this.
|
||||||
|
ClearEnable = true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
|
@ -0,0 +1,719 @@
|
||||||
|
// 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 use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
||||||
|
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
|
||||||
|
// 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-11-29: Passing explicit buffer sizes to wgpuRenderPassEncoderSetVertexBuffer()/wgpuRenderPassEncoderSetIndexBuffer().
|
||||||
|
// 2021-08-24: Fix for latest specs.
|
||||||
|
// 2021-05-24: Add support for draw_data->FramebufferScale.
|
||||||
|
// 2021-05-19: Replaced direct access to ImDrawCmd::TextureId with a call to ImDrawCmd::GetTexID(). (will become a requirement)
|
||||||
|
// 2021-05-16: Update to latest WebGPU specs (compatible with Emscripten 2.0.20 and Chrome Canary 92).
|
||||||
|
// 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)))
|
||||||
|
|
||||||
|
#if defined(__EMSCRIPTEN__) && !HAS_EMSCRIPTEN_VERSION(2, 0, 20)
|
||||||
|
#error "Requires at least emscripten 2.0.20"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// 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 WGPUQueue g_defaultQueue = 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
|
||||||
|
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
|
||||||
|
WGPUBindGroupLayout ImageBindGroupLayout; // Cache layout used for the image bind group. Avoids allocating unnecessary JS objects when working with WebASM
|
||||||
|
};
|
||||||
|
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.ImageBindGroup);
|
||||||
|
SafeRelease(res.ImageBindGroupLayout);
|
||||||
|
};
|
||||||
|
|
||||||
|
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[] = { { nullptr, 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(g_defaultQueue, g_resources.Uniforms, 0, mvp, sizeof(mvp));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Setup viewport
|
||||||
|
wgpuRenderPassEncoderSetViewport(ctx, 0, 0, draw_data->FramebufferScale.x * draw_data->DisplaySize.x, draw_data->FramebufferScale.y * draw_data->DisplaySize.y, 0, 1);
|
||||||
|
|
||||||
|
// Bind shader and vertex buffers
|
||||||
|
wgpuRenderPassEncoderSetVertexBuffer(ctx, 0, fr->VertexBuffer, 0, fr->VertexBufferSize * sizeof(ImDrawVert));
|
||||||
|
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 };
|
||||||
|
wgpuRenderPassEncoderSetBlendConstant(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)
|
||||||
|
{
|
||||||
|
if (fr->VertexBuffer)
|
||||||
|
{
|
||||||
|
wgpuBufferDestroy(fr->VertexBuffer);
|
||||||
|
wgpuBufferRelease(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)
|
||||||
|
{
|
||||||
|
if (fr->IndexBuffer)
|
||||||
|
{
|
||||||
|
wgpuBufferDestroy(fr->IndexBuffer);
|
||||||
|
wgpuBufferRelease(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(g_defaultQueue, fr->VertexBuffer, 0, fr->VertexBufferHost, vb_write_size);
|
||||||
|
wgpuQueueWriteBuffer(g_defaultQueue, 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_scale = draw_data->FramebufferScale;
|
||||||
|
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
|
||||||
|
ImTextureID tex_id = pcmd->GetTexID();
|
||||||
|
ImGuiID tex_id_hash = ImHashData(&tex_id, sizeof(tex_id));
|
||||||
|
auto bind_group = g_resources.ImageBindGroups.GetVoidPtr(tex_id_hash);
|
||||||
|
if (bind_group)
|
||||||
|
{
|
||||||
|
wgpuRenderPassEncoderSetBindGroup(pass_encoder, 1, (WGPUBindGroup)bind_group, 0, NULL);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
WGPUBindGroup image_bind_group = ImGui_ImplWGPU_CreateImageBindGroup(g_resources.ImageBindGroupLayout, (WGPUTextureView)tex_id);
|
||||||
|
g_resources.ImageBindGroups.SetVoidPtr(tex_id_hash, image_bind_group);
|
||||||
|
wgpuRenderPassEncoderSetBindGroup(pass_encoder, 1, image_bind_group, 0, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Project scissor/clipping rectangles into framebuffer space
|
||||||
|
ImVec2 clip_min((pcmd->ClipRect.x - clip_off.x) * clip_scale.x, (pcmd->ClipRect.y - clip_off.y) * clip_scale.y);
|
||||||
|
ImVec2 clip_max((pcmd->ClipRect.z - clip_off.x) * clip_scale.x, (pcmd->ClipRect.w - clip_off.y) * clip_scale.y);
|
||||||
|
if (clip_max.x <= clip_min.x || clip_max.y <= clip_min.y)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Apply scissor/clipping rectangle, Draw
|
||||||
|
wgpuRenderPassEncoderSetScissorRect(pass_encoder, (uint32_t)clip_min.x, (uint32_t)clip_min.y, (uint32_t)(clip_max.x - clip_min.x), (uint32_t)(clip_max.y - clip_min.y));
|
||||||
|
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 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.depthOrArrayLayers = 1;
|
||||||
|
tex_desc.sampleCount = 1;
|
||||||
|
tex_desc.format = WGPUTextureFormat_RGBA8Unorm;
|
||||||
|
tex_desc.mipLevelCount = 1;
|
||||||
|
tex_desc.usage = WGPUTextureUsage_CopyDst | WGPUTextureUsage_TextureBinding;
|
||||||
|
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
|
||||||
|
{
|
||||||
|
WGPUImageCopyTexture dst_view = {};
|
||||||
|
dst_view.texture = g_resources.FontTexture;
|
||||||
|
dst_view.mipLevel = 0;
|
||||||
|
dst_view.origin = { 0, 0, 0 };
|
||||||
|
dst_view.aspect = WGPUTextureAspect_All;
|
||||||
|
WGPUTextureDataLayout layout = {};
|
||||||
|
layout.offset = 0;
|
||||||
|
layout.bytesPerRow = width * size_pp;
|
||||||
|
layout.rowsPerImage = height;
|
||||||
|
WGPUExtent3D size = { (uint32_t)width, (uint32_t)height, 1 };
|
||||||
|
wgpuQueueWriteTexture(g_defaultQueue, &dst_view, pixels, (uint32_t)(width * size_pp * height), &layout, &size);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the associated sampler
|
||||||
|
// (Bilinear sampling is required by default. Set 'io.Fonts->Flags |= ImFontAtlasFlags_NoBakedLines' or 'style.AntiAliasedLinesUseTex = false' to allow point/nearest sampling)
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
sampler_desc.maxAnisotropy = 1;
|
||||||
|
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.primitive.topology = WGPUPrimitiveTopology_TriangleList;
|
||||||
|
graphics_pipeline_desc.primitive.stripIndexFormat = WGPUIndexFormat_Undefined;
|
||||||
|
graphics_pipeline_desc.primitive.frontFace = WGPUFrontFace_CW;
|
||||||
|
graphics_pipeline_desc.primitive.cullMode = WGPUCullMode_None;
|
||||||
|
graphics_pipeline_desc.multisample.count = 1;
|
||||||
|
graphics_pipeline_desc.multisample.mask = UINT_MAX;
|
||||||
|
graphics_pipeline_desc.multisample.alphaToCoverageEnabled = false;
|
||||||
|
graphics_pipeline_desc.layout = nullptr; // Use automatic layout generation
|
||||||
|
|
||||||
|
// 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.vertex.module = vertex_shader_desc.module;
|
||||||
|
graphics_pipeline_desc.vertex.entryPoint = vertex_shader_desc.entryPoint;
|
||||||
|
|
||||||
|
// Vertex input configuration
|
||||||
|
WGPUVertexAttribute attribute_desc[] =
|
||||||
|
{
|
||||||
|
{ WGPUVertexFormat_Float32x2, (uint64_t)IM_OFFSETOF(ImDrawVert, pos), 0 },
|
||||||
|
{ WGPUVertexFormat_Float32x2, (uint64_t)IM_OFFSETOF(ImDrawVert, uv), 1 },
|
||||||
|
{ WGPUVertexFormat_Unorm8x4, (uint64_t)IM_OFFSETOF(ImDrawVert, col), 2 },
|
||||||
|
};
|
||||||
|
|
||||||
|
WGPUVertexBufferLayout buffer_layouts[1];
|
||||||
|
buffer_layouts[0].arrayStride = sizeof(ImDrawVert);
|
||||||
|
buffer_layouts[0].stepMode = WGPUVertexStepMode_Vertex;
|
||||||
|
buffer_layouts[0].attributeCount = 3;
|
||||||
|
buffer_layouts[0].attributes = attribute_desc;
|
||||||
|
|
||||||
|
graphics_pipeline_desc.vertex.bufferCount = 1;
|
||||||
|
graphics_pipeline_desc.vertex.buffers = buffer_layouts;
|
||||||
|
|
||||||
|
// Create the pixel shader
|
||||||
|
WGPUProgrammableStageDescriptor pixel_shader_desc = ImGui_ImplWGPU_CreateShaderModule(__glsl_shader_frag_spv, sizeof(__glsl_shader_frag_spv) / sizeof(uint32_t));
|
||||||
|
|
||||||
|
// Create the blending setup
|
||||||
|
WGPUBlendState blend_state = {};
|
||||||
|
blend_state.alpha.operation = WGPUBlendOperation_Add;
|
||||||
|
blend_state.alpha.srcFactor = WGPUBlendFactor_One;
|
||||||
|
blend_state.alpha.dstFactor = WGPUBlendFactor_OneMinusSrcAlpha;
|
||||||
|
blend_state.color.operation = WGPUBlendOperation_Add;
|
||||||
|
blend_state.color.srcFactor = WGPUBlendFactor_SrcAlpha;
|
||||||
|
blend_state.color.dstFactor = WGPUBlendFactor_OneMinusSrcAlpha;
|
||||||
|
|
||||||
|
WGPUColorTargetState color_state = {};
|
||||||
|
color_state.format = g_renderTargetFormat;
|
||||||
|
color_state.blend = &blend_state;
|
||||||
|
color_state.writeMask = WGPUColorWriteMask_All;
|
||||||
|
|
||||||
|
WGPUFragmentState fragment_state = {};
|
||||||
|
fragment_state.module = pixel_shader_desc.module;
|
||||||
|
fragment_state.entryPoint = pixel_shader_desc.entryPoint;
|
||||||
|
fragment_state.targetCount = 1;
|
||||||
|
fragment_state.targets = &color_state;
|
||||||
|
|
||||||
|
graphics_pipeline_desc.fragment = &fragment_state;
|
||||||
|
|
||||||
|
// Create depth-stencil State
|
||||||
|
WGPUDepthStencilState depth_stencil_state = {};
|
||||||
|
depth_stencil_state.depthBias = 0;
|
||||||
|
depth_stencil_state.depthBiasClamp = 0;
|
||||||
|
depth_stencil_state.depthBiasSlopeScale = 0;
|
||||||
|
|
||||||
|
// Configure disabled depth-stencil state
|
||||||
|
graphics_pipeline_desc.depthStencil = nullptr;
|
||||||
|
|
||||||
|
g_pipelineState = wgpuDeviceCreateRenderPipeline(g_wgpuDevice, &graphics_pipeline_desc);
|
||||||
|
|
||||||
|
ImGui_ImplWGPU_CreateFontsTexture();
|
||||||
|
ImGui_ImplWGPU_CreateUniformBuffer();
|
||||||
|
|
||||||
|
// Create resource bind group
|
||||||
|
WGPUBindGroupLayout bg_layouts[2];
|
||||||
|
bg_layouts[0] = wgpuRenderPipelineGetBindGroupLayout(g_pipelineState, 0);
|
||||||
|
bg_layouts[1] = wgpuRenderPipelineGetBindGroupLayout(g_pipelineState, 1);
|
||||||
|
|
||||||
|
WGPUBindGroupEntry common_bg_entries[] =
|
||||||
|
{
|
||||||
|
{ nullptr, 0, g_resources.Uniforms, 0, sizeof(Uniforms), 0, 0 },
|
||||||
|
{ nullptr, 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);
|
||||||
|
|
||||||
|
WGPUBindGroup image_bind_group = ImGui_ImplWGPU_CreateImageBindGroup(bg_layouts[1], g_resources.FontTextureView);
|
||||||
|
g_resources.ImageBindGroup = image_bind_group;
|
||||||
|
g_resources.ImageBindGroupLayout = bg_layouts[1];
|
||||||
|
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_defaultQueue = wgpuDeviceGetQueue(g_wgpuDevice);
|
||||||
|
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.ImageBindGroups.Data.reserve(100);
|
||||||
|
g_resources.ImageBindGroup = NULL;
|
||||||
|
g_resources.ImageBindGroupLayout = 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;
|
||||||
|
wgpuQueueRelease(g_defaultQueue);
|
||||||
|
g_wgpuDevice = NULL;
|
||||||
|
g_numFramesInFlight = 0;
|
||||||
|
g_frameIndex = UINT_MAX;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGui_ImplWGPU_NewFrame()
|
||||||
|
{
|
||||||
|
if (!g_pipelineState)
|
||||||
|
ImGui_ImplWGPU_CreateDeviceObjects();
|
||||||
|
}
|
|
@ -0,0 +1,25 @@
|
||||||
|
// 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 use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
||||||
|
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
|
||||||
|
// 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();
|
|
@ -0,0 +1,791 @@
|
||||||
|
// 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: Keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy VK_* values will also be supported unless IMGUI_DISABLE_OBSOLETE_KEYIO is set]
|
||||||
|
// [X] Platform: Gamepad support. Enabled with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'.
|
||||||
|
// [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'.
|
||||||
|
|
||||||
|
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
||||||
|
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
|
||||||
|
// 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 <windowsx.h> // GET_X_LPARAM(), GET_Y_LPARAM()
|
||||||
|
#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 was meaningful before <1.81 but we now load XInput dynamically so the option is now less relevant.
|
||||||
|
|
||||||
|
// 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)
|
||||||
|
// 2022-01-26: Inputs: replaced short-lived io.AddKeyModsEvent() (added two weeks ago)with io.AddKeyEvent() using ImGuiKey_ModXXX flags. Sorry for the confusion.
|
||||||
|
// 2021-01-20: Inputs: calling new io.AddKeyAnalogEvent() for gamepad support, instead of writing directly to io.NavInputs[].
|
||||||
|
// 2022-01-17: Inputs: calling new io.AddMousePosEvent(), io.AddMouseButtonEvent(), io.AddMouseWheelEvent() API (1.87+).
|
||||||
|
// 2022-01-17: Inputs: always update key mods next and before a key event (not in NewFrame) to fix input queue with very low framerates.
|
||||||
|
// 2022-01-12: Inputs: Update mouse inputs using WM_MOUSEMOVE/WM_MOUSELEAVE + fallback to provide it when focused but not hovered/captured. More standard and will allow us to pass it to future input queue API.
|
||||||
|
// 2022-01-12: Inputs: Maintain our own copy of MouseButtonsDown mask instead of using ImGui::IsAnyMouseDown() which will be obsoleted.
|
||||||
|
// 2022-01-10: Inputs: calling new io.AddKeyEvent(), io.AddKeyModsEvent() + io.SetKeyEventNativeData() API (1.87+). Support for full ImGuiKey range.
|
||||||
|
// 2021-12-16: Inputs: Fill VK_LCONTROL/VK_RCONTROL/VK_LSHIFT/VK_RSHIFT/VK_LMENU/VK_RMENU for completeness.
|
||||||
|
// 2021-08-17: Calling io.AddFocusEvent() on WM_SETFOCUS/WM_KILLFOCUS messages.
|
||||||
|
// 2021-08-02: Inputs: Fixed keyboard modifiers being reported when host window doesn't have focus.
|
||||||
|
// 2021-07-29: Inputs: MousePos is correctly reported when the host platform window is hovered but not focused (using TrackMouseEvent() to receive WM_MOUSELEAVE events).
|
||||||
|
// 2021-06-29: Reorganized backend to pull data from a single structure to facilitate usage with multiple-contexts (all g_XXXX access changed to bd->XXXX).
|
||||||
|
// 2021-06-08: Fixed ImGui_ImplWin32_EnableDpiAwareness() and ImGui_ImplWin32_GetDpiScaleForMonitor() to handle Windows 8.1/10 features without a manifest (per-monitor DPI, and properly calls SetProcessDpiAwareness() on 8.1).
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
struct ImGui_ImplWin32_Data
|
||||||
|
{
|
||||||
|
HWND hWnd;
|
||||||
|
HWND MouseHwnd;
|
||||||
|
bool MouseTracked;
|
||||||
|
int MouseButtonsDown;
|
||||||
|
INT64 Time;
|
||||||
|
INT64 TicksPerSecond;
|
||||||
|
ImGuiMouseCursor LastMouseCursor;
|
||||||
|
bool HasGamepad;
|
||||||
|
bool WantUpdateHasGamepad;
|
||||||
|
|
||||||
|
#ifndef IMGUI_IMPL_WIN32_DISABLE_GAMEPAD
|
||||||
|
HMODULE XInputDLL;
|
||||||
|
PFN_XInputGetCapabilities XInputGetCapabilities;
|
||||||
|
PFN_XInputGetState XInputGetState;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
ImGui_ImplWin32_Data() { memset((void*)this, 0, sizeof(*this)); }
|
||||||
|
};
|
||||||
|
|
||||||
|
// Backend data stored in io.BackendPlatformUserData to allow support for multiple Dear ImGui contexts
|
||||||
|
// It is STRONGLY preferred that you use docking branch with multi-viewports (== single Dear ImGui context + multiple windows) instead of multiple Dear ImGui contexts.
|
||||||
|
// FIXME: multi-context support is not well tested and probably dysfunctional in this backend.
|
||||||
|
// FIXME: some shared resources (mouse cursor shape, gamepad) are mishandled when using multi-context.
|
||||||
|
static ImGui_ImplWin32_Data* ImGui_ImplWin32_GetBackendData()
|
||||||
|
{
|
||||||
|
return ImGui::GetCurrentContext() ? (ImGui_ImplWin32_Data*)ImGui::GetIO().BackendPlatformUserData : NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Functions
|
||||||
|
bool ImGui_ImplWin32_Init(void* hwnd)
|
||||||
|
{
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
IM_ASSERT(io.BackendPlatformUserData == NULL && "Already initialized a platform backend!");
|
||||||
|
|
||||||
|
INT64 perf_frequency, perf_counter;
|
||||||
|
if (!::QueryPerformanceFrequency((LARGE_INTEGER*)&perf_frequency))
|
||||||
|
return false;
|
||||||
|
if (!::QueryPerformanceCounter((LARGE_INTEGER*)&perf_counter))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Setup backend capabilities flags
|
||||||
|
ImGui_ImplWin32_Data* bd = IM_NEW(ImGui_ImplWin32_Data)();
|
||||||
|
io.BackendPlatformUserData = (void*)bd;
|
||||||
|
io.BackendPlatformName = "imgui_impl_win32";
|
||||||
|
io.BackendFlags |= ImGuiBackendFlags_HasMouseCursors; // We can honor GetMouseCursor() values (optional)
|
||||||
|
io.BackendFlags |= ImGuiBackendFlags_HasSetMousePos; // We can honor io.WantSetMousePos requests (optional, rarely used)
|
||||||
|
|
||||||
|
bd->hWnd = (HWND)hwnd;
|
||||||
|
bd->WantUpdateHasGamepad = true;
|
||||||
|
bd->TicksPerSecond = perf_frequency;
|
||||||
|
bd->Time = perf_counter;
|
||||||
|
bd->LastMouseCursor = ImGuiMouseCursor_COUNT;
|
||||||
|
|
||||||
|
// Set platform dependent data in viewport
|
||||||
|
ImGui::GetMainViewport()->PlatformHandleRaw = (void*)hwnd;
|
||||||
|
|
||||||
|
// 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]))
|
||||||
|
{
|
||||||
|
bd->XInputDLL = dll;
|
||||||
|
bd->XInputGetCapabilities = (PFN_XInputGetCapabilities)::GetProcAddress(dll, "XInputGetCapabilities");
|
||||||
|
bd->XInputGetState = (PFN_XInputGetState)::GetProcAddress(dll, "XInputGetState");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
#endif // IMGUI_IMPL_WIN32_DISABLE_GAMEPAD
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGui_ImplWin32_Shutdown()
|
||||||
|
{
|
||||||
|
ImGui_ImplWin32_Data* bd = ImGui_ImplWin32_GetBackendData();
|
||||||
|
IM_ASSERT(bd != NULL && "No platform backend to shutdown, or already shutdown?");
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
|
||||||
|
// Unload XInput library
|
||||||
|
#ifndef IMGUI_IMPL_WIN32_DISABLE_GAMEPAD
|
||||||
|
if (bd->XInputDLL)
|
||||||
|
::FreeLibrary(bd->XInputDLL);
|
||||||
|
#endif // IMGUI_IMPL_WIN32_DISABLE_GAMEPAD
|
||||||
|
|
||||||
|
io.BackendPlatformName = NULL;
|
||||||
|
io.BackendPlatformUserData = NULL;
|
||||||
|
IM_DELETE(bd);
|
||||||
|
}
|
||||||
|
|
||||||
|
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 bool IsVkDown(int vk)
|
||||||
|
{
|
||||||
|
return (::GetKeyState(vk) & 0x8000) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ImGui_ImplWin32_AddKeyEvent(ImGuiKey key, bool down, int native_keycode, int native_scancode = -1)
|
||||||
|
{
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
io.AddKeyEvent(key, down);
|
||||||
|
io.SetKeyEventNativeData(key, native_keycode, native_scancode); // To support legacy indexing (<1.87 user code)
|
||||||
|
IM_UNUSED(native_scancode);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ImGui_ImplWin32_ProcessKeyEventsWorkarounds()
|
||||||
|
{
|
||||||
|
// Left & right Shift keys: when both are pressed together, Windows tend to not generate the WM_KEYUP event for the first released one.
|
||||||
|
if (ImGui::IsKeyDown(ImGuiKey_LeftShift) && !IsVkDown(VK_LSHIFT))
|
||||||
|
ImGui_ImplWin32_AddKeyEvent(ImGuiKey_LeftShift, false, VK_LSHIFT);
|
||||||
|
if (ImGui::IsKeyDown(ImGuiKey_RightShift) && !IsVkDown(VK_RSHIFT))
|
||||||
|
ImGui_ImplWin32_AddKeyEvent(ImGuiKey_RightShift, false, VK_RSHIFT);
|
||||||
|
|
||||||
|
// Sometimes WM_KEYUP for Win key is not passed down to the app (e.g. for Win+V on some setups, according to GLFW).
|
||||||
|
if (ImGui::IsKeyDown(ImGuiKey_LeftSuper) && !IsVkDown(VK_LWIN))
|
||||||
|
ImGui_ImplWin32_AddKeyEvent(ImGuiKey_LeftSuper, false, VK_LWIN);
|
||||||
|
if (ImGui::IsKeyDown(ImGuiKey_RightSuper) && !IsVkDown(VK_RWIN))
|
||||||
|
ImGui_ImplWin32_AddKeyEvent(ImGuiKey_RightSuper, false, VK_RWIN);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ImGui_ImplWin32_UpdateKeyModifiers()
|
||||||
|
{
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
io.AddKeyEvent(ImGuiKey_ModCtrl, IsVkDown(VK_CONTROL));
|
||||||
|
io.AddKeyEvent(ImGuiKey_ModShift, IsVkDown(VK_SHIFT));
|
||||||
|
io.AddKeyEvent(ImGuiKey_ModAlt, IsVkDown(VK_MENU));
|
||||||
|
io.AddKeyEvent(ImGuiKey_ModSuper, IsVkDown(VK_APPS));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ImGui_ImplWin32_UpdateMouseData()
|
||||||
|
{
|
||||||
|
ImGui_ImplWin32_Data* bd = ImGui_ImplWin32_GetBackendData();
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
IM_ASSERT(bd->hWnd != 0);
|
||||||
|
|
||||||
|
const bool is_app_focused = (::GetForegroundWindow() == bd->hWnd);
|
||||||
|
if (is_app_focused)
|
||||||
|
{
|
||||||
|
// (Optional) Set OS mouse position from Dear ImGui 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(bd->hWnd, &pos))
|
||||||
|
::SetCursorPos(pos.x, pos.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
// (Optional) Fallback to provide mouse position when focused (WM_MOUSEMOVE already provides this when hovered or captured)
|
||||||
|
if (!io.WantSetMousePos && !bd->MouseTracked)
|
||||||
|
{
|
||||||
|
POINT pos;
|
||||||
|
if (::GetCursorPos(&pos) && ::ScreenToClient(bd->hWnd, &pos))
|
||||||
|
io.AddMousePosEvent((float)pos.x, (float)pos.y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Gamepad navigation mapping
|
||||||
|
static void ImGui_ImplWin32_UpdateGamepads()
|
||||||
|
{
|
||||||
|
#ifndef IMGUI_IMPL_WIN32_DISABLE_GAMEPAD
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
ImGui_ImplWin32_Data* bd = ImGui_ImplWin32_GetBackendData();
|
||||||
|
//if ((io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) == 0) // FIXME: Technically feeding gamepad shouldn't depend on this now that they are regular inputs.
|
||||||
|
// 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 (bd->WantUpdateHasGamepad)
|
||||||
|
{
|
||||||
|
XINPUT_CAPABILITIES caps = {};
|
||||||
|
bd->HasGamepad = bd->XInputGetCapabilities ? (bd->XInputGetCapabilities(0, XINPUT_FLAG_GAMEPAD, &caps) == ERROR_SUCCESS) : false;
|
||||||
|
bd->WantUpdateHasGamepad = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
io.BackendFlags &= ~ImGuiBackendFlags_HasGamepad;
|
||||||
|
XINPUT_STATE xinput_state;
|
||||||
|
XINPUT_GAMEPAD& gamepad = xinput_state.Gamepad;
|
||||||
|
if (!bd->HasGamepad || bd->XInputGetState == NULL || bd->XInputGetState(0, &xinput_state) != ERROR_SUCCESS)
|
||||||
|
return;
|
||||||
|
io.BackendFlags |= ImGuiBackendFlags_HasGamepad;
|
||||||
|
|
||||||
|
#define IM_SATURATE(V) (V < 0.0f ? 0.0f : V > 1.0f ? 1.0f : V)
|
||||||
|
#define MAP_BUTTON(KEY_NO, BUTTON_ENUM) { io.AddKeyEvent(KEY_NO, (gamepad.wButtons & BUTTON_ENUM) != 0); }
|
||||||
|
#define MAP_ANALOG(KEY_NO, VALUE, V0, V1) { float vn = (float)(VALUE - V0) / (float)(V1 - V0); io.AddKeyAnalogEvent(KEY_NO, vn > 0.10f, IM_SATURATE(vn)); }
|
||||||
|
MAP_BUTTON(ImGuiKey_GamepadStart, XINPUT_GAMEPAD_START);
|
||||||
|
MAP_BUTTON(ImGuiKey_GamepadBack, XINPUT_GAMEPAD_BACK);
|
||||||
|
MAP_BUTTON(ImGuiKey_GamepadFaceLeft, XINPUT_GAMEPAD_X);
|
||||||
|
MAP_BUTTON(ImGuiKey_GamepadFaceRight, XINPUT_GAMEPAD_B);
|
||||||
|
MAP_BUTTON(ImGuiKey_GamepadFaceUp, XINPUT_GAMEPAD_Y);
|
||||||
|
MAP_BUTTON(ImGuiKey_GamepadFaceDown, XINPUT_GAMEPAD_A);
|
||||||
|
MAP_BUTTON(ImGuiKey_GamepadDpadLeft, XINPUT_GAMEPAD_DPAD_LEFT);
|
||||||
|
MAP_BUTTON(ImGuiKey_GamepadDpadRight, XINPUT_GAMEPAD_DPAD_RIGHT);
|
||||||
|
MAP_BUTTON(ImGuiKey_GamepadDpadUp, XINPUT_GAMEPAD_DPAD_UP);
|
||||||
|
MAP_BUTTON(ImGuiKey_GamepadDpadDown, XINPUT_GAMEPAD_DPAD_DOWN);
|
||||||
|
MAP_BUTTON(ImGuiKey_GamepadL1, XINPUT_GAMEPAD_LEFT_SHOULDER);
|
||||||
|
MAP_BUTTON(ImGuiKey_GamepadR1, XINPUT_GAMEPAD_RIGHT_SHOULDER);
|
||||||
|
MAP_ANALOG(ImGuiKey_GamepadL2, gamepad.bLeftTrigger, XINPUT_GAMEPAD_TRIGGER_THRESHOLD, 255);
|
||||||
|
MAP_ANALOG(ImGuiKey_GamepadR2, gamepad.bRightTrigger, XINPUT_GAMEPAD_TRIGGER_THRESHOLD, 255);
|
||||||
|
MAP_BUTTON(ImGuiKey_GamepadL3, XINPUT_GAMEPAD_LEFT_THUMB);
|
||||||
|
MAP_BUTTON(ImGuiKey_GamepadR3, XINPUT_GAMEPAD_RIGHT_THUMB);
|
||||||
|
MAP_ANALOG(ImGuiKey_GamepadLStickLeft, gamepad.sThumbLX, -XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, -32768);
|
||||||
|
MAP_ANALOG(ImGuiKey_GamepadLStickRight, gamepad.sThumbLX, +XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, +32767);
|
||||||
|
MAP_ANALOG(ImGuiKey_GamepadLStickUp, gamepad.sThumbLY, +XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, +32767);
|
||||||
|
MAP_ANALOG(ImGuiKey_GamepadLStickDown, gamepad.sThumbLY, -XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, -32768);
|
||||||
|
MAP_ANALOG(ImGuiKey_GamepadRStickLeft, gamepad.sThumbRX, -XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, -32768);
|
||||||
|
MAP_ANALOG(ImGuiKey_GamepadRStickRight, gamepad.sThumbRX, +XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, +32767);
|
||||||
|
MAP_ANALOG(ImGuiKey_GamepadRStickUp, gamepad.sThumbRY, +XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, +32767);
|
||||||
|
MAP_ANALOG(ImGuiKey_GamepadRStickDown, gamepad.sThumbRY, -XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, -32768);
|
||||||
|
#undef MAP_BUTTON
|
||||||
|
#undef MAP_ANALOG
|
||||||
|
#endif // #ifndef IMGUI_IMPL_WIN32_DISABLE_GAMEPAD
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGui_ImplWin32_NewFrame()
|
||||||
|
{
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
ImGui_ImplWin32_Data* bd = ImGui_ImplWin32_GetBackendData();
|
||||||
|
IM_ASSERT(bd != NULL && "Did you call ImGui_ImplWin32_Init()?");
|
||||||
|
|
||||||
|
// Setup display size (every frame to accommodate for window resizing)
|
||||||
|
RECT rect = { 0, 0, 0, 0 };
|
||||||
|
::GetClientRect(bd->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 - bd->Time) / bd->TicksPerSecond;
|
||||||
|
bd->Time = current_time;
|
||||||
|
|
||||||
|
// Update OS mouse position
|
||||||
|
ImGui_ImplWin32_UpdateMouseData();
|
||||||
|
|
||||||
|
// Process workarounds for known Windows key handling issues
|
||||||
|
ImGui_ImplWin32_ProcessKeyEventsWorkarounds();
|
||||||
|
|
||||||
|
// Update OS mouse cursor with the cursor requested by imgui
|
||||||
|
ImGuiMouseCursor mouse_cursor = io.MouseDrawCursor ? ImGuiMouseCursor_None : ImGui::GetMouseCursor();
|
||||||
|
if (bd->LastMouseCursor != mouse_cursor)
|
||||||
|
{
|
||||||
|
bd->LastMouseCursor = mouse_cursor;
|
||||||
|
ImGui_ImplWin32_UpdateMouseCursor();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update game controllers (if enabled and available)
|
||||||
|
ImGui_ImplWin32_UpdateGamepads();
|
||||||
|
}
|
||||||
|
|
||||||
|
// There is no distinct VK_xxx for keypad enter, instead it is VK_RETURN + KF_EXTENDED, we assign it an arbitrary value to make code more readable (VK_ codes go up to 255)
|
||||||
|
#define IM_VK_KEYPAD_ENTER (VK_RETURN + 256)
|
||||||
|
|
||||||
|
// Map VK_xxx to ImGuiKey_xxx.
|
||||||
|
static ImGuiKey ImGui_ImplWin32_VirtualKeyToImGuiKey(WPARAM wParam)
|
||||||
|
{
|
||||||
|
switch (wParam)
|
||||||
|
{
|
||||||
|
case VK_TAB: return ImGuiKey_Tab;
|
||||||
|
case VK_LEFT: return ImGuiKey_LeftArrow;
|
||||||
|
case VK_RIGHT: return ImGuiKey_RightArrow;
|
||||||
|
case VK_UP: return ImGuiKey_UpArrow;
|
||||||
|
case VK_DOWN: return ImGuiKey_DownArrow;
|
||||||
|
case VK_PRIOR: return ImGuiKey_PageUp;
|
||||||
|
case VK_NEXT: return ImGuiKey_PageDown;
|
||||||
|
case VK_HOME: return ImGuiKey_Home;
|
||||||
|
case VK_END: return ImGuiKey_End;
|
||||||
|
case VK_INSERT: return ImGuiKey_Insert;
|
||||||
|
case VK_DELETE: return ImGuiKey_Delete;
|
||||||
|
case VK_BACK: return ImGuiKey_Backspace;
|
||||||
|
case VK_SPACE: return ImGuiKey_Space;
|
||||||
|
case VK_RETURN: return ImGuiKey_Enter;
|
||||||
|
case VK_ESCAPE: return ImGuiKey_Escape;
|
||||||
|
case VK_OEM_7: return ImGuiKey_Apostrophe;
|
||||||
|
case VK_OEM_COMMA: return ImGuiKey_Comma;
|
||||||
|
case VK_OEM_MINUS: return ImGuiKey_Minus;
|
||||||
|
case VK_OEM_PERIOD: return ImGuiKey_Period;
|
||||||
|
case VK_OEM_2: return ImGuiKey_Slash;
|
||||||
|
case VK_OEM_1: return ImGuiKey_Semicolon;
|
||||||
|
case VK_OEM_PLUS: return ImGuiKey_Equal;
|
||||||
|
case VK_OEM_4: return ImGuiKey_LeftBracket;
|
||||||
|
case VK_OEM_5: return ImGuiKey_Backslash;
|
||||||
|
case VK_OEM_6: return ImGuiKey_RightBracket;
|
||||||
|
case VK_OEM_3: return ImGuiKey_GraveAccent;
|
||||||
|
case VK_CAPITAL: return ImGuiKey_CapsLock;
|
||||||
|
case VK_SCROLL: return ImGuiKey_ScrollLock;
|
||||||
|
case VK_NUMLOCK: return ImGuiKey_NumLock;
|
||||||
|
case VK_SNAPSHOT: return ImGuiKey_PrintScreen;
|
||||||
|
case VK_PAUSE: return ImGuiKey_Pause;
|
||||||
|
case VK_NUMPAD0: return ImGuiKey_Keypad0;
|
||||||
|
case VK_NUMPAD1: return ImGuiKey_Keypad1;
|
||||||
|
case VK_NUMPAD2: return ImGuiKey_Keypad2;
|
||||||
|
case VK_NUMPAD3: return ImGuiKey_Keypad3;
|
||||||
|
case VK_NUMPAD4: return ImGuiKey_Keypad4;
|
||||||
|
case VK_NUMPAD5: return ImGuiKey_Keypad5;
|
||||||
|
case VK_NUMPAD6: return ImGuiKey_Keypad6;
|
||||||
|
case VK_NUMPAD7: return ImGuiKey_Keypad7;
|
||||||
|
case VK_NUMPAD8: return ImGuiKey_Keypad8;
|
||||||
|
case VK_NUMPAD9: return ImGuiKey_Keypad9;
|
||||||
|
case VK_DECIMAL: return ImGuiKey_KeypadDecimal;
|
||||||
|
case VK_DIVIDE: return ImGuiKey_KeypadDivide;
|
||||||
|
case VK_MULTIPLY: return ImGuiKey_KeypadMultiply;
|
||||||
|
case VK_SUBTRACT: return ImGuiKey_KeypadSubtract;
|
||||||
|
case VK_ADD: return ImGuiKey_KeypadAdd;
|
||||||
|
case IM_VK_KEYPAD_ENTER: return ImGuiKey_KeypadEnter;
|
||||||
|
case VK_LSHIFT: return ImGuiKey_LeftShift;
|
||||||
|
case VK_LCONTROL: return ImGuiKey_LeftCtrl;
|
||||||
|
case VK_LMENU: return ImGuiKey_LeftAlt;
|
||||||
|
case VK_LWIN: return ImGuiKey_LeftSuper;
|
||||||
|
case VK_RSHIFT: return ImGuiKey_RightShift;
|
||||||
|
case VK_RCONTROL: return ImGuiKey_RightCtrl;
|
||||||
|
case VK_RMENU: return ImGuiKey_RightAlt;
|
||||||
|
case VK_RWIN: return ImGuiKey_RightSuper;
|
||||||
|
case VK_APPS: return ImGuiKey_Menu;
|
||||||
|
case '0': return ImGuiKey_0;
|
||||||
|
case '1': return ImGuiKey_1;
|
||||||
|
case '2': return ImGuiKey_2;
|
||||||
|
case '3': return ImGuiKey_3;
|
||||||
|
case '4': return ImGuiKey_4;
|
||||||
|
case '5': return ImGuiKey_5;
|
||||||
|
case '6': return ImGuiKey_6;
|
||||||
|
case '7': return ImGuiKey_7;
|
||||||
|
case '8': return ImGuiKey_8;
|
||||||
|
case '9': return ImGuiKey_9;
|
||||||
|
case 'A': return ImGuiKey_A;
|
||||||
|
case 'B': return ImGuiKey_B;
|
||||||
|
case 'C': return ImGuiKey_C;
|
||||||
|
case 'D': return ImGuiKey_D;
|
||||||
|
case 'E': return ImGuiKey_E;
|
||||||
|
case 'F': return ImGuiKey_F;
|
||||||
|
case 'G': return ImGuiKey_G;
|
||||||
|
case 'H': return ImGuiKey_H;
|
||||||
|
case 'I': return ImGuiKey_I;
|
||||||
|
case 'J': return ImGuiKey_J;
|
||||||
|
case 'K': return ImGuiKey_K;
|
||||||
|
case 'L': return ImGuiKey_L;
|
||||||
|
case 'M': return ImGuiKey_M;
|
||||||
|
case 'N': return ImGuiKey_N;
|
||||||
|
case 'O': return ImGuiKey_O;
|
||||||
|
case 'P': return ImGuiKey_P;
|
||||||
|
case 'Q': return ImGuiKey_Q;
|
||||||
|
case 'R': return ImGuiKey_R;
|
||||||
|
case 'S': return ImGuiKey_S;
|
||||||
|
case 'T': return ImGuiKey_T;
|
||||||
|
case 'U': return ImGuiKey_U;
|
||||||
|
case 'V': return ImGuiKey_V;
|
||||||
|
case 'W': return ImGuiKey_W;
|
||||||
|
case 'X': return ImGuiKey_X;
|
||||||
|
case 'Y': return ImGuiKey_Y;
|
||||||
|
case 'Z': return ImGuiKey_Z;
|
||||||
|
case VK_F1: return ImGuiKey_F1;
|
||||||
|
case VK_F2: return ImGuiKey_F2;
|
||||||
|
case VK_F3: return ImGuiKey_F3;
|
||||||
|
case VK_F4: return ImGuiKey_F4;
|
||||||
|
case VK_F5: return ImGuiKey_F5;
|
||||||
|
case VK_F6: return ImGuiKey_F6;
|
||||||
|
case VK_F7: return ImGuiKey_F7;
|
||||||
|
case VK_F8: return ImGuiKey_F8;
|
||||||
|
case VK_F9: return ImGuiKey_F9;
|
||||||
|
case VK_F10: return ImGuiKey_F10;
|
||||||
|
case VK_F11: return ImGuiKey_F11;
|
||||||
|
case VK_F12: return ImGuiKey_F12;
|
||||||
|
default: return ImGuiKey_None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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. Keep calling your message handler unless this function returns TRUE.
|
||||||
|
// 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, or clear/overwrite your copy of the mouse data.
|
||||||
|
// - When io.WantCaptureKeyboard is true, do not dispatch keyboard input data to your main application, or clear/overwrite your copy of the keyboard data.
|
||||||
|
// 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();
|
||||||
|
ImGui_ImplWin32_Data* bd = ImGui_ImplWin32_GetBackendData();
|
||||||
|
|
||||||
|
switch (msg)
|
||||||
|
{
|
||||||
|
case WM_MOUSEMOVE:
|
||||||
|
// We need to call TrackMouseEvent in order to receive WM_MOUSELEAVE events
|
||||||
|
bd->MouseHwnd = hwnd;
|
||||||
|
if (!bd->MouseTracked)
|
||||||
|
{
|
||||||
|
TRACKMOUSEEVENT tme = { sizeof(tme), TME_LEAVE, hwnd, 0 };
|
||||||
|
::TrackMouseEvent(&tme);
|
||||||
|
bd->MouseTracked = true;
|
||||||
|
}
|
||||||
|
io.AddMousePosEvent((float)GET_X_LPARAM(lParam), (float)GET_Y_LPARAM(lParam));
|
||||||
|
break;
|
||||||
|
case WM_MOUSELEAVE:
|
||||||
|
if (bd->MouseHwnd == hwnd)
|
||||||
|
bd->MouseHwnd = NULL;
|
||||||
|
bd->MouseTracked = false;
|
||||||
|
io.AddMousePosEvent(-FLT_MAX, -FLT_MAX);
|
||||||
|
break;
|
||||||
|
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 (bd->MouseButtonsDown == 0 && ::GetCapture() == NULL)
|
||||||
|
// ::SetCapture(hwnd);
|
||||||
|
bd->MouseButtonsDown |= 1 << button;
|
||||||
|
io.AddMouseButtonEvent(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; }
|
||||||
|
bd->MouseButtonsDown &= ~(1 << button);
|
||||||
|
// if (bd->MouseButtonsDown == 0 && ::GetCapture() == hwnd)
|
||||||
|
// ::ReleaseCapture();
|
||||||
|
io.AddMouseButtonEvent(button, false);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
case WM_MOUSEWHEEL:
|
||||||
|
io.AddMouseWheelEvent(0.0f, (float)GET_WHEEL_DELTA_WPARAM(wParam) / (float)WHEEL_DELTA);
|
||||||
|
return 0;
|
||||||
|
case WM_MOUSEHWHEEL:
|
||||||
|
io.AddMouseWheelEvent((float)GET_WHEEL_DELTA_WPARAM(wParam) / (float)WHEEL_DELTA, 0.0f);
|
||||||
|
return 0;
|
||||||
|
case WM_KEYDOWN:
|
||||||
|
case WM_KEYUP:
|
||||||
|
case WM_SYSKEYDOWN:
|
||||||
|
case WM_SYSKEYUP:
|
||||||
|
{
|
||||||
|
const bool is_key_down = (msg == WM_KEYDOWN || msg == WM_SYSKEYDOWN);
|
||||||
|
if (wParam < 256)
|
||||||
|
{
|
||||||
|
// Submit modifiers
|
||||||
|
ImGui_ImplWin32_UpdateKeyModifiers();
|
||||||
|
|
||||||
|
// Obtain virtual key code
|
||||||
|
// (keypad enter doesn't have its own... VK_RETURN with KF_EXTENDED flag means keypad enter, see IM_VK_KEYPAD_ENTER definition for details, it is mapped to ImGuiKey_KeyPadEnter.)
|
||||||
|
int vk = (int)wParam;
|
||||||
|
if ((wParam == VK_RETURN) && (HIWORD(lParam) & KF_EXTENDED))
|
||||||
|
vk = IM_VK_KEYPAD_ENTER;
|
||||||
|
|
||||||
|
// Submit key event
|
||||||
|
const ImGuiKey key = ImGui_ImplWin32_VirtualKeyToImGuiKey(vk);
|
||||||
|
const int scancode = (int)LOBYTE(HIWORD(lParam));
|
||||||
|
if (key != ImGuiKey_None)
|
||||||
|
ImGui_ImplWin32_AddKeyEvent(key, is_key_down, vk, scancode);
|
||||||
|
|
||||||
|
// Submit individual left/right modifier events
|
||||||
|
if (vk == VK_SHIFT)
|
||||||
|
{
|
||||||
|
// Important: Shift keys tend to get stuck when pressed together, missing key-up events are corrected in ImGui_ImplWin32_ProcessKeyEventsWorkarounds()
|
||||||
|
if (IsVkDown(VK_LSHIFT) == is_key_down) { ImGui_ImplWin32_AddKeyEvent(ImGuiKey_LeftShift, is_key_down, VK_LSHIFT, scancode); }
|
||||||
|
if (IsVkDown(VK_RSHIFT) == is_key_down) { ImGui_ImplWin32_AddKeyEvent(ImGuiKey_RightShift, is_key_down, VK_RSHIFT, scancode); }
|
||||||
|
}
|
||||||
|
else if (vk == VK_CONTROL)
|
||||||
|
{
|
||||||
|
if (IsVkDown(VK_LCONTROL) == is_key_down) { ImGui_ImplWin32_AddKeyEvent(ImGuiKey_LeftCtrl, is_key_down, VK_LCONTROL, scancode); }
|
||||||
|
if (IsVkDown(VK_RCONTROL) == is_key_down) { ImGui_ImplWin32_AddKeyEvent(ImGuiKey_RightCtrl, is_key_down, VK_RCONTROL, scancode); }
|
||||||
|
}
|
||||||
|
else if (vk == VK_MENU)
|
||||||
|
{
|
||||||
|
if (IsVkDown(VK_LMENU) == is_key_down) { ImGui_ImplWin32_AddKeyEvent(ImGuiKey_LeftAlt, is_key_down, VK_LMENU, scancode); }
|
||||||
|
if (IsVkDown(VK_RMENU) == is_key_down) { ImGui_ImplWin32_AddKeyEvent(ImGuiKey_RightAlt, is_key_down, VK_RMENU, scancode); }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
case WM_SETFOCUS:
|
||||||
|
case WM_KILLFOCUS:
|
||||||
|
io.AddFocusEvent(msg == WM_SETFOCUS);
|
||||||
|
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:
|
||||||
|
// This is required to restore cursor when transitioning from e.g resize borders to client area.
|
||||||
|
if (LOWORD(lParam) == HTCLIENT && ImGui_ImplWin32_UpdateMouseCursor())
|
||||||
|
return 1;
|
||||||
|
return 0;
|
||||||
|
case WM_DEVICECHANGE:
|
||||||
|
if ((UINT)wParam == DBT_DEVNODES_CHANGED)
|
||||||
|
bd->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.
|
||||||
|
//---------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// Perform our own check with RtlVerifyVersionInfo() instead of using functions from <VersionHelpers.h> as they
|
||||||
|
// require a manifest to be functional for checks above 8.1. See https://github.com/ocornut/imgui/issues/4200
|
||||||
|
static BOOL _IsWindowsVersionOrGreater(WORD major, WORD minor, WORD)
|
||||||
|
{
|
||||||
|
typedef LONG(WINAPI* PFN_RtlVerifyVersionInfo)(OSVERSIONINFOEXW*, ULONG, ULONGLONG);
|
||||||
|
static PFN_RtlVerifyVersionInfo RtlVerifyVersionInfoFn = NULL;
|
||||||
|
if (RtlVerifyVersionInfoFn == NULL)
|
||||||
|
if (HMODULE ntdllModule = ::GetModuleHandleA("ntdll.dll"))
|
||||||
|
RtlVerifyVersionInfoFn = (PFN_RtlVerifyVersionInfo)GetProcAddress(ntdllModule, "RtlVerifyVersionInfo");
|
||||||
|
if (RtlVerifyVersionInfoFn == NULL)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
RTL_OSVERSIONINFOEXW versionInfo = { };
|
||||||
|
ULONGLONG conditionMask = 0;
|
||||||
|
versionInfo.dwOSVersionInfoSize = sizeof(RTL_OSVERSIONINFOEXW);
|
||||||
|
versionInfo.dwMajorVersion = major;
|
||||||
|
versionInfo.dwMinorVersion = minor;
|
||||||
|
VER_SET_CONDITION(conditionMask, VER_MAJORVERSION, VER_GREATER_EQUAL);
|
||||||
|
VER_SET_CONDITION(conditionMask, VER_MINORVERSION, VER_GREATER_EQUAL);
|
||||||
|
return (RtlVerifyVersionInfoFn(&versionInfo, VER_MAJORVERSION | VER_MINORVERSION, conditionMask) == 0) ? TRUE : FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
#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
|
||||||
|
#define _IsWindows10OrGreater() _IsWindowsVersionOrGreater(HIBYTE(0x0A00), LOBYTE(0x0A00), 0) // _WIN32_WINNT_WINTHRESHOLD / _WIN32_WINNT_WIN10
|
||||||
|
|
||||||
|
#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())
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
if (_IsWindows8Point1OrGreater())
|
||||||
|
{
|
||||||
|
static HINSTANCE shcore_dll = ::LoadLibraryA("shcore.dll"); // Reference counted per-process
|
||||||
|
static PFN_GetDpiForMonitor GetDpiForMonitorFn = NULL;
|
||||||
|
if (GetDpiForMonitorFn == NULL && shcore_dll != NULL)
|
||||||
|
GetDpiForMonitorFn = (PFN_GetDpiForMonitor)::GetProcAddress(shcore_dll, "GetDpiForMonitor");
|
||||||
|
if (GetDpiForMonitorFn != NULL)
|
||||||
|
{
|
||||||
|
GetDpiForMonitorFn((HMONITOR)monitor, MDT_EFFECTIVE_DPI, &xdpi, &ydpi);
|
||||||
|
IM_ASSERT(xdpi == ydpi); // Please contact me if you hit this assert!
|
||||||
|
return xdpi / 96.0f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#ifndef NOGDI
|
||||||
|
const HDC dc = ::GetDC(NULL);
|
||||||
|
xdpi = ::GetDeviceCaps(dc, LOGPIXELSX);
|
||||||
|
ydpi = ::GetDeviceCaps(dc, LOGPIXELSY);
|
||||||
|
IM_ASSERT(xdpi == ydpi); // Please contact me if you hit this assert!
|
||||||
|
::ReleaseDC(NULL, dc);
|
||||||
|
#endif
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------------------------------------
|
|
@ -3,9 +3,9 @@
|
||||||
|
|
||||||
// Implemented features:
|
// Implemented features:
|
||||||
// [X] Platform: Clipboard support (for Win32 this is actually part of core dear imgui)
|
// [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 support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy VK_* values will also be supported unless IMGUI_DISABLE_OBSOLETE_KEYIO is set]
|
||||||
// [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'.
|
// [X] Platform: Gamepad support. Enabled with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'.
|
||||||
|
// [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'.
|
||||||
|
|
||||||
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
||||||
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
|
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
|
||||||
|
@ -22,6 +22,8 @@ IMGUI_IMPL_API void ImGui_ImplWin32_NewFrame();
|
||||||
// Win32 message handler your application need to call.
|
// 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.
|
// - 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.
|
// - You should COPY the line below into your .cpp code to forward declare the function and then you can call it.
|
||||||
|
// - Call from your application's message handler. Keep calling your message handler unless this function returns TRUE.
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
extern IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
|
extern IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
|
||||||
#endif
|
#endif
|
|
@ -0,0 +1,389 @@
|
||||||
|
// dear imgui: Platform Binding for Linux (standard X11 API for 32 and 64 bits applications)
|
||||||
|
// This needs to be used along with a Renderer (e.g. OpenGL3, Vulkan..)
|
||||||
|
|
||||||
|
// https://www.uninformativ.de/blog/postings/2017-04-02/0/POSTING-en.html
|
||||||
|
// https://stackoverflow.com/questions/27378318/c-get-string-from-clipboard-on-linux
|
||||||
|
|
||||||
|
// Implemented features:
|
||||||
|
// [X] Platform: Clipboard support
|
||||||
|
// [ ] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'.
|
||||||
|
// [X] Platform: Keyboard arrays indexed using
|
||||||
|
// [ ] Platform: Gamepad support. Enabled with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'.
|
||||||
|
|
||||||
|
#include "imgui.h"
|
||||||
|
#include "imgui_impl_x11.h"
|
||||||
|
|
||||||
|
#include <X11/X.h>
|
||||||
|
#include <X11/Xlib.h>
|
||||||
|
#include <X11/XKBlib.h>
|
||||||
|
#include <X11/keysym.h>
|
||||||
|
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <climits>
|
||||||
|
#include <ctime>
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
// CHANGELOG
|
||||||
|
// (minor and older changes stripped away, please see git history for details)
|
||||||
|
// 2021-15-06: Clipboard support.
|
||||||
|
// 2019-08-31: Initial X11 implementation.
|
||||||
|
|
||||||
|
// X11 Data
|
||||||
|
static Atom g_BufId;
|
||||||
|
static Atom g_PropId;
|
||||||
|
static Atom g_FmtIdUtf8String;
|
||||||
|
static Atom g_IncrId;
|
||||||
|
|
||||||
|
static char* g_ClipboardBuffer = NULL;
|
||||||
|
static size_t g_ClipboardBufferLength = 0;
|
||||||
|
static size_t g_ClipboardBufferSize = 0;
|
||||||
|
static bool g_ClipboardOwned = false;
|
||||||
|
|
||||||
|
static Display* g_Display = nullptr;
|
||||||
|
static Window g_Window = 0;
|
||||||
|
static uint64_t g_Time = 0;
|
||||||
|
static uint64_t g_TicksPerSecond = 0;
|
||||||
|
static ImGuiMouseCursor g_LastMouseCursor = ImGuiMouseCursor_COUNT;
|
||||||
|
static bool g_HasGamepad = false;
|
||||||
|
static bool g_WantUpdateHasGamepad = true;
|
||||||
|
|
||||||
|
static bool GetKeyState(int keysym, char keys[32])
|
||||||
|
{
|
||||||
|
int keycode = XKeysymToKeycode(g_Display, keysym);
|
||||||
|
return keys[keycode/8] & (1<<keycode%8);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int KeyToImGuiKey(int key)
|
||||||
|
{
|
||||||
|
if (key > 255)
|
||||||
|
return key - 0xFF00;
|
||||||
|
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ImGui_ImplX11_SendClipboard(XSelectionRequestEvent* sender)
|
||||||
|
{
|
||||||
|
XSelectionEvent event;
|
||||||
|
|
||||||
|
XChangeProperty(g_Display, sender->requestor, sender->property, g_FmtIdUtf8String, 8, PropModeReplace,
|
||||||
|
(const unsigned char*)g_ClipboardBuffer, g_ClipboardBufferLength);
|
||||||
|
|
||||||
|
event.type = SelectionNotify;
|
||||||
|
event.requestor = sender->requestor;
|
||||||
|
event.selection = sender->selection;
|
||||||
|
event.target = sender->target;
|
||||||
|
event.property = sender->property;
|
||||||
|
event.time = sender->time;
|
||||||
|
|
||||||
|
XSendEvent(g_Display, sender->requestor, True, NoEventMask, (XEvent *)&event);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ImGui_ImplX11_SetClipboardText(void* user_data, const char* text)
|
||||||
|
{
|
||||||
|
g_ClipboardBufferLength = strlen(text);
|
||||||
|
if(g_ClipboardBufferLength > 0)
|
||||||
|
{
|
||||||
|
if(g_ClipboardBufferLength >= g_ClipboardBufferSize)
|
||||||
|
{
|
||||||
|
free(g_ClipboardBuffer);
|
||||||
|
g_ClipboardBuffer = (char*)malloc(sizeof(char) * g_ClipboardBufferLength);
|
||||||
|
g_ClipboardBufferSize = g_ClipboardBufferLength;
|
||||||
|
}
|
||||||
|
memcpy(g_ClipboardBuffer, text, g_ClipboardBufferLength);
|
||||||
|
|
||||||
|
if(!g_ClipboardOwned)
|
||||||
|
{
|
||||||
|
g_ClipboardOwned = true;
|
||||||
|
XSetSelectionOwner(g_Display, g_BufId, g_Window, CurrentTime);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char* ImGui_ImplX11_GetClipboardText(void *user_data)
|
||||||
|
{
|
||||||
|
XEvent event;
|
||||||
|
char *result;
|
||||||
|
unsigned long ressize, restail;
|
||||||
|
int resbits;
|
||||||
|
bool timed_out;
|
||||||
|
time_t now;
|
||||||
|
|
||||||
|
now = time(NULL);
|
||||||
|
timed_out = false;
|
||||||
|
XConvertSelection(g_Display, g_BufId, g_FmtIdUtf8String, g_PropId, g_Window, CurrentTime);
|
||||||
|
do
|
||||||
|
{
|
||||||
|
XNextEvent(g_Display, &event);
|
||||||
|
if(event.type == SelectionRequest)
|
||||||
|
{// This happens when we are requesting our own buffer.
|
||||||
|
ImGui_ImplX11_SendClipboard(&event.xselectionrequest);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if(time(NULL) - now > 2)
|
||||||
|
{
|
||||||
|
timed_out = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while (event.type != SelectionNotify || event.xselection.selection != g_BufId);
|
||||||
|
|
||||||
|
g_ClipboardBuffer[0] = '\0';
|
||||||
|
if (!timed_out && event.xselection.property)
|
||||||
|
{
|
||||||
|
XGetWindowProperty(g_Display, g_Window, g_PropId, 0, LONG_MAX/4, False, AnyPropertyType,
|
||||||
|
&g_FmtIdUtf8String, &resbits, &ressize, &restail, (unsigned char**)&result);
|
||||||
|
|
||||||
|
if (g_FmtIdUtf8String == g_IncrId)
|
||||||
|
{
|
||||||
|
IM_ASSERT(0 && "Buffer is too large and INCR reading is not implemented yet.\n");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if(ressize > g_ClipboardBufferSize)
|
||||||
|
{
|
||||||
|
free(g_ClipboardBuffer);
|
||||||
|
g_ClipboardBufferSize = ressize + 1;
|
||||||
|
g_ClipboardBuffer = (char*)malloc(sizeof(char) * g_ClipboardBufferSize);
|
||||||
|
}
|
||||||
|
memcpy(g_ClipboardBuffer, result, ressize);
|
||||||
|
g_ClipboardBuffer[ressize] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
XFree(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
return g_ClipboardBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Functions
|
||||||
|
bool ImGui_ImplX11_Init(void *display, void *window)
|
||||||
|
{
|
||||||
|
timespec ts, tsres;
|
||||||
|
clock_getres(CLOCK_MONOTONIC_RAW, &tsres);
|
||||||
|
clock_gettime(CLOCK_MONOTONIC_RAW, &ts);
|
||||||
|
|
||||||
|
g_TicksPerSecond = 1000000000.0f / (static_cast<uint64_t>(tsres.tv_nsec) + static_cast<uint64_t>(tsres.tv_sec)*1000000000);
|
||||||
|
g_Time = static_cast<uint64_t>(ts.tv_nsec) + static_cast<uint64_t>(ts.tv_sec)*1000000000;
|
||||||
|
|
||||||
|
// Setup back-end capabilities flags
|
||||||
|
g_Display = reinterpret_cast<Display*>(display);
|
||||||
|
g_Window = reinterpret_cast<Window>(window);
|
||||||
|
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_x11";
|
||||||
|
io.ImeWindowHandle = nullptr;
|
||||||
|
|
||||||
|
io.GetClipboardTextFn = ImGui_ImplX11_GetClipboardText;
|
||||||
|
io.SetClipboardTextFn = ImGui_ImplX11_SetClipboardText;
|
||||||
|
|
||||||
|
g_ClipboardBuffer = (char*)malloc(sizeof(char) * 256);
|
||||||
|
g_ClipboardBufferSize = 256;
|
||||||
|
|
||||||
|
g_BufId = XInternAtom(g_Display, "CLIPBOARD", False);
|
||||||
|
g_PropId = XInternAtom(g_Display, "XSEL_DATA", False);
|
||||||
|
g_FmtIdUtf8String = XInternAtom(g_Display, "UTF8_STRING", False);
|
||||||
|
g_IncrId = XInternAtom(g_Display, "INCR", False);
|
||||||
|
|
||||||
|
// Keyboard mapping. ImGui will use those indices to peek into the io.KeysDown[] array that we will update during the application lifetime.
|
||||||
|
io.KeyMap[ImGuiKey_Tab] = KeyToImGuiKey(XK_Tab);
|
||||||
|
io.KeyMap[ImGuiKey_LeftArrow] = KeyToImGuiKey(XK_Left);
|
||||||
|
io.KeyMap[ImGuiKey_RightArrow] = KeyToImGuiKey(XK_Right);
|
||||||
|
io.KeyMap[ImGuiKey_UpArrow] = KeyToImGuiKey(XK_Up);
|
||||||
|
io.KeyMap[ImGuiKey_DownArrow] = KeyToImGuiKey(XK_Down);
|
||||||
|
io.KeyMap[ImGuiKey_PageUp] = KeyToImGuiKey(XK_Prior);
|
||||||
|
io.KeyMap[ImGuiKey_PageDown] = KeyToImGuiKey(XK_Next);
|
||||||
|
io.KeyMap[ImGuiKey_Home] = KeyToImGuiKey(XK_Home);
|
||||||
|
io.KeyMap[ImGuiKey_End] = KeyToImGuiKey(XK_End);
|
||||||
|
io.KeyMap[ImGuiKey_Insert] = KeyToImGuiKey(XK_Insert);
|
||||||
|
io.KeyMap[ImGuiKey_Delete] = KeyToImGuiKey(XK_Delete);
|
||||||
|
io.KeyMap[ImGuiKey_Backspace] = KeyToImGuiKey(XK_BackSpace);
|
||||||
|
io.KeyMap[ImGuiKey_Space] = KeyToImGuiKey(XK_space);
|
||||||
|
io.KeyMap[ImGuiKey_Enter] = KeyToImGuiKey(XK_Return);
|
||||||
|
io.KeyMap[ImGuiKey_Escape] = KeyToImGuiKey(XK_Escape);
|
||||||
|
io.KeyMap[ImGuiKey_KeyPadEnter] = KeyToImGuiKey(XK_KP_Enter);
|
||||||
|
io.KeyMap[ImGuiKey_A] = KeyToImGuiKey(XK_a);
|
||||||
|
io.KeyMap[ImGuiKey_C] = KeyToImGuiKey(XK_c);
|
||||||
|
io.KeyMap[ImGuiKey_V] = KeyToImGuiKey(XK_v);
|
||||||
|
io.KeyMap[ImGuiKey_X] = KeyToImGuiKey(XK_x);
|
||||||
|
io.KeyMap[ImGuiKey_Y] = KeyToImGuiKey(XK_y);
|
||||||
|
io.KeyMap[ImGuiKey_Z] = KeyToImGuiKey(XK_z);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGui_ImplX11_Shutdown()
|
||||||
|
{
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
io.GetClipboardTextFn = NULL;
|
||||||
|
io.SetClipboardTextFn = NULL;
|
||||||
|
|
||||||
|
free(g_ClipboardBuffer); g_ClipboardBuffer = NULL;
|
||||||
|
g_ClipboardBufferSize = 0;
|
||||||
|
g_ClipboardBufferLength = 0;
|
||||||
|
|
||||||
|
g_Display = nullptr;
|
||||||
|
g_Window = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool ImGui_ImplX11_UpdateMouseCursor()
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ImGui_ImplX11_UpdateMousePos()
|
||||||
|
{
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
|
||||||
|
// 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 };
|
||||||
|
// ::ClientToScreen(g_hWnd, &pos);
|
||||||
|
// ::SetCursorPos(pos.x, pos.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set mouse position
|
||||||
|
Window unused_window;
|
||||||
|
int rx, ry, x, y;
|
||||||
|
unsigned int mask;
|
||||||
|
|
||||||
|
XQueryPointer(g_Display, g_Window, &unused_window, &unused_window, &rx, &ry, &x, &y, &mask);
|
||||||
|
|
||||||
|
io.MousePos = ImVec2((float)x, (float)y);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Gamepad navigation mapping
|
||||||
|
static void ImGui_ImplX11_UpdateGamepads()
|
||||||
|
{
|
||||||
|
// TODO: support linux gamepad ?
|
||||||
|
#ifndef IMGUI_IMPL_X11_DISABLE_GAMEPAD
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGui_ImplX11_NewFrame()
|
||||||
|
{
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
IM_ASSERT(io.Fonts->IsBuilt() && "Font atlas not built! It is generally built by the renderer back-end. Missing call to renderer _NewFrame() function? e.g. ImGui_ImplOpenGL3_NewFrame().");
|
||||||
|
|
||||||
|
unsigned int width, height;
|
||||||
|
Window unused_window;
|
||||||
|
int unused_int;
|
||||||
|
unsigned int unused_unsigned_int;
|
||||||
|
|
||||||
|
XGetGeometry(g_Display, (Window)g_Window, &unused_window, &unused_int, &unused_int, &width, &height, &unused_unsigned_int, &unused_unsigned_int);
|
||||||
|
|
||||||
|
io.DisplaySize.x = width;
|
||||||
|
io.DisplaySize.y = height;
|
||||||
|
|
||||||
|
timespec ts, tsres;
|
||||||
|
clock_gettime(CLOCK_MONOTONIC_RAW, &ts);
|
||||||
|
|
||||||
|
uint64_t current_time = static_cast<uint64_t>(ts.tv_nsec) + static_cast<uint64_t>(ts.tv_sec)*1000000000;
|
||||||
|
|
||||||
|
io.DeltaTime = (float)(current_time - g_Time) / g_TicksPerSecond;
|
||||||
|
g_Time = current_time;
|
||||||
|
|
||||||
|
// Read keyboard modifiers inputs
|
||||||
|
char keys[32];
|
||||||
|
XQueryKeymap(g_Display, keys);
|
||||||
|
|
||||||
|
io.KeyCtrl = GetKeyState(XK_Control_L, keys);
|
||||||
|
io.KeyShift = GetKeyState(XK_Shift_L, keys);
|
||||||
|
io.KeyAlt = GetKeyState(XK_Alt_L, keys);
|
||||||
|
io.KeySuper = GetKeyState(XK_Super_L, keys);
|
||||||
|
|
||||||
|
// io.KeysDown[], io.MousePos, io.MouseDown[], io.MouseWheel: filled by the WndProc handler below.
|
||||||
|
|
||||||
|
// Update OS mouse position
|
||||||
|
ImGui_ImplX11_UpdateMousePos();
|
||||||
|
|
||||||
|
// Update game controllers (if enabled and available)
|
||||||
|
ImGui_ImplX11_UpdateGamepads();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process X11 mouse/keyboard inputs.
|
||||||
|
// 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.
|
||||||
|
IMGUI_IMPL_API int ImGui_ImplX11_EventHandler(XEvent &event)
|
||||||
|
{
|
||||||
|
if (ImGui::GetCurrentContext() == NULL)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
switch (event.type)
|
||||||
|
{
|
||||||
|
case ButtonPress:
|
||||||
|
case ButtonRelease:
|
||||||
|
switch(event.xbutton.button)
|
||||||
|
{
|
||||||
|
case Button1:
|
||||||
|
io.MouseDown[0] = event.type == ButtonPress;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Button2:
|
||||||
|
io.MouseDown[2] = event.type == ButtonPress;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Button3:
|
||||||
|
io.MouseDown[1] = event.type == ButtonPress;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Button4: // Mouse wheel up
|
||||||
|
if( event.type == ButtonPress )
|
||||||
|
io.MouseWheel += 1;
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
case Button5: // Mouse wheel down
|
||||||
|
if( event.type == ButtonPress )
|
||||||
|
io.MouseWheel -= 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case KeyPress:
|
||||||
|
{
|
||||||
|
int key = XkbKeycodeToKeysym(g_Display, event.xkey.keycode, 0, event.xkey.state & ShiftMask ? 1 : 0);
|
||||||
|
if( key < 255 )
|
||||||
|
{
|
||||||
|
io.KeysDown[key] = true;
|
||||||
|
io.AddInputCharacter(key);
|
||||||
|
}
|
||||||
|
else if( key >= 0x1000100 && key <= 0x110ffff )
|
||||||
|
{
|
||||||
|
io.AddInputCharacterUTF16(key);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
io.KeysDown[key - 0xFF00] = true;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
case KeyRelease:
|
||||||
|
{
|
||||||
|
int key = XkbKeycodeToKeysym(g_Display, event.xkey.keycode, 0, event.xkey.state & ShiftMask ? 1 : 0);
|
||||||
|
io.KeysDown[KeyToImGuiKey(key)] = false;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
case FocusOut:
|
||||||
|
memset(io.KeysDown, 0, sizeof(io.KeysDown));
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
|
||||||
|
case SelectionClear:
|
||||||
|
g_ClipboardOwned = false;
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
case SelectionRequest:
|
||||||
|
{
|
||||||
|
ImGui_ImplX11_SendClipboard(&event.xselectionrequest);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
// dear imgui: Platform Binding for Linux (standard X11 API for 32 and 64 bits applications)
|
||||||
|
// This needs to be used along with a Renderer (e.g. OpenGL3, Vulkan..)
|
||||||
|
|
||||||
|
// Implemented features:
|
||||||
|
// [X] Platform: Clipboard support
|
||||||
|
// [ ] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'.
|
||||||
|
// [X] Platform: Keyboard arrays indexed using XK_* Virtual Key Codes, e.g. ImGui::IsKeyPressed(XK_space).
|
||||||
|
// [ ] Platform: Gamepad support. Enabled with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
IMGUI_IMPL_API bool ImGui_ImplX11_Init(void* display, void* window);
|
||||||
|
IMGUI_IMPL_API void ImGui_ImplX11_Shutdown();
|
||||||
|
IMGUI_IMPL_API void ImGui_ImplX11_NewFrame();
|
||||||
|
|
||||||
|
// Configuration
|
||||||
|
// - Disable gamepad support
|
||||||
|
#define IMGUI_IMPL_X11_DISABLE_GAMEPAD
|
||||||
|
|
||||||
|
// X11 message handler your application need to call.
|
||||||
|
// - Intentionally commented out in a '#if 0' block to avoid dragging dependencies on <X11/*> 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 int ImGui_ImplX11_EventHandler(XEvent &event);
|
||||||
|
#endif
|
|
@ -1,25 +1,6 @@
|
||||||
/*
|
#include "imgui_win_shader_blobs.h"
|
||||||
* Copyright (C) 2019-2020 Nemirtingas
|
|
||||||
* This file is part of the Nemirtingas's Steam Emulator
|
|
||||||
*
|
|
||||||
* The Nemirtingas's Steam Emulator is free software; you can redistribute it
|
|
||||||
* and/or modify it under the terms of the GNU Lesser General Public
|
|
||||||
* License as published by the Free Software Foundation; either
|
|
||||||
* version 3 of the License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* The Nemirtingas's Steam Emulator is distributed in the hope that it will be
|
|
||||||
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
* Lesser General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General Public
|
|
||||||
* License along with the Goldberg Emulator; if not, see
|
|
||||||
* <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "imgui_shaderblobs.h"
|
static unsigned char ImGui_vertexShaderDX10[] = {
|
||||||
|
|
||||||
extern unsigned char ImGui_vertexShaderDX10[] = {
|
|
||||||
0x44, 0x58, 0x42, 0x43, 0x7a, 0x54, 0x84, 0x96, 0xdf, 0xd1, 0x9e, 0x21,
|
0x44, 0x58, 0x42, 0x43, 0x7a, 0x54, 0x84, 0x96, 0xdf, 0xd1, 0x9e, 0x21,
|
||||||
0xfd, 0x85, 0x86, 0x3d, 0x28, 0xd1, 0x03, 0xae, 0x01, 0x00, 0x00, 0x00,
|
0xfd, 0x85, 0x86, 0x3d, 0x28, 0xd1, 0x03, 0xae, 0x01, 0x00, 0x00, 0x00,
|
||||||
0x6c, 0x03, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00,
|
0x6c, 0x03, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00,
|
||||||
|
@ -95,7 +76,7 @@ extern unsigned char ImGui_vertexShaderDX10[] = {
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||||
};
|
};
|
||||||
|
|
||||||
extern unsigned char ImGui_vertexShaderDX11[] = {
|
static unsigned char ImGui_vertexShaderDX11[] = {
|
||||||
0x44, 0x58, 0x42, 0x43, 0x34, 0xbd, 0x62, 0xe1, 0x71, 0x13, 0xaa, 0x19,
|
0x44, 0x58, 0x42, 0x43, 0x34, 0xbd, 0x62, 0xe1, 0x71, 0x13, 0xaa, 0x19,
|
||||||
0x76, 0x89, 0xdb, 0x8a, 0x6e, 0x58, 0xa5, 0x88, 0x01, 0x00, 0x00, 0x00,
|
0x76, 0x89, 0xdb, 0x8a, 0x6e, 0x58, 0xa5, 0x88, 0x01, 0x00, 0x00, 0x00,
|
||||||
0x50, 0x04, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00,
|
0x50, 0x04, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00,
|
||||||
|
@ -190,7 +171,7 @@ extern unsigned char ImGui_vertexShaderDX11[] = {
|
||||||
0x52, 0x00, 0x54, 0x45, 0x58, 0x43, 0x4f, 0x4f, 0x52, 0x44, 0x00, 0xab
|
0x52, 0x00, 0x54, 0x45, 0x58, 0x43, 0x4f, 0x4f, 0x52, 0x44, 0x00, 0xab
|
||||||
};
|
};
|
||||||
|
|
||||||
extern unsigned char ImGui_vertexShaderDX11_9_1[] = {
|
static unsigned char ImGui_vertexShaderDX11_9_1[] = {
|
||||||
0x44, 0x58, 0x42, 0x43, 0x34, 0xbd, 0x62, 0xe1, 0x71, 0x13, 0xaa, 0x19,
|
0x44, 0x58, 0x42, 0x43, 0x34, 0xbd, 0x62, 0xe1, 0x71, 0x13, 0xaa, 0x19,
|
||||||
0x76, 0x89, 0xdb, 0x8a, 0x6e, 0x58, 0xa5, 0x88, 0x01, 0x00, 0x00, 0x00,
|
0x76, 0x89, 0xdb, 0x8a, 0x6e, 0x58, 0xa5, 0x88, 0x01, 0x00, 0x00, 0x00,
|
||||||
0x50, 0x04, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00,
|
0x50, 0x04, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00,
|
||||||
|
@ -285,7 +266,7 @@ extern unsigned char ImGui_vertexShaderDX11_9_1[] = {
|
||||||
0x52, 0x00, 0x54, 0x45, 0x58, 0x43, 0x4f, 0x4f, 0x52, 0x44, 0x00, 0xab
|
0x52, 0x00, 0x54, 0x45, 0x58, 0x43, 0x4f, 0x4f, 0x52, 0x44, 0x00, 0xab
|
||||||
};
|
};
|
||||||
|
|
||||||
extern unsigned char ImGui_vertexShaderDX11_9_3[] = {
|
static unsigned char ImGui_vertexShaderDX11_9_3[] = {
|
||||||
0x44, 0x58, 0x42, 0x43, 0x5d, 0xe0, 0x7a, 0x20, 0xf6, 0x2e, 0x27, 0xbf,
|
0x44, 0x58, 0x42, 0x43, 0x5d, 0xe0, 0x7a, 0x20, 0xf6, 0x2e, 0x27, 0xbf,
|
||||||
0x22, 0xd7, 0x94, 0x61, 0x73, 0xfa, 0xb3, 0x6d, 0x01, 0x00, 0x00, 0x00,
|
0x22, 0xd7, 0x94, 0x61, 0x73, 0xfa, 0xb3, 0x6d, 0x01, 0x00, 0x00, 0x00,
|
||||||
0x50, 0x04, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00,
|
0x50, 0x04, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00,
|
||||||
|
@ -380,7 +361,7 @@ extern unsigned char ImGui_vertexShaderDX11_9_3[] = {
|
||||||
0x52, 0x00, 0x54, 0x45, 0x58, 0x43, 0x4f, 0x4f, 0x52, 0x44, 0x00, 0xab
|
0x52, 0x00, 0x54, 0x45, 0x58, 0x43, 0x4f, 0x4f, 0x52, 0x44, 0x00, 0xab
|
||||||
};
|
};
|
||||||
|
|
||||||
extern unsigned char ImGui_vertexShaderDX11_10_1[] = {
|
static unsigned char ImGui_vertexShaderDX11_10_1[] = {
|
||||||
0x44, 0x58, 0x42, 0x43, 0xd3, 0xde, 0x09, 0xcf, 0xb2, 0x75, 0xc7, 0x09,
|
0x44, 0x58, 0x42, 0x43, 0xd3, 0xde, 0x09, 0xcf, 0xb2, 0x75, 0xc7, 0x09,
|
||||||
0x8b, 0xe6, 0x9d, 0xdc, 0x14, 0xc9, 0x0b, 0x59, 0x01, 0x00, 0x00, 0x00,
|
0x8b, 0xe6, 0x9d, 0xdc, 0x14, 0xc9, 0x0b, 0x59, 0x01, 0x00, 0x00, 0x00,
|
||||||
0x70, 0x03, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00,
|
0x70, 0x03, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00,
|
||||||
|
@ -457,7 +438,7 @@ extern unsigned char ImGui_vertexShaderDX11_10_1[] = {
|
||||||
0x00, 0x00, 0x00, 0x00
|
0x00, 0x00, 0x00, 0x00
|
||||||
};
|
};
|
||||||
|
|
||||||
extern unsigned char ImGui_vertexShaderDX11_11_0[] = {
|
static unsigned char ImGui_vertexShaderDX11_11_0[] = {
|
||||||
0x44, 0x58, 0x42, 0x43, 0xb6, 0xcc, 0x5b, 0x29, 0xde, 0xfb, 0x4d, 0x91,
|
0x44, 0x58, 0x42, 0x43, 0xb6, 0xcc, 0x5b, 0x29, 0xde, 0xfb, 0x4d, 0x91,
|
||||||
0x1f, 0x52, 0xbe, 0xc7, 0x8b, 0x0f, 0xbf, 0x5c, 0x01, 0x00, 0x00, 0x00,
|
0x1f, 0x52, 0xbe, 0xc7, 0x8b, 0x0f, 0xbf, 0x5c, 0x01, 0x00, 0x00, 0x00,
|
||||||
0xdc, 0x03, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00,
|
0xdc, 0x03, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00,
|
||||||
|
@ -545,7 +526,7 @@ extern unsigned char ImGui_vertexShaderDX11_11_0[] = {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
extern unsigned char ImGui_pixelShaderDX10[] = {
|
static unsigned char ImGui_pixelShaderDX10[] = {
|
||||||
0x44, 0x58, 0x42, 0x43, 0x9e, 0xce, 0x85, 0x72, 0xa7, 0x97, 0x52, 0xb4,
|
0x44, 0x58, 0x42, 0x43, 0x9e, 0xce, 0x85, 0x72, 0xa7, 0x97, 0x52, 0xb4,
|
||||||
0x6d, 0xc4, 0x28, 0xfa, 0x10, 0xc0, 0xd2, 0xc1, 0x01, 0x00, 0x00, 0x00,
|
0x6d, 0xc4, 0x28, 0xfa, 0x10, 0xc0, 0xd2, 0xc1, 0x01, 0x00, 0x00, 0x00,
|
||||||
0x94, 0x02, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00,
|
0x94, 0x02, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00,
|
||||||
|
@ -603,7 +584,7 @@ extern unsigned char ImGui_pixelShaderDX10[] = {
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||||
};
|
};
|
||||||
|
|
||||||
extern unsigned char ImGui_pixelShaderDX11[] = {
|
static unsigned char ImGui_pixelShaderDX11[] = {
|
||||||
0x44, 0x58, 0x42, 0x43, 0x34, 0xbd, 0x62, 0xe1, 0x71, 0x13, 0xaa, 0x19,
|
0x44, 0x58, 0x42, 0x43, 0x34, 0xbd, 0x62, 0xe1, 0x71, 0x13, 0xaa, 0x19,
|
||||||
0x76, 0x89, 0xdb, 0x8a, 0x6e, 0x58, 0xa5, 0x88, 0x01, 0x00, 0x00, 0x00,
|
0x76, 0x89, 0xdb, 0x8a, 0x6e, 0x58, 0xa5, 0x88, 0x01, 0x00, 0x00, 0x00,
|
||||||
0x50, 0x04, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00,
|
0x50, 0x04, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00,
|
||||||
|
@ -698,7 +679,7 @@ extern unsigned char ImGui_pixelShaderDX11[] = {
|
||||||
0x52, 0x00, 0x54, 0x45, 0x58, 0x43, 0x4f, 0x4f, 0x52, 0x44, 0x00, 0xab
|
0x52, 0x00, 0x54, 0x45, 0x58, 0x43, 0x4f, 0x4f, 0x52, 0x44, 0x00, 0xab
|
||||||
};
|
};
|
||||||
|
|
||||||
extern unsigned char ImGui_pixelShaderDX11_9_1[] = {
|
static unsigned char ImGui_pixelShaderDX11_9_1[] = {
|
||||||
0x44, 0x58, 0x42, 0x43, 0xfd, 0xf5, 0xd6, 0xef, 0xb1, 0xea, 0x3d, 0x58,
|
0x44, 0x58, 0x42, 0x43, 0xfd, 0xf5, 0xd6, 0xef, 0xb1, 0xea, 0x3d, 0x58,
|
||||||
0xcc, 0xd8, 0xf8, 0x93, 0x11, 0xcb, 0x84, 0xfc, 0x01, 0x00, 0x00, 0x00,
|
0xcc, 0xd8, 0xf8, 0x93, 0x11, 0xcb, 0x84, 0xfc, 0x01, 0x00, 0x00, 0x00,
|
||||||
0x20, 0x03, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00,
|
0x20, 0x03, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00,
|
||||||
|
@ -768,7 +749,7 @@ extern unsigned char ImGui_pixelShaderDX11_9_1[] = {
|
||||||
0x61, 0x72, 0x67, 0x65, 0x74, 0x00, 0xab, 0xab
|
0x61, 0x72, 0x67, 0x65, 0x74, 0x00, 0xab, 0xab
|
||||||
};
|
};
|
||||||
|
|
||||||
extern unsigned char ImGui_pixelShaderDX11_9_3[] = {
|
static unsigned char ImGui_pixelShaderDX11_9_3[] = {
|
||||||
0x44, 0x58, 0x42, 0x43, 0x68, 0xbf, 0x8b, 0x46, 0x89, 0xb4, 0xbe, 0x06,
|
0x44, 0x58, 0x42, 0x43, 0x68, 0xbf, 0x8b, 0x46, 0x89, 0xb4, 0xbe, 0x06,
|
||||||
0xa2, 0x48, 0x16, 0x93, 0xb3, 0x46, 0x9d, 0xaa, 0x01, 0x00, 0x00, 0x00,
|
0xa2, 0x48, 0x16, 0x93, 0xb3, 0x46, 0x9d, 0xaa, 0x01, 0x00, 0x00, 0x00,
|
||||||
0x20, 0x03, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00,
|
0x20, 0x03, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00,
|
||||||
|
@ -838,7 +819,7 @@ extern unsigned char ImGui_pixelShaderDX11_9_3[] = {
|
||||||
0x61, 0x72, 0x67, 0x65, 0x74, 0x00, 0xab, 0xab
|
0x61, 0x72, 0x67, 0x65, 0x74, 0x00, 0xab, 0xab
|
||||||
};
|
};
|
||||||
|
|
||||||
extern unsigned char ImGui_pixelShaderDX11_10_1[] = {
|
static unsigned char ImGui_pixelShaderDX11_10_1[] = {
|
||||||
0x44, 0x58, 0x42, 0x43, 0xed, 0x0b, 0x5f, 0x62, 0x62, 0x1f, 0xad, 0x3c,
|
0x44, 0x58, 0x42, 0x43, 0xed, 0x0b, 0x5f, 0x62, 0x62, 0x1f, 0xad, 0x3c,
|
||||||
0x16, 0xc6, 0xe5, 0x68, 0x51, 0x61, 0xc0, 0x0f, 0x01, 0x00, 0x00, 0x00,
|
0x16, 0xc6, 0xe5, 0x68, 0x51, 0x61, 0xc0, 0x0f, 0x01, 0x00, 0x00, 0x00,
|
||||||
0x98, 0x02, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00,
|
0x98, 0x02, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00,
|
||||||
|
@ -897,7 +878,7 @@ extern unsigned char ImGui_pixelShaderDX11_10_1[] = {
|
||||||
0x00, 0x00, 0x00, 0x00
|
0x00, 0x00, 0x00, 0x00
|
||||||
};
|
};
|
||||||
|
|
||||||
extern unsigned char ImGui_pixelShaderDX11_11_0[] = {
|
static unsigned char ImGui_pixelShaderDX11_11_0[] = {
|
||||||
0x44, 0x58, 0x42, 0x43, 0x7d, 0x67, 0x4f, 0x5f, 0xde, 0x79, 0x94, 0x13,
|
0x44, 0x58, 0x42, 0x43, 0x7d, 0x67, 0x4f, 0x5f, 0xde, 0x79, 0x94, 0x13,
|
||||||
0xc2, 0x10, 0x83, 0x8f, 0x8e, 0x27, 0x9c, 0x34, 0x01, 0x00, 0x00, 0x00,
|
0xc2, 0x10, 0x83, 0x8f, 0x8e, 0x27, 0x9c, 0x34, 0x01, 0x00, 0x00, 0x00,
|
||||||
0xe0, 0x02, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00,
|
0xe0, 0x02, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00,
|
||||||
|
@ -961,3 +942,84 @@ extern unsigned char ImGui_pixelShaderDX11_11_0[] = {
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
0x00, 0x00, 0x00, 0x00
|
0x00, 0x00, 0x00, 0x00
|
||||||
};
|
};
|
||||||
|
|
||||||
|
////// Vertex Shaders //////
|
||||||
|
|
||||||
|
//#include <d3dcommon.h>
|
||||||
|
enum D3D_FEATURE_LEVEL
|
||||||
|
{
|
||||||
|
D3D_FEATURE_LEVEL_1_0_CORE = 0x1000,
|
||||||
|
D3D_FEATURE_LEVEL_9_1 = 0x9100,
|
||||||
|
D3D_FEATURE_LEVEL_9_2 = 0x9200,
|
||||||
|
D3D_FEATURE_LEVEL_9_3 = 0x9300,
|
||||||
|
D3D_FEATURE_LEVEL_10_0 = 0xa000,
|
||||||
|
D3D_FEATURE_LEVEL_10_1 = 0xa100,
|
||||||
|
D3D_FEATURE_LEVEL_11_0 = 0xb000,
|
||||||
|
D3D_FEATURE_LEVEL_11_1 = 0xb100,
|
||||||
|
D3D_FEATURE_LEVEL_12_0 = 0xc000,
|
||||||
|
D3D_FEATURE_LEVEL_12_1 = 0xc100
|
||||||
|
} D3D_FEATURE_LEVEL;
|
||||||
|
|
||||||
|
shader_t getDX10VertexShader()
|
||||||
|
{
|
||||||
|
return { ImGui_vertexShaderDX10, sizeof(ImGui_vertexShaderDX10)/sizeof(*ImGui_vertexShaderDX10) };
|
||||||
|
}
|
||||||
|
|
||||||
|
shader_t getDX11VertexShader(unsigned long feature_level)
|
||||||
|
{
|
||||||
|
switch (feature_level)
|
||||||
|
{
|
||||||
|
case D3D_FEATURE_LEVEL_9_1 : return { ImGui_vertexShaderDX11_9_1 , sizeof(ImGui_vertexShaderDX11_9_1 ) / sizeof(*ImGui_vertexShaderDX11_9_1 ) };
|
||||||
|
// 9.2 is the same shader as 9.1
|
||||||
|
case D3D_FEATURE_LEVEL_9_2 : return { ImGui_vertexShaderDX11_9_1 , sizeof(ImGui_vertexShaderDX11_9_1 ) / sizeof(*ImGui_vertexShaderDX11_9_1 ) };
|
||||||
|
case D3D_FEATURE_LEVEL_9_3 : return { ImGui_vertexShaderDX11_9_3 , sizeof(ImGui_vertexShaderDX11_9_3 ) / sizeof(*ImGui_vertexShaderDX11_9_3 ) };
|
||||||
|
case D3D_FEATURE_LEVEL_10_0: return { ImGui_vertexShaderDX10 , sizeof(ImGui_vertexShaderDX10 ) / sizeof(*ImGui_vertexShaderDX10 ) };
|
||||||
|
case D3D_FEATURE_LEVEL_10_1: return { ImGui_vertexShaderDX11_10_1, sizeof(ImGui_vertexShaderDX11_10_1) / sizeof(*ImGui_vertexShaderDX11_10_1) };
|
||||||
|
case D3D_FEATURE_LEVEL_11_0: return { ImGui_vertexShaderDX11_11_0, sizeof(ImGui_vertexShaderDX11_11_0) / sizeof(*ImGui_vertexShaderDX11_11_0) };
|
||||||
|
// 11.1 is the same shader as 11.0
|
||||||
|
case D3D_FEATURE_LEVEL_11_1: return { ImGui_vertexShaderDX11_11_0, sizeof(ImGui_vertexShaderDX11_11_0) / sizeof(*ImGui_vertexShaderDX11_11_0) };
|
||||||
|
// 12.0 is the same shader as 11.0
|
||||||
|
case D3D_FEATURE_LEVEL_12_0: return { ImGui_vertexShaderDX11_11_0, sizeof(ImGui_vertexShaderDX11_11_0) / sizeof(*ImGui_vertexShaderDX11_11_0) };
|
||||||
|
// 12.1 is the same shader as 11.0
|
||||||
|
case D3D_FEATURE_LEVEL_12_1: return { ImGui_vertexShaderDX11_11_0, sizeof(ImGui_vertexShaderDX11_11_0) / sizeof(*ImGui_vertexShaderDX11_11_0) };
|
||||||
|
default : return { ImGui_vertexShaderDX11_11_0, sizeof(ImGui_vertexShaderDX11_11_0) / sizeof(*ImGui_vertexShaderDX11_11_0) };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
shader_t getDX12VertexShader()
|
||||||
|
{
|
||||||
|
return { ImGui_vertexShaderDX11_11_0, sizeof(ImGui_vertexShaderDX11_11_0) / sizeof(*ImGui_vertexShaderDX11_11_0) };
|
||||||
|
}
|
||||||
|
|
||||||
|
////// Pixel Shaders //////
|
||||||
|
|
||||||
|
shader_t getDX10PixelShader()
|
||||||
|
{
|
||||||
|
return { ImGui_pixelShaderDX10, sizeof(ImGui_pixelShaderDX10) / sizeof(*ImGui_pixelShaderDX10) };
|
||||||
|
}
|
||||||
|
|
||||||
|
shader_t getDX11PixelShader(unsigned long feature_level)
|
||||||
|
{
|
||||||
|
switch (feature_level)
|
||||||
|
{
|
||||||
|
case D3D_FEATURE_LEVEL_9_1 : return { ImGui_pixelShaderDX11_9_1 , sizeof(ImGui_pixelShaderDX11_9_1 ) / sizeof(*ImGui_pixelShaderDX11_9_1 ) };
|
||||||
|
// 9.2 is the same shader as 9.1
|
||||||
|
case D3D_FEATURE_LEVEL_9_2 : return { ImGui_pixelShaderDX11_9_1 , sizeof(ImGui_pixelShaderDX11_9_1 ) / sizeof(*ImGui_pixelShaderDX11_9_1 ) };
|
||||||
|
case D3D_FEATURE_LEVEL_9_3 : return { ImGui_pixelShaderDX11_9_3 , sizeof(ImGui_pixelShaderDX11_9_3 ) / sizeof(*ImGui_pixelShaderDX11_9_3 ) };
|
||||||
|
case D3D_FEATURE_LEVEL_10_0: return { ImGui_pixelShaderDX10 , sizeof(ImGui_pixelShaderDX10 ) / sizeof(*ImGui_pixelShaderDX10 ) };
|
||||||
|
case D3D_FEATURE_LEVEL_10_1: return { ImGui_pixelShaderDX11_10_1 , sizeof(ImGui_pixelShaderDX11_10_1 ) / sizeof(*ImGui_pixelShaderDX11_10_1 ) };
|
||||||
|
case D3D_FEATURE_LEVEL_11_0: return { ImGui_pixelShaderDX11_11_0 , sizeof(ImGui_pixelShaderDX11_11_0 ) / sizeof(*ImGui_pixelShaderDX11_11_0 ) };
|
||||||
|
// 11.1 is the same shader as 11.0
|
||||||
|
case D3D_FEATURE_LEVEL_11_1: return { ImGui_pixelShaderDX11_11_0 , sizeof(ImGui_pixelShaderDX11_11_0 ) / sizeof(*ImGui_pixelShaderDX11_11_0 ) };
|
||||||
|
// 12.0 is the same shader as 11.0
|
||||||
|
case D3D_FEATURE_LEVEL_12_0: return { ImGui_pixelShaderDX11_11_0 , sizeof(ImGui_pixelShaderDX11_11_0 ) / sizeof(*ImGui_pixelShaderDX11_11_0 ) };
|
||||||
|
// 12.1 is the same shader as 11.0
|
||||||
|
case D3D_FEATURE_LEVEL_12_1: return { ImGui_pixelShaderDX11_11_0 , sizeof(ImGui_pixelShaderDX11_11_0 ) / sizeof(*ImGui_pixelShaderDX11_11_0 ) };
|
||||||
|
default : return { ImGui_pixelShaderDX11_11_0 , sizeof(ImGui_pixelShaderDX11_11_0 ) / sizeof(*ImGui_pixelShaderDX11_11_0 ) };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
shader_t getDX12PixelShader()
|
||||||
|
{
|
||||||
|
return { ImGui_pixelShaderDX11_11_0, sizeof(ImGui_pixelShaderDX11_11_0) / sizeof(*ImGui_pixelShaderDX11_11_0) };
|
||||||
|
}
|
|
@ -0,0 +1,26 @@
|
||||||
|
#ifndef __IMGUI_SHADER_BLOBS_INCLUDED__
|
||||||
|
#define __IMGUI_SHADER_BLOBS_INCLUDED__
|
||||||
|
|
||||||
|
struct shader_t
|
||||||
|
{
|
||||||
|
const void* shaderBlob;
|
||||||
|
unsigned int shaderBlobSize;
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
shader_t getDX10VertexShader();
|
||||||
|
shader_t getDX11VertexShader(unsigned long feature_level);
|
||||||
|
shader_t getDX12VertexShader();
|
||||||
|
|
||||||
|
shader_t getDX10PixelShader();
|
||||||
|
shader_t getDX11PixelShader(unsigned long feature_level);
|
||||||
|
shader_t getDX12PixelShader();
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,6 @@
|
||||||
|
#!/bin/bash
|
||||||
|
## -V: create SPIR-V binary
|
||||||
|
## -x: save binary output as text-based 32-bit hexadecimal numbers
|
||||||
|
## -o: output file
|
||||||
|
glslangValidator -V -x -o glsl_shader.frag.u32 glsl_shader.frag
|
||||||
|
glslangValidator -V -x -o glsl_shader.vert.u32 glsl_shader.vert
|
|
@ -0,0 +1,14 @@
|
||||||
|
#version 450 core
|
||||||
|
layout(location = 0) out vec4 fColor;
|
||||||
|
|
||||||
|
layout(set=0, binding=0) uniform sampler2D sTexture;
|
||||||
|
|
||||||
|
layout(location = 0) in struct {
|
||||||
|
vec4 Color;
|
||||||
|
vec2 UV;
|
||||||
|
} In;
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
fColor = In.Color * texture(sTexture, In.UV.st);
|
||||||
|
}
|
|
@ -0,0 +1,25 @@
|
||||||
|
#version 450 core
|
||||||
|
layout(location = 0) in vec2 aPos;
|
||||||
|
layout(location = 1) in vec2 aUV;
|
||||||
|
layout(location = 2) in vec4 aColor;
|
||||||
|
|
||||||
|
layout(push_constant) uniform uPushConstant {
|
||||||
|
vec2 uScale;
|
||||||
|
vec2 uTranslate;
|
||||||
|
} pc;
|
||||||
|
|
||||||
|
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 = vec4(aPos * pc.uScale + pc.uTranslate, 0, 1);
|
||||||
|
}
|
|
@ -28,16 +28,18 @@
|
||||||
|
|
||||||
//---- Don't define obsolete functions/enums/behaviors. Consider enabling from time to time after updating to avoid using soon-to-be obsolete function/names.
|
//---- Don't define obsolete functions/enums/behaviors. Consider enabling from time to time after updating to avoid using soon-to-be obsolete function/names.
|
||||||
//#define IMGUI_DISABLE_OBSOLETE_FUNCTIONS
|
//#define IMGUI_DISABLE_OBSOLETE_FUNCTIONS
|
||||||
|
//#define IMGUI_DISABLE_OBSOLETE_KEYIO // 1.87: disable legacy io.KeyMap[]+io.KeysDown[] in favor io.AddKeyEvent(). This will be folded into IMGUI_DISABLE_OBSOLETE_FUNCTIONS in a few versions.
|
||||||
|
|
||||||
//---- Disable all of Dear ImGui or don't implement standard windows.
|
//---- Disable all of Dear ImGui or don't implement standard windows/tools.
|
||||||
// It is very strongly recommended to NOT disable the demo windows during development. Please read comments in imgui_demo.cpp.
|
// It is very strongly recommended to NOT disable the demo windows and debug tool during development. They are extremely useful in day to day work. Please read comments in imgui_demo.cpp.
|
||||||
//#define IMGUI_DISABLE // Disable everything: all headers and source files will be empty.
|
//#define IMGUI_DISABLE // Disable everything: all headers and source files will be empty.
|
||||||
#define IMGUI_DISABLE_DEMO_WINDOWS // Disable demo windows: ShowDemoWindow()/ShowStyleEditor() will be empty. Not recommended.
|
#define IMGUI_DISABLE_DEMO_WINDOWS // Disable demo windows: ShowDemoWindow()/ShowStyleEditor() will be empty.
|
||||||
#define IMGUI_DISABLE_METRICS_WINDOW // Disable metrics/debugger window: ShowMetricsWindow() will be empty.
|
#define IMGUI_DISABLE_DEBUG_TOOLS // Disable metrics/debugger and other debug tools: ShowMetricsWindow(), ShowDebugLogWindow() and ShowStackToolWindow() will be empty (this was called IMGUI_DISABLE_METRICS_WINDOW before 1.88).
|
||||||
|
|
||||||
//---- Don't implement some functions to reduce linkage requirements.
|
//---- Don't implement some functions to reduce linkage requirements.
|
||||||
//#define IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS // [Win32] Don't implement default clipboard handler. Won't use and link with OpenClipboard/GetClipboardData/CloseClipboard etc. (user32.lib/.a, kernel32.lib/.a)
|
//#define IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS // [Win32] Don't implement default clipboard handler. Won't use and link with OpenClipboard/GetClipboardData/CloseClipboard etc. (user32.lib/.a, kernel32.lib/.a)
|
||||||
#define IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS // [Win32] Don't implement default IME handler. Won't use and link with ImmGetContext/ImmSetCompositionWindow. (imm32.lib/.a)
|
//#define IMGUI_ENABLE_WIN32_DEFAULT_IME_FUNCTIONS // [Win32] [Default with Visual Studio] Implement default IME handler (require imm32.lib/.a, auto-link for Visual Studio, -limm32 on command-line for MinGW)
|
||||||
|
#define IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS // [Win32] [Default with non-Visual Studio compilers] Don't implement default IME handler (won't require imm32.lib/.a)
|
||||||
//#define IMGUI_DISABLE_WIN32_FUNCTIONS // [Win32] Won't use and link with any Win32 function (clipboard, ime).
|
//#define IMGUI_DISABLE_WIN32_FUNCTIONS // [Win32] Won't use and link with any Win32 function (clipboard, ime).
|
||||||
//#define IMGUI_ENABLE_OSX_DEFAULT_CLIPBOARD_FUNCTIONS // [OSX] Implement default OSX clipboard handler (need to link with '-framework ApplicationServices', this is why this is not the default).
|
//#define IMGUI_ENABLE_OSX_DEFAULT_CLIPBOARD_FUNCTIONS // [OSX] Implement default OSX clipboard handler (need to link with '-framework ApplicationServices', this is why this is not the default).
|
||||||
//#define IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS // Don't implement ImFormatString/ImFormatStringV so you can implement them yourself (e.g. if you don't want to link with vsnprintf)
|
//#define IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS // Don't implement ImFormatString/ImFormatStringV so you can implement them yourself (e.g. if you don't want to link with vsnprintf)
|
||||||
|
@ -45,6 +47,7 @@
|
||||||
//#define IMGUI_DISABLE_FILE_FUNCTIONS // Don't implement ImFileOpen/ImFileClose/ImFileRead/ImFileWrite and ImFileHandle at all (replace them with dummies)
|
//#define IMGUI_DISABLE_FILE_FUNCTIONS // Don't implement ImFileOpen/ImFileClose/ImFileRead/ImFileWrite and ImFileHandle at all (replace them with dummies)
|
||||||
//#define IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS // Don't implement ImFileOpen/ImFileClose/ImFileRead/ImFileWrite and ImFileHandle so you can implement them yourself if you don't want to link with fopen/fclose/fread/fwrite. This will also disable the LogToTTY() function.
|
//#define IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS // Don't implement ImFileOpen/ImFileClose/ImFileRead/ImFileWrite and ImFileHandle so you can implement them yourself if you don't want to link with fopen/fclose/fread/fwrite. This will also disable the LogToTTY() function.
|
||||||
//#define IMGUI_DISABLE_DEFAULT_ALLOCATORS // Don't implement default allocators calling malloc()/free() to avoid linking with them. You will need to call ImGui::SetAllocatorFunctions().
|
//#define IMGUI_DISABLE_DEFAULT_ALLOCATORS // Don't implement default allocators calling malloc()/free() to avoid linking with them. You will need to call ImGui::SetAllocatorFunctions().
|
||||||
|
//#define IMGUI_DISABLE_SSE // Disable use of SSE intrinsics even if available
|
||||||
|
|
||||||
//---- Include imgui_user.h at the end of imgui.h as a convenience
|
//---- Include imgui_user.h at the end of imgui.h as a convenience
|
||||||
//#define IMGUI_INCLUDE_IMGUI_USER_H
|
//#define IMGUI_INCLUDE_IMGUI_USER_H
|
||||||
|
@ -59,16 +62,17 @@
|
||||||
// By default the embedded implementations are declared static and not available outside of Dear ImGui sources files.
|
// By default the embedded implementations are declared static and not available outside of Dear ImGui sources files.
|
||||||
//#define IMGUI_STB_TRUETYPE_FILENAME "my_folder/stb_truetype.h"
|
//#define IMGUI_STB_TRUETYPE_FILENAME "my_folder/stb_truetype.h"
|
||||||
//#define IMGUI_STB_RECT_PACK_FILENAME "my_folder/stb_rect_pack.h"
|
//#define IMGUI_STB_RECT_PACK_FILENAME "my_folder/stb_rect_pack.h"
|
||||||
|
//#define IMGUI_STB_SPRINTF_FILENAME "my_folder/stb_sprintf.h" // only used if enabled
|
||||||
//#define IMGUI_DISABLE_STB_TRUETYPE_IMPLEMENTATION
|
//#define IMGUI_DISABLE_STB_TRUETYPE_IMPLEMENTATION
|
||||||
//#define IMGUI_DISABLE_STB_RECT_PACK_IMPLEMENTATION
|
//#define IMGUI_DISABLE_STB_RECT_PACK_IMPLEMENTATION
|
||||||
|
|
||||||
//---- Use stb_printf's faster implementation of vsnprintf instead of the one from libc (unless IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS is defined)
|
//---- Use stb_sprintf.h for a faster implementation of vsnprintf instead of the one from libc (unless IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS is defined)
|
||||||
// Requires 'stb_sprintf.h' to be available in the include path. Compatibility checks of arguments and formats done by clang and GCC will be disabled in order to support the extra formats provided by STB sprintf.
|
// Compatibility checks of arguments and formats done by clang and GCC will be disabled in order to support the extra formats provided by stb_sprintf.h.
|
||||||
// #define IMGUI_USE_STB_SPRINTF
|
//#define IMGUI_USE_STB_SPRINTF
|
||||||
|
|
||||||
//---- Use FreeType to build and rasterize the font atlas (instead of stb_truetype which is embedded by default in Dear ImGui)
|
//---- Use FreeType to build and rasterize the font atlas (instead of stb_truetype which is embedded by default in Dear ImGui)
|
||||||
// Requires FreeType headers to be available in the include path. Requires program to be compiled with 'misc/freetype/imgui_freetype.cpp' (in this repository) + the FreeType library (not provided).
|
// Requires FreeType headers to be available in the include path. Requires program to be compiled with 'misc/freetype/imgui_freetype.cpp' (in this repository) + the FreeType library (not provided).
|
||||||
// On Windows you may use vcpkg with 'vcpkg install freetype' + 'vcpkg integrate install'.
|
// On Windows you may use vcpkg with 'vcpkg install freetype --triplet=x64-windows' + 'vcpkg integrate install'.
|
||||||
//#define IMGUI_ENABLE_FREETYPE
|
//#define IMGUI_ENABLE_FREETYPE
|
||||||
|
|
||||||
//---- Use stb_truetype to build and rasterize the font atlas (default)
|
//---- Use stb_truetype to build and rasterize the font atlas (default)
|
||||||
|
@ -79,11 +83,11 @@
|
||||||
// This will be inlined as part of ImVec2 and ImVec4 class declarations.
|
// This will be inlined as part of ImVec2 and ImVec4 class declarations.
|
||||||
/*
|
/*
|
||||||
#define IM_VEC2_CLASS_EXTRA \
|
#define IM_VEC2_CLASS_EXTRA \
|
||||||
ImVec2(const MyVec2& f) { x = f.x; y = f.y; } \
|
constexpr ImVec2(const MyVec2& f) : x(f.x), y(f.y) {} \
|
||||||
operator MyVec2() const { return MyVec2(x,y); }
|
operator MyVec2() const { return MyVec2(x,y); }
|
||||||
|
|
||||||
#define IM_VEC4_CLASS_EXTRA \
|
#define IM_VEC4_CLASS_EXTRA \
|
||||||
ImVec4(const MyVec4& f) { x = f.x; y = f.y; z = f.z; w = f.w; } \
|
constexpr ImVec4(const MyVec4& f) : x(f.x), y(f.y), z(f.z), w(f.w) {} \
|
||||||
operator MyVec4() const { return MyVec4(x,y,z,w); }
|
operator MyVec4() const { return MyVec4(x,y,z,w); }
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -122,5 +126,5 @@ namespace ImGui
|
||||||
|
|
||||||
#define IMGUI_IMPL_WIN32_DISABLE_GAMEPAD
|
#define IMGUI_IMPL_WIN32_DISABLE_GAMEPAD
|
||||||
#define IMGUI_IMPL_WIN32_DISABLE_LINKING_XINPUT
|
#define IMGUI_IMPL_WIN32_DISABLE_LINKING_XINPUT
|
||||||
#define IMGUI_IMPL_OPENGL_LOADER_GLEW
|
#define IMGUI_IMPL_OPENGL_LOADER_GLAD2
|
||||||
#define ImTextureID ImU64
|
#define ImTextureID ImU64
|
||||||
|
|
4883
ImGui/imgui.cpp
4883
ImGui/imgui.cpp
File diff suppressed because it is too large
Load Diff
838
ImGui/imgui.h
838
ImGui/imgui.h
File diff suppressed because it is too large
Load Diff
|
@ -1,4 +1,4 @@
|
||||||
// dear imgui, v1.84 WIP
|
// dear imgui, v1.89 WIP
|
||||||
// (drawing and font code)
|
// (drawing and font code)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -90,7 +90,7 @@ Index of this file:
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
//-------------------------------------------------------------------------
|
//-------------------------------------------------------------------------
|
||||||
// [SECTION] STB libraries implementation
|
// [SECTION] STB libraries implementation (for stb_truetype and stb_rect_pack)
|
||||||
//-------------------------------------------------------------------------
|
//-------------------------------------------------------------------------
|
||||||
|
|
||||||
// Compile time options:
|
// Compile time options:
|
||||||
|
@ -393,7 +393,7 @@ void ImDrawListSharedData::SetCircleTessellationMaxError(float max_error)
|
||||||
for (int i = 0; i < IM_ARRAYSIZE(CircleSegmentCounts); i++)
|
for (int i = 0; i < IM_ARRAYSIZE(CircleSegmentCounts); i++)
|
||||||
{
|
{
|
||||||
const float radius = (float)i;
|
const float radius = (float)i;
|
||||||
CircleSegmentCounts[i] = (ImU8)((i > 0) ? IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_CALC(radius, CircleSegmentMaxError) : 0);
|
CircleSegmentCounts[i] = (ImU8)((i > 0) ? IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_CALC(radius, CircleSegmentMaxError) : IM_DRAWLIST_ARCFAST_SAMPLE_MAX);
|
||||||
}
|
}
|
||||||
ArcFastRadiusCutoff = IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_CALC_R(IM_DRAWLIST_ARCFAST_SAMPLE_MAX, CircleSegmentMaxError);
|
ArcFastRadiusCutoff = IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_CALC_R(IM_DRAWLIST_ARCFAST_SAMPLE_MAX, CircleSegmentMaxError);
|
||||||
}
|
}
|
||||||
|
@ -402,10 +402,9 @@ void ImDrawListSharedData::SetCircleTessellationMaxError(float max_error)
|
||||||
void ImDrawList::_ResetForNewFrame()
|
void ImDrawList::_ResetForNewFrame()
|
||||||
{
|
{
|
||||||
// Verify that the ImDrawCmd fields we want to memcmp() are contiguous in memory.
|
// Verify that the ImDrawCmd fields we want to memcmp() are contiguous in memory.
|
||||||
// (those should be IM_STATIC_ASSERT() in theory but with our pre C++11 setup the whole check doesn't compile with GCC)
|
IM_STATIC_ASSERT(IM_OFFSETOF(ImDrawCmd, ClipRect) == 0);
|
||||||
IM_ASSERT(IM_OFFSETOF(ImDrawCmd, ClipRect) == 0);
|
IM_STATIC_ASSERT(IM_OFFSETOF(ImDrawCmd, TextureId) == sizeof(ImVec4));
|
||||||
IM_ASSERT(IM_OFFSETOF(ImDrawCmd, TextureId) == sizeof(ImVec4));
|
IM_STATIC_ASSERT(IM_OFFSETOF(ImDrawCmd, VtxOffset) == sizeof(ImVec4) + sizeof(ImTextureID));
|
||||||
IM_ASSERT(IM_OFFSETOF(ImDrawCmd, VtxOffset) == sizeof(ImVec4) + sizeof(ImTextureID));
|
|
||||||
|
|
||||||
CmdBuffer.resize(0);
|
CmdBuffer.resize(0);
|
||||||
IdxBuffer.resize(0);
|
IdxBuffer.resize(0);
|
||||||
|
@ -473,6 +472,7 @@ void ImDrawList::_PopUnusedDrawCmd()
|
||||||
|
|
||||||
void ImDrawList::AddCallback(ImDrawCallback callback, void* callback_data)
|
void ImDrawList::AddCallback(ImDrawCallback callback, void* callback_data)
|
||||||
{
|
{
|
||||||
|
IM_ASSERT_PARANOID(CmdBuffer.Size > 0);
|
||||||
ImDrawCmd* curr_cmd = &CmdBuffer.Data[CmdBuffer.Size - 1];
|
ImDrawCmd* curr_cmd = &CmdBuffer.Data[CmdBuffer.Size - 1];
|
||||||
IM_ASSERT(curr_cmd->UserCallback == NULL);
|
IM_ASSERT(curr_cmd->UserCallback == NULL);
|
||||||
if (curr_cmd->ElemCount != 0)
|
if (curr_cmd->ElemCount != 0)
|
||||||
|
@ -490,12 +490,27 @@ void ImDrawList::AddCallback(ImDrawCallback callback, void* callback_data)
|
||||||
#define ImDrawCmd_HeaderSize (IM_OFFSETOF(ImDrawCmd, VtxOffset) + sizeof(unsigned int))
|
#define ImDrawCmd_HeaderSize (IM_OFFSETOF(ImDrawCmd, VtxOffset) + sizeof(unsigned int))
|
||||||
#define ImDrawCmd_HeaderCompare(CMD_LHS, CMD_RHS) (memcmp(CMD_LHS, CMD_RHS, ImDrawCmd_HeaderSize)) // Compare ClipRect, TextureId, VtxOffset
|
#define ImDrawCmd_HeaderCompare(CMD_LHS, CMD_RHS) (memcmp(CMD_LHS, CMD_RHS, ImDrawCmd_HeaderSize)) // Compare ClipRect, TextureId, VtxOffset
|
||||||
#define ImDrawCmd_HeaderCopy(CMD_DST, CMD_SRC) (memcpy(CMD_DST, CMD_SRC, ImDrawCmd_HeaderSize)) // Copy ClipRect, TextureId, VtxOffset
|
#define ImDrawCmd_HeaderCopy(CMD_DST, CMD_SRC) (memcpy(CMD_DST, CMD_SRC, ImDrawCmd_HeaderSize)) // Copy ClipRect, TextureId, VtxOffset
|
||||||
|
#define ImDrawCmd_AreSequentialIdxOffset(CMD_0, CMD_1) (CMD_0->IdxOffset + CMD_0->ElemCount == CMD_1->IdxOffset)
|
||||||
|
|
||||||
|
// Try to merge two last draw commands
|
||||||
|
void ImDrawList::_TryMergeDrawCmds()
|
||||||
|
{
|
||||||
|
IM_ASSERT_PARANOID(CmdBuffer.Size > 0);
|
||||||
|
ImDrawCmd* curr_cmd = &CmdBuffer.Data[CmdBuffer.Size - 1];
|
||||||
|
ImDrawCmd* prev_cmd = curr_cmd - 1;
|
||||||
|
if (ImDrawCmd_HeaderCompare(curr_cmd, prev_cmd) == 0 && ImDrawCmd_AreSequentialIdxOffset(prev_cmd, curr_cmd) && curr_cmd->UserCallback == NULL && prev_cmd->UserCallback == NULL)
|
||||||
|
{
|
||||||
|
prev_cmd->ElemCount += curr_cmd->ElemCount;
|
||||||
|
CmdBuffer.pop_back();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Our scheme may appears a bit unusual, basically we want the most-common calls AddLine AddRect etc. to not have to perform any check so we always have a command ready in the stack.
|
// Our scheme may appears a bit unusual, basically we want the most-common calls AddLine AddRect etc. to not have to perform any check so we always have a command ready in the stack.
|
||||||
// The cost of figuring out if a new command has to be added or if we can merge is paid in those Update** functions only.
|
// The cost of figuring out if a new command has to be added or if we can merge is paid in those Update** functions only.
|
||||||
void ImDrawList::_OnChangedClipRect()
|
void ImDrawList::_OnChangedClipRect()
|
||||||
{
|
{
|
||||||
// If current command is used with different settings we need to add a new command
|
// If current command is used with different settings we need to add a new command
|
||||||
|
IM_ASSERT_PARANOID(CmdBuffer.Size > 0);
|
||||||
ImDrawCmd* curr_cmd = &CmdBuffer.Data[CmdBuffer.Size - 1];
|
ImDrawCmd* curr_cmd = &CmdBuffer.Data[CmdBuffer.Size - 1];
|
||||||
if (curr_cmd->ElemCount != 0 && memcmp(&curr_cmd->ClipRect, &_CmdHeader.ClipRect, sizeof(ImVec4)) != 0)
|
if (curr_cmd->ElemCount != 0 && memcmp(&curr_cmd->ClipRect, &_CmdHeader.ClipRect, sizeof(ImVec4)) != 0)
|
||||||
{
|
{
|
||||||
|
@ -506,7 +521,7 @@ void ImDrawList::_OnChangedClipRect()
|
||||||
|
|
||||||
// Try to merge with previous command if it matches, else use current command
|
// Try to merge with previous command if it matches, else use current command
|
||||||
ImDrawCmd* prev_cmd = curr_cmd - 1;
|
ImDrawCmd* prev_cmd = curr_cmd - 1;
|
||||||
if (curr_cmd->ElemCount == 0 && CmdBuffer.Size > 1 && ImDrawCmd_HeaderCompare(&_CmdHeader, prev_cmd) == 0 && prev_cmd->UserCallback == NULL)
|
if (curr_cmd->ElemCount == 0 && CmdBuffer.Size > 1 && ImDrawCmd_HeaderCompare(&_CmdHeader, prev_cmd) == 0 && ImDrawCmd_AreSequentialIdxOffset(prev_cmd, curr_cmd) && prev_cmd->UserCallback == NULL)
|
||||||
{
|
{
|
||||||
CmdBuffer.pop_back();
|
CmdBuffer.pop_back();
|
||||||
return;
|
return;
|
||||||
|
@ -518,6 +533,7 @@ void ImDrawList::_OnChangedClipRect()
|
||||||
void ImDrawList::_OnChangedTextureID()
|
void ImDrawList::_OnChangedTextureID()
|
||||||
{
|
{
|
||||||
// If current command is used with different settings we need to add a new command
|
// If current command is used with different settings we need to add a new command
|
||||||
|
IM_ASSERT_PARANOID(CmdBuffer.Size > 0);
|
||||||
ImDrawCmd* curr_cmd = &CmdBuffer.Data[CmdBuffer.Size - 1];
|
ImDrawCmd* curr_cmd = &CmdBuffer.Data[CmdBuffer.Size - 1];
|
||||||
if (curr_cmd->ElemCount != 0 && curr_cmd->TextureId != _CmdHeader.TextureId)
|
if (curr_cmd->ElemCount != 0 && curr_cmd->TextureId != _CmdHeader.TextureId)
|
||||||
{
|
{
|
||||||
|
@ -528,7 +544,7 @@ void ImDrawList::_OnChangedTextureID()
|
||||||
|
|
||||||
// Try to merge with previous command if it matches, else use current command
|
// Try to merge with previous command if it matches, else use current command
|
||||||
ImDrawCmd* prev_cmd = curr_cmd - 1;
|
ImDrawCmd* prev_cmd = curr_cmd - 1;
|
||||||
if (curr_cmd->ElemCount == 0 && CmdBuffer.Size > 1 && ImDrawCmd_HeaderCompare(&_CmdHeader, prev_cmd) == 0 && prev_cmd->UserCallback == NULL)
|
if (curr_cmd->ElemCount == 0 && CmdBuffer.Size > 1 && ImDrawCmd_HeaderCompare(&_CmdHeader, prev_cmd) == 0 && ImDrawCmd_AreSequentialIdxOffset(prev_cmd, curr_cmd) && prev_cmd->UserCallback == NULL)
|
||||||
{
|
{
|
||||||
CmdBuffer.pop_back();
|
CmdBuffer.pop_back();
|
||||||
return;
|
return;
|
||||||
|
@ -541,6 +557,7 @@ void ImDrawList::_OnChangedVtxOffset()
|
||||||
{
|
{
|
||||||
// We don't need to compare curr_cmd->VtxOffset != _CmdHeader.VtxOffset because we know it'll be different at the time we call this.
|
// We don't need to compare curr_cmd->VtxOffset != _CmdHeader.VtxOffset because we know it'll be different at the time we call this.
|
||||||
_VtxCurrentIdx = 0;
|
_VtxCurrentIdx = 0;
|
||||||
|
IM_ASSERT_PARANOID(CmdBuffer.Size > 0);
|
||||||
ImDrawCmd* curr_cmd = &CmdBuffer.Data[CmdBuffer.Size - 1];
|
ImDrawCmd* curr_cmd = &CmdBuffer.Data[CmdBuffer.Size - 1];
|
||||||
//IM_ASSERT(curr_cmd->VtxOffset != _CmdHeader.VtxOffset); // See #3349
|
//IM_ASSERT(curr_cmd->VtxOffset != _CmdHeader.VtxOffset); // See #3349
|
||||||
if (curr_cmd->ElemCount != 0)
|
if (curr_cmd->ElemCount != 0)
|
||||||
|
@ -563,7 +580,7 @@ int ImDrawList::_CalcCircleAutoSegmentCount(float radius) const
|
||||||
}
|
}
|
||||||
|
|
||||||
// Render-level scissoring. This is passed down to your render function but not used for CPU-side coarse clipping. Prefer using higher-level ImGui::PushClipRect() to affect logic (hit-testing and widget culling)
|
// Render-level scissoring. This is passed down to your render function but not used for CPU-side coarse clipping. Prefer using higher-level ImGui::PushClipRect() to affect logic (hit-testing and widget culling)
|
||||||
void ImDrawList::PushClipRect(ImVec2 cr_min, ImVec2 cr_max, bool intersect_with_current_clip_rect)
|
void ImDrawList::PushClipRect(const ImVec2& cr_min, const ImVec2& cr_max, bool intersect_with_current_clip_rect)
|
||||||
{
|
{
|
||||||
ImVec4 cr(cr_min.x, cr_min.y, cr_max.x, cr_max.y);
|
ImVec4 cr(cr_min.x, cr_min.y, cr_max.x, cr_max.y);
|
||||||
if (intersect_with_current_clip_rect)
|
if (intersect_with_current_clip_rect)
|
||||||
|
@ -693,10 +710,11 @@ void ImDrawList::PrimQuadUV(const ImVec2& a, const ImVec2& b, const ImVec2& c, c
|
||||||
}
|
}
|
||||||
|
|
||||||
// On AddPolyline() and AddConvexPolyFilled() we intentionally avoid using ImVec2 and superfluous function calls to optimize debug/non-inlined builds.
|
// On AddPolyline() and AddConvexPolyFilled() we intentionally avoid using ImVec2 and superfluous function calls to optimize debug/non-inlined builds.
|
||||||
// Those macros expects l-values.
|
// - Those macros expects l-values and need to be used as their own statement.
|
||||||
#define IM_NORMALIZE2F_OVER_ZERO(VX,VY) do { float d2 = VX*VX + VY*VY; if (d2 > 0.0f) { float inv_len = ImRsqrt(d2); VX *= inv_len; VY *= inv_len; } } while (0)
|
// - Those macros are intentionally not surrounded by the 'do {} while (0)' idiom because even that translates to runtime with debug compilers.
|
||||||
|
#define IM_NORMALIZE2F_OVER_ZERO(VX,VY) { float d2 = VX*VX + VY*VY; if (d2 > 0.0f) { float inv_len = ImRsqrt(d2); VX *= inv_len; VY *= inv_len; } } (void)0
|
||||||
#define IM_FIXNORMAL2F_MAX_INVLEN2 100.0f // 500.0f (see #4053, #3366)
|
#define IM_FIXNORMAL2F_MAX_INVLEN2 100.0f // 500.0f (see #4053, #3366)
|
||||||
#define IM_FIXNORMAL2F(VX,VY) do { float d2 = VX*VX + VY*VY; if (d2 > 0.000001f) { float inv_len2 = 1.0f / d2; if (inv_len2 > IM_FIXNORMAL2F_MAX_INVLEN2) inv_len2 = IM_FIXNORMAL2F_MAX_INVLEN2; VX *= inv_len2; VY *= inv_len2; } } while (0)
|
#define IM_FIXNORMAL2F(VX,VY) { float d2 = VX*VX + VY*VY; if (d2 > 0.000001f) { float inv_len2 = 1.0f / d2; if (inv_len2 > IM_FIXNORMAL2F_MAX_INVLEN2) inv_len2 = IM_FIXNORMAL2F_MAX_INVLEN2; VX *= inv_len2; VY *= inv_len2; } } (void)0
|
||||||
|
|
||||||
// TODO: Thickness anti-aliased lines cap are missing their AA fringe.
|
// TODO: Thickness anti-aliased lines cap are missing their AA fringe.
|
||||||
// We avoid using the ImVec2 math operators here to reduce cost to a minimum for debug/non-inlined builds.
|
// We avoid using the ImVec2 math operators here to reduce cost to a minimum for debug/non-inlined builds.
|
||||||
|
@ -955,7 +973,8 @@ void ImDrawList::AddPolyline(const ImVec2* points, const int points_count, ImU32
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// We intentionally avoid using ImVec2 and its math operators here to reduce cost to a minimum for debug/non-inlined builds.
|
// - We intentionally avoid using ImVec2 and its math operators here to reduce cost to a minimum for debug/non-inlined builds.
|
||||||
|
// - Filled shapes must always use clockwise winding order. The anti-aliasing fringe depends on it. Counter-clockwise shapes will have "inward" anti-aliasing.
|
||||||
void ImDrawList::AddConvexPolyFilled(const ImVec2* points, const int points_count, ImU32 col)
|
void ImDrawList::AddConvexPolyFilled(const ImVec2* points, const int points_count, ImU32 col)
|
||||||
{
|
{
|
||||||
if (points_count < 3)
|
if (points_count < 3)
|
||||||
|
@ -1039,7 +1058,7 @@ void ImDrawList::AddConvexPolyFilled(const ImVec2* points, const int points_coun
|
||||||
|
|
||||||
void ImDrawList::_PathArcToFastEx(const ImVec2& center, float radius, int a_min_sample, int a_max_sample, int a_step)
|
void ImDrawList::_PathArcToFastEx(const ImVec2& center, float radius, int a_min_sample, int a_max_sample, int a_step)
|
||||||
{
|
{
|
||||||
if (radius <= 0.0f)
|
if (radius < 0.5f)
|
||||||
{
|
{
|
||||||
_Path.push_back(center);
|
_Path.push_back(center);
|
||||||
return;
|
return;
|
||||||
|
@ -1131,7 +1150,7 @@ void ImDrawList::_PathArcToFastEx(const ImVec2& center, float radius, int a_min_
|
||||||
|
|
||||||
void ImDrawList::_PathArcToN(const ImVec2& center, float radius, float a_min, float a_max, int num_segments)
|
void ImDrawList::_PathArcToN(const ImVec2& center, float radius, float a_min, float a_max, int num_segments)
|
||||||
{
|
{
|
||||||
if (radius <= 0.0f)
|
if (radius < 0.5f)
|
||||||
{
|
{
|
||||||
_Path.push_back(center);
|
_Path.push_back(center);
|
||||||
return;
|
return;
|
||||||
|
@ -1150,7 +1169,7 @@ void ImDrawList::_PathArcToN(const ImVec2& center, float radius, float a_min, fl
|
||||||
// 0: East, 3: South, 6: West, 9: North, 12: East
|
// 0: East, 3: South, 6: West, 9: North, 12: East
|
||||||
void ImDrawList::PathArcToFast(const ImVec2& center, float radius, int a_min_of_12, int a_max_of_12)
|
void ImDrawList::PathArcToFast(const ImVec2& center, float radius, int a_min_of_12, int a_max_of_12)
|
||||||
{
|
{
|
||||||
if (radius <= 0.0f)
|
if (radius < 0.5f)
|
||||||
{
|
{
|
||||||
_Path.push_back(center);
|
_Path.push_back(center);
|
||||||
return;
|
return;
|
||||||
|
@ -1160,7 +1179,7 @@ void ImDrawList::PathArcToFast(const ImVec2& center, float radius, int a_min_of_
|
||||||
|
|
||||||
void ImDrawList::PathArcTo(const ImVec2& center, float radius, float a_min, float a_max, int num_segments)
|
void ImDrawList::PathArcTo(const ImVec2& center, float radius, float a_min, float a_max, int num_segments)
|
||||||
{
|
{
|
||||||
if (radius <= 0.0f)
|
if (radius < 0.5f)
|
||||||
{
|
{
|
||||||
_Path.push_back(center);
|
_Path.push_back(center);
|
||||||
return;
|
return;
|
||||||
|
@ -1188,8 +1207,8 @@ void ImDrawList::PathArcTo(const ImVec2& center, float radius, float a_min, floa
|
||||||
|
|
||||||
const float a_min_segment_angle = a_min_sample * IM_PI * 2.0f / IM_DRAWLIST_ARCFAST_SAMPLE_MAX;
|
const float a_min_segment_angle = a_min_sample * IM_PI * 2.0f / IM_DRAWLIST_ARCFAST_SAMPLE_MAX;
|
||||||
const float a_max_segment_angle = a_max_sample * IM_PI * 2.0f / IM_DRAWLIST_ARCFAST_SAMPLE_MAX;
|
const float a_max_segment_angle = a_max_sample * IM_PI * 2.0f / IM_DRAWLIST_ARCFAST_SAMPLE_MAX;
|
||||||
const bool a_emit_start = (a_min_segment_angle - a_min) != 0.0f;
|
const bool a_emit_start = ImAbs(a_min_segment_angle - a_min) >= 1e-5f;
|
||||||
const bool a_emit_end = (a_max - a_max_segment_angle) != 0.0f;
|
const bool a_emit_end = ImAbs(a_max - a_max_segment_angle) >= 1e-5f;
|
||||||
|
|
||||||
_Path.reserve(_Path.Size + (a_mid_samples + 1 + (a_emit_start ? 1 : 0) + (a_emit_end ? 1 : 0)));
|
_Path.reserve(_Path.Size + (a_mid_samples + 1 + (a_emit_start ? 1 : 0) + (a_emit_end ? 1 : 0)));
|
||||||
if (a_emit_start)
|
if (a_emit_start)
|
||||||
|
@ -1341,7 +1360,7 @@ void ImDrawList::PathRect(const ImVec2& a, const ImVec2& b, float rounding, ImDr
|
||||||
rounding = ImMin(rounding, ImFabs(b.x - a.x) * ( ((flags & ImDrawFlags_RoundCornersTop) == ImDrawFlags_RoundCornersTop) || ((flags & ImDrawFlags_RoundCornersBottom) == ImDrawFlags_RoundCornersBottom) ? 0.5f : 1.0f ) - 1.0f);
|
rounding = ImMin(rounding, ImFabs(b.x - a.x) * ( ((flags & ImDrawFlags_RoundCornersTop) == ImDrawFlags_RoundCornersTop) || ((flags & ImDrawFlags_RoundCornersBottom) == ImDrawFlags_RoundCornersBottom) ? 0.5f : 1.0f ) - 1.0f);
|
||||||
rounding = ImMin(rounding, ImFabs(b.y - a.y) * ( ((flags & ImDrawFlags_RoundCornersLeft) == ImDrawFlags_RoundCornersLeft) || ((flags & ImDrawFlags_RoundCornersRight) == ImDrawFlags_RoundCornersRight) ? 0.5f : 1.0f ) - 1.0f);
|
rounding = ImMin(rounding, ImFabs(b.y - a.y) * ( ((flags & ImDrawFlags_RoundCornersLeft) == ImDrawFlags_RoundCornersLeft) || ((flags & ImDrawFlags_RoundCornersRight) == ImDrawFlags_RoundCornersRight) ? 0.5f : 1.0f ) - 1.0f);
|
||||||
|
|
||||||
if (rounding <= 0.0f || (flags & ImDrawFlags_RoundCornersMask_) == ImDrawFlags_RoundCornersNone)
|
if (rounding < 0.5f || (flags & ImDrawFlags_RoundCornersMask_) == ImDrawFlags_RoundCornersNone)
|
||||||
{
|
{
|
||||||
PathLineTo(a);
|
PathLineTo(a);
|
||||||
PathLineTo(ImVec2(b.x, a.y));
|
PathLineTo(ImVec2(b.x, a.y));
|
||||||
|
@ -1387,7 +1406,7 @@ void ImDrawList::AddRectFilled(const ImVec2& p_min, const ImVec2& p_max, ImU32 c
|
||||||
{
|
{
|
||||||
if ((col & IM_COL32_A_MASK) == 0)
|
if ((col & IM_COL32_A_MASK) == 0)
|
||||||
return;
|
return;
|
||||||
if (rounding <= 0.0f || (flags & ImDrawFlags_RoundCornersMask_) == ImDrawFlags_RoundCornersNone)
|
if (rounding < 0.5f || (flags & ImDrawFlags_RoundCornersMask_) == ImDrawFlags_RoundCornersNone)
|
||||||
{
|
{
|
||||||
PrimReserve(6, 4);
|
PrimReserve(6, 4);
|
||||||
PrimRect(p_min, p_max, col);
|
PrimRect(p_min, p_max, col);
|
||||||
|
@ -1463,53 +1482,49 @@ void ImDrawList::AddTriangleFilled(const ImVec2& p1, const ImVec2& p2, const ImV
|
||||||
|
|
||||||
void ImDrawList::AddCircle(const ImVec2& center, float radius, ImU32 col, int num_segments, float thickness)
|
void ImDrawList::AddCircle(const ImVec2& center, float radius, ImU32 col, int num_segments, float thickness)
|
||||||
{
|
{
|
||||||
if ((col & IM_COL32_A_MASK) == 0 || radius <= 0.0f)
|
if ((col & IM_COL32_A_MASK) == 0 || radius < 0.5f)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Obtain segment count
|
|
||||||
if (num_segments <= 0)
|
if (num_segments <= 0)
|
||||||
{
|
{
|
||||||
// Automatic segment count
|
// Use arc with automatic segment count
|
||||||
num_segments = _CalcCircleAutoSegmentCount(radius);
|
_PathArcToFastEx(center, radius - 0.5f, 0, IM_DRAWLIST_ARCFAST_SAMPLE_MAX, 0);
|
||||||
|
_Path.Size--;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Explicit segment count (still clamp to avoid drawing insanely tessellated shapes)
|
// Explicit segment count (still clamp to avoid drawing insanely tessellated shapes)
|
||||||
num_segments = ImClamp(num_segments, 3, IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_MAX);
|
num_segments = ImClamp(num_segments, 3, IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_MAX);
|
||||||
}
|
|
||||||
|
|
||||||
// Because we are filling a closed shape we remove 1 from the count of segments/points
|
// Because we are filling a closed shape we remove 1 from the count of segments/points
|
||||||
const float a_max = (IM_PI * 2.0f) * ((float)num_segments - 1.0f) / (float)num_segments;
|
const float a_max = (IM_PI * 2.0f) * ((float)num_segments - 1.0f) / (float)num_segments;
|
||||||
if (num_segments == 12)
|
|
||||||
PathArcToFast(center, radius - 0.5f, 0, 12 - 1);
|
|
||||||
else
|
|
||||||
PathArcTo(center, radius - 0.5f, 0.0f, a_max, num_segments - 1);
|
PathArcTo(center, radius - 0.5f, 0.0f, a_max, num_segments - 1);
|
||||||
|
}
|
||||||
|
|
||||||
PathStroke(col, ImDrawFlags_Closed, thickness);
|
PathStroke(col, ImDrawFlags_Closed, thickness);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ImDrawList::AddCircleFilled(const ImVec2& center, float radius, ImU32 col, int num_segments)
|
void ImDrawList::AddCircleFilled(const ImVec2& center, float radius, ImU32 col, int num_segments)
|
||||||
{
|
{
|
||||||
if ((col & IM_COL32_A_MASK) == 0 || radius <= 0.0f)
|
if ((col & IM_COL32_A_MASK) == 0 || radius < 0.5f)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Obtain segment count
|
|
||||||
if (num_segments <= 0)
|
if (num_segments <= 0)
|
||||||
{
|
{
|
||||||
// Automatic segment count
|
// Use arc with automatic segment count
|
||||||
num_segments = _CalcCircleAutoSegmentCount(radius);
|
_PathArcToFastEx(center, radius, 0, IM_DRAWLIST_ARCFAST_SAMPLE_MAX, 0);
|
||||||
|
_Path.Size--;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Explicit segment count (still clamp to avoid drawing insanely tessellated shapes)
|
// Explicit segment count (still clamp to avoid drawing insanely tessellated shapes)
|
||||||
num_segments = ImClamp(num_segments, 3, IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_MAX);
|
num_segments = ImClamp(num_segments, 3, IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_MAX);
|
||||||
}
|
|
||||||
|
|
||||||
// Because we are filling a closed shape we remove 1 from the count of segments/points
|
// Because we are filling a closed shape we remove 1 from the count of segments/points
|
||||||
const float a_max = (IM_PI * 2.0f) * ((float)num_segments - 1.0f) / (float)num_segments;
|
const float a_max = (IM_PI * 2.0f) * ((float)num_segments - 1.0f) / (float)num_segments;
|
||||||
if (num_segments == 12)
|
|
||||||
PathArcToFast(center, radius, 0, 12 - 1);
|
|
||||||
else
|
|
||||||
PathArcTo(center, radius, 0.0f, a_max, num_segments - 1);
|
PathArcTo(center, radius, 0.0f, a_max, num_segments - 1);
|
||||||
|
}
|
||||||
|
|
||||||
PathFillConvex(col);
|
PathFillConvex(col);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1631,7 +1646,7 @@ void ImDrawList::AddImageRounded(ImTextureID user_texture_id, const ImVec2& p_mi
|
||||||
return;
|
return;
|
||||||
|
|
||||||
flags = FixRectCornerFlags(flags);
|
flags = FixRectCornerFlags(flags);
|
||||||
if (rounding <= 0.0f || (flags & ImDrawFlags_RoundCornersMask_) == ImDrawFlags_RoundCornersNone)
|
if (rounding < 0.5f || (flags & ImDrawFlags_RoundCornersMask_) == ImDrawFlags_RoundCornersNone)
|
||||||
{
|
{
|
||||||
AddImage(user_texture_id, p_min, p_max, uv_min, uv_max, col);
|
AddImage(user_texture_id, p_min, p_max, uv_min, uv_max, col);
|
||||||
return;
|
return;
|
||||||
|
@ -1719,13 +1734,13 @@ void ImDrawListSplitter::Merge(ImDrawList* draw_list)
|
||||||
for (int i = 1; i < _Count; i++)
|
for (int i = 1; i < _Count; i++)
|
||||||
{
|
{
|
||||||
ImDrawChannel& ch = _Channels[i];
|
ImDrawChannel& ch = _Channels[i];
|
||||||
|
if (ch._CmdBuffer.Size > 0 && ch._CmdBuffer.back().ElemCount == 0 && ch._CmdBuffer.back().UserCallback == NULL) // Equivalent of PopUnusedDrawCmd()
|
||||||
// Equivalent of PopUnusedDrawCmd() for this channel's cmdbuffer and except we don't need to test for UserCallback.
|
|
||||||
if (ch._CmdBuffer.Size > 0 && ch._CmdBuffer.back().ElemCount == 0)
|
|
||||||
ch._CmdBuffer.pop_back();
|
ch._CmdBuffer.pop_back();
|
||||||
|
|
||||||
if (ch._CmdBuffer.Size > 0 && last_cmd != NULL)
|
if (ch._CmdBuffer.Size > 0 && last_cmd != NULL)
|
||||||
{
|
{
|
||||||
|
// Do not include ImDrawCmd_AreSequentialIdxOffset() in the compare as we rebuild IdxOffset values ourselves.
|
||||||
|
// Manipulating IdxOffset (e.g. by reordering draw commands like done by RenderDimmedBackgroundBehindWindow()) is not supported within a splitter.
|
||||||
ImDrawCmd* next_cmd = &ch._CmdBuffer[0];
|
ImDrawCmd* next_cmd = &ch._CmdBuffer[0];
|
||||||
if (ImDrawCmd_HeaderCompare(last_cmd, next_cmd) == 0 && last_cmd->UserCallback == NULL && next_cmd->UserCallback == NULL)
|
if (ImDrawCmd_HeaderCompare(last_cmd, next_cmd) == 0 && last_cmd->UserCallback == NULL && next_cmd->UserCallback == NULL)
|
||||||
{
|
{
|
||||||
|
@ -1910,33 +1925,34 @@ ImFontConfig::ImFontConfig()
|
||||||
|
|
||||||
// A work of art lies ahead! (. = white layer, X = black layer, others are blank)
|
// A work of art lies ahead! (. = white layer, X = black layer, others are blank)
|
||||||
// The 2x2 white texels on the top left are the ones we'll use everywhere in Dear ImGui to render filled shapes.
|
// The 2x2 white texels on the top left are the ones we'll use everywhere in Dear ImGui to render filled shapes.
|
||||||
const int FONT_ATLAS_DEFAULT_TEX_DATA_W = 108; // Actual texture will be 2 times that + 1 spacing.
|
// (This is used when io.MouseDrawCursor = true)
|
||||||
|
const int FONT_ATLAS_DEFAULT_TEX_DATA_W = 122; // Actual texture will be 2 times that + 1 spacing.
|
||||||
const int FONT_ATLAS_DEFAULT_TEX_DATA_H = 27;
|
const int FONT_ATLAS_DEFAULT_TEX_DATA_H = 27;
|
||||||
static const char FONT_ATLAS_DEFAULT_TEX_DATA_PIXELS[FONT_ATLAS_DEFAULT_TEX_DATA_W * FONT_ATLAS_DEFAULT_TEX_DATA_H + 1] =
|
static const char FONT_ATLAS_DEFAULT_TEX_DATA_PIXELS[FONT_ATLAS_DEFAULT_TEX_DATA_W * FONT_ATLAS_DEFAULT_TEX_DATA_H + 1] =
|
||||||
{
|
{
|
||||||
"..- -XXXXXXX- X - X -XXXXXXX - XXXXXXX- XX "
|
"..- -XXXXXXX- X - X -XXXXXXX - XXXXXXX- XX - XX XX "
|
||||||
"..- -X.....X- X.X - X.X -X.....X - X.....X- X..X "
|
"..- -X.....X- X.X - X.X -X.....X - X.....X- X..X -X..X X..X"
|
||||||
"--- -XXX.XXX- X...X - X...X -X....X - X....X- X..X "
|
"--- -XXX.XXX- X...X - X...X -X....X - X....X- X..X -X...X X...X"
|
||||||
"X - X.X - X.....X - X.....X -X...X - X...X- X..X "
|
"X - X.X - X.....X - X.....X -X...X - X...X- X..X - X...X X...X "
|
||||||
"XX - X.X -X.......X- X.......X -X..X.X - X.X..X- X..X "
|
"XX - X.X -X.......X- X.......X -X..X.X - X.X..X- X..X - X...X...X "
|
||||||
"X.X - X.X -XXXX.XXXX- XXXX.XXXX -X.X X.X - X.X X.X- X..XXX "
|
"X.X - X.X -XXXX.XXXX- XXXX.XXXX -X.X X.X - X.X X.X- X..XXX - X.....X "
|
||||||
"X..X - X.X - X.X - X.X -XX X.X - X.X XX- X..X..XXX "
|
"X..X - X.X - X.X - X.X -XX X.X - X.X XX- X..X..XXX - X...X "
|
||||||
"X...X - X.X - X.X - XX X.X XX - X.X - X.X - X..X..X..XX "
|
"X...X - X.X - X.X - XX X.X XX - X.X - X.X - X..X..X..XX - X.X "
|
||||||
"X....X - X.X - X.X - X.X X.X X.X - X.X - X.X - X..X..X..X.X "
|
"X....X - X.X - X.X - X.X X.X X.X - X.X - X.X - X..X..X..X.X - X...X "
|
||||||
"X.....X - X.X - X.X - X..X X.X X..X - X.X - X.X -XXX X..X..X..X..X"
|
"X.....X - X.X - X.X - X..X X.X X..X - X.X - X.X -XXX X..X..X..X..X- X.....X "
|
||||||
"X......X - X.X - X.X - X...XXXXXX.XXXXXX...X - X.X XX-XX X.X -X..XX........X..X"
|
"X......X - X.X - X.X - X...XXXXXX.XXXXXX...X - X.X XX-XX X.X -X..XX........X..X- X...X...X "
|
||||||
"X.......X - X.X - X.X -X.....................X- X.X X.X-X.X X.X -X...X...........X"
|
"X.......X - X.X - X.X -X.....................X- X.X X.X-X.X X.X -X...X...........X- X...X X...X "
|
||||||
"X........X - X.X - X.X - X...XXXXXX.XXXXXX...X - X.X..X-X..X.X - X..............X"
|
"X........X - X.X - X.X - X...XXXXXX.XXXXXX...X - X.X..X-X..X.X - X..............X-X...X X...X"
|
||||||
"X.........X -XXX.XXX- X.X - X..X X.X X..X - X...X-X...X - X.............X"
|
"X.........X -XXX.XXX- X.X - X..X X.X X..X - X...X-X...X - X.............X-X..X X..X"
|
||||||
"X..........X-X.....X- X.X - X.X X.X X.X - X....X-X....X - X.............X"
|
"X..........X-X.....X- X.X - X.X X.X X.X - X....X-X....X - X.............X- XX XX "
|
||||||
"X......XXXXX-XXXXXXX- X.X - XX X.X XX - X.....X-X.....X - X............X"
|
"X......XXXXX-XXXXXXX- X.X - XX X.X XX - X.....X-X.....X - X............X--------------"
|
||||||
"X...X..X --------- X.X - X.X - XXXXXXX-XXXXXXX - X...........X "
|
"X...X..X --------- X.X - X.X - XXXXXXX-XXXXXXX - X...........X - "
|
||||||
"X..X X..X - -XXXX.XXXX- XXXX.XXXX ------------------------------------- X..........X "
|
"X..X X..X - -XXXX.XXXX- XXXX.XXXX ------------------------------------- X..........X - "
|
||||||
"X.X X..X - -X.......X- X.......X - XX XX - - X..........X "
|
"X.X X..X - -X.......X- X.......X - XX XX - - X..........X - "
|
||||||
"XX X..X - - X.....X - X.....X - X.X X.X - - X........X "
|
"XX X..X - - X.....X - X.....X - X.X X.X - - X........X - "
|
||||||
" X..X - X...X - X...X - X..X X..X - - X........X "
|
" X..X - - X...X - X...X - X..X X..X - - X........X - "
|
||||||
" XX - X.X - X.X - X...XXXXXXXXXXXXX...X - - XXXXXXXXXX "
|
" XX - - X.X - X.X - X...XXXXXXXXXXXXX...X - - XXXXXXXXXX - "
|
||||||
"------------ - X - X -X.....................X- ------------------"
|
"------------- - X - X -X.....................X- ------------------- "
|
||||||
" ----------------------------------- X...XXXXXXXXXXXXX...X - "
|
" ----------------------------------- X...XXXXXXXXXXXXX...X - "
|
||||||
" - X..X X..X - "
|
" - X..X X..X - "
|
||||||
" - X.X X.X - "
|
" - X.X X.X - "
|
||||||
|
@ -1954,6 +1970,7 @@ static const ImVec2 FONT_ATLAS_DEFAULT_TEX_CURSOR_DATA[ImGuiMouseCursor_COUNT][3
|
||||||
{ ImVec2(73,0), ImVec2(17,17), ImVec2( 8, 8) }, // ImGuiMouseCursor_ResizeNESW
|
{ ImVec2(73,0), ImVec2(17,17), ImVec2( 8, 8) }, // ImGuiMouseCursor_ResizeNESW
|
||||||
{ ImVec2(55,0), ImVec2(17,17), ImVec2( 8, 8) }, // ImGuiMouseCursor_ResizeNWSE
|
{ ImVec2(55,0), ImVec2(17,17), ImVec2( 8, 8) }, // ImGuiMouseCursor_ResizeNWSE
|
||||||
{ ImVec2(91,0), ImVec2(17,22), ImVec2( 5, 0) }, // ImGuiMouseCursor_Hand
|
{ ImVec2(91,0), ImVec2(17,22), ImVec2( 5, 0) }, // ImGuiMouseCursor_Hand
|
||||||
|
{ ImVec2(109,0),ImVec2(13,15), ImVec2( 6, 7) }, // ImGuiMouseCursor_NotAllowed
|
||||||
};
|
};
|
||||||
|
|
||||||
ImFontAtlas::ImFontAtlas()
|
ImFontAtlas::ImFontAtlas()
|
||||||
|
@ -1989,6 +2006,7 @@ void ImFontAtlas::ClearInputData()
|
||||||
ConfigData.clear();
|
ConfigData.clear();
|
||||||
CustomRects.clear();
|
CustomRects.clear();
|
||||||
PackIdMouseCursors = PackIdLines = -1;
|
PackIdMouseCursors = PackIdLines = -1;
|
||||||
|
// Important: we leave TexReady untouched
|
||||||
}
|
}
|
||||||
|
|
||||||
void ImFontAtlas::ClearTexData()
|
void ImFontAtlas::ClearTexData()
|
||||||
|
@ -2001,14 +2019,14 @@ void ImFontAtlas::ClearTexData()
|
||||||
TexPixelsAlpha8 = NULL;
|
TexPixelsAlpha8 = NULL;
|
||||||
TexPixelsRGBA32 = NULL;
|
TexPixelsRGBA32 = NULL;
|
||||||
TexPixelsUseColors = false;
|
TexPixelsUseColors = false;
|
||||||
|
// Important: we leave TexReady untouched
|
||||||
}
|
}
|
||||||
|
|
||||||
void ImFontAtlas::ClearFonts()
|
void ImFontAtlas::ClearFonts()
|
||||||
{
|
{
|
||||||
IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas between NewFrame() and EndFrame/Render()!");
|
IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas between NewFrame() and EndFrame/Render()!");
|
||||||
for (int i = 0; i < Fonts.Size; i++)
|
Fonts.clear_delete();
|
||||||
IM_DELETE(Fonts[i]);
|
TexReady = false;
|
||||||
Fonts.clear();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ImFontAtlas::Clear()
|
void ImFontAtlas::Clear()
|
||||||
|
@ -2022,11 +2040,7 @@ void ImFontAtlas::GetTexDataAsAlpha8(unsigned char** out_pixels, int* out_wid
|
||||||
{
|
{
|
||||||
// Build atlas on demand
|
// Build atlas on demand
|
||||||
if (TexPixelsAlpha8 == NULL)
|
if (TexPixelsAlpha8 == NULL)
|
||||||
{
|
|
||||||
if (ConfigData.empty())
|
|
||||||
AddFontDefault();
|
|
||||||
Build();
|
Build();
|
||||||
}
|
|
||||||
|
|
||||||
*out_pixels = TexPixelsAlpha8;
|
*out_pixels = TexPixelsAlpha8;
|
||||||
if (out_width) *out_width = TexWidth;
|
if (out_width) *out_width = TexWidth;
|
||||||
|
@ -2085,6 +2099,7 @@ ImFont* ImFontAtlas::AddFont(const ImFontConfig* font_cfg)
|
||||||
new_font_cfg.DstFont->EllipsisChar = font_cfg->EllipsisChar;
|
new_font_cfg.DstFont->EllipsisChar = font_cfg->EllipsisChar;
|
||||||
|
|
||||||
// Invalidate texture
|
// Invalidate texture
|
||||||
|
TexReady = false;
|
||||||
ClearTexData();
|
ClearTexData();
|
||||||
return new_font_cfg.DstFont;
|
return new_font_cfg.DstFont;
|
||||||
}
|
}
|
||||||
|
@ -2156,7 +2171,7 @@ ImFont* ImFontAtlas::AddFontFromMemoryTTF(void* ttf_data, int ttf_size, float si
|
||||||
IM_ASSERT(font_cfg.FontData == NULL);
|
IM_ASSERT(font_cfg.FontData == NULL);
|
||||||
font_cfg.FontData = ttf_data;
|
font_cfg.FontData = ttf_data;
|
||||||
font_cfg.FontDataSize = ttf_size;
|
font_cfg.FontDataSize = ttf_size;
|
||||||
font_cfg.SizePixels = size_pixels;
|
font_cfg.SizePixels = size_pixels > 0.0f ? size_pixels : font_cfg.SizePixels;
|
||||||
if (glyph_ranges)
|
if (glyph_ranges)
|
||||||
font_cfg.GlyphRanges = glyph_ranges;
|
font_cfg.GlyphRanges = glyph_ranges;
|
||||||
return AddFont(&font_cfg);
|
return AddFont(&font_cfg);
|
||||||
|
@ -2247,6 +2262,10 @@ bool ImFontAtlas::Build()
|
||||||
{
|
{
|
||||||
IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas between NewFrame() and EndFrame/Render()!");
|
IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas between NewFrame() and EndFrame/Render()!");
|
||||||
|
|
||||||
|
// Default font is none are specified
|
||||||
|
if (ConfigData.Size == 0)
|
||||||
|
AddFontDefault();
|
||||||
|
|
||||||
// Select builder
|
// Select builder
|
||||||
// - Note that we do not reassign to atlas->FontBuilderIO, since it is likely to point to static data which
|
// - Note that we do not reassign to atlas->FontBuilderIO, since it is likely to point to static data which
|
||||||
// may mess with some hot-reloading schemes. If you need to assign to this (for dynamic selection) AND are
|
// may mess with some hot-reloading schemes. If you need to assign to this (for dynamic selection) AND are
|
||||||
|
@ -2568,9 +2587,8 @@ static bool ImFontAtlasBuildWithStbTruetype(ImFontAtlas* atlas)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cleanup temporary (ImVector doesn't honor destructor)
|
// Cleanup
|
||||||
for (int src_i = 0; src_i < src_tmp_array.Size; src_i++)
|
src_tmp_array.clear_destruct();
|
||||||
src_tmp_array[src_i].~ImFontBuildSrcData();
|
|
||||||
|
|
||||||
ImFontAtlasBuildFinish(atlas);
|
ImFontAtlasBuildFinish(atlas);
|
||||||
return true;
|
return true;
|
||||||
|
@ -2620,8 +2638,8 @@ void ImFontAtlasBuildPackCustomRects(ImFontAtlas* atlas, void* stbrp_context_opa
|
||||||
for (int i = 0; i < pack_rects.Size; i++)
|
for (int i = 0; i < pack_rects.Size; i++)
|
||||||
if (pack_rects[i].was_packed)
|
if (pack_rects[i].was_packed)
|
||||||
{
|
{
|
||||||
user_rects[i].X = pack_rects[i].x;
|
user_rects[i].X = (unsigned short)pack_rects[i].x;
|
||||||
user_rects[i].Y = pack_rects[i].y;
|
user_rects[i].Y = (unsigned short)pack_rects[i].y;
|
||||||
IM_ASSERT(pack_rects[i].w == user_rects[i].Width && pack_rects[i].h == user_rects[i].Height);
|
IM_ASSERT(pack_rects[i].w == user_rects[i].Width && pack_rects[i].h == user_rects[i].Height);
|
||||||
atlas->TexHeight = ImMax(atlas->TexHeight, pack_rects[i].y + pack_rects[i].h);
|
atlas->TexHeight = ImMax(atlas->TexHeight, pack_rects[i].y + pack_rects[i].h);
|
||||||
}
|
}
|
||||||
|
@ -2721,13 +2739,13 @@ static void ImFontAtlasBuildRenderLinesTexData(ImFontAtlas* atlas)
|
||||||
{
|
{
|
||||||
unsigned int* write_ptr = &atlas->TexPixelsRGBA32[r->X + ((r->Y + y) * atlas->TexWidth)];
|
unsigned int* write_ptr = &atlas->TexPixelsRGBA32[r->X + ((r->Y + y) * atlas->TexWidth)];
|
||||||
for (unsigned int i = 0; i < pad_left; i++)
|
for (unsigned int i = 0; i < pad_left; i++)
|
||||||
*(write_ptr + i) = IM_COL32_BLACK_TRANS;
|
*(write_ptr + i) = IM_COL32(255, 255, 255, 0);
|
||||||
|
|
||||||
for (unsigned int i = 0; i < line_width; i++)
|
for (unsigned int i = 0; i < line_width; i++)
|
||||||
*(write_ptr + pad_left + i) = IM_COL32_WHITE;
|
*(write_ptr + pad_left + i) = IM_COL32_WHITE;
|
||||||
|
|
||||||
for (unsigned int i = 0; i < pad_right; i++)
|
for (unsigned int i = 0; i < pad_right; i++)
|
||||||
*(write_ptr + pad_left + line_width + i) = IM_COL32_BLACK_TRANS;
|
*(write_ptr + pad_left + line_width + i) = IM_COL32(255, 255, 255, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Calculate UVs for this line
|
// Calculate UVs for this line
|
||||||
|
@ -2786,22 +2804,7 @@ void ImFontAtlasBuildFinish(ImFontAtlas* atlas)
|
||||||
if (atlas->Fonts[i]->DirtyLookupTables)
|
if (atlas->Fonts[i]->DirtyLookupTables)
|
||||||
atlas->Fonts[i]->BuildLookupTable();
|
atlas->Fonts[i]->BuildLookupTable();
|
||||||
|
|
||||||
// Ellipsis character is required for rendering elided text. We prefer using U+2026 (horizontal ellipsis).
|
atlas->TexReady = true;
|
||||||
// However some old fonts may contain ellipsis at U+0085. Here we auto-detect most suitable ellipsis character.
|
|
||||||
// FIXME: Also note that 0x2026 is currently seldom included in our font ranges. Because of this we are more likely to use three individual dots.
|
|
||||||
for (int i = 0; i < atlas->Fonts.size(); i++)
|
|
||||||
{
|
|
||||||
ImFont* font = atlas->Fonts[i];
|
|
||||||
if (font->EllipsisChar != (ImWchar)-1)
|
|
||||||
continue;
|
|
||||||
const ImWchar ellipsis_variants[] = { (ImWchar)0x2026, (ImWchar)0x0085 };
|
|
||||||
for (int j = 0; j < IM_ARRAYSIZE(ellipsis_variants); j++)
|
|
||||||
if (font->FindGlyphNoFallback(ellipsis_variants[j]) != NULL) // Verify glyph exists
|
|
||||||
{
|
|
||||||
font->EllipsisChar = ellipsis_variants[j];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Retrieve list of range (2 int per range, values are inclusive)
|
// Retrieve list of range (2 int per range, values are inclusive)
|
||||||
|
@ -2822,6 +2825,7 @@ const ImWchar* ImFontAtlas::GetGlyphRangesKorean()
|
||||||
0x0020, 0x00FF, // Basic Latin + Latin Supplement
|
0x0020, 0x00FF, // Basic Latin + Latin Supplement
|
||||||
0x3131, 0x3163, // Korean alphabets
|
0x3131, 0x3163, // Korean alphabets
|
||||||
0xAC00, 0xD7A3, // Korean characters
|
0xAC00, 0xD7A3, // Korean characters
|
||||||
|
0xFFFD, 0xFFFD, // Invalid
|
||||||
0,
|
0,
|
||||||
};
|
};
|
||||||
return &ranges[0];
|
return &ranges[0];
|
||||||
|
@ -2836,6 +2840,7 @@ const ImWchar* ImFontAtlas::GetGlyphRangesChineseFull()
|
||||||
0x3000, 0x30FF, // CJK Symbols and Punctuations, Hiragana, Katakana
|
0x3000, 0x30FF, // CJK Symbols and Punctuations, Hiragana, Katakana
|
||||||
0x31F0, 0x31FF, // Katakana Phonetic Extensions
|
0x31F0, 0x31FF, // Katakana Phonetic Extensions
|
||||||
0xFF00, 0xFFEF, // Half-width characters
|
0xFF00, 0xFFEF, // Half-width characters
|
||||||
|
0xFFFD, 0xFFFD, // Invalid
|
||||||
0x4e00, 0x9FAF, // CJK Ideograms
|
0x4e00, 0x9FAF, // CJK Ideograms
|
||||||
0,
|
0,
|
||||||
};
|
};
|
||||||
|
@ -2912,7 +2917,8 @@ const ImWchar* ImFontAtlas::GetGlyphRangesChineseSimplifiedCommon()
|
||||||
0x2000, 0x206F, // General Punctuation
|
0x2000, 0x206F, // General Punctuation
|
||||||
0x3000, 0x30FF, // CJK Symbols and Punctuations, Hiragana, Katakana
|
0x3000, 0x30FF, // CJK Symbols and Punctuations, Hiragana, Katakana
|
||||||
0x31F0, 0x31FF, // Katakana Phonetic Extensions
|
0x31F0, 0x31FF, // Katakana Phonetic Extensions
|
||||||
0xFF00, 0xFFEF // Half-width characters
|
0xFF00, 0xFFEF, // Half-width characters
|
||||||
|
0xFFFD, 0xFFFD // Invalid
|
||||||
};
|
};
|
||||||
static ImWchar full_ranges[IM_ARRAYSIZE(base_ranges) + IM_ARRAYSIZE(accumulative_offsets_from_0x4E00) * 2 + 1] = { 0 };
|
static ImWchar full_ranges[IM_ARRAYSIZE(base_ranges) + IM_ARRAYSIZE(accumulative_offsets_from_0x4E00) * 2 + 1] = { 0 };
|
||||||
if (!full_ranges[0])
|
if (!full_ranges[0])
|
||||||
|
@ -3001,7 +3007,8 @@ const ImWchar* ImFontAtlas::GetGlyphRangesJapanese()
|
||||||
0x0020, 0x00FF, // Basic Latin + Latin Supplement
|
0x0020, 0x00FF, // Basic Latin + Latin Supplement
|
||||||
0x3000, 0x30FF, // CJK Symbols and Punctuations, Hiragana, Katakana
|
0x3000, 0x30FF, // CJK Symbols and Punctuations, Hiragana, Katakana
|
||||||
0x31F0, 0x31FF, // Katakana Phonetic Extensions
|
0x31F0, 0x31FF, // Katakana Phonetic Extensions
|
||||||
0xFF00, 0xFFEF // Half-width characters
|
0xFF00, 0xFFEF, // Half-width characters
|
||||||
|
0xFFFD, 0xFFFD // Invalid
|
||||||
};
|
};
|
||||||
static ImWchar full_ranges[IM_ARRAYSIZE(base_ranges) + IM_ARRAYSIZE(accumulative_offsets_from_0x4E00)*2 + 1] = { 0 };
|
static ImWchar full_ranges[IM_ARRAYSIZE(base_ranges) + IM_ARRAYSIZE(accumulative_offsets_from_0x4E00)*2 + 1] = { 0 };
|
||||||
if (!full_ranges[0])
|
if (!full_ranges[0])
|
||||||
|
@ -3074,8 +3081,8 @@ void ImFontGlyphRangesBuilder::AddText(const char* text, const char* text_end)
|
||||||
void ImFontGlyphRangesBuilder::AddRanges(const ImWchar* ranges)
|
void ImFontGlyphRangesBuilder::AddRanges(const ImWchar* ranges)
|
||||||
{
|
{
|
||||||
for (; ranges[0]; ranges += 2)
|
for (; ranges[0]; ranges += 2)
|
||||||
for (ImWchar c = ranges[0]; c <= ranges[1]; c++)
|
for (unsigned int c = ranges[0]; c <= ranges[1] && c <= IM_UNICODE_CODEPOINT_MAX; c++) //-V560
|
||||||
AddChar(c);
|
AddChar((ImWchar)c);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ImFontGlyphRangesBuilder::BuildRanges(ImVector<ImWchar>* out_ranges)
|
void ImFontGlyphRangesBuilder::BuildRanges(ImVector<ImWchar>* out_ranges)
|
||||||
|
@ -3100,8 +3107,9 @@ ImFont::ImFont()
|
||||||
{
|
{
|
||||||
FontSize = 0.0f;
|
FontSize = 0.0f;
|
||||||
FallbackAdvanceX = 0.0f;
|
FallbackAdvanceX = 0.0f;
|
||||||
FallbackChar = (ImWchar)'?';
|
FallbackChar = (ImWchar)-1;
|
||||||
EllipsisChar = (ImWchar)-1;
|
EllipsisChar = (ImWchar)-1;
|
||||||
|
DotChar = (ImWchar)-1;
|
||||||
FallbackGlyph = NULL;
|
FallbackGlyph = NULL;
|
||||||
ContainerAtlas = NULL;
|
ContainerAtlas = NULL;
|
||||||
ConfigData = NULL;
|
ConfigData = NULL;
|
||||||
|
@ -3132,6 +3140,14 @@ void ImFont::ClearOutputData()
|
||||||
MetricsTotalSurface = 0;
|
MetricsTotalSurface = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static ImWchar FindFirstExistingGlyph(ImFont* font, const ImWchar* candidate_chars, int candidate_chars_count)
|
||||||
|
{
|
||||||
|
for (int n = 0; n < candidate_chars_count; n++)
|
||||||
|
if (font->FindGlyphNoFallback(candidate_chars[n]) != NULL)
|
||||||
|
return candidate_chars[n];
|
||||||
|
return (ImWchar)-1;
|
||||||
|
}
|
||||||
|
|
||||||
void ImFont::BuildLookupTable()
|
void ImFont::BuildLookupTable()
|
||||||
{
|
{
|
||||||
int max_codepoint = 0;
|
int max_codepoint = 0;
|
||||||
|
@ -3174,9 +3190,31 @@ void ImFont::BuildLookupTable()
|
||||||
SetGlyphVisible((ImWchar)' ', false);
|
SetGlyphVisible((ImWchar)' ', false);
|
||||||
SetGlyphVisible((ImWchar)'\t', false);
|
SetGlyphVisible((ImWchar)'\t', false);
|
||||||
|
|
||||||
// Setup fall-backs
|
// Ellipsis character is required for rendering elided text. We prefer using U+2026 (horizontal ellipsis).
|
||||||
|
// However some old fonts may contain ellipsis at U+0085. Here we auto-detect most suitable ellipsis character.
|
||||||
|
// FIXME: Note that 0x2026 is rarely included in our font ranges. Because of this we are more likely to use three individual dots.
|
||||||
|
const ImWchar ellipsis_chars[] = { (ImWchar)0x2026, (ImWchar)0x0085 };
|
||||||
|
const ImWchar dots_chars[] = { (ImWchar)'.', (ImWchar)0xFF0E };
|
||||||
|
if (EllipsisChar == (ImWchar)-1)
|
||||||
|
EllipsisChar = FindFirstExistingGlyph(this, ellipsis_chars, IM_ARRAYSIZE(ellipsis_chars));
|
||||||
|
if (DotChar == (ImWchar)-1)
|
||||||
|
DotChar = FindFirstExistingGlyph(this, dots_chars, IM_ARRAYSIZE(dots_chars));
|
||||||
|
|
||||||
|
// Setup fallback character
|
||||||
|
const ImWchar fallback_chars[] = { (ImWchar)IM_UNICODE_CODEPOINT_INVALID, (ImWchar)'?', (ImWchar)' ' };
|
||||||
FallbackGlyph = FindGlyphNoFallback(FallbackChar);
|
FallbackGlyph = FindGlyphNoFallback(FallbackChar);
|
||||||
FallbackAdvanceX = FallbackGlyph ? FallbackGlyph->AdvanceX : 0.0f;
|
if (FallbackGlyph == NULL)
|
||||||
|
{
|
||||||
|
FallbackChar = FindFirstExistingGlyph(this, fallback_chars, IM_ARRAYSIZE(fallback_chars));
|
||||||
|
FallbackGlyph = FindGlyphNoFallback(FallbackChar);
|
||||||
|
if (FallbackGlyph == NULL)
|
||||||
|
{
|
||||||
|
FallbackGlyph = &Glyphs.back();
|
||||||
|
FallbackChar = (ImWchar)FallbackGlyph->Codepoint;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
FallbackAdvanceX = FallbackGlyph->AdvanceX;
|
||||||
for (int i = 0; i < max_codepoint + 1; i++)
|
for (int i = 0; i < max_codepoint + 1; i++)
|
||||||
if (IndexAdvanceX[i] < 0.0f)
|
if (IndexAdvanceX[i] < 0.0f)
|
||||||
IndexAdvanceX[i] = FallbackAdvanceX;
|
IndexAdvanceX[i] = FallbackAdvanceX;
|
||||||
|
@ -3201,12 +3239,6 @@ void ImFont::SetGlyphVisible(ImWchar c, bool visible)
|
||||||
glyph->Visible = visible ? 1 : 0;
|
glyph->Visible = visible ? 1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ImFont::SetFallbackChar(ImWchar c)
|
|
||||||
{
|
|
||||||
FallbackChar = c;
|
|
||||||
BuildLookupTable();
|
|
||||||
}
|
|
||||||
|
|
||||||
void ImFont::GrowIndex(int new_size)
|
void ImFont::GrowIndex(int new_size)
|
||||||
{
|
{
|
||||||
IM_ASSERT(IndexAdvanceX.Size == IndexLookup.Size);
|
IM_ASSERT(IndexAdvanceX.Size == IndexLookup.Size);
|
||||||
|
@ -3492,7 +3524,7 @@ ImVec2 ImFont::CalcTextSizeA(float size, float max_width, float wrap_width, cons
|
||||||
}
|
}
|
||||||
|
|
||||||
// Note: as with every ImDrawList drawing function, this expects that the font atlas texture is bound.
|
// Note: as with every ImDrawList drawing function, this expects that the font atlas texture is bound.
|
||||||
void ImFont::RenderChar(ImDrawList* draw_list, float size, ImVec2 pos, ImU32 col, ImWchar c) const
|
void ImFont::RenderChar(ImDrawList* draw_list, float size, const ImVec2& pos, ImU32 col, ImWchar c) const
|
||||||
{
|
{
|
||||||
const ImFontGlyph* glyph = FindGlyph(c);
|
const ImFontGlyph* glyph = FindGlyph(c);
|
||||||
if (!glyph || !glyph->Visible)
|
if (!glyph || !glyph->Visible)
|
||||||
|
@ -3500,26 +3532,25 @@ void ImFont::RenderChar(ImDrawList* draw_list, float size, ImVec2 pos, ImU32 col
|
||||||
if (glyph->Colored)
|
if (glyph->Colored)
|
||||||
col |= ~IM_COL32_A_MASK;
|
col |= ~IM_COL32_A_MASK;
|
||||||
float scale = (size >= 0.0f) ? (size / FontSize) : 1.0f;
|
float scale = (size >= 0.0f) ? (size / FontSize) : 1.0f;
|
||||||
pos.x = IM_FLOOR(pos.x);
|
float x = IM_FLOOR(pos.x);
|
||||||
pos.y = IM_FLOOR(pos.y);
|
float y = IM_FLOOR(pos.y);
|
||||||
draw_list->PrimReserve(6, 4);
|
draw_list->PrimReserve(6, 4);
|
||||||
draw_list->PrimRectUV(ImVec2(pos.x + glyph->X0 * scale, pos.y + glyph->Y0 * scale), ImVec2(pos.x + glyph->X1 * scale, pos.y + glyph->Y1 * scale), ImVec2(glyph->U0, glyph->V0), ImVec2(glyph->U1, glyph->V1), col);
|
draw_list->PrimRectUV(ImVec2(x + glyph->X0 * scale, y + glyph->Y0 * scale), ImVec2(x + glyph->X1 * scale, y + glyph->Y1 * scale), ImVec2(glyph->U0, glyph->V0), ImVec2(glyph->U1, glyph->V1), col);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Note: as with every ImDrawList drawing function, this expects that the font atlas texture is bound.
|
// Note: as with every ImDrawList drawing function, this expects that the font atlas texture is bound.
|
||||||
void ImFont::RenderText(ImDrawList* draw_list, float size, ImVec2 pos, ImU32 col, const ImVec4& clip_rect, const char* text_begin, const char* text_end, float wrap_width, bool cpu_fine_clip) const
|
void ImFont::RenderText(ImDrawList* draw_list, float size, const ImVec2& pos, ImU32 col, const ImVec4& clip_rect, const char* text_begin, const char* text_end, float wrap_width, bool cpu_fine_clip) const
|
||||||
{
|
{
|
||||||
if (!text_end)
|
if (!text_end)
|
||||||
text_end = text_begin + strlen(text_begin); // ImGui:: functions generally already provides a valid text_end, so this is merely to handle direct calls.
|
text_end = text_begin + strlen(text_begin); // ImGui:: functions generally already provides a valid text_end, so this is merely to handle direct calls.
|
||||||
|
|
||||||
// Align to be pixel perfect
|
// Align to be pixel perfect
|
||||||
pos.x = IM_FLOOR(pos.x);
|
float x = IM_FLOOR(pos.x);
|
||||||
pos.y = IM_FLOOR(pos.y);
|
float y = IM_FLOOR(pos.y);
|
||||||
float x = pos.x;
|
|
||||||
float y = pos.y;
|
|
||||||
if (y > clip_rect.w)
|
if (y > clip_rect.w)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
const float start_x = x;
|
||||||
const float scale = size / FontSize;
|
const float scale = size / FontSize;
|
||||||
const float line_height = FontSize * scale;
|
const float line_height = FontSize * scale;
|
||||||
const bool word_wrap_enabled = (wrap_width > 0.0f);
|
const bool word_wrap_enabled = (wrap_width > 0.0f);
|
||||||
|
@ -3571,14 +3602,14 @@ void ImFont::RenderText(ImDrawList* draw_list, float size, ImVec2 pos, ImU32 col
|
||||||
// Calculate how far we can render. Requires two passes on the string data but keeps the code simple and not intrusive for what's essentially an uncommon feature.
|
// Calculate how far we can render. Requires two passes on the string data but keeps the code simple and not intrusive for what's essentially an uncommon feature.
|
||||||
if (!word_wrap_eol)
|
if (!word_wrap_eol)
|
||||||
{
|
{
|
||||||
word_wrap_eol = CalcWordWrapPositionA(scale, s, text_end, wrap_width - (x - pos.x));
|
word_wrap_eol = CalcWordWrapPositionA(scale, s, text_end, wrap_width - (x - start_x));
|
||||||
if (word_wrap_eol == s) // Wrap_width is too small to fit anything. Force displaying 1 character to minimize the height discontinuity.
|
if (word_wrap_eol == s) // Wrap_width is too small to fit anything. Force displaying 1 character to minimize the height discontinuity.
|
||||||
word_wrap_eol++; // +1 may not be a character start point in UTF-8 but it's ok because we use s >= word_wrap_eol below
|
word_wrap_eol++; // +1 may not be a character start point in UTF-8 but it's ok because we use s >= word_wrap_eol below
|
||||||
}
|
}
|
||||||
|
|
||||||
if (s >= word_wrap_eol)
|
if (s >= word_wrap_eol)
|
||||||
{
|
{
|
||||||
x = pos.x;
|
x = start_x;
|
||||||
y += line_height;
|
y += line_height;
|
||||||
word_wrap_eol = NULL;
|
word_wrap_eol = NULL;
|
||||||
|
|
||||||
|
@ -3609,7 +3640,7 @@ void ImFont::RenderText(ImDrawList* draw_list, float size, ImVec2 pos, ImU32 col
|
||||||
{
|
{
|
||||||
if (c == '\n')
|
if (c == '\n')
|
||||||
{
|
{
|
||||||
x = pos.x;
|
x = start_x;
|
||||||
y += line_height;
|
y += line_height;
|
||||||
if (y > clip_rect.w)
|
if (y > clip_rect.w)
|
||||||
break; // break out of main loop
|
break; // break out of main loop
|
||||||
|
@ -3705,9 +3736,9 @@ void ImFont::RenderText(ImDrawList* draw_list, float size, ImVec2 pos, ImU32 col
|
||||||
// - RenderArrow()
|
// - RenderArrow()
|
||||||
// - RenderBullet()
|
// - RenderBullet()
|
||||||
// - RenderCheckMark()
|
// - RenderCheckMark()
|
||||||
// - RenderMouseCursor()
|
|
||||||
// - RenderArrowPointingAt()
|
// - RenderArrowPointingAt()
|
||||||
// - RenderRectFilledRangeH()
|
// - RenderRectFilledRangeH()
|
||||||
|
// - RenderRectFilledWithHole()
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
// Function in need of a redesign (legacy mess)
|
// Function in need of a redesign (legacy mess)
|
||||||
// - RenderColorRectWithAlphaCheckerboard()
|
// - RenderColorRectWithAlphaCheckerboard()
|
||||||
|
@ -3765,27 +3796,6 @@ void ImGui::RenderCheckMark(ImDrawList* draw_list, ImVec2 pos, ImU32 col, float
|
||||||
draw_list->PathStroke(col, 0, thickness);
|
draw_list->PathStroke(col, 0, thickness);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ImGui::RenderMouseCursor(ImDrawList* draw_list, ImVec2 pos, float scale, ImGuiMouseCursor mouse_cursor, ImU32 col_fill, ImU32 col_border, ImU32 col_shadow)
|
|
||||||
{
|
|
||||||
if (mouse_cursor == ImGuiMouseCursor_None)
|
|
||||||
return;
|
|
||||||
IM_ASSERT(mouse_cursor > ImGuiMouseCursor_None && mouse_cursor < ImGuiMouseCursor_COUNT);
|
|
||||||
|
|
||||||
ImFontAtlas* font_atlas = draw_list->_Data->Font->ContainerAtlas;
|
|
||||||
ImVec2 offset, size, uv[4];
|
|
||||||
if (font_atlas->GetMouseCursorTexData(mouse_cursor, &offset, &size, &uv[0], &uv[2]))
|
|
||||||
{
|
|
||||||
pos -= offset;
|
|
||||||
ImTextureID tex_id = font_atlas->TexID;
|
|
||||||
draw_list->PushTextureID(tex_id);
|
|
||||||
draw_list->AddImage(tex_id, pos + ImVec2(1, 0) * scale, pos + (ImVec2(1, 0) + size) * scale, uv[2], uv[3], col_shadow);
|
|
||||||
draw_list->AddImage(tex_id, pos + ImVec2(2, 0) * scale, pos + (ImVec2(2, 0) + size) * scale, uv[2], uv[3], col_shadow);
|
|
||||||
draw_list->AddImage(tex_id, pos, pos + size * scale, uv[2], uv[3], col_border);
|
|
||||||
draw_list->AddImage(tex_id, pos, pos + size * scale, uv[0], uv[1], col_fill);
|
|
||||||
draw_list->PopTextureID();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Render an arrow. 'pos' is position of the arrow tip. half_sz.x is length from base to tip. half_sz.y is length on each side.
|
// Render an arrow. 'pos' is position of the arrow tip. half_sz.x is length from base to tip. half_sz.y is length on each side.
|
||||||
void ImGui::RenderArrowPointingAt(ImDrawList* draw_list, ImVec2 pos, ImVec2 half_sz, ImGuiDir direction, ImU32 col)
|
void ImGui::RenderArrowPointingAt(ImDrawList* draw_list, ImVec2 pos, ImVec2 half_sz, ImGuiDir direction, ImU32 col)
|
||||||
{
|
{
|
||||||
|
@ -3868,16 +3878,16 @@ void ImGui::RenderRectFilledRangeH(ImDrawList* draw_list, const ImRect& rect, Im
|
||||||
draw_list->PathFillConvex(col);
|
draw_list->PathFillConvex(col);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ImGui::RenderRectFilledWithHole(ImDrawList* draw_list, ImRect outer, ImRect inner, ImU32 col, float rounding)
|
void ImGui::RenderRectFilledWithHole(ImDrawList* draw_list, const ImRect& outer, const ImRect& inner, ImU32 col, float rounding)
|
||||||
{
|
{
|
||||||
const bool fill_L = (inner.Min.x > outer.Min.x);
|
const bool fill_L = (inner.Min.x > outer.Min.x);
|
||||||
const bool fill_R = (inner.Max.x < outer.Max.x);
|
const bool fill_R = (inner.Max.x < outer.Max.x);
|
||||||
const bool fill_U = (inner.Min.y > outer.Min.y);
|
const bool fill_U = (inner.Min.y > outer.Min.y);
|
||||||
const bool fill_D = (inner.Max.y < outer.Max.y);
|
const bool fill_D = (inner.Max.y < outer.Max.y);
|
||||||
if (fill_L) draw_list->AddRectFilled(ImVec2(outer.Min.x, inner.Min.y), ImVec2(inner.Min.x, inner.Max.y), col, rounding, (fill_U ? 0 : ImDrawFlags_RoundCornersTopLeft) | (fill_D ? 0 : ImDrawFlags_RoundCornersBottomLeft));
|
if (fill_L) draw_list->AddRectFilled(ImVec2(outer.Min.x, inner.Min.y), ImVec2(inner.Min.x, inner.Max.y), col, rounding, ImDrawFlags_RoundCornersNone | (fill_U ? 0 : ImDrawFlags_RoundCornersTopLeft) | (fill_D ? 0 : ImDrawFlags_RoundCornersBottomLeft));
|
||||||
if (fill_R) draw_list->AddRectFilled(ImVec2(inner.Max.x, inner.Min.y), ImVec2(outer.Max.x, inner.Max.y), col, rounding, (fill_U ? 0 : ImDrawFlags_RoundCornersTopRight) | (fill_D ? 0 : ImDrawFlags_RoundCornersBottomRight));
|
if (fill_R) draw_list->AddRectFilled(ImVec2(inner.Max.x, inner.Min.y), ImVec2(outer.Max.x, inner.Max.y), col, rounding, ImDrawFlags_RoundCornersNone | (fill_U ? 0 : ImDrawFlags_RoundCornersTopRight) | (fill_D ? 0 : ImDrawFlags_RoundCornersBottomRight));
|
||||||
if (fill_U) draw_list->AddRectFilled(ImVec2(inner.Min.x, outer.Min.y), ImVec2(inner.Max.x, inner.Min.y), col, rounding, (fill_L ? 0 : ImDrawFlags_RoundCornersTopLeft) | (fill_R ? 0 : ImDrawFlags_RoundCornersTopRight));
|
if (fill_U) draw_list->AddRectFilled(ImVec2(inner.Min.x, outer.Min.y), ImVec2(inner.Max.x, inner.Min.y), col, rounding, ImDrawFlags_RoundCornersNone | (fill_L ? 0 : ImDrawFlags_RoundCornersTopLeft) | (fill_R ? 0 : ImDrawFlags_RoundCornersTopRight));
|
||||||
if (fill_D) draw_list->AddRectFilled(ImVec2(inner.Min.x, inner.Max.y), ImVec2(inner.Max.x, outer.Max.y), col, rounding, (fill_L ? 0 : ImDrawFlags_RoundCornersBottomLeft) | (fill_R ? 0 : ImDrawFlags_RoundCornersBottomRight));
|
if (fill_D) draw_list->AddRectFilled(ImVec2(inner.Min.x, inner.Max.y), ImVec2(inner.Max.x, outer.Max.y), col, rounding, ImDrawFlags_RoundCornersNone | (fill_L ? 0 : ImDrawFlags_RoundCornersBottomLeft) | (fill_R ? 0 : ImDrawFlags_RoundCornersBottomRight));
|
||||||
if (fill_L && fill_U) draw_list->AddRectFilled(ImVec2(outer.Min.x, outer.Min.y), ImVec2(inner.Min.x, inner.Min.y), col, rounding, ImDrawFlags_RoundCornersTopLeft);
|
if (fill_L && fill_U) draw_list->AddRectFilled(ImVec2(outer.Min.x, outer.Min.y), ImVec2(inner.Min.x, inner.Min.y), col, rounding, ImDrawFlags_RoundCornersTopLeft);
|
||||||
if (fill_R && fill_U) draw_list->AddRectFilled(ImVec2(inner.Max.x, outer.Min.y), ImVec2(outer.Max.x, inner.Min.y), col, rounding, ImDrawFlags_RoundCornersTopRight);
|
if (fill_R && fill_U) draw_list->AddRectFilled(ImVec2(inner.Max.x, outer.Min.y), ImVec2(outer.Max.x, inner.Min.y), col, rounding, ImDrawFlags_RoundCornersTopRight);
|
||||||
if (fill_L && fill_D) draw_list->AddRectFilled(ImVec2(outer.Min.x, inner.Max.y), ImVec2(inner.Min.x, outer.Max.y), col, rounding, ImDrawFlags_RoundCornersBottomLeft);
|
if (fill_L && fill_D) draw_list->AddRectFilled(ImVec2(outer.Min.x, inner.Max.y), ImVec2(inner.Min.x, outer.Max.y), col, rounding, ImDrawFlags_RoundCornersBottomLeft);
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,4 +1,4 @@
|
||||||
// dear imgui, v1.84 WIP
|
// dear imgui, v1.89 WIP
|
||||||
// (tables and columns code)
|
// (tables and columns code)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -24,7 +24,7 @@ Index of this file:
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// Navigating this file:
|
// Navigating this file:
|
||||||
// - In Visual Studio IDE: CTRL+comma ("Edit.NavigateTo") can follow symbols in comments, whereas CTRL+F12 ("Edit.GoToImplementation") cannot.
|
// - In Visual Studio IDE: CTRL+comma ("Edit.GoToAll") can follow symbols in comments, whereas CTRL+F12 ("Edit.GoToImplementation") cannot.
|
||||||
// - With Visual Assist installed: ALT+G ("VAssistX.GoToImplementation") can also follow symbols in comments.
|
// - With Visual Assist installed: ALT+G ("VAssistX.GoToImplementation") can also follow symbols in comments.
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
@ -288,12 +288,7 @@ inline ImGuiTableFlags TableFixFlags(ImGuiTableFlags flags, ImGuiWindow* outer_w
|
||||||
flags |= ImGuiTableFlags_NoSavedSettings;
|
flags |= ImGuiTableFlags_NoSavedSettings;
|
||||||
|
|
||||||
// Inherit _NoSavedSettings from top-level window (child windows always have _NoSavedSettings set)
|
// Inherit _NoSavedSettings from top-level window (child windows always have _NoSavedSettings set)
|
||||||
#ifdef IMGUI_HAS_DOCK
|
if (outer_window->RootWindow->Flags & ImGuiWindowFlags_NoSavedSettings)
|
||||||
ImGuiWindow* window_for_settings = outer_window->RootWindowDockStop;
|
|
||||||
#else
|
|
||||||
ImGuiWindow* window_for_settings = outer_window->RootWindow;
|
|
||||||
#endif
|
|
||||||
if (window_for_settings->Flags & ImGuiWindowFlags_NoSavedSettings)
|
|
||||||
flags |= ImGuiTableFlags_NoSavedSettings;
|
flags |= ImGuiTableFlags_NoSavedSettings;
|
||||||
|
|
||||||
return flags;
|
return flags;
|
||||||
|
@ -329,7 +324,7 @@ bool ImGui::BeginTableEx(const char* name, ImGuiID id, int columns_count, ImG
|
||||||
const ImVec2 avail_size = GetContentRegionAvail();
|
const ImVec2 avail_size = GetContentRegionAvail();
|
||||||
ImVec2 actual_outer_size = CalcItemSize(outer_size, ImMax(avail_size.x, 1.0f), use_child_window ? ImMax(avail_size.y, 1.0f) : 0.0f);
|
ImVec2 actual_outer_size = CalcItemSize(outer_size, ImMax(avail_size.x, 1.0f), use_child_window ? ImMax(avail_size.y, 1.0f) : 0.0f);
|
||||||
ImRect outer_rect(outer_window->DC.CursorPos, outer_window->DC.CursorPos + actual_outer_size);
|
ImRect outer_rect(outer_window->DC.CursorPos, outer_window->DC.CursorPos + actual_outer_size);
|
||||||
if (use_child_window && IsClippedEx(outer_rect, 0, false))
|
if (use_child_window && IsClippedEx(outer_rect, 0))
|
||||||
{
|
{
|
||||||
ItemSize(outer_rect);
|
ItemSize(outer_rect);
|
||||||
return false;
|
return false;
|
||||||
|
@ -345,10 +340,9 @@ bool ImGui::BeginTableEx(const char* name, ImGuiID id, int columns_count, ImG
|
||||||
|
|
||||||
// Acquire temporary buffers
|
// Acquire temporary buffers
|
||||||
const int table_idx = g.Tables.GetIndex(table);
|
const int table_idx = g.Tables.GetIndex(table);
|
||||||
g.CurrentTableStackIdx++;
|
if (++g.TablesTempDataStacked > g.TablesTempData.Size)
|
||||||
if (g.CurrentTableStackIdx + 1 > g.TablesTempDataStack.Size)
|
g.TablesTempData.resize(g.TablesTempDataStacked, ImGuiTableTempData());
|
||||||
g.TablesTempDataStack.resize(g.CurrentTableStackIdx + 1, ImGuiTableTempData());
|
ImGuiTableTempData* temp_data = table->TempData = &g.TablesTempData[g.TablesTempDataStacked - 1];
|
||||||
ImGuiTableTempData* temp_data = table->TempData = &g.TablesTempDataStack[g.CurrentTableStackIdx];
|
|
||||||
temp_data->TableIndex = table_idx;
|
temp_data->TableIndex = table_idx;
|
||||||
table->DrawSplitter = &table->TempData->DrawSplitter;
|
table->DrawSplitter = &table->TempData->DrawSplitter;
|
||||||
table->DrawSplitter->Clear();
|
table->DrawSplitter->Clear();
|
||||||
|
@ -367,6 +361,8 @@ bool ImGui::BeginTableEx(const char* name, ImGuiID id, int columns_count, ImG
|
||||||
table->IsLayoutLocked = false;
|
table->IsLayoutLocked = false;
|
||||||
table->InnerWidth = inner_width;
|
table->InnerWidth = inner_width;
|
||||||
temp_data->UserOuterSize = outer_size;
|
temp_data->UserOuterSize = outer_size;
|
||||||
|
if (instance_no > 0 && table->InstanceDataExtra.Size < instance_no)
|
||||||
|
table->InstanceDataExtra.push_back(ImGuiTableInstanceData());
|
||||||
|
|
||||||
// When not using a child window, WorkRect.Max will grow as we append contents.
|
// When not using a child window, WorkRect.Max will grow as we append contents.
|
||||||
if (use_child_window)
|
if (use_child_window)
|
||||||
|
@ -522,7 +518,7 @@ bool ImGui::BeginTableEx(const char* name, ImGuiID id, int columns_count, ImG
|
||||||
*column = ImGuiTableColumn();
|
*column = ImGuiTableColumn();
|
||||||
column->WidthAuto = width_auto;
|
column->WidthAuto = width_auto;
|
||||||
column->IsPreserveWidthAuto = true; // Preserve WidthAuto when reinitializing a live table: not technically necessary but remove a visible flicker
|
column->IsPreserveWidthAuto = true; // Preserve WidthAuto when reinitializing a live table: not technically necessary but remove a visible flicker
|
||||||
column->IsEnabled = column->IsEnabledNextFrame = true;
|
column->IsEnabled = column->IsUserEnabled = column->IsUserEnabledNextFrame = true;
|
||||||
}
|
}
|
||||||
column->DisplayOrder = table->DisplayOrderToIndex[n] = (ImGuiTableColumnIdx)n;
|
column->DisplayOrder = table->DisplayOrderToIndex[n] = (ImGuiTableColumnIdx)n;
|
||||||
}
|
}
|
||||||
|
@ -543,7 +539,7 @@ bool ImGui::BeginTableEx(const char* name, ImGuiID id, int columns_count, ImG
|
||||||
if (table->RefScale != 0.0f && table->RefScale != new_ref_scale_unit)
|
if (table->RefScale != 0.0f && table->RefScale != new_ref_scale_unit)
|
||||||
{
|
{
|
||||||
const float scale_factor = new_ref_scale_unit / table->RefScale;
|
const float scale_factor = new_ref_scale_unit / table->RefScale;
|
||||||
//IMGUI_DEBUG_LOG("[table] %08X RefScaleUnit %.3f -> %.3f, scaling width by %.3f\n", table->ID, table->RefScaleUnit, new_ref_scale_unit, scale_factor);
|
//IMGUI_DEBUG_PRINT("[table] %08X RefScaleUnit %.3f -> %.3f, scaling width by %.3f\n", table->ID, table->RefScaleUnit, new_ref_scale_unit, scale_factor);
|
||||||
for (int n = 0; n < columns_count; n++)
|
for (int n = 0; n < columns_count; n++)
|
||||||
table->Columns[n].WidthRequest = table->Columns[n].WidthRequest * scale_factor;
|
table->Columns[n].WidthRequest = table->Columns[n].WidthRequest * scale_factor;
|
||||||
}
|
}
|
||||||
|
@ -569,6 +565,7 @@ bool ImGui::BeginTableEx(const char* name, ImGuiID id, int columns_count, ImG
|
||||||
// + 0 (for ImGuiTable instance, we are pooling allocations in g.Tables)
|
// + 0 (for ImGuiTable instance, we are pooling allocations in g.Tables)
|
||||||
// + 1 (for table->RawData allocated below)
|
// + 1 (for table->RawData allocated below)
|
||||||
// + 1 (for table->ColumnsNames, if names are used)
|
// + 1 (for table->ColumnsNames, if names are used)
|
||||||
|
// Shared allocations per number of nested tables
|
||||||
// + 1 (for table->Splitter._Channels)
|
// + 1 (for table->Splitter._Channels)
|
||||||
// + 2 * active_channels_count (for ImDrawCmd and ImDrawIdx buffers inside channels)
|
// + 2 * active_channels_count (for ImDrawCmd and ImDrawIdx buffers inside channels)
|
||||||
// Where active_channels_count is variable but often == columns_count or columns_count + 1, see TableSetupDrawChannels() for details.
|
// Where active_channels_count is variable but often == columns_count or columns_count + 1, see TableSetupDrawChannels() for details.
|
||||||
|
@ -756,16 +753,18 @@ void ImGui::TableUpdateLayout(ImGuiTable* table)
|
||||||
column->InitStretchWeightOrWidth = -1.0f;
|
column->InitStretchWeightOrWidth = -1.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update Enabled state, mark settings/sortspecs dirty
|
// Update Enabled state, mark settings and sort specs dirty
|
||||||
if (!(table->Flags & ImGuiTableFlags_Hideable) || (column->Flags & ImGuiTableColumnFlags_NoHide))
|
if (!(table->Flags & ImGuiTableFlags_Hideable) || (column->Flags & ImGuiTableColumnFlags_NoHide))
|
||||||
column->IsEnabledNextFrame = true;
|
column->IsUserEnabledNextFrame = true;
|
||||||
if (column->IsEnabled != column->IsEnabledNextFrame)
|
if (column->IsUserEnabled != column->IsUserEnabledNextFrame)
|
||||||
{
|
{
|
||||||
column->IsEnabled = column->IsEnabledNextFrame;
|
column->IsUserEnabled = column->IsUserEnabledNextFrame;
|
||||||
table->IsSettingsDirty = true;
|
table->IsSettingsDirty = true;
|
||||||
if (!column->IsEnabled && column->SortOrder != -1)
|
|
||||||
table->IsSortSpecsDirty = true;
|
|
||||||
}
|
}
|
||||||
|
column->IsEnabled = column->IsUserEnabled && (column->Flags & ImGuiTableColumnFlags_Disabled) == 0;
|
||||||
|
|
||||||
|
if (column->SortOrder != -1 && !column->IsEnabled)
|
||||||
|
table->IsSortSpecsDirty = true;
|
||||||
if (column->SortOrder > 0 && !(table->Flags & ImGuiTableFlags_SortMulti))
|
if (column->SortOrder > 0 && !(table->Flags & ImGuiTableFlags_SortMulti))
|
||||||
table->IsSortSpecsDirty = true;
|
table->IsSortSpecsDirty = true;
|
||||||
|
|
||||||
|
@ -889,6 +888,7 @@ void ImGui::TableUpdateLayout(ImGuiTable* table)
|
||||||
sum_width_requests += table->CellPaddingX * 2.0f;
|
sum_width_requests += table->CellPaddingX * 2.0f;
|
||||||
}
|
}
|
||||||
table->ColumnsEnabledFixedCount = (ImGuiTableColumnIdx)count_fixed;
|
table->ColumnsEnabledFixedCount = (ImGuiTableColumnIdx)count_fixed;
|
||||||
|
table->ColumnsStretchSumWeights = stretch_sum_weights;
|
||||||
|
|
||||||
// [Part 4] Apply final widths based on requested widths
|
// [Part 4] Apply final widths based on requested widths
|
||||||
const ImRect work_rect = table->WorkRect;
|
const ImRect work_rect = table->WorkRect;
|
||||||
|
@ -936,9 +936,10 @@ void ImGui::TableUpdateLayout(ImGuiTable* table)
|
||||||
width_remaining_for_stretched_columns -= 1.0f;
|
width_remaining_for_stretched_columns -= 1.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ImGuiTableInstanceData* table_instance = TableGetInstanceData(table, table->InstanceCurrent);
|
||||||
table->HoveredColumnBody = -1;
|
table->HoveredColumnBody = -1;
|
||||||
table->HoveredColumnBorder = -1;
|
table->HoveredColumnBorder = -1;
|
||||||
const ImRect mouse_hit_rect(table->OuterRect.Min.x, table->OuterRect.Min.y, table->OuterRect.Max.x, ImMax(table->OuterRect.Max.y, table->OuterRect.Min.y + table->LastOuterHeight));
|
const ImRect mouse_hit_rect(table->OuterRect.Min.x, table->OuterRect.Min.y, table->OuterRect.Max.x, ImMax(table->OuterRect.Max.y, table->OuterRect.Min.y + table_instance->LastOuterHeight));
|
||||||
const bool is_hovering_table = ItemHoverable(mouse_hit_rect, 0);
|
const bool is_hovering_table = ItemHoverable(mouse_hit_rect, 0);
|
||||||
|
|
||||||
// [Part 6] Setup final position, offset, skip/clip states and clipping rectangles, detect hovered column
|
// [Part 6] Setup final position, offset, skip/clip states and clipping rectangles, detect hovered column
|
||||||
|
@ -1099,24 +1100,16 @@ void ImGui::TableUpdateLayout(ImGuiTable* table)
|
||||||
// [Part 10] Hit testing on borders
|
// [Part 10] Hit testing on borders
|
||||||
if (table->Flags & ImGuiTableFlags_Resizable)
|
if (table->Flags & ImGuiTableFlags_Resizable)
|
||||||
TableUpdateBorders(table);
|
TableUpdateBorders(table);
|
||||||
table->LastFirstRowHeight = 0.0f;
|
table_instance->LastFirstRowHeight = 0.0f;
|
||||||
table->IsLayoutLocked = true;
|
table->IsLayoutLocked = true;
|
||||||
table->IsUsingHeaders = false;
|
table->IsUsingHeaders = false;
|
||||||
|
|
||||||
// [Part 11] Context menu
|
// [Part 11] Context menu
|
||||||
if (table->IsContextPopupOpen && table->InstanceCurrent == table->InstanceInteracted)
|
if (TableBeginContextMenuPopup(table))
|
||||||
{
|
|
||||||
const ImGuiID context_menu_id = ImHashStr("##ContextMenu", 0, table->ID);
|
|
||||||
if (BeginPopupEx(context_menu_id, ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoSavedSettings))
|
|
||||||
{
|
{
|
||||||
TableDrawContextMenu(table);
|
TableDrawContextMenu(table);
|
||||||
EndPopup();
|
EndPopup();
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
table->IsContextPopupOpen = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// [Part 13] Sanitize and build sort specs before we have a change to use them for display.
|
// [Part 13] Sanitize and build sort specs before we have a change to use them for display.
|
||||||
// This path will only be exercised when sort specs are modified before header rows (e.g. init or visibility change)
|
// This path will only be exercised when sort specs are modified before header rows (e.g. init or visibility change)
|
||||||
|
@ -1144,10 +1137,11 @@ void ImGui::TableUpdateBorders(ImGuiTable* table)
|
||||||
// use the final height from last frame. Because this is only affecting _interaction_ with columns, it is not
|
// use the final height from last frame. Because this is only affecting _interaction_ with columns, it is not
|
||||||
// really problematic (whereas the actual visual will be displayed in EndTable() and using the current frame height).
|
// really problematic (whereas the actual visual will be displayed in EndTable() and using the current frame height).
|
||||||
// Actual columns highlight/render will be performed in EndTable() and not be affected.
|
// Actual columns highlight/render will be performed in EndTable() and not be affected.
|
||||||
|
ImGuiTableInstanceData* table_instance = TableGetInstanceData(table, table->InstanceCurrent);
|
||||||
const float hit_half_width = TABLE_RESIZE_SEPARATOR_HALF_THICKNESS;
|
const float hit_half_width = TABLE_RESIZE_SEPARATOR_HALF_THICKNESS;
|
||||||
const float hit_y1 = table->OuterRect.Min.y;
|
const float hit_y1 = table->OuterRect.Min.y;
|
||||||
const float hit_y2_body = ImMax(table->OuterRect.Max.y, hit_y1 + table->LastOuterHeight);
|
const float hit_y2_body = ImMax(table->OuterRect.Max.y, hit_y1 + table_instance->LastOuterHeight);
|
||||||
const float hit_y2_head = hit_y1 + table->LastFirstRowHeight;
|
const float hit_y2_head = hit_y1 + table_instance->LastFirstRowHeight;
|
||||||
|
|
||||||
for (int order_n = 0; order_n < table->ColumnsCount; order_n++)
|
for (int order_n = 0; order_n < table->ColumnsCount; order_n++)
|
||||||
{
|
{
|
||||||
|
@ -1164,8 +1158,7 @@ void ImGui::TableUpdateBorders(ImGuiTable* table)
|
||||||
if ((table->Flags & ImGuiTableFlags_NoBordersInBody) && table->IsUsingHeaders == false)
|
if ((table->Flags & ImGuiTableFlags_NoBordersInBody) && table->IsUsingHeaders == false)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (table->FreezeColumnsCount > 0)
|
if (!column->IsVisibleX && table->LastResizedColumn != column_n)
|
||||||
if (column->MaxX < table->Columns[table->DisplayOrderToIndex[table->FreezeColumnsCount - 1]].MaxX)
|
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
ImGuiID column_id = TableGetColumnResizeID(table, column_n, table->InstanceCurrent);
|
ImGuiID column_id = TableGetColumnResizeID(table, column_n, table->InstanceCurrent);
|
||||||
|
@ -1174,7 +1167,7 @@ void ImGui::TableUpdateBorders(ImGuiTable* table)
|
||||||
KeepAliveID(column_id);
|
KeepAliveID(column_id);
|
||||||
|
|
||||||
bool hovered = false, held = false;
|
bool hovered = false, held = false;
|
||||||
bool pressed = ButtonBehavior(hit_rect, column_id, &hovered, &held, ImGuiButtonFlags_FlattenChildren | ImGuiButtonFlags_AllowItemOverlap | ImGuiButtonFlags_PressedOnClick | ImGuiButtonFlags_PressedOnDoubleClick);
|
bool pressed = ButtonBehavior(hit_rect, column_id, &hovered, &held, ImGuiButtonFlags_FlattenChildren | ImGuiButtonFlags_AllowItemOverlap | ImGuiButtonFlags_PressedOnClick | ImGuiButtonFlags_PressedOnDoubleClick | ImGuiButtonFlags_NoNavFocus);
|
||||||
if (pressed && IsMouseDoubleClicked(0))
|
if (pressed && IsMouseDoubleClicked(0))
|
||||||
{
|
{
|
||||||
TableSetColumnWidthAutoSingle(table, column_n);
|
TableSetColumnWidthAutoSingle(table, column_n);
|
||||||
|
@ -1227,6 +1220,7 @@ void ImGui::EndTable()
|
||||||
TableOpenContextMenu((int)table->HoveredColumnBody);
|
TableOpenContextMenu((int)table->HoveredColumnBody);
|
||||||
|
|
||||||
// Finalize table height
|
// Finalize table height
|
||||||
|
ImGuiTableInstanceData* table_instance = TableGetInstanceData(table, table->InstanceCurrent);
|
||||||
inner_window->DC.PrevLineSize = temp_data->HostBackupPrevLineSize;
|
inner_window->DC.PrevLineSize = temp_data->HostBackupPrevLineSize;
|
||||||
inner_window->DC.CurrLineSize = temp_data->HostBackupCurrLineSize;
|
inner_window->DC.CurrLineSize = temp_data->HostBackupCurrLineSize;
|
||||||
inner_window->DC.CursorMaxPos = temp_data->HostBackupCursorMaxPos;
|
inner_window->DC.CursorMaxPos = temp_data->HostBackupCursorMaxPos;
|
||||||
|
@ -1237,7 +1231,7 @@ void ImGui::EndTable()
|
||||||
else if (!(flags & ImGuiTableFlags_NoHostExtendY))
|
else if (!(flags & ImGuiTableFlags_NoHostExtendY))
|
||||||
table->OuterRect.Max.y = table->InnerRect.Max.y = ImMax(table->OuterRect.Max.y, inner_content_max_y); // Patch OuterRect/InnerRect height
|
table->OuterRect.Max.y = table->InnerRect.Max.y = ImMax(table->OuterRect.Max.y, inner_content_max_y); // Patch OuterRect/InnerRect height
|
||||||
table->WorkRect.Max.y = ImMax(table->WorkRect.Max.y, table->OuterRect.Max.y);
|
table->WorkRect.Max.y = ImMax(table->WorkRect.Max.y, table->OuterRect.Max.y);
|
||||||
table->LastOuterHeight = table->OuterRect.GetHeight();
|
table_instance->LastOuterHeight = table->OuterRect.GetHeight();
|
||||||
|
|
||||||
// Setup inner scrolling range
|
// Setup inner scrolling range
|
||||||
// FIXME: This ideally should be done earlier, in BeginTable() SetNextWindowContentSize call, just like writing to inner_window->DC.CursorMaxPos.y,
|
// FIXME: This ideally should be done earlier, in BeginTable() SetNextWindowContentSize call, just like writing to inner_window->DC.CursorMaxPos.y,
|
||||||
|
@ -1283,17 +1277,23 @@ void ImGui::EndTable()
|
||||||
splitter->Merge(inner_window->DrawList);
|
splitter->Merge(inner_window->DrawList);
|
||||||
|
|
||||||
// Update ColumnsAutoFitWidth to get us ahead for host using our size to auto-resize without waiting for next BeginTable()
|
// Update ColumnsAutoFitWidth to get us ahead for host using our size to auto-resize without waiting for next BeginTable()
|
||||||
const float width_spacings = (table->OuterPaddingX * 2.0f) + (table->CellSpacingX1 + table->CellSpacingX2) * (table->ColumnsEnabledCount - 1);
|
float auto_fit_width_for_fixed = 0.0f;
|
||||||
table->ColumnsAutoFitWidth = width_spacings + (table->CellPaddingX * 2.0f) * table->ColumnsEnabledCount;
|
float auto_fit_width_for_stretched = 0.0f;
|
||||||
|
float auto_fit_width_for_stretched_min = 0.0f;
|
||||||
for (int column_n = 0; column_n < table->ColumnsCount; column_n++)
|
for (int column_n = 0; column_n < table->ColumnsCount; column_n++)
|
||||||
if (table->EnabledMaskByIndex & ((ImU64)1 << column_n))
|
if (table->EnabledMaskByIndex & ((ImU64)1 << column_n))
|
||||||
{
|
{
|
||||||
ImGuiTableColumn* column = &table->Columns[column_n];
|
ImGuiTableColumn* column = &table->Columns[column_n];
|
||||||
if ((column->Flags & ImGuiTableColumnFlags_WidthFixed) && !(column->Flags & ImGuiTableColumnFlags_NoResize))
|
float column_width_request = ((column->Flags & ImGuiTableColumnFlags_WidthFixed) && !(column->Flags & ImGuiTableColumnFlags_NoResize)) ? column->WidthRequest : TableGetColumnWidthAuto(table, column);
|
||||||
table->ColumnsAutoFitWidth += column->WidthRequest;
|
if (column->Flags & ImGuiTableColumnFlags_WidthFixed)
|
||||||
|
auto_fit_width_for_fixed += column_width_request;
|
||||||
else
|
else
|
||||||
table->ColumnsAutoFitWidth += TableGetColumnWidthAuto(table, column);
|
auto_fit_width_for_stretched += column_width_request;
|
||||||
|
if ((column->Flags & ImGuiTableColumnFlags_WidthStretch) && (column->Flags & ImGuiTableColumnFlags_NoResize) != 0)
|
||||||
|
auto_fit_width_for_stretched_min = ImMax(auto_fit_width_for_stretched_min, column_width_request / (column->StretchWeight / table->ColumnsStretchSumWeights));
|
||||||
}
|
}
|
||||||
|
const float width_spacings = (table->OuterPaddingX * 2.0f) + (table->CellSpacingX1 + table->CellSpacingX2) * (table->ColumnsEnabledCount - 1);
|
||||||
|
table->ColumnsAutoFitWidth = width_spacings + (table->CellPaddingX * 2.0f) * table->ColumnsEnabledCount + auto_fit_width_for_fixed + ImMax(auto_fit_width_for_stretched, auto_fit_width_for_stretched_min);
|
||||||
|
|
||||||
// Update scroll
|
// Update scroll
|
||||||
if ((table->Flags & ImGuiTableFlags_ScrollX) == 0 && inner_window != outer_window)
|
if ((table->Flags & ImGuiTableFlags_ScrollX) == 0 && inner_window != outer_window)
|
||||||
|
@ -1385,9 +1385,8 @@ void ImGui::EndTable()
|
||||||
|
|
||||||
// Clear or restore current table, if any
|
// Clear or restore current table, if any
|
||||||
IM_ASSERT(g.CurrentWindow == outer_window && g.CurrentTable == table);
|
IM_ASSERT(g.CurrentWindow == outer_window && g.CurrentTable == table);
|
||||||
IM_ASSERT(g.CurrentTableStackIdx >= 0);
|
IM_ASSERT(g.TablesTempDataStacked > 0);
|
||||||
g.CurrentTableStackIdx--;
|
temp_data = (--g.TablesTempDataStacked > 0) ? &g.TablesTempData[g.TablesTempDataStacked - 1] : NULL;
|
||||||
temp_data = g.CurrentTableStackIdx >= 0 ? &g.TablesTempDataStack[g.CurrentTableStackIdx] : NULL;
|
|
||||||
g.CurrentTable = temp_data ? g.Tables.GetByIndex(temp_data->TableIndex) : NULL;
|
g.CurrentTable = temp_data ? g.Tables.GetByIndex(temp_data->TableIndex) : NULL;
|
||||||
if (g.CurrentTable)
|
if (g.CurrentTable)
|
||||||
{
|
{
|
||||||
|
@ -1449,7 +1448,7 @@ void ImGui::TableSetupColumn(const char* label, ImGuiTableColumnFlags flags, flo
|
||||||
|
|
||||||
// Init default visibility/sort state
|
// Init default visibility/sort state
|
||||||
if ((flags & ImGuiTableColumnFlags_DefaultHide) && (table->SettingsLoadedFlags & ImGuiTableFlags_Hideable) == 0)
|
if ((flags & ImGuiTableColumnFlags_DefaultHide) && (table->SettingsLoadedFlags & ImGuiTableFlags_Hideable) == 0)
|
||||||
column->IsEnabled = column->IsEnabledNextFrame = false;
|
column->IsUserEnabled = column->IsUserEnabledNextFrame = false;
|
||||||
if (flags & ImGuiTableColumnFlags_DefaultSort && (table->SettingsLoadedFlags & ImGuiTableFlags_Sortable) == 0)
|
if (flags & ImGuiTableColumnFlags_DefaultSort && (table->SettingsLoadedFlags & ImGuiTableFlags_Sortable) == 0)
|
||||||
{
|
{
|
||||||
column->SortOrder = 0; // Multiple columns using _DefaultSort will be reassigned unique SortOrder values when building the sort specs.
|
column->SortOrder = 0; // Multiple columns using _DefaultSort will be reassigned unique SortOrder values when building the sort specs.
|
||||||
|
@ -1476,11 +1475,23 @@ void ImGui::TableSetupScrollFreeze(int columns, int rows)
|
||||||
IM_ASSERT(columns >= 0 && columns < IMGUI_TABLE_MAX_COLUMNS);
|
IM_ASSERT(columns >= 0 && columns < IMGUI_TABLE_MAX_COLUMNS);
|
||||||
IM_ASSERT(rows >= 0 && rows < 128); // Arbitrary limit
|
IM_ASSERT(rows >= 0 && rows < 128); // Arbitrary limit
|
||||||
|
|
||||||
table->FreezeColumnsRequest = (table->Flags & ImGuiTableFlags_ScrollX) ? (ImGuiTableColumnIdx)columns : 0;
|
table->FreezeColumnsRequest = (table->Flags & ImGuiTableFlags_ScrollX) ? (ImGuiTableColumnIdx)ImMin(columns, table->ColumnsCount) : 0;
|
||||||
table->FreezeColumnsCount = (table->InnerWindow->Scroll.x != 0.0f) ? table->FreezeColumnsRequest : 0;
|
table->FreezeColumnsCount = (table->InnerWindow->Scroll.x != 0.0f) ? table->FreezeColumnsRequest : 0;
|
||||||
table->FreezeRowsRequest = (table->Flags & ImGuiTableFlags_ScrollY) ? (ImGuiTableColumnIdx)rows : 0;
|
table->FreezeRowsRequest = (table->Flags & ImGuiTableFlags_ScrollY) ? (ImGuiTableColumnIdx)rows : 0;
|
||||||
table->FreezeRowsCount = (table->InnerWindow->Scroll.y != 0.0f) ? table->FreezeRowsRequest : 0;
|
table->FreezeRowsCount = (table->InnerWindow->Scroll.y != 0.0f) ? table->FreezeRowsRequest : 0;
|
||||||
table->IsUnfrozenRows = (table->FreezeRowsCount == 0); // Make sure this is set before TableUpdateLayout() so ImGuiListClipper can benefit from it.b
|
table->IsUnfrozenRows = (table->FreezeRowsCount == 0); // Make sure this is set before TableUpdateLayout() so ImGuiListClipper can benefit from it.b
|
||||||
|
|
||||||
|
// Ensure frozen columns are ordered in their section. We still allow multiple frozen columns to be reordered.
|
||||||
|
// FIXME-TABLE: This work for preserving 2143 into 21|43. How about 4321 turning into 21|43? (preserve relative order in each section)
|
||||||
|
for (int column_n = 0; column_n < table->FreezeColumnsRequest; column_n++)
|
||||||
|
{
|
||||||
|
int order_n = table->DisplayOrderToIndex[column_n];
|
||||||
|
if (order_n != column_n && order_n >= table->FreezeColumnsRequest)
|
||||||
|
{
|
||||||
|
ImSwap(table->Columns[table->DisplayOrderToIndex[order_n]].DisplayOrder, table->Columns[table->DisplayOrderToIndex[column_n]].DisplayOrder);
|
||||||
|
ImSwap(table->DisplayOrderToIndex[order_n], table->DisplayOrderToIndex[column_n]);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
@ -1489,7 +1500,7 @@ void ImGui::TableSetupScrollFreeze(int columns, int rows)
|
||||||
// - TableGetColumnCount()
|
// - TableGetColumnCount()
|
||||||
// - TableGetColumnName()
|
// - TableGetColumnName()
|
||||||
// - TableGetColumnName() [Internal]
|
// - TableGetColumnName() [Internal]
|
||||||
// - TableSetColumnEnabled() [Internal]
|
// - TableSetColumnEnabled()
|
||||||
// - TableGetColumnFlags()
|
// - TableGetColumnFlags()
|
||||||
// - TableGetCellBgRect() [Internal]
|
// - TableGetCellBgRect() [Internal]
|
||||||
// - TableGetColumnResizeID() [Internal]
|
// - TableGetColumnResizeID() [Internal]
|
||||||
|
@ -1525,10 +1536,12 @@ const char* ImGui::TableGetColumnName(const ImGuiTable* table, int column_n)
|
||||||
return &table->ColumnsNames.Buf[column->NameOffset];
|
return &table->ColumnsNames.Buf[column->NameOffset];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Request enabling/disabling a column (often perceived as "showing/hiding" from users point of view)
|
// Change user accessible enabled/disabled state of a column (often perceived as "showing/hiding" from users point of view)
|
||||||
// Note that end-user can use the context menu to change this themselves (right-click in headers, or right-click in columns body with ImGuiTableFlags_ContextMenuInBody)
|
// Note that end-user can use the context menu to change this themselves (right-click in headers, or right-click in columns body with ImGuiTableFlags_ContextMenuInBody)
|
||||||
// Request will be applied during next layout, which happens on the first call to TableNextRow() after BeginTable()
|
// - Require table to have the ImGuiTableFlags_Hideable flag because we are manipulating user accessible state.
|
||||||
// For the getter you can use (TableGetColumnFlags() & ImGuiTableColumnFlags_IsEnabled)
|
// - Request will be applied during next layout, which happens on the first call to TableNextRow() after BeginTable().
|
||||||
|
// - For the getter you can test (TableGetColumnFlags() & ImGuiTableColumnFlags_IsEnabled) != 0.
|
||||||
|
// - Alternative: the ImGuiTableColumnFlags_Disabled is an overriding/master disable flag which will also hide the column from context menu.
|
||||||
void ImGui::TableSetColumnEnabled(int column_n, bool enabled)
|
void ImGui::TableSetColumnEnabled(int column_n, bool enabled)
|
||||||
{
|
{
|
||||||
ImGuiContext& g = *GImGui;
|
ImGuiContext& g = *GImGui;
|
||||||
|
@ -1536,11 +1549,12 @@ void ImGui::TableSetColumnEnabled(int column_n, bool enabled)
|
||||||
IM_ASSERT(table != NULL);
|
IM_ASSERT(table != NULL);
|
||||||
if (!table)
|
if (!table)
|
||||||
return;
|
return;
|
||||||
|
IM_ASSERT(table->Flags & ImGuiTableFlags_Hideable); // See comments above
|
||||||
if (column_n < 0)
|
if (column_n < 0)
|
||||||
column_n = table->CurrentColumn;
|
column_n = table->CurrentColumn;
|
||||||
IM_ASSERT(column_n >= 0 && column_n < table->ColumnsCount);
|
IM_ASSERT(column_n >= 0 && column_n < table->ColumnsCount);
|
||||||
ImGuiTableColumn* column = &table->Columns[column_n];
|
ImGuiTableColumn* column = &table->Columns[column_n];
|
||||||
column->IsEnabledNextFrame = enabled;
|
column->IsUserEnabledNextFrame = enabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
// We allow querying for an extra column in order to poll the IsHovered state of the right-most section
|
// We allow querying for an extra column in order to poll the IsHovered state of the right-most section
|
||||||
|
@ -1559,18 +1573,21 @@ ImGuiTableColumnFlags ImGui::TableGetColumnFlags(int column_n)
|
||||||
|
|
||||||
// Return the cell rectangle based on currently known height.
|
// Return the cell rectangle based on currently known height.
|
||||||
// - Important: we generally don't know our row height until the end of the row, so Max.y will be incorrect in many situations.
|
// - Important: we generally don't know our row height until the end of the row, so Max.y will be incorrect in many situations.
|
||||||
// The only case where this is correct is if we provided a min_row_height to TableNextRow() and don't go below it.
|
// The only case where this is correct is if we provided a min_row_height to TableNextRow() and don't go below it, or in TableEndRow() when we locked that height.
|
||||||
// - Important: if ImGuiTableFlags_PadOuterX is set but ImGuiTableFlags_PadInnerX is not set, the outer-most left and right
|
// - Important: if ImGuiTableFlags_PadOuterX is set but ImGuiTableFlags_PadInnerX is not set, the outer-most left and right
|
||||||
// columns report a small offset so their CellBgRect can extend up to the outer border.
|
// columns report a small offset so their CellBgRect can extend up to the outer border.
|
||||||
|
// FIXME: But the rendering code in TableEndRow() nullifies that with clamping required for scrolling.
|
||||||
ImRect ImGui::TableGetCellBgRect(const ImGuiTable* table, int column_n)
|
ImRect ImGui::TableGetCellBgRect(const ImGuiTable* table, int column_n)
|
||||||
{
|
{
|
||||||
const ImGuiTableColumn* column = &table->Columns[column_n];
|
const ImGuiTableColumn* column = &table->Columns[column_n];
|
||||||
float x1 = column->MinX;
|
float x1 = column->MinX;
|
||||||
float x2 = column->MaxX;
|
float x2 = column->MaxX;
|
||||||
if (column->PrevEnabledColumn == -1)
|
//if (column->PrevEnabledColumn == -1)
|
||||||
x1 -= table->CellSpacingX1;
|
// x1 -= table->OuterPaddingX;
|
||||||
if (column->NextEnabledColumn == -1)
|
//if (column->NextEnabledColumn == -1)
|
||||||
x2 += table->CellSpacingX2;
|
// x2 += table->OuterPaddingX;
|
||||||
|
x1 = ImMax(x1, table->WorkRect.Min.x);
|
||||||
|
x2 = ImMin(x2, table->WorkRect.Max.x);
|
||||||
return ImRect(x1, table->RowPosY1, x2, table->RowPosY2);
|
return ImRect(x1, table->RowPosY1, x2, table->RowPosY2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1700,6 +1717,8 @@ void ImGui::TableBeginRow(ImGuiTable* table)
|
||||||
table->RowTextBaseline = 0.0f;
|
table->RowTextBaseline = 0.0f;
|
||||||
table->RowIndentOffsetX = window->DC.Indent.x - table->HostIndentX; // Lock indent
|
table->RowIndentOffsetX = window->DC.Indent.x - table->HostIndentX; // Lock indent
|
||||||
window->DC.PrevLineTextBaseOffset = 0.0f;
|
window->DC.PrevLineTextBaseOffset = 0.0f;
|
||||||
|
window->DC.CurrLineSize = ImVec2(0.0f, 0.0f);
|
||||||
|
window->DC.IsSameLine = false;
|
||||||
window->DC.CursorMaxPos.y = next_y1;
|
window->DC.CursorMaxPos.y = next_y1;
|
||||||
|
|
||||||
// Making the header BG color non-transparent will allow us to overlay it multiple times when handling smooth dragging.
|
// Making the header BG color non-transparent will allow us to overlay it multiple times when handling smooth dragging.
|
||||||
|
@ -1736,7 +1755,7 @@ void ImGui::TableEndRow(ImGuiTable* table)
|
||||||
const bool unfreeze_rows_actual = (table->CurrentRow + 1 == table->FreezeRowsCount);
|
const bool unfreeze_rows_actual = (table->CurrentRow + 1 == table->FreezeRowsCount);
|
||||||
const bool unfreeze_rows_request = (table->CurrentRow + 1 == table->FreezeRowsRequest);
|
const bool unfreeze_rows_request = (table->CurrentRow + 1 == table->FreezeRowsRequest);
|
||||||
if (table->CurrentRow == 0)
|
if (table->CurrentRow == 0)
|
||||||
table->LastFirstRowHeight = bg_y2 - bg_y1;
|
TableGetInstanceData(table, table->InstanceCurrent)->LastFirstRowHeight = bg_y2 - bg_y1;
|
||||||
|
|
||||||
const bool is_visible = (bg_y2 >= table->InnerClipRect.Min.y && bg_y1 <= table->InnerClipRect.Max.y);
|
const bool is_visible = (bg_y2 >= table->InnerClipRect.Min.y && bg_y1 <= table->InnerClipRect.Max.y);
|
||||||
if (is_visible)
|
if (is_visible)
|
||||||
|
@ -1787,10 +1806,12 @@ void ImGui::TableEndRow(ImGuiTable* table)
|
||||||
ImGuiTableCellData* cell_data_end = &table->RowCellData[table->RowCellDataCurrent];
|
ImGuiTableCellData* cell_data_end = &table->RowCellData[table->RowCellDataCurrent];
|
||||||
for (ImGuiTableCellData* cell_data = &table->RowCellData[0]; cell_data <= cell_data_end; cell_data++)
|
for (ImGuiTableCellData* cell_data = &table->RowCellData[0]; cell_data <= cell_data_end; cell_data++)
|
||||||
{
|
{
|
||||||
|
// As we render the BG here we need to clip things (for layout we would not)
|
||||||
|
// FIXME: This cancels the OuterPadding addition done by TableGetCellBgRect(), need to keep it while rendering correctly while scrolling.
|
||||||
const ImGuiTableColumn* column = &table->Columns[cell_data->Column];
|
const ImGuiTableColumn* column = &table->Columns[cell_data->Column];
|
||||||
ImRect cell_bg_rect = TableGetCellBgRect(table, cell_data->Column);
|
ImRect cell_bg_rect = TableGetCellBgRect(table, cell_data->Column);
|
||||||
cell_bg_rect.ClipWith(table->BgClipRect);
|
cell_bg_rect.ClipWith(table->BgClipRect);
|
||||||
cell_bg_rect.Min.x = ImMax(cell_bg_rect.Min.x, column->ClipRect.Min.x); // So that first column after frozen one gets clipped
|
cell_bg_rect.Min.x = ImMax(cell_bg_rect.Min.x, column->ClipRect.Min.x); // So that first column after frozen one gets clipped when scrolling
|
||||||
cell_bg_rect.Max.x = ImMin(cell_bg_rect.Max.x, column->MaxX);
|
cell_bg_rect.Max.x = ImMin(cell_bg_rect.Max.x, column->MaxX);
|
||||||
window->DrawList->AddRectFilled(cell_bg_rect.Min, cell_bg_rect.Max, cell_data->BgColor);
|
window->DrawList->AddRectFilled(cell_bg_rect.Min, cell_bg_rect.Max, cell_data->BgColor);
|
||||||
}
|
}
|
||||||
|
@ -1946,8 +1967,9 @@ void ImGui::TableBeginCell(ImGuiTable* table, int column_n)
|
||||||
window->SkipItems = column->IsSkipItems;
|
window->SkipItems = column->IsSkipItems;
|
||||||
if (column->IsSkipItems)
|
if (column->IsSkipItems)
|
||||||
{
|
{
|
||||||
window->DC.LastItemId = 0;
|
ImGuiContext& g = *GImGui;
|
||||||
window->DC.LastItemStatusFlags = 0;
|
g.LastItemData.ID = 0;
|
||||||
|
g.LastItemData.StatusFlags = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (table->Flags & ImGuiTableFlags_NoClip)
|
if (table->Flags & ImGuiTableFlags_NoClip)
|
||||||
|
@ -2013,6 +2035,7 @@ float ImGui::TableGetMaxColumnWidth(const ImGuiTable* table, int column_n)
|
||||||
if (table->Flags & ImGuiTableFlags_ScrollX)
|
if (table->Flags & ImGuiTableFlags_ScrollX)
|
||||||
{
|
{
|
||||||
// Frozen columns can't reach beyond visible width else scrolling will naturally break.
|
// Frozen columns can't reach beyond visible width else scrolling will naturally break.
|
||||||
|
// (we use DisplayOrder as within a set of multiple frozen column reordering is possible)
|
||||||
if (column->DisplayOrder < table->FreezeColumnsRequest)
|
if (column->DisplayOrder < table->FreezeColumnsRequest)
|
||||||
{
|
{
|
||||||
max_width = (table->InnerClipRect.Max.x - (table->FreezeColumnsRequest - column->DisplayOrder) * min_column_distance) - column->MinX;
|
max_width = (table->InnerClipRect.Max.x - (table->FreezeColumnsRequest - column->DisplayOrder) * min_column_distance) - column->MinX;
|
||||||
|
@ -2071,7 +2094,7 @@ void ImGui::TableSetColumnWidth(int column_n, float width)
|
||||||
if (column_0->WidthGiven == column_0_width || column_0->WidthRequest == column_0_width)
|
if (column_0->WidthGiven == column_0_width || column_0->WidthRequest == column_0_width)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
//IMGUI_DEBUG_LOG("TableSetColumnWidth(%d, %.1f->%.1f)\n", column_0_idx, column_0->WidthGiven, column_0_width);
|
//IMGUI_DEBUG_PRINT("TableSetColumnWidth(%d, %.1f->%.1f)\n", column_0_idx, column_0->WidthGiven, column_0_width);
|
||||||
ImGuiTableColumn* column_1 = (column_0->NextEnabledColumn != -1) ? &table->Columns[column_0->NextEnabledColumn] : NULL;
|
ImGuiTableColumn* column_1 = (column_0->NextEnabledColumn != -1) ? &table->Columns[column_0->NextEnabledColumn] : NULL;
|
||||||
|
|
||||||
// In this surprisingly not simple because of how we support mixing Fixed and multiple Stretch columns.
|
// In this surprisingly not simple because of how we support mixing Fixed and multiple Stretch columns.
|
||||||
|
@ -2341,7 +2364,7 @@ void ImGui::TableMergeDrawChannels(ImGuiTable* table)
|
||||||
|
|
||||||
// Don't attempt to merge if there are multiple draw calls within the column
|
// Don't attempt to merge if there are multiple draw calls within the column
|
||||||
ImDrawChannel* src_channel = &splitter->_Channels[channel_no];
|
ImDrawChannel* src_channel = &splitter->_Channels[channel_no];
|
||||||
if (src_channel->_CmdBuffer.Size > 0 && src_channel->_CmdBuffer.back().ElemCount == 0)
|
if (src_channel->_CmdBuffer.Size > 0 && src_channel->_CmdBuffer.back().ElemCount == 0 && src_channel->_CmdBuffer.back().UserCallback == NULL) // Equivalent of PopUnusedDrawCmd()
|
||||||
src_channel->_CmdBuffer.pop_back();
|
src_channel->_CmdBuffer.pop_back();
|
||||||
if (src_channel->_CmdBuffer.Size != 1)
|
if (src_channel->_CmdBuffer.Size != 1)
|
||||||
continue;
|
continue;
|
||||||
|
@ -2485,10 +2508,11 @@ void ImGui::TableDrawBorders(ImGuiTable* table)
|
||||||
inner_drawlist->PushClipRect(table->Bg0ClipRectForDrawCmd.Min, table->Bg0ClipRectForDrawCmd.Max, false);
|
inner_drawlist->PushClipRect(table->Bg0ClipRectForDrawCmd.Min, table->Bg0ClipRectForDrawCmd.Max, false);
|
||||||
|
|
||||||
// Draw inner border and resizing feedback
|
// Draw inner border and resizing feedback
|
||||||
|
ImGuiTableInstanceData* table_instance = TableGetInstanceData(table, table->InstanceCurrent);
|
||||||
const float border_size = TABLE_BORDER_SIZE;
|
const float border_size = TABLE_BORDER_SIZE;
|
||||||
const float draw_y1 = table->InnerRect.Min.y;
|
const float draw_y1 = table->InnerRect.Min.y;
|
||||||
const float draw_y2_body = table->InnerRect.Max.y;
|
const float draw_y2_body = table->InnerRect.Max.y;
|
||||||
const float draw_y2_head = table->IsUsingHeaders ? ImMin(table->InnerRect.Max.y, (table->FreezeRowsCount >= 1 ? table->InnerRect.Min.y : table->WorkRect.Min.y) + table->LastFirstRowHeight) : draw_y1;
|
const float draw_y2_head = table->IsUsingHeaders ? ImMin(table->InnerRect.Max.y, (table->FreezeRowsCount >= 1 ? table->InnerRect.Min.y : table->WorkRect.Min.y) + table_instance->LastFirstRowHeight) : draw_y1;
|
||||||
if (table->Flags & ImGuiTableFlags_BordersInnerV)
|
if (table->Flags & ImGuiTableFlags_BordersInnerV)
|
||||||
{
|
{
|
||||||
for (int order_n = 0; order_n < table->ColumnsCount; order_n++)
|
for (int order_n = 0; order_n < table->ColumnsCount; order_n++)
|
||||||
|
@ -2501,7 +2525,7 @@ void ImGui::TableDrawBorders(ImGuiTable* table)
|
||||||
const bool is_hovered = (table->HoveredColumnBorder == column_n);
|
const bool is_hovered = (table->HoveredColumnBorder == column_n);
|
||||||
const bool is_resized = (table->ResizedColumn == column_n) && (table->InstanceInteracted == table->InstanceCurrent);
|
const bool is_resized = (table->ResizedColumn == column_n) && (table->InstanceInteracted == table->InstanceCurrent);
|
||||||
const bool is_resizable = (column->Flags & (ImGuiTableColumnFlags_NoResize | ImGuiTableColumnFlags_NoDirectResize_)) == 0;
|
const bool is_resizable = (column->Flags & (ImGuiTableColumnFlags_NoResize | ImGuiTableColumnFlags_NoDirectResize_)) == 0;
|
||||||
const bool is_frozen_separator = (table->FreezeColumnsCount != -1 && table->FreezeColumnsCount == order_n + 1);
|
const bool is_frozen_separator = (table->FreezeColumnsCount == order_n + 1);
|
||||||
if (column->MaxX > table->InnerClipRect.Max.x && !is_resized)
|
if (column->MaxX > table->InnerClipRect.Max.x && !is_resized)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
@ -2597,7 +2621,6 @@ ImGuiTableSortSpecs* ImGui::TableGetSortSpecs()
|
||||||
if (!table->IsLayoutLocked)
|
if (!table->IsLayoutLocked)
|
||||||
TableUpdateLayout(table);
|
TableUpdateLayout(table);
|
||||||
|
|
||||||
if (table->IsSortSpecsDirty)
|
|
||||||
TableSortSpecsBuild(table);
|
TableSortSpecsBuild(table);
|
||||||
|
|
||||||
return &table->SortSpecs;
|
return &table->SortSpecs;
|
||||||
|
@ -2737,14 +2760,18 @@ void ImGui::TableSortSpecsSanitize(ImGuiTable* table)
|
||||||
|
|
||||||
void ImGui::TableSortSpecsBuild(ImGuiTable* table)
|
void ImGui::TableSortSpecsBuild(ImGuiTable* table)
|
||||||
{
|
{
|
||||||
IM_ASSERT(table->IsSortSpecsDirty);
|
bool dirty = table->IsSortSpecsDirty;
|
||||||
|
if (dirty)
|
||||||
|
{
|
||||||
TableSortSpecsSanitize(table);
|
TableSortSpecsSanitize(table);
|
||||||
|
table->SortSpecsMulti.resize(table->SortSpecsCount <= 1 ? 0 : table->SortSpecsCount);
|
||||||
|
table->SortSpecs.SpecsDirty = true; // Mark as dirty for user
|
||||||
|
table->IsSortSpecsDirty = false; // Mark as not dirty for us
|
||||||
|
}
|
||||||
|
|
||||||
// Write output
|
// Write output
|
||||||
ImGuiTableTempData* temp_data = table->TempData;
|
ImGuiTableColumnSortSpecs* sort_specs = (table->SortSpecsCount == 0) ? NULL : (table->SortSpecsCount == 1) ? &table->SortSpecsSingle : table->SortSpecsMulti.Data;
|
||||||
temp_data->SortSpecsMulti.resize(table->SortSpecsCount <= 1 ? 0 : table->SortSpecsCount);
|
if (dirty && sort_specs != NULL)
|
||||||
ImGuiTableColumnSortSpecs* sort_specs = (table->SortSpecsCount == 0) ? NULL : (table->SortSpecsCount == 1) ? &temp_data->SortSpecsSingle : temp_data->SortSpecsMulti.Data;
|
|
||||||
if (sort_specs != NULL)
|
|
||||||
for (int column_n = 0; column_n < table->ColumnsCount; column_n++)
|
for (int column_n = 0; column_n < table->ColumnsCount; column_n++)
|
||||||
{
|
{
|
||||||
ImGuiTableColumn* column = &table->Columns[column_n];
|
ImGuiTableColumn* column = &table->Columns[column_n];
|
||||||
|
@ -2757,10 +2784,9 @@ void ImGui::TableSortSpecsBuild(ImGuiTable* table)
|
||||||
sort_spec->SortOrder = (ImGuiTableColumnIdx)column->SortOrder;
|
sort_spec->SortOrder = (ImGuiTableColumnIdx)column->SortOrder;
|
||||||
sort_spec->SortDirection = column->SortDirection;
|
sort_spec->SortDirection = column->SortDirection;
|
||||||
}
|
}
|
||||||
|
|
||||||
table->SortSpecs.Specs = sort_specs;
|
table->SortSpecs.Specs = sort_specs;
|
||||||
table->SortSpecs.SpecsCount = table->SortSpecsCount;
|
table->SortSpecs.SpecsCount = table->SortSpecsCount;
|
||||||
table->SortSpecs.SpecsDirty = true; // Mark as dirty for user
|
|
||||||
table->IsSortSpecsDirty = false; // Mark as not dirty for us
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//-------------------------------------------------------------------------
|
//-------------------------------------------------------------------------
|
||||||
|
@ -2780,8 +2806,11 @@ float ImGui::TableGetHeaderRowHeight()
|
||||||
float row_height = GetTextLineHeight();
|
float row_height = GetTextLineHeight();
|
||||||
int columns_count = TableGetColumnCount();
|
int columns_count = TableGetColumnCount();
|
||||||
for (int column_n = 0; column_n < columns_count; column_n++)
|
for (int column_n = 0; column_n < columns_count; column_n++)
|
||||||
if (TableGetColumnFlags(column_n) & ImGuiTableColumnFlags_IsEnabled)
|
{
|
||||||
|
ImGuiTableColumnFlags flags = TableGetColumnFlags(column_n);
|
||||||
|
if ((flags & ImGuiTableColumnFlags_IsEnabled) && !(flags & ImGuiTableColumnFlags_NoHeaderLabel))
|
||||||
row_height = ImMax(row_height, CalcTextSize(TableGetColumnName(column_n)).y);
|
row_height = ImMax(row_height, CalcTextSize(TableGetColumnName(column_n)).y);
|
||||||
|
}
|
||||||
row_height += GetStyle().CellPadding.y * 2.0f;
|
row_height += GetStyle().CellPadding.y * 2.0f;
|
||||||
return row_height;
|
return row_height;
|
||||||
}
|
}
|
||||||
|
@ -2818,7 +2847,7 @@ void ImGui::TableHeadersRow()
|
||||||
// Push an id to allow unnamed labels (generally accidental, but let's behave nicely with them)
|
// Push an id to allow unnamed labels (generally accidental, but let's behave nicely with them)
|
||||||
// - in your own code you may omit the PushID/PopID all-together, provided you know they won't collide
|
// - in your own code you may omit the PushID/PopID all-together, provided you know they won't collide
|
||||||
// - table->InstanceCurrent is only >0 when we use multiple BeginTable/EndTable calls with same identifier.
|
// - table->InstanceCurrent is only >0 when we use multiple BeginTable/EndTable calls with same identifier.
|
||||||
const char* name = TableGetColumnName(column_n);
|
const char* name = (TableGetColumnFlags(column_n) & ImGuiTableColumnFlags_NoHeaderLabel) ? "" : TableGetColumnName(column_n);
|
||||||
PushID(table->InstanceCurrent * table->ColumnsCount + column_n);
|
PushID(table->InstanceCurrent * table->ColumnsCount + column_n);
|
||||||
TableHeader(name);
|
TableHeader(name);
|
||||||
PopID();
|
PopID();
|
||||||
|
@ -2900,7 +2929,6 @@ void ImGui::TableHeader(const char* label)
|
||||||
const ImU32 col = GetColorU32(held ? ImGuiCol_HeaderActive : hovered ? ImGuiCol_HeaderHovered : ImGuiCol_Header);
|
const ImU32 col = GetColorU32(held ? ImGuiCol_HeaderActive : hovered ? ImGuiCol_HeaderHovered : ImGuiCol_Header);
|
||||||
//RenderFrame(bb.Min, bb.Max, col, false, 0.0f);
|
//RenderFrame(bb.Min, bb.Max, col, false, 0.0f);
|
||||||
TableSetBgColor(ImGuiTableBgTarget_CellBg, col, table->CurrentColumn);
|
TableSetBgColor(ImGuiTableBgTarget_CellBg, col, table->CurrentColumn);
|
||||||
RenderNavHighlight(bb, id, ImGuiNavHighlightFlags_TypeThin | ImGuiNavHighlightFlags_NoRounding);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -2908,6 +2936,7 @@ void ImGui::TableHeader(const char* label)
|
||||||
if ((table->RowFlags & ImGuiTableRowFlags_Headers) == 0)
|
if ((table->RowFlags & ImGuiTableRowFlags_Headers) == 0)
|
||||||
TableSetBgColor(ImGuiTableBgTarget_CellBg, GetColorU32(ImGuiCol_TableHeaderBg), table->CurrentColumn);
|
TableSetBgColor(ImGuiTableBgTarget_CellBg, GetColorU32(ImGuiCol_TableHeaderBg), table->CurrentColumn);
|
||||||
}
|
}
|
||||||
|
RenderNavHighlight(bb, id, ImGuiNavHighlightFlags_TypeThin | ImGuiNavHighlightFlags_NoRounding);
|
||||||
if (held)
|
if (held)
|
||||||
table->HeldHeaderColumn = (ImGuiTableColumnIdx)column_n;
|
table->HeldHeaderColumn = (ImGuiTableColumnIdx)column_n;
|
||||||
window->DC.CursorPos.y -= g.Style.ItemSpacing.y * 0.5f;
|
window->DC.CursorPos.y -= g.Style.ItemSpacing.y * 0.5f;
|
||||||
|
@ -3000,6 +3029,17 @@ void ImGui::TableOpenContextMenu(int column_n)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ImGui::TableBeginContextMenuPopup(ImGuiTable* table)
|
||||||
|
{
|
||||||
|
if (!table->IsContextPopupOpen || table->InstanceCurrent != table->InstanceInteracted)
|
||||||
|
return false;
|
||||||
|
const ImGuiID context_menu_id = ImHashStr("##ContextMenu", 0, table->ID);
|
||||||
|
if (BeginPopupEx(context_menu_id, ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoSavedSettings))
|
||||||
|
return true;
|
||||||
|
table->IsContextPopupOpen = false;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// Output context menu into current window (generally a popup)
|
// Output context menu into current window (generally a popup)
|
||||||
// FIXME-TABLE: Ideally this should be writable by the user. Full programmatic access to that data?
|
// FIXME-TABLE: Ideally this should be writable by the user. Full programmatic access to that data?
|
||||||
void ImGui::TableDrawContextMenu(ImGuiTable* table)
|
void ImGui::TableDrawContextMenu(ImGuiTable* table)
|
||||||
|
@ -3073,16 +3113,19 @@ void ImGui::TableDrawContextMenu(ImGuiTable* table)
|
||||||
for (int other_column_n = 0; other_column_n < table->ColumnsCount; other_column_n++)
|
for (int other_column_n = 0; other_column_n < table->ColumnsCount; other_column_n++)
|
||||||
{
|
{
|
||||||
ImGuiTableColumn* other_column = &table->Columns[other_column_n];
|
ImGuiTableColumn* other_column = &table->Columns[other_column_n];
|
||||||
|
if (other_column->Flags & ImGuiTableColumnFlags_Disabled)
|
||||||
|
continue;
|
||||||
|
|
||||||
const char* name = TableGetColumnName(table, other_column_n);
|
const char* name = TableGetColumnName(table, other_column_n);
|
||||||
if (name == NULL || name[0] == 0)
|
if (name == NULL || name[0] == 0)
|
||||||
name = "<Unknown>";
|
name = "<Unknown>";
|
||||||
|
|
||||||
// Make sure we can't hide the last active column
|
// Make sure we can't hide the last active column
|
||||||
bool menu_item_active = (other_column->Flags & ImGuiTableColumnFlags_NoHide) ? false : true;
|
bool menu_item_active = (other_column->Flags & ImGuiTableColumnFlags_NoHide) ? false : true;
|
||||||
if (other_column->IsEnabled && table->ColumnsEnabledCount <= 1)
|
if (other_column->IsUserEnabled && table->ColumnsEnabledCount <= 1)
|
||||||
menu_item_active = false;
|
menu_item_active = false;
|
||||||
if (MenuItem(name, NULL, other_column->IsEnabled, menu_item_active))
|
if (MenuItem(name, NULL, other_column->IsUserEnabled, menu_item_active))
|
||||||
other_column->IsEnabledNextFrame = !other_column->IsEnabled;
|
other_column->IsUserEnabledNextFrame = !other_column->IsUserEnabled;
|
||||||
}
|
}
|
||||||
PopItemFlag();
|
PopItemFlag();
|
||||||
}
|
}
|
||||||
|
@ -3207,7 +3250,7 @@ void ImGui::TableSaveSettings(ImGuiTable* table)
|
||||||
column_settings->DisplayOrder = column->DisplayOrder;
|
column_settings->DisplayOrder = column->DisplayOrder;
|
||||||
column_settings->SortOrder = column->SortOrder;
|
column_settings->SortOrder = column->SortOrder;
|
||||||
column_settings->SortDirection = column->SortDirection;
|
column_settings->SortDirection = column->SortDirection;
|
||||||
column_settings->IsEnabled = column->IsEnabled;
|
column_settings->IsEnabled = column->IsUserEnabled;
|
||||||
column_settings->IsStretch = (column->Flags & ImGuiTableColumnFlags_WidthStretch) ? 1 : 0;
|
column_settings->IsStretch = (column->Flags & ImGuiTableColumnFlags_WidthStretch) ? 1 : 0;
|
||||||
if ((column->Flags & ImGuiTableColumnFlags_WidthStretch) == 0)
|
if ((column->Flags & ImGuiTableColumnFlags_WidthStretch) == 0)
|
||||||
save_ref_scale = true;
|
save_ref_scale = true;
|
||||||
|
@ -3221,7 +3264,7 @@ void ImGui::TableSaveSettings(ImGuiTable* table)
|
||||||
settings->SaveFlags |= ImGuiTableFlags_Reorderable;
|
settings->SaveFlags |= ImGuiTableFlags_Reorderable;
|
||||||
if (column->SortOrder != -1)
|
if (column->SortOrder != -1)
|
||||||
settings->SaveFlags |= ImGuiTableFlags_Sortable;
|
settings->SaveFlags |= ImGuiTableFlags_Sortable;
|
||||||
if (column->IsEnabled != ((column->Flags & ImGuiTableColumnFlags_DefaultHide) == 0))
|
if (column->IsUserEnabled != ((column->Flags & ImGuiTableColumnFlags_DefaultHide) == 0))
|
||||||
settings->SaveFlags |= ImGuiTableFlags_Hideable;
|
settings->SaveFlags |= ImGuiTableFlags_Hideable;
|
||||||
}
|
}
|
||||||
settings->SaveFlags &= table->Flags;
|
settings->SaveFlags &= table->Flags;
|
||||||
|
@ -3279,7 +3322,7 @@ void ImGui::TableLoadSettings(ImGuiTable* table)
|
||||||
else
|
else
|
||||||
column->DisplayOrder = (ImGuiTableColumnIdx)column_n;
|
column->DisplayOrder = (ImGuiTableColumnIdx)column_n;
|
||||||
display_order_mask |= (ImU64)1 << column->DisplayOrder;
|
display_order_mask |= (ImU64)1 << column->DisplayOrder;
|
||||||
column->IsEnabled = column->IsEnabledNextFrame = column_settings->IsEnabled;
|
column->IsUserEnabled = column->IsUserEnabledNextFrame = column_settings->IsEnabled;
|
||||||
column->SortOrder = column_settings->SortOrder;
|
column->SortOrder = column_settings->SortOrder;
|
||||||
column->SortDirection = column_settings->SortDirection;
|
column->SortDirection = column_settings->SortDirection;
|
||||||
}
|
}
|
||||||
|
@ -3402,9 +3445,8 @@ static void TableSettingsHandler_WriteAll(ImGuiContext* ctx, ImGuiSettingsHandle
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ImGui::TableSettingsInstallHandler(ImGuiContext* context)
|
void ImGui::TableSettingsAddSettingsHandler()
|
||||||
{
|
{
|
||||||
ImGuiContext& g = *context;
|
|
||||||
ImGuiSettingsHandler ini_handler;
|
ImGuiSettingsHandler ini_handler;
|
||||||
ini_handler.TypeName = "Table";
|
ini_handler.TypeName = "Table";
|
||||||
ini_handler.TypeHash = ImHashStr("Table");
|
ini_handler.TypeHash = ImHashStr("Table");
|
||||||
|
@ -3413,7 +3455,7 @@ void ImGui::TableSettingsInstallHandler(ImGuiContext* context)
|
||||||
ini_handler.ReadLineFn = TableSettingsHandler_ReadLine;
|
ini_handler.ReadLineFn = TableSettingsHandler_ReadLine;
|
||||||
ini_handler.ApplyAllFn = TableSettingsHandler_ApplyAll;
|
ini_handler.ApplyAllFn = TableSettingsHandler_ApplyAll;
|
||||||
ini_handler.WriteAllFn = TableSettingsHandler_WriteAll;
|
ini_handler.WriteAllFn = TableSettingsHandler_WriteAll;
|
||||||
g.SettingsHandlers.push_back(ini_handler);
|
AddSettingsHandler(&ini_handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
//-------------------------------------------------------------------------
|
//-------------------------------------------------------------------------
|
||||||
|
@ -3427,7 +3469,7 @@ void ImGui::TableSettingsInstallHandler(ImGuiContext* context)
|
||||||
// Remove Table (currently only used by TestEngine)
|
// Remove Table (currently only used by TestEngine)
|
||||||
void ImGui::TableRemove(ImGuiTable* table)
|
void ImGui::TableRemove(ImGuiTable* table)
|
||||||
{
|
{
|
||||||
//IMGUI_DEBUG_LOG("TableRemove() id=0x%08X\n", table->ID);
|
//IMGUI_DEBUG_PRINT("TableRemove() id=0x%08X\n", table->ID);
|
||||||
ImGuiContext& g = *GImGui;
|
ImGuiContext& g = *GImGui;
|
||||||
int table_idx = g.Tables.GetIndex(table);
|
int table_idx = g.Tables.GetIndex(table);
|
||||||
//memset(table->RawData.Data, 0, table->RawData.size_in_bytes());
|
//memset(table->RawData.Data, 0, table->RawData.size_in_bytes());
|
||||||
|
@ -3439,11 +3481,12 @@ void ImGui::TableRemove(ImGuiTable* table)
|
||||||
// Free up/compact internal Table buffers for when it gets unused
|
// Free up/compact internal Table buffers for when it gets unused
|
||||||
void ImGui::TableGcCompactTransientBuffers(ImGuiTable* table)
|
void ImGui::TableGcCompactTransientBuffers(ImGuiTable* table)
|
||||||
{
|
{
|
||||||
//IMGUI_DEBUG_LOG("TableGcCompactTransientBuffers() id=0x%08X\n", table->ID);
|
//IMGUI_DEBUG_PRINT("TableGcCompactTransientBuffers() id=0x%08X\n", table->ID);
|
||||||
ImGuiContext& g = *GImGui;
|
ImGuiContext& g = *GImGui;
|
||||||
IM_ASSERT(table->MemoryCompacted == false);
|
IM_ASSERT(table->MemoryCompacted == false);
|
||||||
table->SortSpecs.Specs = NULL;
|
table->SortSpecs.Specs = NULL;
|
||||||
table->IsSortSpecsDirty = true;
|
table->SortSpecsMulti.clear();
|
||||||
|
table->IsSortSpecsDirty = true; // FIXME: shouldn't have to leak into user performing a sort
|
||||||
table->ColumnsNames.clear();
|
table->ColumnsNames.clear();
|
||||||
table->MemoryCompacted = true;
|
table->MemoryCompacted = true;
|
||||||
for (int n = 0; n < table->ColumnsCount; n++)
|
for (int n = 0; n < table->ColumnsCount; n++)
|
||||||
|
@ -3454,7 +3497,6 @@ void ImGui::TableGcCompactTransientBuffers(ImGuiTable* table)
|
||||||
void ImGui::TableGcCompactTransientBuffers(ImGuiTableTempData* temp_data)
|
void ImGui::TableGcCompactTransientBuffers(ImGuiTableTempData* temp_data)
|
||||||
{
|
{
|
||||||
temp_data->DrawSplitter.ClearFreeMemory();
|
temp_data->DrawSplitter.ClearFreeMemory();
|
||||||
temp_data->SortSpecsMulti.clear();
|
|
||||||
temp_data->LastTimeActive = -1.0f;
|
temp_data->LastTimeActive = -1.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3483,7 +3525,7 @@ void ImGui::TableGcCompactSettings()
|
||||||
// - DebugNodeTable() [Internal]
|
// - DebugNodeTable() [Internal]
|
||||||
//-------------------------------------------------------------------------
|
//-------------------------------------------------------------------------
|
||||||
|
|
||||||
#ifndef IMGUI_DISABLE_METRICS_WINDOW
|
#ifndef IMGUI_DISABLE_DEBUG_TOOLS
|
||||||
|
|
||||||
static const char* DebugNodeTableGetSizingPolicyDesc(ImGuiTableFlags sizing_policy)
|
static const char* DebugNodeTableGetSizingPolicyDesc(ImGuiTableFlags sizing_policy)
|
||||||
{
|
{
|
||||||
|
@ -3511,6 +3553,8 @@ void ImGui::DebugNodeTable(ImGuiTable* table)
|
||||||
GetForegroundDrawList()->AddRect(GetItemRectMin(), GetItemRectMax(), IM_COL32(255, 255, 0, 255));
|
GetForegroundDrawList()->AddRect(GetItemRectMin(), GetItemRectMax(), IM_COL32(255, 255, 0, 255));
|
||||||
if (!open)
|
if (!open)
|
||||||
return;
|
return;
|
||||||
|
if (table->InstanceCurrent > 0)
|
||||||
|
ImGui::Text("** %d instances of same table! Some data below will refer to last instance.", table->InstanceCurrent + 1);
|
||||||
bool clear_settings = SmallButton("Clear settings");
|
bool clear_settings = SmallButton("Clear settings");
|
||||||
BulletText("OuterRect: Pos: (%.1f,%.1f) Size: (%.1f,%.1f) Sizing: '%s'", table->OuterRect.Min.x, table->OuterRect.Min.y, table->OuterRect.GetWidth(), table->OuterRect.GetHeight(), DebugNodeTableGetSizingPolicyDesc(table->Flags));
|
BulletText("OuterRect: Pos: (%.1f,%.1f) Size: (%.1f,%.1f) Sizing: '%s'", table->OuterRect.Min.x, table->OuterRect.Min.y, table->OuterRect.GetWidth(), table->OuterRect.GetHeight(), DebugNodeTableGetSizingPolicyDesc(table->Flags));
|
||||||
BulletText("ColumnsGivenWidth: %.1f, ColumnsAutoFitWidth: %.1f, InnerWidth: %.1f%s", table->ColumnsGivenWidth, table->ColumnsAutoFitWidth, table->InnerWidth, table->InnerWidth == 0.0f ? " (auto)" : "");
|
BulletText("ColumnsGivenWidth: %.1f, ColumnsAutoFitWidth: %.1f, InnerWidth: %.1f%s", table->ColumnsGivenWidth, table->ColumnsAutoFitWidth, table->InnerWidth, table->InnerWidth == 0.0f ? " (auto)" : "");
|
||||||
|
@ -3575,7 +3619,7 @@ void ImGui::DebugNodeTableSettings(ImGuiTableSettings* settings)
|
||||||
TreePop();
|
TreePop();
|
||||||
}
|
}
|
||||||
|
|
||||||
#else // #ifndef IMGUI_DISABLE_METRICS_WINDOW
|
#else // #ifndef IMGUI_DISABLE_DEBUG_TOOLS
|
||||||
|
|
||||||
void ImGui::DebugNodeTable(ImGuiTable*) {}
|
void ImGui::DebugNodeTable(ImGuiTable*) {}
|
||||||
void ImGui::DebugNodeTableSettings(ImGuiTableSettings*) {}
|
void ImGui::DebugNodeTableSettings(ImGuiTableSettings*) {}
|
||||||
|
@ -3915,6 +3959,7 @@ void ImGui::NextColumn()
|
||||||
{
|
{
|
||||||
// New row/line: column 0 honor IndentX.
|
// New row/line: column 0 honor IndentX.
|
||||||
window->DC.ColumnsOffset.x = ImMax(column_padding - window->WindowPadding.x, 0.0f);
|
window->DC.ColumnsOffset.x = ImMax(column_padding - window->WindowPadding.x, 0.0f);
|
||||||
|
window->DC.IsSameLine = false;
|
||||||
columns->LineMinY = columns->LineMaxY;
|
columns->LineMinY = columns->LineMaxY;
|
||||||
}
|
}
|
||||||
window->DC.CursorPos.x = IM_FLOOR(window->Pos.x + window->DC.Indent.x + window->DC.ColumnsOffset.x);
|
window->DC.CursorPos.x = IM_FLOOR(window->Pos.x + window->DC.Indent.x + window->DC.ColumnsOffset.x);
|
||||||
|
@ -3967,7 +4012,7 @@ void ImGui::EndColumns()
|
||||||
const float column_hit_hw = COLUMNS_HIT_RECT_HALF_WIDTH;
|
const float column_hit_hw = COLUMNS_HIT_RECT_HALF_WIDTH;
|
||||||
const ImRect column_hit_rect(ImVec2(x - column_hit_hw, y1), ImVec2(x + column_hit_hw, y2));
|
const ImRect column_hit_rect(ImVec2(x - column_hit_hw, y1), ImVec2(x + column_hit_hw, y2));
|
||||||
KeepAliveID(column_id);
|
KeepAliveID(column_id);
|
||||||
if (IsClippedEx(column_hit_rect, column_id, false))
|
if (IsClippedEx(column_hit_rect, column_id)) // FIXME: Can be removed or replaced with a lower-level test
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
bool hovered = false, held = false;
|
bool hovered = false, held = false;
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,338 +0,0 @@
|
||||||
// dear imgui: Platform Binding 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:
|
|
||||||
// [?] Platform: Clipboard support
|
|
||||||
// [?] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'.
|
|
||||||
// [?] Platform: Keyboard arrays indexed using
|
|
||||||
// [?] Platform: Gamepad support. Enabled with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'.
|
|
||||||
|
|
||||||
#include "imgui.h"
|
|
||||||
#include "imgui_impl_x11.h"
|
|
||||||
|
|
||||||
#include <X11/X.h>
|
|
||||||
#include <X11/Xlib.h>
|
|
||||||
#include <X11/keysym.h>
|
|
||||||
#include <GL/glew.h>
|
|
||||||
|
|
||||||
#include <ctime>
|
|
||||||
|
|
||||||
// CHANGELOG
|
|
||||||
// (minor and older changes stripped away, please see git history for details)
|
|
||||||
// 2019-08-31: Initial X11 implementation
|
|
||||||
|
|
||||||
// X11 Data
|
|
||||||
static Display* g_Display = nullptr;
|
|
||||||
static Window g_Window = 0;
|
|
||||||
static uint64_t g_Time = 0;
|
|
||||||
static uint64_t g_TicksPerSecond = 0;
|
|
||||||
static ImGuiMouseCursor g_LastMouseCursor = ImGuiMouseCursor_COUNT;
|
|
||||||
static bool g_HasGamepad = false;
|
|
||||||
static bool g_WantUpdateHasGamepad = true;
|
|
||||||
|
|
||||||
bool GetKeyState(int keysym, char keys[32])
|
|
||||||
{
|
|
||||||
int keycode = XKeysymToKeycode(g_Display, keysym);
|
|
||||||
return keys[keycode/8] & (1<<keycode%8);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool IsKeySys(int key)
|
|
||||||
{
|
|
||||||
switch(key)
|
|
||||||
{
|
|
||||||
case XK_Shift_L : case XK_Shift_R :
|
|
||||||
case XK_Control_L: case XK_Control_R :
|
|
||||||
case XK_Alt_L : case XK_Alt_R :
|
|
||||||
case XK_Super_L : case XK_Super_R :
|
|
||||||
case XK_Caps_Lock: case XK_Shift_Lock:
|
|
||||||
case XK_BackSpace: case XK_Delete :
|
|
||||||
case XK_Left : case XK_Right :
|
|
||||||
case XK_Up : case XK_Down :
|
|
||||||
case XK_Prior : case XK_Next :
|
|
||||||
case XK_Home : case XK_End :
|
|
||||||
case XK_Insert : case XK_Return :
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Functions
|
|
||||||
bool ImGui_ImplX11_Init(void *display, void *window)
|
|
||||||
{
|
|
||||||
timespec ts, tsres;
|
|
||||||
clock_getres(CLOCK_MONOTONIC_RAW, &tsres);
|
|
||||||
clock_gettime(CLOCK_MONOTONIC_RAW, &ts);
|
|
||||||
|
|
||||||
g_TicksPerSecond = 1000000000.0f / (static_cast<uint64_t>(tsres.tv_nsec) + static_cast<uint64_t>(tsres.tv_sec)*1000000000);
|
|
||||||
g_Time = static_cast<uint64_t>(ts.tv_nsec) + static_cast<uint64_t>(ts.tv_sec)*1000000000;
|
|
||||||
|
|
||||||
//if (!::QueryPerformanceFrequency((LARGE_INTEGER *)&g_TicksPerSecond))
|
|
||||||
// return false;
|
|
||||||
//if (!::QueryPerformanceCounter((LARGE_INTEGER *)&g_Time))
|
|
||||||
// return false;
|
|
||||||
|
|
||||||
// Setup back-end capabilities flags
|
|
||||||
g_Display = reinterpret_cast<Display*>(display);
|
|
||||||
g_Window = reinterpret_cast<Window>(window);
|
|
||||||
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_x11";
|
|
||||||
io.ImeWindowHandle = nullptr;
|
|
||||||
|
|
||||||
// Keyboard mapping. ImGui will use those indices to peek into the io.KeysDown[] array that we will update during the application lifetime.
|
|
||||||
io.KeyMap[ImGuiKey_Tab] = XKeysymToKeycode(g_Display, XK_Tab);
|
|
||||||
io.KeyMap[ImGuiKey_LeftArrow] = XKeysymToKeycode(g_Display, XK_Left);
|
|
||||||
io.KeyMap[ImGuiKey_RightArrow] = XKeysymToKeycode(g_Display, XK_Right);
|
|
||||||
io.KeyMap[ImGuiKey_UpArrow] = XKeysymToKeycode(g_Display, XK_Up);
|
|
||||||
io.KeyMap[ImGuiKey_DownArrow] = XKeysymToKeycode(g_Display, XK_Down);
|
|
||||||
io.KeyMap[ImGuiKey_PageUp] = XKeysymToKeycode(g_Display, XK_Prior);
|
|
||||||
io.KeyMap[ImGuiKey_PageDown] = XKeysymToKeycode(g_Display, XK_Next);
|
|
||||||
io.KeyMap[ImGuiKey_Home] = XKeysymToKeycode(g_Display, XK_Home);
|
|
||||||
io.KeyMap[ImGuiKey_End] = XKeysymToKeycode(g_Display, XK_End);
|
|
||||||
io.KeyMap[ImGuiKey_Insert] = XKeysymToKeycode(g_Display, XK_Insert);
|
|
||||||
io.KeyMap[ImGuiKey_Delete] = XKeysymToKeycode(g_Display, XK_Delete);
|
|
||||||
io.KeyMap[ImGuiKey_Backspace] = XKeysymToKeycode(g_Display, XK_BackSpace);
|
|
||||||
io.KeyMap[ImGuiKey_Space] = XKeysymToKeycode(g_Display, XK_space);
|
|
||||||
io.KeyMap[ImGuiKey_Enter] = XKeysymToKeycode(g_Display, XK_Return);
|
|
||||||
io.KeyMap[ImGuiKey_Escape] = XKeysymToKeycode(g_Display, XK_Escape);
|
|
||||||
io.KeyMap[ImGuiKey_A] = XKeysymToKeycode(g_Display, XK_A);
|
|
||||||
io.KeyMap[ImGuiKey_C] = XKeysymToKeycode(g_Display, XK_C);
|
|
||||||
io.KeyMap[ImGuiKey_V] = XKeysymToKeycode(g_Display, XK_V);
|
|
||||||
io.KeyMap[ImGuiKey_X] = XKeysymToKeycode(g_Display, XK_X);
|
|
||||||
io.KeyMap[ImGuiKey_Y] = XKeysymToKeycode(g_Display, XK_Y);
|
|
||||||
io.KeyMap[ImGuiKey_Z] = XKeysymToKeycode(g_Display, XK_Z);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ImGui_ImplX11_Shutdown()
|
|
||||||
{
|
|
||||||
g_Display = nullptr;
|
|
||||||
g_Window = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool ImGui_ImplX11_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;
|
|
||||||
}
|
|
||||||
::SetCursor(::LoadCursor(NULL, win32_cursor));
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void ImGui_ImplX11_UpdateMousePos()
|
|
||||||
{
|
|
||||||
ImGuiIO& io = ImGui::GetIO();
|
|
||||||
|
|
||||||
// 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 };
|
|
||||||
// ::ClientToScreen(g_hWnd, &pos);
|
|
||||||
// ::SetCursorPos(pos.x, pos.y);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set mouse position
|
|
||||||
Window unused_window;
|
|
||||||
int rx, ry, x, y;
|
|
||||||
unsigned int mask;
|
|
||||||
|
|
||||||
XQueryPointer(g_Display, g_Window, &unused_window, &unused_window, &rx, &ry, &x, &y, &mask);
|
|
||||||
|
|
||||||
io.MousePos = ImVec2((float)x, (float)y);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Gamepad navigation mapping
|
|
||||||
static void ImGui_ImplX11_UpdateGamepads()
|
|
||||||
{
|
|
||||||
/* TODO: support linux 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 = (XInputGetCapabilities(0, XINPUT_FLAG_GAMEPAD, &caps) == ERROR_SUCCESS);
|
|
||||||
g_WantUpdateHasGamepad = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
XINPUT_STATE xinput_state;
|
|
||||||
io.BackendFlags &= ~ImGuiBackendFlags_HasGamepad;
|
|
||||||
if (g_HasGamepad && 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
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
|
|
||||||
void ImGui_ImplX11_NewFrame()
|
|
||||||
{
|
|
||||||
ImGuiIO& io = ImGui::GetIO();
|
|
||||||
IM_ASSERT(io.Fonts->IsBuilt() && "Font atlas not built! It is generally built by the renderer back-end. Missing call to renderer _NewFrame() function? e.g. ImGui_ImplOpenGL3_NewFrame().");
|
|
||||||
|
|
||||||
unsigned int width, height;
|
|
||||||
Window unused_window;
|
|
||||||
int unused_int;
|
|
||||||
unsigned int unused_unsigned_int;
|
|
||||||
|
|
||||||
XGetGeometry(g_Display, (Window)g_Window, &unused_window, &unused_int, &unused_int, &width, &height, &unused_unsigned_int, &unused_unsigned_int);
|
|
||||||
|
|
||||||
io.DisplaySize.x = width;
|
|
||||||
io.DisplaySize.y = height;
|
|
||||||
|
|
||||||
timespec ts, tsres;
|
|
||||||
clock_gettime(CLOCK_MONOTONIC_RAW, &ts);
|
|
||||||
|
|
||||||
uint64_t current_time = static_cast<uint64_t>(ts.tv_nsec) + static_cast<uint64_t>(ts.tv_sec)*1000000000;
|
|
||||||
|
|
||||||
io.DeltaTime = (float)(current_time - g_Time) / g_TicksPerSecond;
|
|
||||||
g_Time = current_time;
|
|
||||||
|
|
||||||
// Read keyboard modifiers inputs
|
|
||||||
char keys[32];
|
|
||||||
XQueryKeymap(g_Display, keys);
|
|
||||||
|
|
||||||
io.KeyCtrl = GetKeyState(XK_Control_L, keys);
|
|
||||||
io.KeyShift = GetKeyState(XK_Shift_L, keys);
|
|
||||||
io.KeyAlt = GetKeyState(XK_Alt_L, keys);
|
|
||||||
io.KeySuper = false;
|
|
||||||
// io.KeysDown[], io.MousePos, io.MouseDown[], io.MouseWheel: filled by the WndProc handler below.
|
|
||||||
|
|
||||||
// Update OS mouse position
|
|
||||||
ImGui_ImplX11_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_ImplX11_UpdateMouseCursor();
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Update game controllers (if enabled and available)
|
|
||||||
ImGui_ImplX11_UpdateGamepads();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Process X11 mouse/keyboard inputs.
|
|
||||||
// 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.
|
|
||||||
IMGUI_IMPL_API int ImGui_ImplX11_EventHandler(XEvent &event)
|
|
||||||
{
|
|
||||||
if (ImGui::GetCurrentContext() == NULL)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
ImGuiIO& io = ImGui::GetIO();
|
|
||||||
switch (event.type)
|
|
||||||
{
|
|
||||||
case ButtonPress:
|
|
||||||
case ButtonRelease:
|
|
||||||
switch(event.xbutton.button)
|
|
||||||
{
|
|
||||||
case Button1:
|
|
||||||
io.MouseDown[0] = event.type == ButtonPress;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case Button2:
|
|
||||||
io.MouseDown[2] = event.type == ButtonPress;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case Button3:
|
|
||||||
io.MouseDown[1] = event.type == ButtonPress;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case Button4: // Mouse wheel up
|
|
||||||
if( event.type == ButtonPress )
|
|
||||||
io.MouseWheel += 1;
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
case Button5: // Mouse wheel down
|
|
||||||
if( event.type == ButtonPress )
|
|
||||||
io.MouseWheel -= 1;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
case KeyPress:
|
|
||||||
{
|
|
||||||
int key = XKeycodeToKeysym(g_Display, event.xkey.keycode, event.xkey.state & ShiftMask ? 1 : 0);
|
|
||||||
if( IsKeySys(key) )
|
|
||||||
io.KeysDown[event.xkey.keycode] = true;
|
|
||||||
else
|
|
||||||
io.AddInputCharacter(key);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
case KeyRelease:
|
|
||||||
{
|
|
||||||
int key = XKeycodeToKeysym(g_Display, event.xkey.keycode, event.xkey.state & ShiftMask ? 1 : 0);
|
|
||||||
if( IsKeySys(key) )
|
|
||||||
io.KeysDown[event.xkey.keycode] = false;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
case WM_DEVICECHANGE:
|
|
||||||
if ((UINT)wParam == DBT_DEVNODES_CHANGED)
|
|
||||||
g_WantUpdateHasGamepad = true;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,21 +0,0 @@
|
||||||
// dear imgui: Platform Binding 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 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'.
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
IMGUI_IMPL_API bool ImGui_ImplX11_Init(void* display, void* window);
|
|
||||||
IMGUI_IMPL_API void ImGui_ImplX11_Shutdown();
|
|
||||||
IMGUI_IMPL_API void ImGui_ImplX11_NewFrame();
|
|
||||||
|
|
||||||
// Handler for Win32 messages, update mouse/keyboard data.
|
|
||||||
// You may or not need this for your implementation, but it can serve as reference for handling inputs.
|
|
||||||
// Intentionally commented out to avoid dragging dependencies on <windows.h> types. You can COPY this line into your .cpp code instead.
|
|
||||||
/*
|
|
||||||
IMGUI_IMPL_API int ImGui_ImplX11_EventHandler(XEvent *event);
|
|
||||||
*/
|
|
|
@ -1,543 +0,0 @@
|
||||||
// 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 use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
|
||||||
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
|
|
||||||
// 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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//---------------------------------------------------------------------------------------------------------
|
|
|
@ -1,90 +0,0 @@
|
||||||
#ifndef __IMGUI_SHADER_BLOBS_INCLUDED__
|
|
||||||
#define __IMGUI_SHADER_BLOBS_INCLUDED__
|
|
||||||
|
|
||||||
////// Vertex Shaders //////
|
|
||||||
|
|
||||||
#define ImGui_vertexShaderDX10_len 876
|
|
||||||
extern unsigned char ImGui_vertexShaderDX10[ImGui_vertexShaderDX10_len];
|
|
||||||
|
|
||||||
#define ImGui_vertexShaderDX11_len 1104
|
|
||||||
extern unsigned char ImGui_vertexShaderDX11[ImGui_vertexShaderDX11_len];
|
|
||||||
|
|
||||||
#define ImGui_vertexShaderDX11_9_1_len 1104
|
|
||||||
extern unsigned char ImGui_vertexShaderDX11_9_1[ImGui_vertexShaderDX11_9_1_len];
|
|
||||||
|
|
||||||
#define ImGui_vertexShaderDX11_9_2_len ImGui_vertexShaderDX11_9_1_len
|
|
||||||
#define ImGui_vertexShaderDX11_9_2 ImGui_vertexShaderDX11_9_1
|
|
||||||
|
|
||||||
#define ImGui_vertexShaderDX11_9_3_len 1104
|
|
||||||
extern unsigned char ImGui_vertexShaderDX11_9_3[ImGui_vertexShaderDX11_9_3_len];
|
|
||||||
|
|
||||||
// DX11_10_0 is identical to DX10
|
|
||||||
#define ImGui_vertexShaderDX11_10_0_len ImGui_vertexShaderDX10_len
|
|
||||||
#define ImGui_vertexShaderDX11_10_0 ImGui_vertexShaderDX10
|
|
||||||
|
|
||||||
#define ImGui_vertexShaderDX11_10_1_len 880
|
|
||||||
extern unsigned char ImGui_vertexShaderDX11_10_1[ImGui_vertexShaderDX11_10_1_len];
|
|
||||||
|
|
||||||
#define ImGui_vertexShaderDX11_11_0_len 988
|
|
||||||
extern unsigned char ImGui_vertexShaderDX11_11_0[ImGui_vertexShaderDX11_11_0_len];
|
|
||||||
|
|
||||||
// DX11_11_1 is identical to DX11_11_0
|
|
||||||
#define ImGui_vertexShaderDX11_11_1_len ImGui_vertexShaderDX11_11_0_len
|
|
||||||
#define ImGui_vertexShaderDX11_11_1 ImGui_vertexShaderDX11_11_0
|
|
||||||
|
|
||||||
// DX11_12_0 is identical to DX11_11_0
|
|
||||||
#define ImGui_vertexShaderDX11_12_0_len ImGui_vertexShaderDX11_11_0_len
|
|
||||||
#define ImGui_vertexShaderDX11_12_0 ImGui_vertexShaderDX11_11_0
|
|
||||||
|
|
||||||
// DX11_12_1 is identical to DX11_11_0
|
|
||||||
#define ImGui_vertexShaderDX11_12_1_len ImGui_vertexShaderDX11_11_0_len
|
|
||||||
#define ImGui_vertexShaderDX11_12_1 ImGui_vertexShaderDX11_11_0
|
|
||||||
|
|
||||||
// DX12 is identical to DX11_11_0
|
|
||||||
#define ImGui_vertexShaderDX12_len ImGui_vertexShaderDX11_11_0_len
|
|
||||||
#define ImGui_vertexShaderDX12 ImGui_vertexShaderDX11_11_0
|
|
||||||
|
|
||||||
////// Pixel Shaders //////
|
|
||||||
|
|
||||||
#define ImGui_pixelShaderDX10_len 660
|
|
||||||
extern unsigned char ImGui_pixelShaderDX10[ImGui_pixelShaderDX10_len];
|
|
||||||
|
|
||||||
#define ImGui_pixelShaderDX11_len 1104
|
|
||||||
extern unsigned char ImGui_pixelShaderDX11[ImGui_pixelShaderDX11_len];
|
|
||||||
|
|
||||||
#define ImGui_pixelShaderDX11_9_1_len 800
|
|
||||||
extern unsigned char ImGui_pixelShaderDX11_9_1[ImGui_pixelShaderDX11_9_1_len];
|
|
||||||
|
|
||||||
#define ImGui_pixelShaderDX11_9_2_len ImGui_pixelShaderDX11_9_1_len
|
|
||||||
#define ImGui_pixelShaderDX11_9_2 ImGui_pixelShaderDX11_9_1
|
|
||||||
|
|
||||||
#define ImGui_pixelShaderDX11_9_3_len 800
|
|
||||||
extern unsigned char ImGui_pixelShaderDX11_9_3[ImGui_pixelShaderDX11_9_3_len];
|
|
||||||
|
|
||||||
// DX11_10_0 is identical to DX10
|
|
||||||
#define ImGui_pixelShaderDX11_10_0_len ImGui_pixelShaderDX10_len
|
|
||||||
#define ImGui_pixelShaderDX11_10_0 ImGui_pixelShaderDX10
|
|
||||||
|
|
||||||
#define ImGui_pixelShaderDX11_10_1_len 664
|
|
||||||
extern unsigned char ImGui_pixelShaderDX11_10_1[ImGui_pixelShaderDX11_10_1_len];
|
|
||||||
|
|
||||||
#define ImGui_pixelShaderDX11_11_0_len 736
|
|
||||||
extern unsigned char ImGui_pixelShaderDX11_11_0[ImGui_pixelShaderDX11_11_0_len];
|
|
||||||
|
|
||||||
// DX11_11_1 is identical to DX11_11_0
|
|
||||||
#define ImGui_pixelShaderDX11_11_1_len ImGui_pixelShaderDX11_11_0_len
|
|
||||||
#define ImGui_pixelShaderDX11_11_1 ImGui_pixelShaderDX11_11_0
|
|
||||||
|
|
||||||
// DX11_12_0 is identical to DX11_11_0
|
|
||||||
#define ImGui_pixelShaderDX11_12_0_len ImGui_pixelShaderDX11_11_0_len
|
|
||||||
#define ImGui_pixelShaderDX11_12_0 ImGui_pixelShaderDX11_11_0
|
|
||||||
|
|
||||||
// DX11_12_1 is identical to DX11_11_0
|
|
||||||
#define ImGui_pixelShaderDX11_12_1_len ImGui_pixelShaderDX11_11_0_len
|
|
||||||
#define ImGui_pixelShaderDX11_12_1 ImGui_pixelShaderDX11_11_0
|
|
||||||
|
|
||||||
// DX12 is identical to DX11_11_0
|
|
||||||
#define ImGui_pixelShaderDX12_len ImGui_pixelShaderDX11_11_0_len
|
|
||||||
#define ImGui_pixelShaderDX12 ImGui_pixelShaderDX11_11_0
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,15 +1,19 @@
|
||||||
// [DEAR IMGUI]
|
// [DEAR IMGUI]
|
||||||
// This is a slightly modified version of stb_rect_pack.h 1.00.
|
// This is a slightly modified version of stb_rect_pack.h 1.01.
|
||||||
// Those changes would need to be pushed into nothings/stb:
|
|
||||||
// - Added STBRP__CDECL
|
|
||||||
// Grep for [DEAR IMGUI] to find the changes.
|
// Grep for [DEAR IMGUI] to find the changes.
|
||||||
|
//
|
||||||
// stb_rect_pack.h - v1.00 - public domain - rectangle packing
|
// stb_rect_pack.h - v1.01 - public domain - rectangle packing
|
||||||
// Sean Barrett 2014
|
// Sean Barrett 2014
|
||||||
//
|
//
|
||||||
// Useful for e.g. packing rectangular textures into an atlas.
|
// Useful for e.g. packing rectangular textures into an atlas.
|
||||||
// Does not do rotation.
|
// Does not do rotation.
|
||||||
//
|
//
|
||||||
|
// Before #including,
|
||||||
|
//
|
||||||
|
// #define STB_RECT_PACK_IMPLEMENTATION
|
||||||
|
//
|
||||||
|
// in the file that you want to have the implementation.
|
||||||
|
//
|
||||||
// Not necessarily the awesomest packing method, but better than
|
// Not necessarily the awesomest packing method, but better than
|
||||||
// the totally naive one in stb_truetype (which is primarily what
|
// the totally naive one in stb_truetype (which is primarily what
|
||||||
// this is meant to replace).
|
// this is meant to replace).
|
||||||
|
@ -41,6 +45,7 @@
|
||||||
//
|
//
|
||||||
// Version history:
|
// Version history:
|
||||||
//
|
//
|
||||||
|
// 1.01 (2021-07-11) always use large rect mode, expose STBRP__MAXVAL in public section
|
||||||
// 1.00 (2019-02-25) avoid small space waste; gracefully fail too-wide rectangles
|
// 1.00 (2019-02-25) avoid small space waste; gracefully fail too-wide rectangles
|
||||||
// 0.99 (2019-02-07) warning fixes
|
// 0.99 (2019-02-07) warning fixes
|
||||||
// 0.11 (2017-03-03) return packing success/fail result
|
// 0.11 (2017-03-03) return packing success/fail result
|
||||||
|
@ -81,11 +86,10 @@ typedef struct stbrp_context stbrp_context;
|
||||||
typedef struct stbrp_node stbrp_node;
|
typedef struct stbrp_node stbrp_node;
|
||||||
typedef struct stbrp_rect stbrp_rect;
|
typedef struct stbrp_rect stbrp_rect;
|
||||||
|
|
||||||
#ifdef STBRP_LARGE_RECTS
|
|
||||||
typedef int stbrp_coord;
|
typedef int stbrp_coord;
|
||||||
#else
|
|
||||||
typedef unsigned short stbrp_coord;
|
#define STBRP__MAXVAL 0x7fffffff
|
||||||
#endif
|
// Mostly for internal use, but this is the maximum supported coordinate value.
|
||||||
|
|
||||||
STBRP_DEF int stbrp_pack_rects (stbrp_context *context, stbrp_rect *rects, int num_rects);
|
STBRP_DEF int stbrp_pack_rects (stbrp_context *context, stbrp_rect *rects, int num_rects);
|
||||||
// Assign packed locations to rectangles. The rectangles are of type
|
// Assign packed locations to rectangles. The rectangles are of type
|
||||||
|
@ -213,7 +217,6 @@ struct stbrp_context
|
||||||
#define STBRP_ASSERT assert
|
#define STBRP_ASSERT assert
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// [DEAR IMGUI] Added STBRP__CDECL
|
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
#define STBRP__NOTUSED(v) (void)(v)
|
#define STBRP__NOTUSED(v) (void)(v)
|
||||||
#define STBRP__CDECL __cdecl
|
#define STBRP__CDECL __cdecl
|
||||||
|
@ -262,9 +265,6 @@ STBRP_DEF void stbrp_setup_allow_out_of_mem(stbrp_context *context, int allow_ou
|
||||||
STBRP_DEF void stbrp_init_target(stbrp_context *context, int width, int height, stbrp_node *nodes, int num_nodes)
|
STBRP_DEF void stbrp_init_target(stbrp_context *context, int width, int height, stbrp_node *nodes, int num_nodes)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
#ifndef STBRP_LARGE_RECTS
|
|
||||||
STBRP_ASSERT(width <= 0xffff && height <= 0xffff);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
for (i=0; i < num_nodes-1; ++i)
|
for (i=0; i < num_nodes-1; ++i)
|
||||||
nodes[i].next = &nodes[i+1];
|
nodes[i].next = &nodes[i+1];
|
||||||
|
@ -283,11 +283,7 @@ STBRP_DEF void stbrp_init_target(stbrp_context *context, int width, int height,
|
||||||
context->extra[0].y = 0;
|
context->extra[0].y = 0;
|
||||||
context->extra[0].next = &context->extra[1];
|
context->extra[0].next = &context->extra[1];
|
||||||
context->extra[1].x = (stbrp_coord) width;
|
context->extra[1].x = (stbrp_coord) width;
|
||||||
#ifdef STBRP_LARGE_RECTS
|
|
||||||
context->extra[1].y = (1<<30);
|
context->extra[1].y = (1<<30);
|
||||||
#else
|
|
||||||
context->extra[1].y = 65535;
|
|
||||||
#endif
|
|
||||||
context->extra[1].next = NULL;
|
context->extra[1].next = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -433,7 +429,7 @@ static stbrp__findresult stbrp__skyline_find_best_pos(stbrp_context *c, int widt
|
||||||
if (y <= best_y) {
|
if (y <= best_y) {
|
||||||
if (y < best_y || waste < best_waste || (waste==best_waste && xpos < best_x)) {
|
if (y < best_y || waste < best_waste || (waste==best_waste && xpos < best_x)) {
|
||||||
best_x = xpos;
|
best_x = xpos;
|
||||||
STBRP_ASSERT(y <= best_y);
|
//STBRP_ASSERT(y <= best_y); [DEAR IMGUI]
|
||||||
best_y = y;
|
best_y = y;
|
||||||
best_waste = waste;
|
best_waste = waste;
|
||||||
best = prev;
|
best = prev;
|
||||||
|
@ -529,7 +525,6 @@ static stbrp__findresult stbrp__skyline_pack_rectangle(stbrp_context *context, i
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
// [DEAR IMGUI] Added STBRP__CDECL
|
|
||||||
static int STBRP__CDECL rect_height_compare(const void *a, const void *b)
|
static int STBRP__CDECL rect_height_compare(const void *a, const void *b)
|
||||||
{
|
{
|
||||||
const stbrp_rect *p = (const stbrp_rect *) a;
|
const stbrp_rect *p = (const stbrp_rect *) a;
|
||||||
|
@ -541,7 +536,6 @@ static int STBRP__CDECL rect_height_compare(const void *a, const void *b)
|
||||||
return (p->w > q->w) ? -1 : (p->w < q->w);
|
return (p->w > q->w) ? -1 : (p->w < q->w);
|
||||||
}
|
}
|
||||||
|
|
||||||
// [DEAR IMGUI] Added STBRP__CDECL
|
|
||||||
static int STBRP__CDECL rect_original_order(const void *a, const void *b)
|
static int STBRP__CDECL rect_original_order(const void *a, const void *b)
|
||||||
{
|
{
|
||||||
const stbrp_rect *p = (const stbrp_rect *) a;
|
const stbrp_rect *p = (const stbrp_rect *) a;
|
||||||
|
@ -549,12 +543,6 @@ static int STBRP__CDECL rect_original_order(const void *a, const void *b)
|
||||||
return (p->was_packed < q->was_packed) ? -1 : (p->was_packed > q->was_packed);
|
return (p->was_packed < q->was_packed) ? -1 : (p->was_packed > q->was_packed);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef STBRP_LARGE_RECTS
|
|
||||||
#define STBRP__MAXVAL 0xffffffff
|
|
||||||
#else
|
|
||||||
#define STBRP__MAXVAL 0xffff
|
|
||||||
#endif
|
|
||||||
|
|
||||||
STBRP_DEF int stbrp_pack_rects(stbrp_context *context, stbrp_rect *rects, int num_rects)
|
STBRP_DEF int stbrp_pack_rects(stbrp_context *context, stbrp_rect *rects, int num_rects)
|
||||||
{
|
{
|
||||||
int i, all_rects_packed = 1;
|
int i, all_rects_packed = 1;
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
// [DEAR IMGUI]
|
// [DEAR IMGUI]
|
||||||
// This is a slightly modified version of stb_textedit.h 1.13.
|
// This is a slightly modified version of stb_textedit.h 1.14.
|
||||||
// Those changes would need to be pushed into nothings/stb:
|
// Those changes would need to be pushed into nothings/stb:
|
||||||
// - Fix in stb_textedit_discard_redo (see https://github.com/nothings/stb/issues/321)
|
// - Fix in stb_textedit_discard_redo (see https://github.com/nothings/stb/issues/321)
|
||||||
// Grep for [DEAR IMGUI] to find the changes.
|
// Grep for [DEAR IMGUI] to find the changes.
|
||||||
|
|
||||||
// stb_textedit.h - v1.13 - public domain - Sean Barrett
|
// stb_textedit.h - v1.14 - public domain - Sean Barrett
|
||||||
// Development of this library was sponsored by RAD Game Tools
|
// Development of this library was sponsored by RAD Game Tools
|
||||||
//
|
//
|
||||||
// This C header file implements the guts of a multi-line text-editing
|
// This C header file implements the guts of a multi-line text-editing
|
||||||
|
@ -35,6 +35,7 @@
|
||||||
//
|
//
|
||||||
// VERSION HISTORY
|
// VERSION HISTORY
|
||||||
//
|
//
|
||||||
|
// 1.14 (2021-07-11) page up/down, various fixes
|
||||||
// 1.13 (2019-02-07) fix bug in undo size management
|
// 1.13 (2019-02-07) fix bug in undo size management
|
||||||
// 1.12 (2018-01-29) user can change STB_TEXTEDIT_KEYTYPE, fix redo to avoid crash
|
// 1.12 (2018-01-29) user can change STB_TEXTEDIT_KEYTYPE, fix redo to avoid crash
|
||||||
// 1.11 (2017-03-03) fix HOME on last line, dragging off single-line textfield
|
// 1.11 (2017-03-03) fix HOME on last line, dragging off single-line textfield
|
||||||
|
@ -58,6 +59,7 @@
|
||||||
// Ulf Winklemann: move-by-word in 1.1
|
// Ulf Winklemann: move-by-word in 1.1
|
||||||
// Fabian Giesen: secondary key inputs in 1.5
|
// Fabian Giesen: secondary key inputs in 1.5
|
||||||
// Martins Mozeiko: STB_TEXTEDIT_memmove in 1.6
|
// Martins Mozeiko: STB_TEXTEDIT_memmove in 1.6
|
||||||
|
// Louis Schnellbach: page up/down in 1.14
|
||||||
//
|
//
|
||||||
// Bugfixes:
|
// Bugfixes:
|
||||||
// Scott Graham
|
// Scott Graham
|
||||||
|
@ -93,8 +95,8 @@
|
||||||
// moderate sizes. The undo system does no memory allocations, so
|
// moderate sizes. The undo system does no memory allocations, so
|
||||||
// it grows STB_TexteditState by the worst-case storage which is (in bytes):
|
// it grows STB_TexteditState by the worst-case storage which is (in bytes):
|
||||||
//
|
//
|
||||||
// [4 + 3 * sizeof(STB_TEXTEDIT_POSITIONTYPE)] * STB_TEXTEDIT_UNDOSTATE_COUNT
|
// [4 + 3 * sizeof(STB_TEXTEDIT_POSITIONTYPE)] * STB_TEXTEDIT_UNDOSTATECOUNT
|
||||||
// + sizeof(STB_TEXTEDIT_CHARTYPE) * STB_TEXTEDIT_UNDOCHAR_COUNT
|
// + sizeof(STB_TEXTEDIT_CHARTYPE) * STB_TEXTEDIT_UNDOCHARCOUNT
|
||||||
//
|
//
|
||||||
//
|
//
|
||||||
// Implementation mode:
|
// Implementation mode:
|
||||||
|
@ -716,9 +718,7 @@ static int stb_textedit_paste_internal(STB_TEXTEDIT_STRING *str, STB_TexteditSta
|
||||||
state->has_preferred_x = 0;
|
state->has_preferred_x = 0;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
// remove the undo since we didn't actually insert the characters
|
// note: paste failure will leave deleted selection, may be restored with an undo (see https://github.com/nothings/stb/issues/734 for details)
|
||||||
if (state->undostate.undo_point)
|
|
||||||
--state->undostate.undo_point;
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,19 @@
|
||||||
// [DEAR IMGUI]
|
// [DEAR IMGUI]
|
||||||
// This is a slightly modified version of stb_truetype.h 1.20.
|
// This is a slightly modified version of stb_truetype.h 1.26.
|
||||||
// Mostly fixing for compiler and static analyzer warnings.
|
// Mostly fixing for compiler and static analyzer warnings.
|
||||||
// Grep for [DEAR IMGUI] to find the changes.
|
// Grep for [DEAR IMGUI] to find the changes.
|
||||||
|
|
||||||
// stb_truetype.h - v1.20 - public domain
|
// stb_truetype.h - v1.26 - public domain
|
||||||
// authored from 2009-2016 by Sean Barrett / RAD Game Tools
|
// authored from 2009-2021 by Sean Barrett / RAD Game Tools
|
||||||
|
//
|
||||||
|
// =======================================================================
|
||||||
|
//
|
||||||
|
// NO SECURITY GUARANTEE -- DO NOT USE THIS ON UNTRUSTED FONT FILES
|
||||||
|
//
|
||||||
|
// This library does no range checking of the offsets found in the file,
|
||||||
|
// meaning an attacker can use it to read arbitrary memory.
|
||||||
|
//
|
||||||
|
// =======================================================================
|
||||||
//
|
//
|
||||||
// This library processes TrueType files:
|
// This library processes TrueType files:
|
||||||
// parse files
|
// parse files
|
||||||
|
@ -37,11 +46,11 @@
|
||||||
// Daniel Ribeiro Maciel
|
// Daniel Ribeiro Maciel
|
||||||
//
|
//
|
||||||
// Bug/warning reports/fixes:
|
// Bug/warning reports/fixes:
|
||||||
// "Zer" on mollyrocket Fabian "ryg" Giesen
|
// "Zer" on mollyrocket Fabian "ryg" Giesen github:NiLuJe
|
||||||
// Cass Everitt Martins Mozeiko
|
// Cass Everitt Martins Mozeiko github:aloucks
|
||||||
// stoiko (Haemimont Games) Cap Petschulat
|
// stoiko (Haemimont Games) Cap Petschulat github:oyvindjam
|
||||||
// Brian Hook Omar Cornut
|
// Brian Hook Omar Cornut github:vassvik
|
||||||
// Walter van Niftrik github:aloucks
|
// Walter van Niftrik Ryan Griege
|
||||||
// David Gow Peter LaValle
|
// David Gow Peter LaValle
|
||||||
// David Given Sergey Popov
|
// David Given Sergey Popov
|
||||||
// Ivan-Assen Ivanov Giumo X. Clanjor
|
// Ivan-Assen Ivanov Giumo X. Clanjor
|
||||||
|
@ -49,11 +58,17 @@
|
||||||
// Johan Duparc Thomas Fields
|
// Johan Duparc Thomas Fields
|
||||||
// Hou Qiming Derek Vinyard
|
// Hou Qiming Derek Vinyard
|
||||||
// Rob Loach Cort Stratton
|
// Rob Loach Cort Stratton
|
||||||
// Kenney Phillis Jr. github:oyvindjam
|
// Kenney Phillis Jr. Brian Costabile
|
||||||
// Brian Costabile github:vassvik
|
// Ken Voskuil (kaesve)
|
||||||
//
|
//
|
||||||
// VERSION HISTORY
|
// VERSION HISTORY
|
||||||
//
|
//
|
||||||
|
// 1.26 (2021-08-28) fix broken rasterizer
|
||||||
|
// 1.25 (2021-07-11) many fixes
|
||||||
|
// 1.24 (2020-02-05) fix warning
|
||||||
|
// 1.23 (2020-02-02) query SVG data for glyphs; query whole kerning table (but only kern not GPOS)
|
||||||
|
// 1.22 (2019-08-11) minimize missing-glyph duplication; fix kerning if both 'GPOS' and 'kern' are defined
|
||||||
|
// 1.21 (2019-02-25) fix warning
|
||||||
// 1.20 (2019-02-07) PackFontRange skips missing codepoints; GetScaleFontVMetrics()
|
// 1.20 (2019-02-07) PackFontRange skips missing codepoints; GetScaleFontVMetrics()
|
||||||
// 1.19 (2018-02-11) GPOS kerning, STBTT_fmod
|
// 1.19 (2018-02-11) GPOS kerning, STBTT_fmod
|
||||||
// 1.18 (2018-01-29) add missing function
|
// 1.18 (2018-01-29) add missing function
|
||||||
|
@ -248,19 +263,6 @@
|
||||||
// recommend it.
|
// recommend it.
|
||||||
//
|
//
|
||||||
//
|
//
|
||||||
// SOURCE STATISTICS (based on v0.6c, 2050 LOC)
|
|
||||||
//
|
|
||||||
// Documentation & header file 520 LOC \___ 660 LOC documentation
|
|
||||||
// Sample code 140 LOC /
|
|
||||||
// Truetype parsing 620 LOC ---- 620 LOC TrueType
|
|
||||||
// Software rasterization 240 LOC \.
|
|
||||||
// Curve tessellation 120 LOC \__ 550 LOC Bitmap creation
|
|
||||||
// Bitmap management 100 LOC /
|
|
||||||
// Baked bitmap interface 70 LOC /
|
|
||||||
// Font name matching & access 150 LOC ---- 150
|
|
||||||
// C runtime library abstraction 60 LOC ---- 60
|
|
||||||
//
|
|
||||||
//
|
|
||||||
// PERFORMANCE MEASUREMENTS FOR 1.06:
|
// PERFORMANCE MEASUREMENTS FOR 1.06:
|
||||||
//
|
//
|
||||||
// 32-bit 64-bit
|
// 32-bit 64-bit
|
||||||
|
@ -275,8 +277,8 @@
|
||||||
//// SAMPLE PROGRAMS
|
//// SAMPLE PROGRAMS
|
||||||
////
|
////
|
||||||
//
|
//
|
||||||
// Incomplete text-in-3d-api example, which draws quads properly aligned to be lossless
|
// Incomplete text-in-3d-api example, which draws quads properly aligned to be lossless.
|
||||||
//
|
// See "tests/truetype_demo_win32.c" for a complete version.
|
||||||
#if 0
|
#if 0
|
||||||
#define STB_TRUETYPE_IMPLEMENTATION // force following include to generate implementation
|
#define STB_TRUETYPE_IMPLEMENTATION // force following include to generate implementation
|
||||||
#include "stb_truetype.h"
|
#include "stb_truetype.h"
|
||||||
|
@ -302,6 +304,8 @@ void my_stbtt_initfont(void)
|
||||||
void my_stbtt_print(float x, float y, char *text)
|
void my_stbtt_print(float x, float y, char *text)
|
||||||
{
|
{
|
||||||
// assume orthographic projection with units = screen pixels, origin at top left
|
// assume orthographic projection with units = screen pixels, origin at top left
|
||||||
|
glEnable(GL_BLEND);
|
||||||
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||||
glEnable(GL_TEXTURE_2D);
|
glEnable(GL_TEXTURE_2D);
|
||||||
glBindTexture(GL_TEXTURE_2D, ftex);
|
glBindTexture(GL_TEXTURE_2D, ftex);
|
||||||
glBegin(GL_QUADS);
|
glBegin(GL_QUADS);
|
||||||
|
@ -309,10 +313,10 @@ void my_stbtt_print(float x, float y, char *text)
|
||||||
if (*text >= 32 && *text < 128) {
|
if (*text >= 32 && *text < 128) {
|
||||||
stbtt_aligned_quad q;
|
stbtt_aligned_quad q;
|
||||||
stbtt_GetBakedQuad(cdata, 512,512, *text-32, &x,&y,&q,1);//1=opengl & d3d10+,0=d3d9
|
stbtt_GetBakedQuad(cdata, 512,512, *text-32, &x,&y,&q,1);//1=opengl & d3d10+,0=d3d9
|
||||||
glTexCoord2f(q.s0,q.t1); glVertex2f(q.x0,q.y0);
|
glTexCoord2f(q.s0,q.t0); glVertex2f(q.x0,q.y0);
|
||||||
glTexCoord2f(q.s1,q.t1); glVertex2f(q.x1,q.y0);
|
glTexCoord2f(q.s1,q.t0); glVertex2f(q.x1,q.y0);
|
||||||
glTexCoord2f(q.s1,q.t0); glVertex2f(q.x1,q.y1);
|
glTexCoord2f(q.s1,q.t1); glVertex2f(q.x1,q.y1);
|
||||||
glTexCoord2f(q.s0,q.t0); glVertex2f(q.x0,q.y1);
|
glTexCoord2f(q.s0,q.t1); glVertex2f(q.x0,q.y1);
|
||||||
}
|
}
|
||||||
++text;
|
++text;
|
||||||
}
|
}
|
||||||
|
@ -719,7 +723,7 @@ struct stbtt_fontinfo
|
||||||
|
|
||||||
int numGlyphs; // number of glyphs, needed for range checking
|
int numGlyphs; // number of glyphs, needed for range checking
|
||||||
|
|
||||||
int loca,head,glyf,hhea,hmtx,kern,gpos; // table locations as offset from start of .ttf
|
int loca,head,glyf,hhea,hmtx,kern,gpos,svg; // table locations as offset from start of .ttf
|
||||||
int index_map; // a cmap mapping for our chosen character encoding
|
int index_map; // a cmap mapping for our chosen character encoding
|
||||||
int indexToLocFormat; // format needed to map from glyph index to glyph
|
int indexToLocFormat; // format needed to map from glyph index to glyph
|
||||||
|
|
||||||
|
@ -802,6 +806,18 @@ STBTT_DEF int stbtt_GetGlyphKernAdvance(const stbtt_fontinfo *info, int glyph1,
|
||||||
STBTT_DEF int stbtt_GetGlyphBox(const stbtt_fontinfo *info, int glyph_index, int *x0, int *y0, int *x1, int *y1);
|
STBTT_DEF int stbtt_GetGlyphBox(const stbtt_fontinfo *info, int glyph_index, int *x0, int *y0, int *x1, int *y1);
|
||||||
// as above, but takes one or more glyph indices for greater efficiency
|
// as above, but takes one or more glyph indices for greater efficiency
|
||||||
|
|
||||||
|
typedef struct stbtt_kerningentry
|
||||||
|
{
|
||||||
|
int glyph1; // use stbtt_FindGlyphIndex
|
||||||
|
int glyph2;
|
||||||
|
int advance;
|
||||||
|
} stbtt_kerningentry;
|
||||||
|
|
||||||
|
STBTT_DEF int stbtt_GetKerningTableLength(const stbtt_fontinfo *info);
|
||||||
|
STBTT_DEF int stbtt_GetKerningTable(const stbtt_fontinfo *info, stbtt_kerningentry* table, int table_length);
|
||||||
|
// Retrieves a complete list of all of the kerning pairs provided by the font
|
||||||
|
// stbtt_GetKerningTable never writes more than table_length entries and returns how many entries it did write.
|
||||||
|
// The table will be sorted by (a.glyph1 == b.glyph1)?(a.glyph2 < b.glyph2):(a.glyph1 < b.glyph1)
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
//
|
//
|
||||||
|
@ -846,6 +862,12 @@ STBTT_DEF int stbtt_GetGlyphShape(const stbtt_fontinfo *info, int glyph_index, s
|
||||||
STBTT_DEF void stbtt_FreeShape(const stbtt_fontinfo *info, stbtt_vertex *vertices);
|
STBTT_DEF void stbtt_FreeShape(const stbtt_fontinfo *info, stbtt_vertex *vertices);
|
||||||
// frees the data allocated above
|
// frees the data allocated above
|
||||||
|
|
||||||
|
STBTT_DEF unsigned char *stbtt_FindSVGDoc(const stbtt_fontinfo *info, int gl);
|
||||||
|
STBTT_DEF int stbtt_GetCodepointSVG(const stbtt_fontinfo *info, int unicode_codepoint, const char **svg);
|
||||||
|
STBTT_DEF int stbtt_GetGlyphSVG(const stbtt_fontinfo *info, int gl, const char **svg);
|
||||||
|
// fills svg with the character's SVG data.
|
||||||
|
// returns data size or 0 if SVG not found.
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
//
|
//
|
||||||
// BITMAP RENDERING
|
// BITMAP RENDERING
|
||||||
|
@ -1347,6 +1369,22 @@ static stbtt__buf stbtt__get_subrs(stbtt__buf cff, stbtt__buf fontdict)
|
||||||
return stbtt__cff_get_index(&cff);
|
return stbtt__cff_get_index(&cff);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// since most people won't use this, find this table the first time it's needed
|
||||||
|
static int stbtt__get_svg(stbtt_fontinfo *info)
|
||||||
|
{
|
||||||
|
stbtt_uint32 t;
|
||||||
|
if (info->svg < 0) {
|
||||||
|
t = stbtt__find_table(info->data, info->fontstart, "SVG ");
|
||||||
|
if (t) {
|
||||||
|
stbtt_uint32 offset = ttULONG(info->data + t + 2);
|
||||||
|
info->svg = t + offset;
|
||||||
|
} else {
|
||||||
|
info->svg = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return info->svg;
|
||||||
|
}
|
||||||
|
|
||||||
static int stbtt_InitFont_internal(stbtt_fontinfo *info, unsigned char *data, int fontstart)
|
static int stbtt_InitFont_internal(stbtt_fontinfo *info, unsigned char *data, int fontstart)
|
||||||
{
|
{
|
||||||
stbtt_uint32 cmap, t;
|
stbtt_uint32 cmap, t;
|
||||||
|
@ -1426,6 +1464,8 @@ static int stbtt_InitFont_internal(stbtt_fontinfo *info, unsigned char *data, in
|
||||||
else
|
else
|
||||||
info->numGlyphs = 0xffff;
|
info->numGlyphs = 0xffff;
|
||||||
|
|
||||||
|
info->svg = -1;
|
||||||
|
|
||||||
// find a cmap encoding table we understand *now* to avoid searching
|
// find a cmap encoding table we understand *now* to avoid searching
|
||||||
// later. (todo: could make this installable)
|
// later. (todo: could make this installable)
|
||||||
// the same regardless of glyph.
|
// the same regardless of glyph.
|
||||||
|
@ -1509,12 +1549,12 @@ STBTT_DEF int stbtt_FindGlyphIndex(const stbtt_fontinfo *info, int unicode_codep
|
||||||
search += 2;
|
search += 2;
|
||||||
|
|
||||||
{
|
{
|
||||||
stbtt_uint16 offset, start;
|
stbtt_uint16 offset, start, last;
|
||||||
stbtt_uint16 item = (stbtt_uint16) ((search - endCount) >> 1);
|
stbtt_uint16 item = (stbtt_uint16) ((search - endCount) >> 1);
|
||||||
|
|
||||||
STBTT_assert(unicode_codepoint <= ttUSHORT(data + endCount + 2*item));
|
|
||||||
start = ttUSHORT(data + index_map + 14 + segcount*2 + 2 + 2*item);
|
start = ttUSHORT(data + index_map + 14 + segcount*2 + 2 + 2*item);
|
||||||
if (unicode_codepoint < start)
|
last = ttUSHORT(data + endCount + 2*item);
|
||||||
|
if (unicode_codepoint < start || unicode_codepoint > last)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
offset = ttUSHORT(data + index_map + 14 + segcount*6 + 2 + 2*item);
|
offset = ttUSHORT(data + index_map + 14 + segcount*6 + 2 + 2*item);
|
||||||
|
@ -1774,7 +1814,7 @@ static int stbtt__GetGlyphShapeTT(const stbtt_fontinfo *info, int glyph_index, s
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
num_vertices = stbtt__close_shape(vertices, num_vertices, was_off, start_off, sx,sy,scx,scy,cx,cy);
|
num_vertices = stbtt__close_shape(vertices, num_vertices, was_off, start_off, sx,sy,scx,scy,cx,cy);
|
||||||
} else if (numberOfContours == -1) {
|
} else if (numberOfContours < 0) {
|
||||||
// Compound shapes.
|
// Compound shapes.
|
||||||
int more = 1;
|
int more = 1;
|
||||||
stbtt_uint8 *comp = data + g + 10;
|
stbtt_uint8 *comp = data + g + 10;
|
||||||
|
@ -1841,7 +1881,7 @@ static int stbtt__GetGlyphShapeTT(const stbtt_fontinfo *info, int glyph_index, s
|
||||||
if (comp_verts) STBTT_free(comp_verts, info->userdata);
|
if (comp_verts) STBTT_free(comp_verts, info->userdata);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if (num_vertices > 0) STBTT_memcpy(tmp, vertices, num_vertices*sizeof(stbtt_vertex)); //-V595
|
if (num_vertices > 0 && vertices) STBTT_memcpy(tmp, vertices, num_vertices*sizeof(stbtt_vertex));
|
||||||
STBTT_memcpy(tmp+num_vertices, comp_verts, comp_num_verts*sizeof(stbtt_vertex));
|
STBTT_memcpy(tmp+num_vertices, comp_verts, comp_num_verts*sizeof(stbtt_vertex));
|
||||||
if (vertices) STBTT_free(vertices, info->userdata);
|
if (vertices) STBTT_free(vertices, info->userdata);
|
||||||
vertices = tmp;
|
vertices = tmp;
|
||||||
|
@ -1851,9 +1891,6 @@ static int stbtt__GetGlyphShapeTT(const stbtt_fontinfo *info, int glyph_index, s
|
||||||
// More components ?
|
// More components ?
|
||||||
more = flags & (1<<5);
|
more = flags & (1<<5);
|
||||||
}
|
}
|
||||||
} else if (numberOfContours < 0) {
|
|
||||||
// @TODO other compound variations?
|
|
||||||
STBTT_assert(0);
|
|
||||||
} else {
|
} else {
|
||||||
// numberOfCounters == 0, do nothing
|
// numberOfCounters == 0, do nothing
|
||||||
}
|
}
|
||||||
|
@ -2107,7 +2144,7 @@ static int stbtt__run_charstring(const stbtt_fontinfo *info, int glyph_index, st
|
||||||
subrs = stbtt__cid_get_glyph_subrs(info, glyph_index);
|
subrs = stbtt__cid_get_glyph_subrs(info, glyph_index);
|
||||||
has_subrs = 1;
|
has_subrs = 1;
|
||||||
}
|
}
|
||||||
// fallthrough
|
// FALLTHROUGH
|
||||||
case 0x1D: // callgsubr
|
case 0x1D: // callgsubr
|
||||||
if (sp < 1) return STBTT__CSERR("call(g|)subr stack");
|
if (sp < 1) return STBTT__CSERR("call(g|)subr stack");
|
||||||
v = (int) s[--sp];
|
v = (int) s[--sp];
|
||||||
|
@ -2212,7 +2249,7 @@ static int stbtt__run_charstring(const stbtt_fontinfo *info, int glyph_index, st
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
if (b0 != 255 && b0 != 28 && (b0 < 32 || b0 > 254)) //-V560
|
if (b0 != 255 && b0 != 28 && b0 < 32)
|
||||||
return STBTT__CSERR("reserved operator");
|
return STBTT__CSERR("reserved operator");
|
||||||
|
|
||||||
// push immediate
|
// push immediate
|
||||||
|
@ -2282,6 +2319,48 @@ STBTT_DEF void stbtt_GetGlyphHMetrics(const stbtt_fontinfo *info, int glyph_inde
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
STBTT_DEF int stbtt_GetKerningTableLength(const stbtt_fontinfo *info)
|
||||||
|
{
|
||||||
|
stbtt_uint8 *data = info->data + info->kern;
|
||||||
|
|
||||||
|
// we only look at the first table. it must be 'horizontal' and format 0.
|
||||||
|
if (!info->kern)
|
||||||
|
return 0;
|
||||||
|
if (ttUSHORT(data+2) < 1) // number of tables, need at least 1
|
||||||
|
return 0;
|
||||||
|
if (ttUSHORT(data+8) != 1) // horizontal flag must be set in format
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return ttUSHORT(data+10);
|
||||||
|
}
|
||||||
|
|
||||||
|
STBTT_DEF int stbtt_GetKerningTable(const stbtt_fontinfo *info, stbtt_kerningentry* table, int table_length)
|
||||||
|
{
|
||||||
|
stbtt_uint8 *data = info->data + info->kern;
|
||||||
|
int k, length;
|
||||||
|
|
||||||
|
// we only look at the first table. it must be 'horizontal' and format 0.
|
||||||
|
if (!info->kern)
|
||||||
|
return 0;
|
||||||
|
if (ttUSHORT(data+2) < 1) // number of tables, need at least 1
|
||||||
|
return 0;
|
||||||
|
if (ttUSHORT(data+8) != 1) // horizontal flag must be set in format
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
length = ttUSHORT(data+10);
|
||||||
|
if (table_length < length)
|
||||||
|
length = table_length;
|
||||||
|
|
||||||
|
for (k = 0; k < length; k++)
|
||||||
|
{
|
||||||
|
table[k].glyph1 = ttUSHORT(data+18+(k*6));
|
||||||
|
table[k].glyph2 = ttUSHORT(data+20+(k*6));
|
||||||
|
table[k].advance = ttSHORT(data+22+(k*6));
|
||||||
|
}
|
||||||
|
|
||||||
|
return length;
|
||||||
|
}
|
||||||
|
|
||||||
static int stbtt__GetGlyphKernInfoAdvance(const stbtt_fontinfo *info, int glyph1, int glyph2)
|
static int stbtt__GetGlyphKernInfoAdvance(const stbtt_fontinfo *info, int glyph1, int glyph2)
|
||||||
{
|
{
|
||||||
stbtt_uint8 *data = info->data + info->kern;
|
stbtt_uint8 *data = info->data + info->kern;
|
||||||
|
@ -2315,7 +2394,7 @@ static int stbtt__GetGlyphKernInfoAdvance(const stbtt_fontinfo *info, int glyph
|
||||||
static stbtt_int32 stbtt__GetCoverageIndex(stbtt_uint8 *coverageTable, int glyph)
|
static stbtt_int32 stbtt__GetCoverageIndex(stbtt_uint8 *coverageTable, int glyph)
|
||||||
{
|
{
|
||||||
stbtt_uint16 coverageFormat = ttUSHORT(coverageTable);
|
stbtt_uint16 coverageFormat = ttUSHORT(coverageTable);
|
||||||
switch(coverageFormat) {
|
switch (coverageFormat) {
|
||||||
case 1: {
|
case 1: {
|
||||||
stbtt_uint16 glyphCount = ttUSHORT(coverageTable + 2);
|
stbtt_uint16 glyphCount = ttUSHORT(coverageTable + 2);
|
||||||
|
|
||||||
|
@ -2336,7 +2415,8 @@ static stbtt_int32 stbtt__GetCoverageIndex(stbtt_uint8 *coverageTable, int glyp
|
||||||
return m;
|
return m;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case 2: {
|
case 2: {
|
||||||
stbtt_uint16 rangeCount = ttUSHORT(coverageTable + 2);
|
stbtt_uint16 rangeCount = ttUSHORT(coverageTable + 2);
|
||||||
|
@ -2360,12 +2440,10 @@ static stbtt_int32 stbtt__GetCoverageIndex(stbtt_uint8 *coverageTable, int glyp
|
||||||
return startCoverageIndex + glyph - strawStart;
|
return startCoverageIndex + glyph - strawStart;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
default: {
|
default: return -1; // unsupported
|
||||||
// There are no other cases.
|
|
||||||
STBTT_assert(0);
|
|
||||||
} break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -2374,7 +2452,7 @@ static stbtt_int32 stbtt__GetCoverageIndex(stbtt_uint8 *coverageTable, int glyp
|
||||||
static stbtt_int32 stbtt__GetGlyphClass(stbtt_uint8 *classDefTable, int glyph)
|
static stbtt_int32 stbtt__GetGlyphClass(stbtt_uint8 *classDefTable, int glyph)
|
||||||
{
|
{
|
||||||
stbtt_uint16 classDefFormat = ttUSHORT(classDefTable);
|
stbtt_uint16 classDefFormat = ttUSHORT(classDefTable);
|
||||||
switch(classDefFormat)
|
switch (classDefFormat)
|
||||||
{
|
{
|
||||||
case 1: {
|
case 1: {
|
||||||
stbtt_uint16 startGlyphID = ttUSHORT(classDefTable + 2);
|
stbtt_uint16 startGlyphID = ttUSHORT(classDefTable + 2);
|
||||||
|
@ -2383,10 +2461,8 @@ static stbtt_int32 stbtt__GetGlyphClass(stbtt_uint8 *classDefTable, int glyph)
|
||||||
|
|
||||||
if (glyph >= startGlyphID && glyph < startGlyphID + glyphCount)
|
if (glyph >= startGlyphID && glyph < startGlyphID + glyphCount)
|
||||||
return (stbtt_int32)ttUSHORT(classDef1ValueArray + 2 * (glyph - startGlyphID));
|
return (stbtt_int32)ttUSHORT(classDef1ValueArray + 2 * (glyph - startGlyphID));
|
||||||
|
break;
|
||||||
// [DEAR IMGUI] Commented to fix static analyzer warning
|
}
|
||||||
//classDefTable = classDef1ValueArray + 2 * glyphCount;
|
|
||||||
} break;
|
|
||||||
|
|
||||||
case 2: {
|
case 2: {
|
||||||
stbtt_uint16 classRangeCount = ttUSHORT(classDefTable + 2);
|
stbtt_uint16 classRangeCount = ttUSHORT(classDefTable + 2);
|
||||||
|
@ -2408,18 +2484,15 @@ static stbtt_int32 stbtt__GetGlyphClass(stbtt_uint8 *classDefTable, int glyph)
|
||||||
else
|
else
|
||||||
return (stbtt_int32)ttUSHORT(classRangeRecord + 4);
|
return (stbtt_int32)ttUSHORT(classRangeRecord + 4);
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
// [DEAR IMGUI] Commented to fix static analyzer warning
|
|
||||||
//classDefTable = classRangeRecords + 6 * classRangeCount;
|
|
||||||
} break;
|
|
||||||
|
|
||||||
default: {
|
|
||||||
// There are no other cases.
|
|
||||||
STBTT_assert(0);
|
|
||||||
} break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return -1;
|
default:
|
||||||
|
return -1; // Unsupported definition type, return an error.
|
||||||
|
}
|
||||||
|
|
||||||
|
// "All glyphs not assigned to a class fall into class 0". (OpenType spec)
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Define to STBTT_assert(x) if you want to break on unimplemented formats.
|
// Define to STBTT_assert(x) if you want to break on unimplemented formats.
|
||||||
|
@ -2431,7 +2504,7 @@ static stbtt_int32 stbtt__GetGlyphGPOSInfoAdvance(const stbtt_fontinfo *info, i
|
||||||
stbtt_uint8 *lookupList;
|
stbtt_uint8 *lookupList;
|
||||||
stbtt_uint16 lookupCount;
|
stbtt_uint16 lookupCount;
|
||||||
stbtt_uint8 *data;
|
stbtt_uint8 *data;
|
||||||
stbtt_int32 i;
|
stbtt_int32 i, sti;
|
||||||
|
|
||||||
if (!info->gpos) return 0;
|
if (!info->gpos) return 0;
|
||||||
|
|
||||||
|
@ -2451,9 +2524,9 @@ static stbtt_int32 stbtt__GetGlyphGPOSInfoAdvance(const stbtt_fontinfo *info, i
|
||||||
stbtt_uint16 lookupType = ttUSHORT(lookupTable);
|
stbtt_uint16 lookupType = ttUSHORT(lookupTable);
|
||||||
stbtt_uint16 subTableCount = ttUSHORT(lookupTable + 4);
|
stbtt_uint16 subTableCount = ttUSHORT(lookupTable + 4);
|
||||||
stbtt_uint8 *subTableOffsets = lookupTable + 6;
|
stbtt_uint8 *subTableOffsets = lookupTable + 6;
|
||||||
switch(lookupType) {
|
if (lookupType != 2) // Pair Adjustment Positioning Subtable
|
||||||
case 2: { // Pair Adjustment Positioning Subtable
|
continue;
|
||||||
stbtt_int32 sti;
|
|
||||||
for (sti=0; sti<subTableCount; sti++) {
|
for (sti=0; sti<subTableCount; sti++) {
|
||||||
stbtt_uint16 subtableOffset = ttUSHORT(subTableOffsets + 2 * sti);
|
stbtt_uint16 subtableOffset = ttUSHORT(subTableOffsets + 2 * sti);
|
||||||
stbtt_uint8 *table = lookupTable + subtableOffset;
|
stbtt_uint8 *table = lookupTable + subtableOffset;
|
||||||
|
@ -2468,20 +2541,15 @@ static stbtt_int32 stbtt__GetGlyphGPOSInfoAdvance(const stbtt_fontinfo *info, i
|
||||||
int straw, needle;
|
int straw, needle;
|
||||||
stbtt_uint16 valueFormat1 = ttUSHORT(table + 4);
|
stbtt_uint16 valueFormat1 = ttUSHORT(table + 4);
|
||||||
stbtt_uint16 valueFormat2 = ttUSHORT(table + 6);
|
stbtt_uint16 valueFormat2 = ttUSHORT(table + 6);
|
||||||
|
if (valueFormat1 == 4 && valueFormat2 == 0) { // Support more formats?
|
||||||
stbtt_int32 valueRecordPairSizeInBytes = 2;
|
stbtt_int32 valueRecordPairSizeInBytes = 2;
|
||||||
stbtt_uint16 pairSetCount = ttUSHORT(table + 8);
|
stbtt_uint16 pairSetCount = ttUSHORT(table + 8);
|
||||||
stbtt_uint16 pairPosOffset = ttUSHORT(table + 10 + 2 * coverageIndex);
|
stbtt_uint16 pairPosOffset = ttUSHORT(table + 10 + 2 * coverageIndex);
|
||||||
stbtt_uint8 *pairValueTable = table + pairPosOffset;
|
stbtt_uint8 *pairValueTable = table + pairPosOffset;
|
||||||
stbtt_uint16 pairValueCount = ttUSHORT(pairValueTable);
|
stbtt_uint16 pairValueCount = ttUSHORT(pairValueTable);
|
||||||
stbtt_uint8 *pairValueArray = pairValueTable + 2;
|
stbtt_uint8 *pairValueArray = pairValueTable + 2;
|
||||||
// TODO: Support more formats.
|
|
||||||
STBTT_GPOS_TODO_assert(valueFormat1 == 4);
|
|
||||||
if (valueFormat1 != 4) return 0;
|
|
||||||
STBTT_GPOS_TODO_assert(valueFormat2 == 0);
|
|
||||||
if (valueFormat2 != 0) return 0;
|
|
||||||
|
|
||||||
STBTT_assert(coverageIndex < pairSetCount);
|
if (coverageIndex >= pairSetCount) return 0;
|
||||||
STBTT__NOTUSED(pairSetCount);
|
|
||||||
|
|
||||||
needle=glyph2;
|
needle=glyph2;
|
||||||
r=pairValueCount-1;
|
r=pairValueCount-1;
|
||||||
|
@ -2504,12 +2572,15 @@ static stbtt_int32 stbtt__GetGlyphGPOSInfoAdvance(const stbtt_fontinfo *info, i
|
||||||
return xAdvance;
|
return xAdvance;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} break;
|
} else
|
||||||
|
return 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case 2: {
|
case 2: {
|
||||||
stbtt_uint16 valueFormat1 = ttUSHORT(table + 4);
|
stbtt_uint16 valueFormat1 = ttUSHORT(table + 4);
|
||||||
stbtt_uint16 valueFormat2 = ttUSHORT(table + 6);
|
stbtt_uint16 valueFormat2 = ttUSHORT(table + 6);
|
||||||
|
if (valueFormat1 == 4 && valueFormat2 == 0) { // Support more formats?
|
||||||
stbtt_uint16 classDef1Offset = ttUSHORT(table + 8);
|
stbtt_uint16 classDef1Offset = ttUSHORT(table + 8);
|
||||||
stbtt_uint16 classDef2Offset = ttUSHORT(table + 10);
|
stbtt_uint16 classDef2Offset = ttUSHORT(table + 10);
|
||||||
int glyph1class = stbtt__GetGlyphClass(table + classDef1Offset, glyph1);
|
int glyph1class = stbtt__GetGlyphClass(table + classDef1Offset, glyph1);
|
||||||
|
@ -2517,36 +2588,24 @@ static stbtt_int32 stbtt__GetGlyphGPOSInfoAdvance(const stbtt_fontinfo *info, i
|
||||||
|
|
||||||
stbtt_uint16 class1Count = ttUSHORT(table + 12);
|
stbtt_uint16 class1Count = ttUSHORT(table + 12);
|
||||||
stbtt_uint16 class2Count = ttUSHORT(table + 14);
|
stbtt_uint16 class2Count = ttUSHORT(table + 14);
|
||||||
STBTT_assert(glyph1class < class1Count);
|
stbtt_uint8 *class1Records, *class2Records;
|
||||||
STBTT_assert(glyph2class < class2Count);
|
stbtt_int16 xAdvance;
|
||||||
|
|
||||||
// TODO: Support more formats.
|
if (glyph1class < 0 || glyph1class >= class1Count) return 0; // malformed
|
||||||
STBTT_GPOS_TODO_assert(valueFormat1 == 4);
|
if (glyph2class < 0 || glyph2class >= class2Count) return 0; // malformed
|
||||||
if (valueFormat1 != 4) return 0;
|
|
||||||
STBTT_GPOS_TODO_assert(valueFormat2 == 0);
|
|
||||||
if (valueFormat2 != 0) return 0;
|
|
||||||
|
|
||||||
if (glyph1class >= 0 && glyph1class < class1Count && glyph2class >= 0 && glyph2class < class2Count) {
|
class1Records = table + 16;
|
||||||
stbtt_uint8 *class1Records = table + 16;
|
class2Records = class1Records + 2 * (glyph1class * class2Count);
|
||||||
stbtt_uint8 *class2Records = class1Records + 2 * (glyph1class * class2Count);
|
xAdvance = ttSHORT(class2Records + 2 * glyph2class);
|
||||||
stbtt_int16 xAdvance = ttSHORT(class2Records + 2 * glyph2class);
|
|
||||||
return xAdvance;
|
return xAdvance;
|
||||||
}
|
} else
|
||||||
} break;
|
return 0;
|
||||||
|
|
||||||
default: {
|
|
||||||
// There are no other cases.
|
|
||||||
STBTT_assert(0);
|
|
||||||
break;
|
break;
|
||||||
} // [DEAR IMGUI] removed ;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
break;
|
|
||||||
} // [DEAR IMGUI] removed ;
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
// TODO: Implement other stuff.
|
return 0; // Unsupported position format
|
||||||
break;
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2559,8 +2618,7 @@ STBTT_DEF int stbtt_GetGlyphKernAdvance(const stbtt_fontinfo *info, int g1, int
|
||||||
|
|
||||||
if (info->gpos)
|
if (info->gpos)
|
||||||
xAdvance += stbtt__GetGlyphGPOSInfoAdvance(info, g1, g2);
|
xAdvance += stbtt__GetGlyphGPOSInfoAdvance(info, g1, g2);
|
||||||
|
else if (info->kern)
|
||||||
if (info->kern)
|
|
||||||
xAdvance += stbtt__GetGlyphKernInfoAdvance(info, g1, g2);
|
xAdvance += stbtt__GetGlyphKernInfoAdvance(info, g1, g2);
|
||||||
|
|
||||||
return xAdvance;
|
return xAdvance;
|
||||||
|
@ -2621,6 +2679,45 @@ STBTT_DEF void stbtt_FreeShape(const stbtt_fontinfo *info, stbtt_vertex *v)
|
||||||
STBTT_free(v, info->userdata);
|
STBTT_free(v, info->userdata);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
STBTT_DEF stbtt_uint8 *stbtt_FindSVGDoc(const stbtt_fontinfo *info, int gl)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
stbtt_uint8 *data = info->data;
|
||||||
|
stbtt_uint8 *svg_doc_list = data + stbtt__get_svg((stbtt_fontinfo *) info);
|
||||||
|
|
||||||
|
int numEntries = ttUSHORT(svg_doc_list);
|
||||||
|
stbtt_uint8 *svg_docs = svg_doc_list + 2;
|
||||||
|
|
||||||
|
for(i=0; i<numEntries; i++) {
|
||||||
|
stbtt_uint8 *svg_doc = svg_docs + (12 * i);
|
||||||
|
if ((gl >= ttUSHORT(svg_doc)) && (gl <= ttUSHORT(svg_doc + 2)))
|
||||||
|
return svg_doc;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
STBTT_DEF int stbtt_GetGlyphSVG(const stbtt_fontinfo *info, int gl, const char **svg)
|
||||||
|
{
|
||||||
|
stbtt_uint8 *data = info->data;
|
||||||
|
stbtt_uint8 *svg_doc;
|
||||||
|
|
||||||
|
if (info->svg == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
svg_doc = stbtt_FindSVGDoc(info, gl);
|
||||||
|
if (svg_doc != NULL) {
|
||||||
|
*svg = (char *) data + info->svg + ttULONG(svg_doc + 4);
|
||||||
|
return ttULONG(svg_doc + 8);
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
STBTT_DEF int stbtt_GetCodepointSVG(const stbtt_fontinfo *info, int unicode_codepoint, const char **svg)
|
||||||
|
{
|
||||||
|
return stbtt_GetGlyphSVG(info, stbtt_FindGlyphIndex(info, unicode_codepoint), svg);
|
||||||
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
//
|
//
|
||||||
// antialiasing software rasterizer
|
// antialiasing software rasterizer
|
||||||
|
@ -2970,6 +3067,23 @@ static void stbtt__handle_clipped_edge(float *scanline, int x, stbtt__active_edg
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static float stbtt__sized_trapezoid_area(float height, float top_width, float bottom_width)
|
||||||
|
{
|
||||||
|
STBTT_assert(top_width >= 0);
|
||||||
|
STBTT_assert(bottom_width >= 0);
|
||||||
|
return (top_width + bottom_width) / 2.0f * height;
|
||||||
|
}
|
||||||
|
|
||||||
|
static float stbtt__position_trapezoid_area(float height, float tx0, float tx1, float bx0, float bx1)
|
||||||
|
{
|
||||||
|
return stbtt__sized_trapezoid_area(height, tx1 - tx0, bx1 - bx0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static float stbtt__sized_triangle_area(float height, float width)
|
||||||
|
{
|
||||||
|
return height * width / 2;
|
||||||
|
}
|
||||||
|
|
||||||
static void stbtt__fill_active_edges_new(float *scanline, float *scanline_fill, int len, stbtt__active_edge *e, float y_top)
|
static void stbtt__fill_active_edges_new(float *scanline, float *scanline_fill, int len, stbtt__active_edge *e, float y_top)
|
||||||
{
|
{
|
||||||
float y_bottom = y_top+1;
|
float y_bottom = y_top+1;
|
||||||
|
@ -3024,13 +3138,13 @@ static void stbtt__fill_active_edges_new(float *scanline, float *scanline_fill,
|
||||||
float height;
|
float height;
|
||||||
// simple case, only spans one pixel
|
// simple case, only spans one pixel
|
||||||
int x = (int) x_top;
|
int x = (int) x_top;
|
||||||
height = sy1 - sy0;
|
height = (sy1 - sy0) * e->direction;
|
||||||
STBTT_assert(x >= 0 && x < len);
|
STBTT_assert(x >= 0 && x < len);
|
||||||
scanline[x] += e->direction * (1-((x_top - x) + (x_bottom-x))/2) * height;
|
scanline[x] += stbtt__position_trapezoid_area(height, x_top, x+1.0f, x_bottom, x+1.0f);
|
||||||
scanline_fill[x] += e->direction * height; // everything right of this pixel is filled
|
scanline_fill[x] += height; // everything right of this pixel is filled
|
||||||
} else {
|
} else {
|
||||||
int x,x1,x2;
|
int x,x1,x2;
|
||||||
float y_crossing, step, sign, area;
|
float y_crossing, y_final, step, sign, area;
|
||||||
// covers 2+ pixels
|
// covers 2+ pixels
|
||||||
if (x_top > x_bottom) {
|
if (x_top > x_bottom) {
|
||||||
// flip scanline vertically; signed area is the same
|
// flip scanline vertically; signed area is the same
|
||||||
|
@ -3042,32 +3156,83 @@ static void stbtt__fill_active_edges_new(float *scanline, float *scanline_fill,
|
||||||
dx = -dx;
|
dx = -dx;
|
||||||
dy = -dy;
|
dy = -dy;
|
||||||
t = x0, x0 = xb, xb = t;
|
t = x0, x0 = xb, xb = t;
|
||||||
// [DEAR IMGUI] Fix static analyzer warning
|
|
||||||
(void)dx; // [ImGui: fix static analyzer warning]
|
|
||||||
}
|
}
|
||||||
|
STBTT_assert(dy >= 0);
|
||||||
|
STBTT_assert(dx >= 0);
|
||||||
|
|
||||||
x1 = (int) x_top;
|
x1 = (int) x_top;
|
||||||
x2 = (int) x_bottom;
|
x2 = (int) x_bottom;
|
||||||
// compute intersection with y axis at x1+1
|
// compute intersection with y axis at x1+1
|
||||||
y_crossing = (x1+1 - x0) * dy + y_top;
|
y_crossing = y_top + dy * (x1+1 - x0);
|
||||||
|
|
||||||
|
// compute intersection with y axis at x2
|
||||||
|
y_final = y_top + dy * (x2 - x0);
|
||||||
|
|
||||||
|
// x1 x_top x2 x_bottom
|
||||||
|
// y_top +------|-----+------------+------------+--------|---+------------+
|
||||||
|
// | | | | | |
|
||||||
|
// | | | | | |
|
||||||
|
// sy0 | Txxxxx|............|............|............|............|
|
||||||
|
// y_crossing | *xxxxx.......|............|............|............|
|
||||||
|
// | | xxxxx..|............|............|............|
|
||||||
|
// | | /- xx*xxxx........|............|............|
|
||||||
|
// | | dy < | xxxxxx..|............|............|
|
||||||
|
// y_final | | \- | xx*xxx.........|............|
|
||||||
|
// sy1 | | | | xxxxxB...|............|
|
||||||
|
// | | | | | |
|
||||||
|
// | | | | | |
|
||||||
|
// y_bottom +------------+------------+------------+------------+------------+
|
||||||
|
//
|
||||||
|
// goal is to measure the area covered by '.' in each pixel
|
||||||
|
|
||||||
|
// if x2 is right at the right edge of x1, y_crossing can blow up, github #1057
|
||||||
|
// @TODO: maybe test against sy1 rather than y_bottom?
|
||||||
|
if (y_crossing > y_bottom)
|
||||||
|
y_crossing = y_bottom;
|
||||||
|
|
||||||
sign = e->direction;
|
sign = e->direction;
|
||||||
// area of the rectangle covered from y0..y_crossing
|
|
||||||
area = sign * (y_crossing-sy0);
|
|
||||||
// area of the triangle (x_top,y0), (x+1,y0), (x+1,y_crossing)
|
|
||||||
scanline[x1] += area * (1-((x_top - x1)+(x1+1-x1))/2);
|
|
||||||
|
|
||||||
step = sign * dy;
|
// area of the rectangle covered from sy0..y_crossing
|
||||||
|
area = sign * (y_crossing-sy0);
|
||||||
|
|
||||||
|
// area of the triangle (x_top,sy0), (x1+1,sy0), (x1+1,y_crossing)
|
||||||
|
scanline[x1] += stbtt__sized_triangle_area(area, x1+1 - x_top);
|
||||||
|
|
||||||
|
// check if final y_crossing is blown up; no test case for this
|
||||||
|
if (y_final > y_bottom) {
|
||||||
|
int denom = (x2 - (x1+1));
|
||||||
|
y_final = y_bottom;
|
||||||
|
if (denom != 0) { // [DEAR IMGUI] Avoid div by zero (https://github.com/nothings/stb/issues/1316)
|
||||||
|
dy = (y_final - y_crossing ) / denom; // if denom=0, y_final = y_crossing, so y_final <= y_bottom
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// in second pixel, area covered by line segment found in first pixel
|
||||||
|
// is always a rectangle 1 wide * the height of that line segment; this
|
||||||
|
// is exactly what the variable 'area' stores. it also gets a contribution
|
||||||
|
// from the line segment within it. the THIRD pixel will get the first
|
||||||
|
// pixel's rectangle contribution, the second pixel's rectangle contribution,
|
||||||
|
// and its own contribution. the 'own contribution' is the same in every pixel except
|
||||||
|
// the leftmost and rightmost, a trapezoid that slides down in each pixel.
|
||||||
|
// the second pixel's contribution to the third pixel will be the
|
||||||
|
// rectangle 1 wide times the height change in the second pixel, which is dy.
|
||||||
|
|
||||||
|
step = sign * dy * 1; // dy is dy/dx, change in y for every 1 change in x,
|
||||||
|
// which multiplied by 1-pixel-width is how much pixel area changes for each step in x
|
||||||
|
// so the area advances by 'step' every time
|
||||||
|
|
||||||
for (x = x1+1; x < x2; ++x) {
|
for (x = x1+1; x < x2; ++x) {
|
||||||
scanline[x] += area + step/2;
|
scanline[x] += area + step/2; // area of trapezoid is 1*step/2
|
||||||
area += step;
|
area += step;
|
||||||
}
|
}
|
||||||
y_crossing += dy * (x2 - (x1+1));
|
STBTT_assert(STBTT_fabs(area) <= 1.01f); // accumulated error from area += step unless we round step down
|
||||||
|
STBTT_assert(sy1 > y_final-0.01f);
|
||||||
|
|
||||||
STBTT_assert(STBTT_fabs(area) <= 1.01f);
|
// area covered in the last pixel is the rectangle from all the pixels to the left,
|
||||||
|
// plus the trapezoid filled by the line segment in this pixel all the way to the right edge
|
||||||
scanline[x2] += area + sign * (1-((x2-x2)+(x_bottom-x2))/2) * (sy1-y_crossing);
|
scanline[x2] += area + sign * stbtt__position_trapezoid_area(sy1-y_final, (float) x2, x2+1.0f, x_bottom, x2+1.0f);
|
||||||
|
|
||||||
|
// the rest of the line is filled based on the total height of the line segment in this pixel
|
||||||
scanline_fill[x2] += sign * (sy1-sy0);
|
scanline_fill[x2] += sign * (sy1-sy0);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -3075,6 +3240,9 @@ static void stbtt__fill_active_edges_new(float *scanline, float *scanline_fill,
|
||||||
// clipping logic. since this does not match the intended use
|
// clipping logic. since this does not match the intended use
|
||||||
// of this library, we use a different, very slow brute
|
// of this library, we use a different, very slow brute
|
||||||
// force implementation
|
// force implementation
|
||||||
|
// note though that this does happen some of the time because
|
||||||
|
// x_top and x_bottom can be extrapolated at the top & bottom of
|
||||||
|
// the shape and actually lie outside the bounding box
|
||||||
int x;
|
int x;
|
||||||
for (x=0; x < len; ++x) {
|
for (x=0; x < len; ++x) {
|
||||||
// cases:
|
// cases:
|
||||||
|
@ -3989,6 +4157,7 @@ static float stbtt__oversample_shift(int oversample)
|
||||||
STBTT_DEF int stbtt_PackFontRangesGatherRects(stbtt_pack_context *spc, const stbtt_fontinfo *info, stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects)
|
STBTT_DEF int stbtt_PackFontRangesGatherRects(stbtt_pack_context *spc, const stbtt_fontinfo *info, stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects)
|
||||||
{
|
{
|
||||||
int i,j,k;
|
int i,j,k;
|
||||||
|
int missing_glyph_added = 0;
|
||||||
|
|
||||||
k=0;
|
k=0;
|
||||||
for (i=0; i < num_ranges; ++i) {
|
for (i=0; i < num_ranges; ++i) {
|
||||||
|
@ -4000,7 +4169,7 @@ STBTT_DEF int stbtt_PackFontRangesGatherRects(stbtt_pack_context *spc, const stb
|
||||||
int x0,y0,x1,y1;
|
int x0,y0,x1,y1;
|
||||||
int codepoint = ranges[i].array_of_unicode_codepoints == NULL ? ranges[i].first_unicode_codepoint_in_range + j : ranges[i].array_of_unicode_codepoints[j];
|
int codepoint = ranges[i].array_of_unicode_codepoints == NULL ? ranges[i].first_unicode_codepoint_in_range + j : ranges[i].array_of_unicode_codepoints[j];
|
||||||
int glyph = stbtt_FindGlyphIndex(info, codepoint);
|
int glyph = stbtt_FindGlyphIndex(info, codepoint);
|
||||||
if (glyph == 0 && spc->skip_missing) {
|
if (glyph == 0 && (spc->skip_missing || missing_glyph_added)) {
|
||||||
rects[k].w = rects[k].h = 0;
|
rects[k].w = rects[k].h = 0;
|
||||||
} else {
|
} else {
|
||||||
stbtt_GetGlyphBitmapBoxSubpixel(info,glyph,
|
stbtt_GetGlyphBitmapBoxSubpixel(info,glyph,
|
||||||
|
@ -4010,6 +4179,8 @@ STBTT_DEF int stbtt_PackFontRangesGatherRects(stbtt_pack_context *spc, const stb
|
||||||
&x0,&y0,&x1,&y1);
|
&x0,&y0,&x1,&y1);
|
||||||
rects[k].w = (stbrp_coord) (x1-x0 + spc->padding + spc->h_oversample-1);
|
rects[k].w = (stbrp_coord) (x1-x0 + spc->padding + spc->h_oversample-1);
|
||||||
rects[k].h = (stbrp_coord) (y1-y0 + spc->padding + spc->v_oversample-1);
|
rects[k].h = (stbrp_coord) (y1-y0 + spc->padding + spc->v_oversample-1);
|
||||||
|
if (glyph == 0)
|
||||||
|
missing_glyph_added = 1;
|
||||||
}
|
}
|
||||||
++k;
|
++k;
|
||||||
}
|
}
|
||||||
|
@ -4044,7 +4215,7 @@ STBTT_DEF void stbtt_MakeGlyphBitmapSubpixelPrefilter(const stbtt_fontinfo *info
|
||||||
// rects array must be big enough to accommodate all characters in the given ranges
|
// rects array must be big enough to accommodate all characters in the given ranges
|
||||||
STBTT_DEF int stbtt_PackFontRangesRenderIntoRects(stbtt_pack_context *spc, const stbtt_fontinfo *info, stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects)
|
STBTT_DEF int stbtt_PackFontRangesRenderIntoRects(stbtt_pack_context *spc, const stbtt_fontinfo *info, stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects)
|
||||||
{
|
{
|
||||||
int i,j,k, return_value = 1;
|
int i,j,k, missing_glyph = -1, return_value = 1;
|
||||||
|
|
||||||
// save current values
|
// save current values
|
||||||
int old_h_over = spc->h_oversample;
|
int old_h_over = spc->h_oversample;
|
||||||
|
@ -4109,6 +4280,13 @@ STBTT_DEF int stbtt_PackFontRangesRenderIntoRects(stbtt_pack_context *spc, const
|
||||||
bc->yoff = (float) y0 * recip_v + sub_y;
|
bc->yoff = (float) y0 * recip_v + sub_y;
|
||||||
bc->xoff2 = (x0 + r->w) * recip_h + sub_x;
|
bc->xoff2 = (x0 + r->w) * recip_h + sub_x;
|
||||||
bc->yoff2 = (y0 + r->h) * recip_v + sub_y;
|
bc->yoff2 = (y0 + r->h) * recip_v + sub_y;
|
||||||
|
|
||||||
|
if (glyph == 0)
|
||||||
|
missing_glyph = j;
|
||||||
|
} else if (spc->skip_missing) {
|
||||||
|
return_value = 0;
|
||||||
|
} else if (r->was_packed && r->w == 0 && r->h == 0 && missing_glyph >= 0) {
|
||||||
|
ranges[i].chardata_for_range[j] = ranges[i].chardata_for_range[missing_glyph];
|
||||||
} else {
|
} else {
|
||||||
return_value = 0; // if any fail, report failure
|
return_value = 0; // if any fail, report failure
|
||||||
}
|
}
|
||||||
|
@ -4132,7 +4310,7 @@ STBTT_DEF void stbtt_PackFontRangesPackRects(stbtt_pack_context *spc, stbrp_rect
|
||||||
STBTT_DEF int stbtt_PackFontRanges(stbtt_pack_context *spc, const unsigned char *fontdata, int font_index, stbtt_pack_range *ranges, int num_ranges)
|
STBTT_DEF int stbtt_PackFontRanges(stbtt_pack_context *spc, const unsigned char *fontdata, int font_index, stbtt_pack_range *ranges, int num_ranges)
|
||||||
{
|
{
|
||||||
stbtt_fontinfo info;
|
stbtt_fontinfo info;
|
||||||
int i,j,n, return_value; // [DEAR IMGUI] removed = 1
|
int i, j, n, return_value; // [DEAR IMGUI] removed = 1;
|
||||||
//stbrp_context *context = (stbrp_context *) spc->pack_info;
|
//stbrp_context *context = (stbrp_context *) spc->pack_info;
|
||||||
stbrp_rect *rects;
|
stbrp_rect *rects;
|
||||||
|
|
||||||
|
@ -4301,15 +4479,14 @@ static int stbtt__compute_crossings_x(float x, float y, int nverts, stbtt_vertex
|
||||||
float y_frac;
|
float y_frac;
|
||||||
int winding = 0;
|
int winding = 0;
|
||||||
|
|
||||||
orig[0] = x;
|
|
||||||
//orig[1] = y; // [DEAR IMGUI] commented double assignment
|
|
||||||
|
|
||||||
// make sure y never passes through a vertex of the shape
|
// make sure y never passes through a vertex of the shape
|
||||||
y_frac = (float) STBTT_fmod(y, 1.0f);
|
y_frac = (float) STBTT_fmod(y, 1.0f);
|
||||||
if (y_frac < 0.01f)
|
if (y_frac < 0.01f)
|
||||||
y += 0.01f;
|
y += 0.01f;
|
||||||
else if (y_frac > 0.99f)
|
else if (y_frac > 0.99f)
|
||||||
y -= 0.01f;
|
y -= 0.01f;
|
||||||
|
|
||||||
|
orig[0] = x;
|
||||||
orig[1] = y;
|
orig[1] = y;
|
||||||
|
|
||||||
// test a ray from (-infinity,y) to (x,y)
|
// test a ray from (-infinity,y) to (x,y)
|
||||||
|
@ -4371,7 +4548,7 @@ static float stbtt__cuberoot( float x )
|
||||||
return (float) STBTT_pow( x,1.0f/3.0f);
|
return (float) STBTT_pow( x,1.0f/3.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
// x^3 + c*x^2 + b*x + a = 0
|
// x^3 + a*x^2 + b*x + c = 0
|
||||||
static int stbtt__solve_cubic(float a, float b, float c, float* r)
|
static int stbtt__solve_cubic(float a, float b, float c, float* r)
|
||||||
{
|
{
|
||||||
float s = -a / 3;
|
float s = -a / 3;
|
||||||
|
@ -4410,12 +4587,7 @@ STBTT_DEF unsigned char * stbtt_GetGlyphSDF(const stbtt_fontinfo *info, float sc
|
||||||
int w,h;
|
int w,h;
|
||||||
unsigned char *data;
|
unsigned char *data;
|
||||||
|
|
||||||
// if one scale is 0, use same scale for both
|
if (scale == 0) return NULL;
|
||||||
if (scale_x == 0) scale_x = scale_y;
|
|
||||||
if (scale_y == 0) {
|
|
||||||
if (scale_x == 0) return NULL; // if both scales are 0, return NULL
|
|
||||||
scale_y = scale_x;
|
|
||||||
}
|
|
||||||
|
|
||||||
stbtt_GetGlyphBitmapBoxSubpixel(info, glyph, scale, scale, 0.0f,0.0f, &ix0,&iy0,&ix1,&iy1);
|
stbtt_GetGlyphBitmapBoxSubpixel(info, glyph, scale, scale, 0.0f,0.0f, &ix0,&iy0,&ix1,&iy1);
|
||||||
|
|
||||||
|
@ -4481,18 +4653,17 @@ STBTT_DEF unsigned char * stbtt_GetGlyphSDF(const stbtt_fontinfo *info, float sc
|
||||||
for (i=0; i < num_verts; ++i) {
|
for (i=0; i < num_verts; ++i) {
|
||||||
float x0 = verts[i].x*scale_x, y0 = verts[i].y*scale_y;
|
float x0 = verts[i].x*scale_x, y0 = verts[i].y*scale_y;
|
||||||
|
|
||||||
// check against every point here rather than inside line/curve primitives -- @TODO: wrong if multiple 'moves' in a row produce a garbage point, and given culling, probably more efficient to do within line/curve
|
if (verts[i].type == STBTT_vline && precompute[i] != 0.0f) {
|
||||||
float dist2 = (x0-sx)*(x0-sx) + (y0-sy)*(y0-sy);
|
float x1 = verts[i-1].x*scale_x, y1 = verts[i-1].y*scale_y;
|
||||||
|
|
||||||
|
float dist,dist2 = (x0-sx)*(x0-sx) + (y0-sy)*(y0-sy);
|
||||||
if (dist2 < min_dist*min_dist)
|
if (dist2 < min_dist*min_dist)
|
||||||
min_dist = (float) STBTT_sqrt(dist2);
|
min_dist = (float) STBTT_sqrt(dist2);
|
||||||
|
|
||||||
if (verts[i].type == STBTT_vline) {
|
|
||||||
float x1 = verts[i-1].x*scale_x, y1 = verts[i-1].y*scale_y;
|
|
||||||
|
|
||||||
// coarse culling against bbox
|
// coarse culling against bbox
|
||||||
//if (sx > STBTT_min(x0,x1)-min_dist && sx < STBTT_max(x0,x1)+min_dist &&
|
//if (sx > STBTT_min(x0,x1)-min_dist && sx < STBTT_max(x0,x1)+min_dist &&
|
||||||
// sy > STBTT_min(y0,y1)-min_dist && sy < STBTT_max(y0,y1)+min_dist)
|
// sy > STBTT_min(y0,y1)-min_dist && sy < STBTT_max(y0,y1)+min_dist)
|
||||||
float dist = (float) STBTT_fabs((x1-x0)*(y0-sy) - (y1-y0)*(x0-sx)) * precompute[i];
|
dist = (float) STBTT_fabs((x1-x0)*(y0-sy) - (y1-y0)*(x0-sx)) * precompute[i];
|
||||||
STBTT_assert(i != 0);
|
STBTT_assert(i != 0);
|
||||||
if (dist < min_dist) {
|
if (dist < min_dist) {
|
||||||
// check position along line
|
// check position along line
|
||||||
|
@ -4519,7 +4690,8 @@ STBTT_DEF unsigned char * stbtt_GetGlyphSDF(const stbtt_fontinfo *info, float sc
|
||||||
float ax = x1-x0, ay = y1-y0;
|
float ax = x1-x0, ay = y1-y0;
|
||||||
float bx = x0 - 2*x1 + x2, by = y0 - 2*y1 + y2;
|
float bx = x0 - 2*x1 + x2, by = y0 - 2*y1 + y2;
|
||||||
float mx = x0 - sx, my = y0 - sy;
|
float mx = x0 - sx, my = y0 - sy;
|
||||||
float res[3],px,py,t,it;
|
float res[3] = {0.f,0.f,0.f};
|
||||||
|
float px,py,t,it,dist2;
|
||||||
float a_inv = precompute[i];
|
float a_inv = precompute[i];
|
||||||
if (a_inv == 0.0) { // if a_inv is 0, it's 2nd degree so use quadratic formula
|
if (a_inv == 0.0) { // if a_inv is 0, it's 2nd degree so use quadratic formula
|
||||||
float a = 3*(ax*bx + ay*by);
|
float a = 3*(ax*bx + ay*by);
|
||||||
|
@ -4546,6 +4718,10 @@ STBTT_DEF unsigned char * stbtt_GetGlyphSDF(const stbtt_fontinfo *info, float sc
|
||||||
float d = (mx*ax+my*ay) * a_inv;
|
float d = (mx*ax+my*ay) * a_inv;
|
||||||
num = stbtt__solve_cubic(b, c, d, res);
|
num = stbtt__solve_cubic(b, c, d, res);
|
||||||
}
|
}
|
||||||
|
dist2 = (x0-sx)*(x0-sx) + (y0-sy)*(y0-sy);
|
||||||
|
if (dist2 < min_dist*min_dist)
|
||||||
|
min_dist = (float) STBTT_sqrt(dist2);
|
||||||
|
|
||||||
if (num >= 1 && res[0] >= 0.0f && res[0] <= 1.0f) {
|
if (num >= 1 && res[0] >= 0.0f && res[0] <= 1.0f) {
|
||||||
t = res[0], it = 1.0f - t;
|
t = res[0], it = 1.0f - t;
|
||||||
px = it*it*x0 + 2*t*it*x1 + t*t*x2;
|
px = it*it*x0 + 2*t*it*x1 + t*t*x2;
|
||||||
|
@ -4805,6 +4981,12 @@ STBTT_DEF int stbtt_CompareUTF8toUTF16_bigendian(const char *s1, int len1, const
|
||||||
|
|
||||||
// FULL VERSION HISTORY
|
// FULL VERSION HISTORY
|
||||||
//
|
//
|
||||||
|
// 1.25 (2021-07-11) many fixes
|
||||||
|
// 1.24 (2020-02-05) fix warning
|
||||||
|
// 1.23 (2020-02-02) query SVG data for glyphs; query whole kerning table (but only kern not GPOS)
|
||||||
|
// 1.22 (2019-08-11) minimize missing-glyph duplication; fix kerning if both 'GPOS' and 'kern' are defined
|
||||||
|
// 1.21 (2019-02-25) fix warning
|
||||||
|
// 1.20 (2019-02-07) PackFontRange skips missing codepoints; GetScaleFontVMetrics()
|
||||||
// 1.19 (2018-02-11) OpenType GPOS kerning (horizontal only), STBTT_fmod
|
// 1.19 (2018-02-11) OpenType GPOS kerning (horizontal only), STBTT_fmod
|
||||||
// 1.18 (2018-01-29) add missing function
|
// 1.18 (2018-01-29) add missing function
|
||||||
// 1.17 (2017-07-23) make more arguments const; doc fix
|
// 1.17 (2017-07-23) make more arguments const; doc fix
|
||||||
|
|
Loading…
Reference in New Issue