Last active
February 17, 2021 19:56
-
-
Save shakesoda/f5ce0c34146b208d7fb62e79128a7cfc to your computer and use it in GitHub Desktop.
imgui for bgfx (works with unmodified imgui)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <imgui/imgui.h> | |
#include <SDL2/SDL_syswm.h> | |
#include "myon/imgui.hpp" | |
#include "myon/window.hpp" | |
#include "myon/timer.hpp" | |
#include "myon/cache.hpp" | |
#include "math/matrix.hpp" | |
#include <bgfx/bgfx.h> | |
#include <imgui/imgui_demo.cpp> | |
#include <imgui/imgui_lua_bindings.cpp> | |
#include "myon/graphics/views.hpp" | |
using namespace myon; | |
using namespace math; | |
using namespace graphics; | |
static bool g_MousePressed[3] = { false, false, false }; | |
static float g_MouseWheel = 0.0f; | |
static double g_Time = 0.0f; | |
static bgfx::TextureHandle g_FontTexture; | |
static bgfx::UniformHandle g_AttribLocationTex; | |
static bgfx::VertexDecl g_imguiVertex; | |
void ImGui_Myon_RenderDrawLists(ImDrawData* draw_data) { | |
ImGuiIO& io = ImGui::GetIO(); | |
// scale coordinates for retina displays (screen coordinates != framebuffer coordinates) | |
int fb_height = (int)(io.DisplaySize.y * io.DisplayFramebufferScale.y); | |
draw_data->ScaleClipRects(io.DisplayFramebufferScale); | |
for (int n = 0; n < draw_data->CmdListsCount; n++) { | |
const ImDrawList* cmd_list = draw_data->CmdLists[n]; | |
ImDrawIdx idx_buffer_offset = 0; | |
bgfx::TransientVertexBuffer vb; | |
if (bgfx::getAvailTransientVertexBuffer(cmd_list->VtxBuffer.Size, g_imguiVertex)) { | |
bgfx::allocTransientVertexBuffer(&vb, cmd_list->VtxBuffer.Size, g_imguiVertex); | |
memcpy(vb.data, cmd_list->VtxBuffer.Data, cmd_list->VtxBuffer.Size * sizeof(ImDrawVert)); | |
} | |
bgfx::TransientIndexBuffer ib; | |
if (bgfx::getAvailTransientIndexBuffer(cmd_list->IdxBuffer.Size)) { | |
bgfx::allocTransientIndexBuffer(&ib, cmd_list->IdxBuffer.Size); | |
memcpy(ib.data, cmd_list->IdxBuffer.Data, 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) { | |
pcmd->UserCallback(cmd_list, pcmd); | |
} | |
else { | |
bgfx::setTexture(0, g_AttribLocationTex, g_FontTexture); | |
bgfx::setScissor( | |
(uint16_t)(pcmd->ClipRect.x*window::get_dpi()), | |
(uint16_t)(pcmd->ClipRect.y*window::get_dpi()), | |
(uint16_t)(pcmd->ClipRect.z*window::get_dpi()), | |
(uint16_t)((pcmd->ClipRect.w - pcmd->ClipRect.y)*window::get_dpi()) | |
); | |
bgfx::setVertexBuffer(&vb); | |
bgfx::setIndexBuffer(&ib, idx_buffer_offset, pcmd->ElemCount); | |
bgfx::setState(0 | |
| BGFX_STATE_BLEND_ALPHA | |
| BGFX_STATE_RGB_WRITE | |
| BGFX_STATE_ALPHA_WRITE | |
| BGFX_STATE_CULL_CCW | |
); | |
bgfx::submit(VIEW_IMGUI, cache::get_shader(SHADER_INTERN_IMGUI)); | |
} | |
idx_buffer_offset += pcmd->ElemCount; | |
} | |
} | |
} | |
ImGui_Myon::ImGui_Myon() { | |
printf("[ImGui] Initializing...\n"); | |
ImGuiIO& io = ImGui::GetIO(); | |
io.KeyMap[ImGuiKey_Tab] = SDLK_TAB; | |
io.KeyMap[ImGuiKey_LeftArrow] = SDL_SCANCODE_LEFT; | |
io.KeyMap[ImGuiKey_RightArrow] = SDL_SCANCODE_RIGHT; | |
io.KeyMap[ImGuiKey_UpArrow] = SDL_SCANCODE_UP; | |
io.KeyMap[ImGuiKey_DownArrow] = SDL_SCANCODE_DOWN; | |
io.KeyMap[ImGuiKey_PageUp] = SDL_SCANCODE_PAGEUP; | |
io.KeyMap[ImGuiKey_PageDown] = SDL_SCANCODE_PAGEDOWN; | |
io.KeyMap[ImGuiKey_Home] = SDL_SCANCODE_HOME; | |
io.KeyMap[ImGuiKey_End] = SDL_SCANCODE_END; | |
io.KeyMap[ImGuiKey_Delete] = SDLK_DELETE; | |
io.KeyMap[ImGuiKey_Backspace] = SDLK_BACKSPACE; | |
io.KeyMap[ImGuiKey_Enter] = SDLK_RETURN; | |
io.KeyMap[ImGuiKey_Escape] = SDLK_ESCAPE; | |
io.KeyMap[ImGuiKey_A] = SDLK_a; | |
io.KeyMap[ImGuiKey_C] = SDLK_c; | |
io.KeyMap[ImGuiKey_V] = SDLK_v; | |
io.KeyMap[ImGuiKey_X] = SDLK_x; | |
io.KeyMap[ImGuiKey_Y] = SDLK_y; | |
io.KeyMap[ImGuiKey_Z] = SDLK_z; | |
// Alternatively you can set this to NULL and call ImGui::GetDrawData() after ImGui::Render() to get the same ImDrawData pointer. | |
io.RenderDrawListsFn = ImGui_Myon_RenderDrawLists; | |
io.SetClipboardTextFn = [](void*, const char* text) { | |
SDL_SetClipboardText(text); | |
}; | |
io.GetClipboardTextFn = [](void*) { | |
return (const char*)SDL_GetClipboardText(); | |
}; | |
io.ClipboardUserData = NULL; | |
#ifdef MYON_WINDOWS | |
SDL_Window *window = window::handle; | |
SDL_SysWMinfo wmInfo; | |
SDL_VERSION(&wmInfo.version); | |
SDL_GetWindowWMInfo(window, &wmInfo); | |
io.ImeWindowHandle = wmInfo.info.win.window; | |
#endif | |
// setup uniforms | |
g_AttribLocationTex = bgfx::createUniform("s_albedo", bgfx::UniformType::Int1); | |
// setup vertex format | |
g_imguiVertex.begin(); | |
g_imguiVertex.add(bgfx::Attrib::Position, 2, bgfx::AttribType::Float); | |
g_imguiVertex.add(bgfx::Attrib::TexCoord0, 2, bgfx::AttribType::Float); | |
g_imguiVertex.add(bgfx::Attrib::Color0, 4, bgfx::AttribType::Uint8, true); | |
g_imguiVertex.end(); | |
// Load fonts | |
// Build texture atlas | |
unsigned char* pixels; | |
int width, height; | |
// Load as RGBA 32-bits for OpenGL3 demo because it is more likely to be compatible with user's existing shader. | |
io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); | |
// Upload texture to graphics system | |
const bgfx::Memory *mem = bgfx::makeRef(pixels, width*height*4); | |
g_FontTexture = bgfx::createTexture2D(width, height, false, 1, bgfx::TextureFormat::RGBA8, BGFX_TEXTURE_NONE, mem); | |
} | |
ImGui_Myon::~ImGui_Myon() { | |
if (g_FontTexture.idx != bgfx::invalidHandle) { | |
bgfx::destroyTexture(g_FontTexture); | |
} | |
ImGui::Shutdown(); | |
} | |
void ImGui_Myon::wrap(lua_State *L) { | |
lState = L; | |
LoadImguiBindings(); | |
} | |
void ImGui_Myon::new_frame() { | |
ImGuiIO& io = ImGui::GetIO(); | |
// Setup display size every frame to accommodate for window resizing) | |
int w, h; | |
int display_w, display_h; | |
SDL_GetWindowSize(window::handle, &w, &h); | |
display_w = window::get_width(); | |
display_h = window::get_height(); | |
io.DisplaySize = ImVec2((float)w / window::get_dpi(), (float)h / window::get_dpi()); | |
io.DisplayFramebufferScale = ImVec2(w > 0 ? ((float)display_w / w) : 0, h > 0 ? ((float)display_h / h) : 0); | |
// Setup orthographic projection matrix | |
const float ortho_projection[] = { | |
2.0f/io.DisplaySize.x, 0.0f, 0.0f, 0.0f, | |
0.0f, 2.0f/-io.DisplaySize.y, 0.0f, 0.0f, | |
0.0f, 0.0f, -1.0f, 0.0f, | |
-1.0f, 1.0f, 0.0f, 1.0f | |
}; | |
mat4 proj(ortho_projection); | |
// update view properties | |
bgfx::setViewName(VIEW_IMGUI, "ImGui"); | |
bgfx::setViewRect(VIEW_IMGUI, 0, 0, bgfx::BackbufferRatio::Equal); | |
bgfx::setViewSeq(VIEW_IMGUI, true); | |
bgfx::setViewTransform(VIEW_IMGUI, NULL, proj.data, BGFX_VIEW_STEREO); | |
bgfx::touch(VIEW_IMGUI); | |
// Setup time step | |
double current_time = Timer::now(); | |
io.DeltaTime = g_Time > 0.0 ? (float)(current_time - g_Time) : (float)(1.0f / 60.0f); | |
g_Time = current_time; | |
// Hide OS mouse cursor if ImGui is drawing it | |
SDL_ShowCursor(io.MouseDrawCursor ? 0 : 1); | |
// Setup inputs | |
// (we already got mouse wheel, keyboard keys & characters from SDL_PollEvent()) | |
int mx, my; | |
Uint32 mouseMask = SDL_GetMouseState(&mx, &my); | |
// make sure not to grab mouse when it's grabbed (relative mode) | |
if (SDL_GetWindowFlags(window::handle) & SDL_WINDOW_MOUSE_FOCUS && !SDL_GetRelativeMouseMode()) { | |
// Mouse position, in pixels (set to -1,-1 if no mouse / on another screen, etc.) | |
io.MousePos = ImVec2((float)(mx / window::get_dpi()), (float)(my / window::get_dpi())); | |
} | |
else { | |
io.MousePos = ImVec2(-1, -1); | |
} | |
// If a mouse press event came, always pass it as "mouse held this frame", | |
// so we don't miss click-release events that are shorter than 1 frame. | |
io.MouseDown[0] = g_MousePressed[0] || (mouseMask & SDL_BUTTON(SDL_BUTTON_LEFT)) != 0; | |
io.MouseDown[1] = g_MousePressed[1] || (mouseMask & SDL_BUTTON(SDL_BUTTON_RIGHT)) != 0; | |
io.MouseDown[2] = g_MousePressed[2] || (mouseMask & SDL_BUTTON(SDL_BUTTON_MIDDLE)) != 0; | |
g_MousePressed[0] = g_MousePressed[1] = g_MousePressed[2] = false; | |
io.MouseWheel = g_MouseWheel; | |
g_MouseWheel = 0.0f; | |
ImGui::NewFrame(); | |
} | |
bool ImGui_Myon::process_event(SDL_Event* event) { | |
if (SDL_GetRelativeMouseMode()) { | |
return false; | |
} | |
ImGuiIO& io = ImGui::GetIO(); | |
switch (event->type) { | |
case SDL_MOUSEWHEEL: { | |
if (event->wheel.y > 0) { | |
g_MouseWheel = 1; | |
} | |
if (event->wheel.y < 0) { | |
g_MouseWheel = -1; | |
} | |
return true; | |
} | |
case SDL_MOUSEBUTTONDOWN: { | |
if (event->button.button == SDL_BUTTON_LEFT) { g_MousePressed[0] = true; } | |
if (event->button.button == SDL_BUTTON_RIGHT) { g_MousePressed[1] = true; } | |
if (event->button.button == SDL_BUTTON_MIDDLE) { g_MousePressed[2] = true; } | |
return true; | |
} | |
case SDL_TEXTINPUT: { | |
io.AddInputCharactersUTF8(event->text.text); | |
return true; | |
} | |
case SDL_KEYDOWN: | |
case SDL_KEYUP: { | |
int key = event->key.keysym.sym & ~SDLK_SCANCODE_MASK; | |
io.KeysDown[key] = (event->type == SDL_KEYDOWN); | |
io.KeyShift = ((SDL_GetModState() & KMOD_SHIFT) != 0); | |
io.KeyCtrl = ((SDL_GetModState() & KMOD_CTRL) != 0); | |
io.KeyAlt = ((SDL_GetModState() & KMOD_ALT) != 0); | |
io.KeySuper = ((SDL_GetModState() & KMOD_GUI) != 0); | |
return true; | |
} | |
} | |
return false; | |
} | |
bool ImGui_Myon::want_textinput() { | |
ImGuiIO &io = ImGui::GetIO(); | |
return io.WantTextInput; | |
} | |
bool ImGui_Myon::want_keyboard() { | |
ImGuiIO &io = ImGui::GetIO(); | |
return io.WantCaptureKeyboard; | |
} | |
bool ImGui_Myon::want_mouse() { | |
ImGuiIO &io = ImGui::GetIO(); | |
return io.WantCaptureMouse; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment