From 6db6c0c8c0f66b96f92fca77d44dc97cfd3e00da Mon Sep 17 00:00:00 2001 From: ocornut Date: Sat, 7 Mar 2015 00:35:47 +0000 Subject: [PATCH 01/48] Collapse triangle uses text color (not border color) --- imgui.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/imgui.cpp b/imgui.cpp index 2c213d2d..ca785a3e 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -2255,7 +2255,7 @@ static void RenderCollapseTriangle(ImVec2 p_min, bool opened, float scale, bool if (shadow && (window->Flags & ImGuiWindowFlags_ShowBorders) != 0) window->DrawList->AddTriangleFilled(a+ImVec2(2,2), b+ImVec2(2,2), c+ImVec2(2,2), window->Color(ImGuiCol_BorderShadow)); - window->DrawList->AddTriangleFilled(a, b, c, window->Color(ImGuiCol_Border)); + window->DrawList->AddTriangleFilled(a, b, c, window->Color(ImGuiCol_Text)); } // Calculate text size. Text can be multi-line. Optionally ignore text after a ## marker. From e01500f046a35470ca8a6b370d87a27f313bfa7e Mon Sep 17 00:00:00 2001 From: ocornut Date: Sat, 7 Mar 2015 12:18:01 +0000 Subject: [PATCH 02/48] Added comments on columns function; Added GetColumnIndex(), GetColumnsCount(), #154 --- imgui.cpp | 12 ++++++++++++ imgui.h | 8 +++++--- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index ca785a3e..dad3cd43 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -6465,6 +6465,18 @@ void ImGui::NextColumn() } } +int ImGui::GetColumnIndex() +{ + ImGuiWindow* window = GetCurrentWindow(); + return window->DC.ColumnsCurrent; +} + +int ImGui::GetColumnsCount() +{ + ImGuiWindow* window = GetCurrentWindow(); + return window->DC.ColumnsCount; +} + float ImGui::GetColumnOffset(int column_index) { ImGuiState& g = *GImGui; diff --git a/imgui.h b/imgui.h index c8addc70..5cac69e1 100644 --- a/imgui.h +++ b/imgui.h @@ -226,9 +226,11 @@ namespace ImGui IMGUI_API void Spacing(); IMGUI_API void Columns(int count = 1, const char* id = NULL, bool border=true); // setup number of columns IMGUI_API void NextColumn(); // next column - IMGUI_API float GetColumnOffset(int column_index = -1); - IMGUI_API void SetColumnOffset(int column_index, float offset); - IMGUI_API float GetColumnWidth(int column_index = -1); + IMGUI_API int GetColumnIndex(); // get current column index + IMGUI_API float GetColumnOffset(int column_index = -1); // get position of column line (in pixels, from the left side of the contents region). pass -1 to use current column, otherwise 0..GetcolumnsCount() inclusive. column 0 is usually 0.0f and not resizable unless you call this. + IMGUI_API void SetColumnOffset(int column_index, float offset_x); // set position of column line (in pixels, from the left side of the contents region). pass -1 to use current column. + IMGUI_API float GetColumnWidth(int column_index = -1); // column width (== GetColumnOffset(GetColumnIndex()+1) - GetColumnOffset(GetColumnOffset()) + IMGUI_API int GetColumnsCount(); // number of columns (what was passed to Columns()) IMGUI_API ImVec2 GetCursorPos(); // cursor position is relative to window position IMGUI_API float GetCursorPosX(); // " IMGUI_API float GetCursorPosY(); // " From 3cac43473784f09bee056ee175066d8cb72c0477 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sat, 7 Mar 2015 19:36:18 +0000 Subject: [PATCH 03/48] Minor FindTextDisplayEnd() optimisation --- imgui.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/imgui.cpp b/imgui.cpp index dad3cd43..8909e84a 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -2048,7 +2048,9 @@ void ImGui::Render() static const char* FindTextDisplayEnd(const char* text, const char* text_end = NULL) { const char* text_display_end = text; - while ((!text_end || text_display_end < text_end) && *text_display_end != '\0' && (text_display_end[0] != '#' || text_display_end[1] != '#')) + if (!text_end) + text_end = (const char*)-1; + while (text_display_end < text_end && *text_display_end != '\0' && (text_display_end[0] != '#' || text_display_end[1] != '#')) text_display_end++; return text_display_end; } From 81a742bf547a317c13473418d64077661a9ee0cb Mon Sep 17 00:00:00 2001 From: ocornut Date: Sat, 7 Mar 2015 21:53:33 +0000 Subject: [PATCH 04/48] Added "###" syntax to specify label that isn't part of the hashed ID (#107) --- imgui.cpp | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 8909e84a..1c40852a 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -657,6 +657,7 @@ static const char* ImStristr(const char* haystack, const char* needle, const cha } // Pass data_size==0 for zero-terminated string +// Try to replace with FNV1a hash? static ImU32 ImCrc32(const void* data, size_t data_size, ImU32 seed = 0) { static ImU32 crc32_lut[256] = { 0 }; @@ -671,7 +672,9 @@ static ImU32 ImCrc32(const void* data, size_t data_size, ImU32 seed = 0) crc32_lut[i] = crc; } } - ImU32 crc = ~seed; + + seed = ~seed; + ImU32 crc = seed; const unsigned char* current = (const unsigned char*)data; if (data_size > 0) @@ -684,7 +687,16 @@ static ImU32 ImCrc32(const void* data, size_t data_size, ImU32 seed = 0) { // Zero-terminated string while (unsigned char c = *current++) - crc = (crc >> 8) ^ crc32_lut[(crc & 0xFF) ^ c]; + { + // We support a syntax of "label###id" where only "###id" is included in the hash, and only "label" gets displayed. + // Because this syntax is rarely used we are optimizing for the common case. + // - If we reach ### in the string we discard the hash so far and reset to the seed. + // - We don't do 'current += 2; continue;' after handling ### to keep the code smaller. + if (c == '#' && current[0] == '#' && current[1] == '#') + crc = seed; + + crc = (crc >> 8) ^ crc32_lut[(crc & 0xFF) ^ c]; + } } return ~crc; } @@ -4283,9 +4295,8 @@ bool ImGui::CollapsingHeader(const char* label, const char* str_id, bool display // When logging is enabled, if automatically expand tree nodes (but *NOT* collapsing headers.. seems like sensible behaviour). // NB- If we are above max depth we still allow manually opened nodes to be logged. - if (!display_frame) - if (g.LogEnabled && window->DC.TreeDepth < g.LogAutoExpandMaxDepth) - opened = true; + if (g.LogEnabled && !display_frame && window->DC.TreeDepth < g.LogAutoExpandMaxDepth) + opened = true; if (!ItemAdd(bb, &id)) return opened; @@ -6389,7 +6400,6 @@ bool ImGui::IsClipped(const ImVec2& item_size) static bool ItemAdd(const ImGuiAabb& bb, const ImGuiID* id) { - //ImGuiState& g = *GImGui; ImGuiWindow* window = GetCurrentWindow(); window->DC.LastItemID = id ? *id : 0; window->DC.LastItemAabb = bb; From fbbde3a7c0364c618edbfda667e08cd75614d653 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sat, 7 Mar 2015 21:54:46 +0000 Subject: [PATCH 05/48] Updated documentation, better FAQ on ids and usage of "##" and "###" (#107) --- imgui.cpp | 82 +++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 55 insertions(+), 27 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 1c40852a..6c377812 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -9,9 +9,9 @@ Index - MISSION STATEMENT - END-USER GUIDE - - PROGRAMMER GUIDE - - API BREAKING CHANGES - - TROUBLESHOOTING & FREQUENTLY ASKED QUESTIONS + - PROGRAMMER GUIDE (read me!) + - API BREAKING CHANGES (read me when you update!) + - FREQUENTLY ASKED QUESTIONS & TROUBLESHOOTING (read me!) - ISSUES & TODO-LIST - CODE - SAMPLE CODE @@ -27,15 +27,15 @@ - minimize screen real-estate usage - minimize setup and maintenance - minimize state storage on user side - - portable, minimize dependencies, run on target (consoles, etc.) + - portable, minimize dependencies, run on target (consoles, phones, etc.) - efficient runtime (NB- we do allocate when "growing" content - creating a window / opening a tree node for the first time, etc. - but a typical frame won't allocate anything) - - read about immediate-mode GUI principles @ http://mollyrocket.com/861, http://mollyrocket.com/forums/index.html + - read about immediate-mode gui principles @ http://mollyrocket.com/861, http://mollyrocket.com/forums/index.html Designed for developers and content-creators, not the typical end-user! Some of the weaknesses includes: - doesn't look fancy, doesn't animate - limited layout features, intricate layouts are typically crafted in code - - occasionally use statically sized buffers for string manipulations - won't crash, but some long text may be clipped - + - occasionally uses statically sized buffers for string manipulations - won't crash, but some long text may be clipped. functions like ImGui::TextUnformatted() don't have such restriction. + END-USER GUIDE ============== @@ -63,12 +63,12 @@ PROGRAMMER GUIDE ================ - - your code creates the UI, if your code doesn't run the UI is gone! == dynamic UI, no construction step, less data retention on your side, no state duplication, less sync, less errors. - - call and read ImGui::ShowTestWindow() for user-side sample code + - read the FAQ below this section! + - your code creates the UI, if your code doesn't run the UI is gone! == very dynamic UI, no construction/destructions steps, less data retention on your side, no state duplication, less sync, less bugs. + - call and read ImGui::ShowTestWindow() for sample code demonstrating most features. - see examples/ folder for standalone sample applications. - customization: use the style editor or PushStyleColor/PushStyleVar to tweak the look of the interface (e.g. if you want a more compact UI or a different color scheme). - - getting started: - initialisation: call ImGui::GetIO() and fill the 'Settings' data. - every frame: @@ -167,29 +167,57 @@ - 2014/08/28 (1.09) - changed the behavior of IO.PixelCenterOffset following various rendering fixes - TROUBLESHOOTING & FREQUENTLY ASKED QUESTIONS + FREQUENTLY ASKED QUESTIONS & TROUBLESHOOTING ============================================ If text or lines are blurry when integrating ImGui in your engine: + - in your Render function, try translating your projection matrix by (0.5f,0.5f) or (0.375f,0.375f) - If you are confused about the meaning or use of ID in ImGui: - - many widgets requires state to be carried over multiple frames (most typically ImGui often wants remember what is the "active" widget). - to do so they need an unique ID. unique ID are typically derived from a string label, an indice or a pointer. - when you call Button("OK") the button shows "OK" and also use "OK" as an ID. + A primer on the meaning and use of ID in ImGui: + + - widgets require state to be carried over multiple frames (most typically ImGui often needs to remember what is the "active" widget). + to do so they need an unique ID. unique ID are typically derived from a string label, an integer index or a pointer. + + Button("OK"); // Label = "OK", ID = hash of "OK" + Button("Cancel"); // Label = "Cancel", ID = hash of "Cancel" + - ID are uniquely scoped within Windows so no conflict can happen if you have two buttons called "OK" in two different Windows. - within a same Window, use PushID() / PopID() to easily create scopes and avoid ID conflicts. - so if you have a loop creating "multiple" items, you can use PushID() / PopID() with the index of each item, or their pointer, etc. - some functions like TreeNode() implicitly creates a scope for you by calling PushID() - - when dealing with trees, ID are important because you want to preserve the opened/closed state of tree nodes. - depending on your use cases you may want to use strings, indices or pointers as ID. experiment and see what makes more sense! - e.g. When displaying a single object that may change over time, using a static string as ID will preserve your node open/closed state when the targeted object change - e.g. When displaying a list of objects, using indices or pointers as ID will preserve the node open/closed state per object - - when passing a label you can optionally specify extra unique ID information within the same string using "##". This helps solving the simpler collision cases. - e.g. "Label" display "Label" and uses "Label" as ID - e.g. "Label##Foobar" display "Label" and uses "Label##Foobar" as ID - e.g. "##Foobar" display an empty label and uses "##Foobar" as ID - - read articles about immediate-mode ui principles (see web links) to understand the requirement and use of ID. + + - when passing a label you can optionally specify extra unique ID information within string itself. This helps solving the simpler collision cases. + use "##" to pass a complement to the ID that won't be visible to the end-user: + + Button("Play##0"); // Label = "Play", ID = hash of "Play##0" + Button("Play##1"); // Label = "Play", ID = hash of "Play##1" (different from above) + + use "###" to pass a label that isn't part of ID. You can use that to change labels while preserving a constant ID. + + Button("Hello###ID"; // Label = "Hello", ID = hash of "ID" + Button("World###ID"; // Label = "World", ID = hash of "ID" (same as above) + + - use PushID() / PopID() to create scopes and avoid ID conflicts within the same Window: + + Button("Click"); // Label = "Click", ID = hash of "Click" + PushID("node"); + Button("Click"); // Label = "Click", ID = hash of "node" and "Click" + for (int i = 0; i < 100; i++) + { + PushID(i); + Button("Click"); // Label = "Click", ID = hash of "node" and i and "label" + PopID(); + } + PopID(); + PushID(my_ptr); + Button("Click"); // Label = "Click", ID = hash of ptr and "Click" + PopID(); + + so if you have a loop creating multiple items, you can use PushID() / PopID() with the index of each item, or their pointer, etc. + some functions like TreeNode() implicitly creates a scope for you by calling PushID(). + + - when working with trees, ID are used to preserve the opened/closed state of tree nodes. + depending on your use cases you may want to use strings, indices or pointers as ID. + e.g. when displaying a single object that may change over time (1-1 relationship), using a static string as ID will preserve your node open/closed state when the targeted object change. + e.g. when displaying a list of objects, using indices or pointers as ID will preserve the node open/closed state differerently. experiment and see what makes more sense! If you want to load a different font than the default (ProggyClean.ttf, size 13) From a8c58c7a359704e357c54a9e773e3e88ff5dd217 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sat, 7 Mar 2015 22:01:06 +0000 Subject: [PATCH 06/48] Minor tweaks. --- imgui.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 6c377812..6dbaf41f 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -2708,7 +2708,8 @@ static ImGuiWindow* CreateNewWindow(const char* name, ImVec2 size, ImGuiWindowFl // - 'size' for a regular window denote the initial size for first-time creation (no saved data) and isn't that useful. Use SetNextWindowSize() prior to calling Begin() for more flexible window manipulation. // - A default window called "Debug" is automatically stacked at the beginning of every frame so you can use widgets without explicitly calling a Begin/End pair. // - Begin/End can be called multiple times during the frame with the same window name to append content. -// - The window name is used as a unique identifier to preserve window information across frames (and save rudimentary information to the .ini file). Note that you can use ## to append unique data that isn't displayed, e.g. "My window##1" will use "My window##1" as unique window ID but display "My window" to the user. +// - The window name is used as a unique identifier to preserve window information across frames (and save rudimentary information to the .ini file). +// You can use the "##" or "###" markers to use the same label with different id, or same id with different label. See documentation at the top of this file. // - Return false when window is collapsed, so you can early out in your code. You always need to call ImGui::End() even if false is returned. // - Passing 'bool* p_opened' displays a Close button on the upper-right corner of the window, the pointed value will be set to false when the button is pressed. // - Passing non-zero 'size' is roughly equivalent to calling SetNextWindowSize(size, ImGuiSetCond_FirstUseEver) prior to calling Begin(). @@ -2947,7 +2948,7 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size, float bg { // Manual resize grip const ImGuiAabb resize_aabb(window->Aabb().GetBR()-ImVec2(18,18), window->Aabb().GetBR()); - const ImGuiID resize_id = window->GetID("##RESIZE"); + const ImGuiID resize_id = window->GetID("#RESIZE"); bool hovered, held; ButtonBehaviour(resize_aabb, resize_id, &hovered, &held, true); resize_col = window->Color(held ? ImGuiCol_ResizeGripActive : hovered ? ImGuiCol_ResizeGripHovered : ImGuiCol_ResizeGrip); @@ -4064,7 +4065,7 @@ static bool CloseWindowButton(bool* p_opened) { ImGuiWindow* window = GetCurrentWindow(); - const ImGuiID id = window->GetID("##CLOSE"); + const ImGuiID id = window->GetID("#CLOSE"); const float size = window->TitleBarHeight() - 4.0f; const ImGuiAabb bb(window->Aabb().GetTR() + ImVec2(-3.0f-size,2.0f), window->Aabb().GetTR() + ImVec2(-3.0f,2.0f+size)); @@ -6159,7 +6160,7 @@ bool ImGui::ColorButton(const ImVec4& col, bool small_height, bool outline_borde return false; const ImGuiStyle& style = g.Style; - const ImGuiID id = window->GetID("##colorbutton"); + const ImGuiID id = window->GetID("#colorbutton"); const float square_size = window->FontSize(); const ImGuiAabb bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(square_size + style.FramePadding.x*2, square_size + (small_height ? 0 : style.FramePadding.y*2))); ItemSize(bb); From 45a35c24c8e3b9042fd5960c6265589629417fd2 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sat, 7 Mar 2015 22:20:34 +0000 Subject: [PATCH 07/48] ShowTestWindow(): Added "Manipulating Window Title" example. --- imgui.cpp | 36 +++++++++++++++++++++++++++++++++--- 1 file changed, 33 insertions(+), 3 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 6dbaf41f..4ef66c7a 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -11,7 +11,7 @@ - END-USER GUIDE - PROGRAMMER GUIDE (read me!) - API BREAKING CHANGES (read me when you update!) - - FREQUENTLY ASKED QUESTIONS & TROUBLESHOOTING (read me!) + - FREQUENTLY ASKED QUESTIONS (FAQ) & TROUBLESHOOTING (read me!) - ISSUES & TODO-LIST - CODE - SAMPLE CODE @@ -167,8 +167,8 @@ - 2014/08/28 (1.09) - changed the behavior of IO.PixelCenterOffset following various rendering fixes - FREQUENTLY ASKED QUESTIONS & TROUBLESHOOTING - ============================================ + FREQUENTLY ASKED QUESTIONS (FAQ) & TROUBLESHOOTING + ================================================== If text or lines are blurry when integrating ImGui in your engine: @@ -8398,6 +8398,7 @@ static void ShowExampleAppConsole(bool* opened); static void ShowExampleAppLongText(bool* opened); static void ShowExampleAppAutoResize(bool* opened); static void ShowExampleAppFixedOverlay(bool* opened); +static void ShowExampleAppManipulatingWindowTitle(bool* opened); static void ShowExampleAppCustomRendering(bool* opened); // Demonstrate ImGui features (unfortunately this makes this function a little bloated!) @@ -9112,12 +9113,14 @@ void ImGui::ShowTestWindow(bool* opened) static bool show_app_auto_resize = false; static bool show_app_fixed_overlay = false; static bool show_app_custom_rendering = false; + static bool show_app_manipulating_window_title = false; if (ImGui::CollapsingHeader("App Examples")) { ImGui::Checkbox("Console", &show_app_console); ImGui::Checkbox("Long text display", &show_app_long_text); ImGui::Checkbox("Auto-resizing window", &show_app_auto_resize); ImGui::Checkbox("Simple overlay", &show_app_fixed_overlay); + ImGui::Checkbox("Manipulating window title", &show_app_manipulating_window_title); ImGui::Checkbox("Custom rendering", &show_app_custom_rendering); } if (show_app_console) @@ -9128,6 +9131,8 @@ void ImGui::ShowTestWindow(bool* opened) ShowExampleAppAutoResize(&show_app_auto_resize); if (show_app_fixed_overlay) ShowExampleAppFixedOverlay(&show_app_fixed_overlay); + if (show_app_manipulating_window_title) + ShowExampleAppManipulatingWindowTitle(&show_app_manipulating_window_title); if (show_app_custom_rendering) ShowExampleAppCustomRendering(&show_app_custom_rendering); @@ -9167,6 +9172,31 @@ static void ShowExampleAppFixedOverlay(bool* opened) ImGui::End(); } +static void ShowExampleAppManipulatingWindowTitle(bool* opened) +{ + // By default, Windows are uniquely identified by their title. + // You can use the "##" and "###" markers to manipulate the display/ID. Read FAQ at the top of this file! + + // Using "##" to display same title but have unique identifier. + ImGui::SetNextWindowPos(ImVec2(100,100), ImGuiSetCond_FirstUseEver); + ImGui::Begin("Same title as another window##1"); + ImGui::Text("This is window 1.\nMy title is the same as window 2, but my identifier is unique."); + ImGui::End(); + + ImGui::SetNextWindowPos(ImVec2(100,200), ImGuiSetCond_FirstUseEver); + ImGui::Begin("Same title as another window##2"); + ImGui::Text("This is window 2.\nMy title is the same as window 1, but my identifier is unique."); + ImGui::End(); + + // Using "###" to display a changing title but keep a static identifier "MyWindow" + char buf[128]; + ImFormatString(buf, IM_ARRAYSIZE(buf), "Animated title %c %d###MyWindow", "|/-\\"[(int)(ImGui::GetTime()/0.25f)&3], rand()); + ImGui::SetNextWindowPos(ImVec2(100,300), ImGuiSetCond_FirstUseEver); + ImGui::Begin(buf); + ImGui::Text("This window has a changing title."); + ImGui::End(); +} + static void ShowExampleAppCustomRendering(bool* opened) { if (!ImGui::Begin("Example: Custom Rendering", opened)) From 3c225bbf886ca8e937e26956ff25b2dd4ab8a9cf Mon Sep 17 00:00:00 2001 From: ocornut Date: Sat, 7 Mar 2015 22:24:45 +0000 Subject: [PATCH 08/48] Fixed typo in comments --- imgui.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/imgui.cpp b/imgui.cpp index 4ef66c7a..51295ba9 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -217,7 +217,7 @@ - when working with trees, ID are used to preserve the opened/closed state of tree nodes. depending on your use cases you may want to use strings, indices or pointers as ID. e.g. when displaying a single object that may change over time (1-1 relationship), using a static string as ID will preserve your node open/closed state when the targeted object change. - e.g. when displaying a list of objects, using indices or pointers as ID will preserve the node open/closed state differerently. experiment and see what makes more sense! + e.g. when displaying a list of objects, using indices or pointers as ID will preserve the node open/closed state differently. experiment and see what makes more sense! If you want to load a different font than the default (ProggyClean.ttf, size 13) From f9473b807b015e10a543ac8633dc19cd655edbb6 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sat, 7 Mar 2015 22:49:16 +0000 Subject: [PATCH 09/48] Fixed comments --- imgui.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/imgui.cpp b/imgui.cpp index 51295ba9..42c7d186 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -7459,7 +7459,7 @@ void ImFontAtlas::RenderCustomTexData() TexUvWhitePixel = ImVec2((TexExtraDataPos.x + 0.5f) / TexWidth, (TexExtraDataPos.y + 0.5f) / TexHeight); // Draw a mouse cursor into texture - // Because our font uses an alpha texture, we have to spread the cursor in 2 parts (black/white) which will be rendered separately. + // Because our font uses a single color channel, we have to spread the cursor in 2 layers (black/white) which will be rendered separately. const char cursor_pixels[] = { "X " From 62c900606dd50c175544328ebe9bb2e89e78bfb6 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sat, 7 Mar 2015 23:35:36 +0000 Subject: [PATCH 10/48] Fixed .ini saving for windows using ### marker. FindWindowSettings() uses ID compares (#107) --- imgui.cpp | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 42c7d186..1937c109 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -980,6 +980,7 @@ struct ImGuiTextEditState struct ImGuiIniData { char* Name; + ImGuiID ID; ImVec2 Pos; ImVec2 Size; bool Collapsed; @@ -1578,10 +1579,11 @@ void ImGui::MemFree(void* ptr) static ImGuiIniData* FindWindowSettings(const char* name) { ImGuiState& g = *GImGui; + ImGuiID id = ImCrc32(name, 0); for (size_t i = 0; i != g.Settings.size(); i++) { ImGuiIniData* ini = g.Settings[i]; - if (ImStricmp(ini->Name, name) == 0) + if (ini->ID == id) return ini; } return NULL; @@ -1592,6 +1594,7 @@ static ImGuiIniData* AddWindowSettings(const char* name) ImGuiIniData* ini = (ImGuiIniData*)ImGui::MemAlloc(sizeof(ImGuiIniData)); new(ini) ImGuiIniData(); ini->Name = ImStrdup(name); + ini->ID = ImCrc32(name, 0); ini->Collapsed = false; ini->Pos = ImVec2(FLT_MAX,FLT_MAX); ini->Size = ImVec2(0,0); @@ -1676,7 +1679,10 @@ static void SaveSettings() const ImGuiIniData* settings = g.Settings[i]; if (settings->Pos.x == FLT_MAX) continue; - fprintf(f, "[%s]\n", settings->Name); + const char* name = settings->Name; + if (const char* p = strstr(name, "###")) // Skip to the "###" marker if any. We don't skip past to match the behavior of GetID() + name = p; + fprintf(f, "[%s]\n", name); fprintf(f, "Pos=%d,%d\n", (int)settings->Pos.x, (int)settings->Pos.y); fprintf(f, "Size=%d,%d\n", (int)settings->Size.x, (int)settings->Size.y); fprintf(f, "Collapsed=%d\n", settings->Collapsed); @@ -2648,8 +2654,8 @@ void ImGui::EndChildFrame() static ImGuiWindow* FindWindowByName(const char* name) { // FIXME-OPT: Store sorted hashes -> pointers. - ImGuiID id = ImCrc32(name, 0, 0); ImGuiState& g = *GImGui; + ImGuiID id = ImCrc32(name, 0); for (size_t i = 0; i < g.Windows.size(); i++) if (g.Windows[i]->ID == id) return g.Windows[i]; From a691a245b7c4bc7bdee56a99e8884d8fd8c2d310 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sat, 7 Mar 2015 23:52:26 +0000 Subject: [PATCH 11/48] GetID() doesn't need to account for empty IDStack --- imgui.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 1937c109..58e92916 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1451,7 +1451,9 @@ void ImGuiTextBuffer::append(const char* fmt, ...) ImGuiWindow::ImGuiWindow(const char* name) { Name = ImStrdup(name); - ID = GetID(name); + ID = ImCrc32(name, 0); + IDStack.push_back(ID); + Flags = 0; PosFloat = Pos = ImVec2(0.0f, 0.0f); Size = SizeFull = ImVec2(0.0f, 0.0f); @@ -1467,7 +1469,6 @@ ImGuiWindow::ImGuiWindow(const char* name) AutoFitOnlyGrows = false; SetWindowPosAllowFlags = SetWindowSizeAllowFlags = SetWindowCollapsedAllowFlags = ImGuiSetCond_Always | ImGuiSetCond_Once | ImGuiSetCond_FirstUseEver; - IDStack.push_back(ID); LastFrameDrawn = -1; ItemWidthDefault = 0.0f; FontWindowScale = 1.0f; @@ -1498,7 +1499,7 @@ ImGuiWindow::~ImGuiWindow() ImGuiID ImGuiWindow::GetID(const char* str) { - const ImGuiID seed = IDStack.empty() ? 0 : IDStack.back(); + ImGuiID seed = IDStack.back(); const ImGuiID id = ImCrc32(str, 0, seed); RegisterAliveId(id); return id; @@ -1506,7 +1507,7 @@ ImGuiID ImGuiWindow::GetID(const char* str) ImGuiID ImGuiWindow::GetID(const void* ptr) { - const ImGuiID seed = IDStack.empty() ? 0 : IDStack.back(); + ImGuiID seed = IDStack.back(); const ImGuiID id = ImCrc32(&ptr, sizeof(void*), seed); RegisterAliveId(id); return id; @@ -2816,9 +2817,8 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size, float bg // Setup and draw window if (first_begin_of_the_frame) { - // Seed ID stack with our window pointer - window->IDStack.resize(0); - ImGui::PushID(window); + // Reset ID stack + window->IDStack.resize(1); // Move window (at the beginning of the frame to avoid input lag or sheering). Only valid for root windows. const ImGuiID move_id = window->GetID("#MOVE"); From 92c35e2772c7ac248ce4ab02193e9e1cd94feb1e Mon Sep 17 00:00:00 2001 From: ocornut Date: Sat, 7 Mar 2015 23:53:03 +0000 Subject: [PATCH 12/48] Rename ImCrc32() -> ImHash() --- imgui.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 58e92916..3e140a47 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -445,7 +445,7 @@ static size_t ImFormatString(char* buf, size_t buf_size, const char* fmt, static size_t ImFormatStringV(char* buf, size_t buf_size, const char* fmt, va_list args); // Helpers: Misc -static ImU32 ImCrc32(const void* data, size_t data_size, ImU32 seed); +static ImU32 ImHash(const void* data, size_t data_size, ImU32 seed); static bool ImLoadFileToMemory(const char* filename, const char* file_open_mode, void** out_file_data, size_t* out_file_size, size_t padding_bytes = 0); static inline int ImUpperPowerOfTwo(int v) { v--; v |= v >> 1; v |= v >> 2; v |= v >> 4; v |= v >> 8; v |= v >> 16; v++; return v; } static inline bool ImCharIsSpace(int c) { return c == ' ' || c == '\t' || c == 0x3000; } @@ -686,7 +686,7 @@ static const char* ImStristr(const char* haystack, const char* needle, const cha // Pass data_size==0 for zero-terminated string // Try to replace with FNV1a hash? -static ImU32 ImCrc32(const void* data, size_t data_size, ImU32 seed = 0) +static ImU32 ImHash(const void* data, size_t data_size, ImU32 seed = 0) { static ImU32 crc32_lut[256] = { 0 }; if (!crc32_lut[1]) @@ -1451,7 +1451,7 @@ void ImGuiTextBuffer::append(const char* fmt, ...) ImGuiWindow::ImGuiWindow(const char* name) { Name = ImStrdup(name); - ID = ImCrc32(name, 0); + ID = ImHash(name, 0); IDStack.push_back(ID); Flags = 0; @@ -1500,7 +1500,7 @@ ImGuiWindow::~ImGuiWindow() ImGuiID ImGuiWindow::GetID(const char* str) { ImGuiID seed = IDStack.back(); - const ImGuiID id = ImCrc32(str, 0, seed); + const ImGuiID id = ImHash(str, 0, seed); RegisterAliveId(id); return id; } @@ -1508,7 +1508,7 @@ ImGuiID ImGuiWindow::GetID(const char* str) ImGuiID ImGuiWindow::GetID(const void* ptr) { ImGuiID seed = IDStack.back(); - const ImGuiID id = ImCrc32(&ptr, sizeof(void*), seed); + const ImGuiID id = ImHash(&ptr, sizeof(void*), seed); RegisterAliveId(id); return id; } @@ -1580,7 +1580,7 @@ void ImGui::MemFree(void* ptr) static ImGuiIniData* FindWindowSettings(const char* name) { ImGuiState& g = *GImGui; - ImGuiID id = ImCrc32(name, 0); + ImGuiID id = ImHash(name, 0); for (size_t i = 0; i != g.Settings.size(); i++) { ImGuiIniData* ini = g.Settings[i]; @@ -1595,7 +1595,7 @@ static ImGuiIniData* AddWindowSettings(const char* name) ImGuiIniData* ini = (ImGuiIniData*)ImGui::MemAlloc(sizeof(ImGuiIniData)); new(ini) ImGuiIniData(); ini->Name = ImStrdup(name); - ini->ID = ImCrc32(name, 0); + ini->ID = ImHash(name, 0); ini->Collapsed = false; ini->Pos = ImVec2(FLT_MAX,FLT_MAX); ini->Size = ImVec2(0,0); @@ -2656,7 +2656,7 @@ static ImGuiWindow* FindWindowByName(const char* name) { // FIXME-OPT: Store sorted hashes -> pointers. ImGuiState& g = *GImGui; - ImGuiID id = ImCrc32(name, 0); + ImGuiID id = ImHash(name, 0); for (size_t i = 0; i < g.Windows.size(); i++) if (g.Windows[i]->ID == id) return g.Windows[i]; From e843539aab7945a1eb277b886b76c336371ee503 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 8 Mar 2015 10:38:13 +0000 Subject: [PATCH 13/48] ShowTestWindow: example apps showing even if main window is collaposed. --- imgui.cpp | 38 ++++++++++++++++++++------------------ 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 3e140a47..98040a72 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -8410,6 +8410,26 @@ static void ShowExampleAppCustomRendering(bool* opened); // Demonstrate ImGui features (unfortunately this makes this function a little bloated!) void ImGui::ShowTestWindow(bool* opened) { + // Examples apps + static bool show_app_console = false; + static bool show_app_long_text = false; + static bool show_app_auto_resize = false; + static bool show_app_fixed_overlay = false; + static bool show_app_custom_rendering = false; + static bool show_app_manipulating_window_title = false; + if (show_app_console) + ShowExampleAppConsole(&show_app_console); + if (show_app_long_text) + ShowExampleAppLongText(&show_app_long_text); + if (show_app_auto_resize) + ShowExampleAppAutoResize(&show_app_auto_resize); + if (show_app_fixed_overlay) + ShowExampleAppFixedOverlay(&show_app_fixed_overlay); + if (show_app_manipulating_window_title) + ShowExampleAppManipulatingWindowTitle(&show_app_manipulating_window_title); + if (show_app_custom_rendering) + ShowExampleAppCustomRendering(&show_app_custom_rendering); + static bool no_titlebar = false; static bool no_border = true; static bool no_resize = false; @@ -9114,12 +9134,6 @@ void ImGui::ShowTestWindow(bool* opened) } } - static bool show_app_console = false; - static bool show_app_long_text = false; - static bool show_app_auto_resize = false; - static bool show_app_fixed_overlay = false; - static bool show_app_custom_rendering = false; - static bool show_app_manipulating_window_title = false; if (ImGui::CollapsingHeader("App Examples")) { ImGui::Checkbox("Console", &show_app_console); @@ -9129,18 +9143,6 @@ void ImGui::ShowTestWindow(bool* opened) ImGui::Checkbox("Manipulating window title", &show_app_manipulating_window_title); ImGui::Checkbox("Custom rendering", &show_app_custom_rendering); } - if (show_app_console) - ShowExampleAppConsole(&show_app_console); - if (show_app_long_text) - ShowExampleAppLongText(&show_app_long_text); - if (show_app_auto_resize) - ShowExampleAppAutoResize(&show_app_auto_resize); - if (show_app_fixed_overlay) - ShowExampleAppFixedOverlay(&show_app_fixed_overlay); - if (show_app_manipulating_window_title) - ShowExampleAppManipulatingWindowTitle(&show_app_manipulating_window_title); - if (show_app_custom_rendering) - ShowExampleAppCustomRendering(&show_app_custom_rendering); ImGui::End(); } From ede45389f4bc29ea5c0bc3623051412f7b30c5d9 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 8 Mar 2015 11:24:02 +0000 Subject: [PATCH 14/48] Scrollbar grab have a minimum size (mentioned in #150) --- imgui.cpp | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 98040a72..63882a24 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -263,7 +263,6 @@ - main: IsItemHovered() make it more consistent for various type of widgets, widgets with multiple components, etc. also effectively IsHovered() region sometimes differs from hot region, e.g tree nodes - main: IsItemHovered() info stored in a stack? so that 'if TreeNode() { Text; TreePop; } if IsHovered' return the hover state of the TreeNode? - scrollbar: use relative mouse movement when first-clicking inside of scroll grab box. - - scrollbar: make the grab visible and a minimum size for long scroll regions !- input number: very large int not reliably supported because of int<>float conversions. - input number: optional range min/max for Input*() functions - input number: holding [-]/[+] buttons could increase the step speed non-linearly (or user-controlled) @@ -3014,35 +3013,35 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size, float bg if (window->ScrollbarY) { ImGuiAabb scrollbar_bb(window->Aabb().Max.x - style.ScrollBarWidth, title_bar_aabb.Max.y+1, window->Aabb().Max.x, window->Aabb().Max.y-1); - //window->DrawList->AddLine(scrollbar_bb.GetTL(), scrollbar_bb.GetBL(), g.Colors[ImGuiCol_Border]); window->DrawList->AddRectFilled(scrollbar_bb.Min, scrollbar_bb.Max, window->Color(ImGuiCol_ScrollbarBg)); scrollbar_bb.Expand(ImVec2(-3,-3)); - + const float scrollbar_height = scrollbar_bb.GetHeight(); + const float grab_size_y_norm = ImSaturate(window->Size.y / ImMax(window->SizeContentsFit.y, window->Size.y)); - const float grab_size_y = scrollbar_bb.GetHeight() * grab_size_y_norm; + const float grab_size_y_pixels = ImMax(10.0f, scrollbar_height * grab_size_y_norm); // Handle input right away (none of the code above is relying on scrolling position) bool held = false; bool hovered = false; - if (grab_size_y_norm < 1.0f) + if (grab_size_y_pixels < scrollbar_height) { const ImGuiID scrollbar_id = window->GetID("#SCROLLY"); ButtonBehaviour(scrollbar_bb, scrollbar_id, &hovered, &held, true); if (held) { g.HoveredId = scrollbar_id; - const float pos_y_norm = ImSaturate((g.IO.MousePos.y - (scrollbar_bb.Min.y + grab_size_y*0.5f)) / (scrollbar_bb.GetHeight() - grab_size_y)) * (1.0f - grab_size_y_norm); - window->ScrollY = (float)(int)(pos_y_norm * window->SizeContentsFit.y); + const float pos_y_norm = ImSaturate((g.IO.MousePos.y - (scrollbar_bb.Min.y + grab_size_y_pixels*0.5f)) / (scrollbar_height - grab_size_y_pixels)); + window->ScrollY = (float)(int)(pos_y_norm * (window->SizeContentsFit.y - window->Size.y)); window->NextScrollY = window->ScrollY; } } // Normalized height of the grab - const float pos_y_norm = ImSaturate(window->ScrollY / ImMax(0.0f, window->SizeContentsFit.y)); + const float pos_y_norm = ImSaturate(window->ScrollY / ImMax(0.0f, window->SizeContentsFit.y - window->Size.y)); const ImU32 grab_col = window->Color(held ? ImGuiCol_ScrollbarGrabActive : hovered ? ImGuiCol_ScrollbarGrabHovered : ImGuiCol_ScrollbarGrab); window->DrawList->AddRectFilled( - ImVec2(scrollbar_bb.Min.x, ImLerp(scrollbar_bb.Min.y, scrollbar_bb.Max.y, pos_y_norm)), - ImVec2(scrollbar_bb.Max.x, ImLerp(scrollbar_bb.Min.y, scrollbar_bb.Max.y, pos_y_norm + grab_size_y_norm)), grab_col); + ImVec2(scrollbar_bb.Min.x, ImLerp(scrollbar_bb.Min.y, scrollbar_bb.Max.y - grab_size_y_pixels, pos_y_norm)), + ImVec2(scrollbar_bb.Max.x, ImLerp(scrollbar_bb.Min.y, scrollbar_bb.Max.y - grab_size_y_pixels, pos_y_norm) + grab_size_y_pixels), grab_col); } // Render resize grip @@ -4637,7 +4636,7 @@ bool ImGui::SliderFloat(const char* label, float* v, float v_min, float v_max, c if (decimal_precision > 0 || is_unbound) grab_size_in_pixels = 10.0f; else - grab_size_in_pixels = ImMax(grab_size_in_units * (w / (v_max-v_min+1.0f)), 8.0f); // Integer sliders + grab_size_in_pixels = ImMax(grab_size_in_units * (w / (v_max-v_min+1.0f)), 10.0f); // Integer sliders const float slider_effective_w = slider_bb.GetWidth() - grab_size_in_pixels; const float slider_effective_x1 = slider_bb.Min.x + grab_size_in_pixels*0.5f; const float slider_effective_x2 = slider_bb.Max.x - grab_size_in_pixels*0.5f; From 849c72c5c34d53fb67147c8dc8e8568d6273e907 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 8 Mar 2015 11:32:39 +0000 Subject: [PATCH 15/48] Forward declare struct in imgui.cpp. Removed two forward declarations leaking in imgui.h --- imgui.cpp | 11 +++++++++-- imgui.h | 21 ++++++++++----------- 2 files changed, 19 insertions(+), 13 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 63882a24..5dec5d56 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -392,8 +392,8 @@ namespace IMGUI_STB_NAMESPACE #endif #include "stb_truetype.h" -#define STB_TEXTEDIT_STRING ImGuiTextEditState -#define STB_TEXTEDIT_CHARTYPE ImWchar +#define STB_TEXTEDIT_STRING ImGuiTextEditState +#define STB_TEXTEDIT_CHARTYPE ImWchar #include "stb_textedit.h" #ifdef __clang__ @@ -409,7 +409,14 @@ using namespace IMGUI_STB_NAMESPACE; // Forward Declarations //------------------------------------------------------------------------- +struct ImGuiColMod; +struct ImGuiStyleMod; struct ImGuiAabb; +struct ImGuiDrawContext; +struct ImGuiTextEditState; +struct ImGuiIniData; +struct ImGuiState; +struct ImGuiWindow; static bool ButtonBehaviour(const ImGuiAabb& bb, const ImGuiID& id, bool* out_hovered, bool* out_held, bool allow_key_modifiers, bool repeat = false, bool pressed_on_click = false); static void LogText(const ImVec2& ref_pos, const char* text, const char* text_end = NULL); diff --git a/imgui.h b/imgui.h index 5cac69e1..3ba53dd2 100644 --- a/imgui.h +++ b/imgui.h @@ -6,17 +6,7 @@ #pragma once -struct ImDrawCmd; -struct ImDrawList; -struct ImFont; -struct ImFontAtlas; -struct ImGuiAabb; -struct ImGuiIO; -struct ImGuiStorage; -struct ImGuiStyle; -struct ImGuiWindow; - -#include "imconfig.h" +#include "imconfig.h" // User-editable configuration file #include // FLT_MAX #include // va_list #include // ptrdiff_t @@ -34,6 +24,15 @@ struct ImGuiWindow; #define IMGUI_API #endif +// Forward declarations +struct ImDrawCmd; +struct ImDrawList; +struct ImFont; +struct ImFontAtlas; +struct ImGuiIO; +struct ImGuiStorage; +struct ImGuiStyle; + typedef unsigned int ImU32; typedef unsigned short ImWchar; // character for display typedef void* ImTextureID; // user data to refer to a texture (e.g. store your texture handle/id) From a5daea940804cacf98af6250147d036ec3d0c7c3 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 8 Mar 2015 11:43:57 +0000 Subject: [PATCH 16/48] Added style.GrabSizeMin --- imgui.cpp | 10 ++++++---- imgui.h | 1 + 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 5dec5d56..c61df119 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -504,6 +504,7 @@ ImGuiStyle::ImGuiStyle() TreeNodeSpacing = 22.0f; // Horizontal spacing when entering a tree node ColumnsMinSpacing = 6.0f; // Minimum horizontal spacing between two columns ScrollBarWidth = 16.0f; // Width of the vertical scroll bar + GrabMinSize = 10.0f; // Minimum width/height of a slider or scroll bar grab Colors[ImGuiCol_Text] = ImVec4(0.90f, 0.90f, 0.90f, 1.00f); Colors[ImGuiCol_WindowBg] = ImVec4(0.00f, 0.00f, 0.00f, 1.00f); @@ -3025,7 +3026,7 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size, float bg const float scrollbar_height = scrollbar_bb.GetHeight(); const float grab_size_y_norm = ImSaturate(window->Size.y / ImMax(window->SizeContentsFit.y, window->Size.y)); - const float grab_size_y_pixels = ImMax(10.0f, scrollbar_height * grab_size_y_norm); + const float grab_size_y_pixels = ImMax(style.GrabMinSize, scrollbar_height * grab_size_y_norm); // Handle input right away (none of the code above is relying on scrolling position) bool held = false; @@ -4641,9 +4642,9 @@ bool ImGui::SliderFloat(const char* label, float* v, float v_min, float v_max, c const float grab_size_in_units = 1.0f; // In 'v' units. Probably needs to be parametrized, based on a 'v_step' value? decimal precision? float grab_size_in_pixels; if (decimal_precision > 0 || is_unbound) - grab_size_in_pixels = 10.0f; + grab_size_in_pixels = style.GrabMinSize; else - grab_size_in_pixels = ImMax(grab_size_in_units * (w / (v_max-v_min+1.0f)), 10.0f); // Integer sliders + grab_size_in_pixels = ImMax(grab_size_in_units * (w / (v_max-v_min+1.0f)), style.GrabMinSize); // Integer sliders const float slider_effective_w = slider_bb.GetWidth() - grab_size_in_pixels; const float slider_effective_x1 = slider_bb.Min.x + grab_size_in_pixels*0.5f; const float slider_effective_x2 = slider_bb.Max.x - grab_size_in_pixels*0.5f; @@ -8339,7 +8340,8 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref) ImGui::SliderFloat2("ItemInnerSpacing", (float*)&style.ItemInnerSpacing, 0.0f, 20.0f, "%.0f"); ImGui::SliderFloat2("TouchExtraPadding", (float*)&style.TouchExtraPadding, 0.0f, 10.0f, "%.0f"); ImGui::SliderFloat("TreeNodeSpacing", &style.TreeNodeSpacing, 0.0f, 20.0f, "%.0f"); - ImGui::SliderFloat("ScrollBarWidth", &style.ScrollBarWidth, 0.0f, 20.0f, "%.0f"); + ImGui::SliderFloat("ScrollBarWidth", &style.ScrollBarWidth, 1.0f, 20.0f, "%.0f"); + ImGui::SliderFloat("GrabMinSize", &style.GrabMinSize, 1.0f, 20.0f, "%.0f"); ImGui::TreePop(); } diff --git a/imgui.h b/imgui.h index 3ba53dd2..9d96ae57 100644 --- a/imgui.h +++ b/imgui.h @@ -533,6 +533,7 @@ struct ImGuiStyle float TreeNodeSpacing; // Horizontal spacing when entering a tree node float ColumnsMinSpacing; // Minimum horizontal spacing between two columns float ScrollBarWidth; // Width of the vertical scroll bar + float GrabMinSize; // Minimum width/height of a slider or scroll bar grab ImVec4 Colors[ImGuiCol_COUNT]; IMGUI_API ImGuiStyle(); From 2af8e0238cb5e26a1d8b9a1f04cee85c15e40ad0 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 8 Mar 2015 12:04:38 +0000 Subject: [PATCH 17/48] Added GetScrollPosY(), GetScrollMaxY() (mentioned in #150) --- imgui.cpp | 45 ++++++++++++++++++++++++++++++--------------- imgui.h | 2 ++ 2 files changed, 32 insertions(+), 15 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index c61df119..8e18d01f 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1122,7 +1122,8 @@ struct ImGuiWindow ImVec2 Pos; // Position rounded-up to nearest pixel ImVec2 Size; // Current size (==SizeFull or collapsed title bar size) ImVec2 SizeFull; // Size when non collapsed - ImVec2 SizeContentsFit; // Size of contents (extents reach by the drawing cursor) - may not fit within Size. + ImVec2 SizeContents; // Size of contents (== extents reach of the drawing cursor) from previous frame + ImVec2 SizeContentsCurrent; // Size of contents, currently extending float ScrollY; float NextScrollY; bool ScrollbarY; @@ -1464,7 +1465,7 @@ ImGuiWindow::ImGuiWindow(const char* name) Flags = 0; PosFloat = Pos = ImVec2(0.0f, 0.0f); Size = SizeFull = ImVec2(0.0f, 0.0f); - SizeContentsFit = ImVec2(0.0f, 0.0f); + SizeContents = SizeContentsCurrent = ImVec2(0.0f, 0.0f); ScrollY = 0.0f; NextScrollY = 0.0f; ScrollbarY = false; @@ -2802,6 +2803,10 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size, float bg window->LastFrameDrawn = current_frame; window->ClipRectStack.resize(0); + // Reset contents size for auto-fitting + window->SizeContents = window->SizeContentsCurrent; + window->SizeContentsCurrent = ImVec2(0.0f, 0.0f); + if (flags & ImGuiWindowFlags_ChildWindow) { parent_window->DC.ChildWindows.push_back(window); @@ -2896,7 +2901,7 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size, float bg window->ScrollY = window->NextScrollY; window->ScrollY = ImMax(window->ScrollY, 0.0f); if (!window->Collapsed && !window->SkipItems) - window->ScrollY = ImMin(window->ScrollY, ImMax(0.0f, (float)window->SizeContentsFit.y - window->SizeFull.y)); + window->ScrollY = ImMin(window->ScrollY, ImMax(0.0f, (float)window->SizeContents.y - window->SizeFull.y)); window->NextScrollY = window->ScrollY; // At this point we don't have a clipping rectangle setup yet, so we can test and draw in title bar @@ -2936,12 +2941,12 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size, float bg if ((window->Flags & ImGuiWindowFlags_Tooltip) != 0) { // Tooltip always resize. We keep the spacing symmetric on both axises for aesthetic purpose. - const ImVec2 size_auto_fit = window->SizeContentsFit + style.WindowPadding - ImVec2(0.0f, style.ItemSpacing.y); + const ImVec2 size_auto_fit = window->SizeContents + style.WindowPadding - ImVec2(0.0f, style.ItemSpacing.y); window->SizeFull = size_auto_fit; } else { - const ImVec2 size_auto_fit = ImClamp(window->SizeContentsFit + style.AutoFitPadding, style.WindowMinSize, ImMax(style.WindowMinSize, g.IO.DisplaySize - style.AutoFitPadding)); + const ImVec2 size_auto_fit = ImClamp(window->SizeContents + style.AutoFitPadding, style.WindowMinSize, ImMax(style.WindowMinSize, g.IO.DisplaySize - style.AutoFitPadding)); if ((window->Flags & ImGuiWindowFlags_AlwaysAutoResize) != 0) { // Don't continuously mark settings as dirty, the size of the window doesn't need to be stored. @@ -2989,7 +2994,7 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size, float bg } // Scrollbar - window->ScrollbarY = (window->SizeContentsFit.y > window->Size.y) && !(window->Flags & ImGuiWindowFlags_NoScrollbar); + window->ScrollbarY = (window->SizeContents.y > window->Size.y) && !(window->Flags & ImGuiWindowFlags_NoScrollbar); // Window background if (bg_alpha > 0.0f) @@ -3025,7 +3030,7 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size, float bg scrollbar_bb.Expand(ImVec2(-3,-3)); const float scrollbar_height = scrollbar_bb.GetHeight(); - const float grab_size_y_norm = ImSaturate(window->Size.y / ImMax(window->SizeContentsFit.y, window->Size.y)); + const float grab_size_y_norm = ImSaturate(window->Size.y / ImMax(window->SizeContents.y, window->Size.y)); const float grab_size_y_pixels = ImMax(style.GrabMinSize, scrollbar_height * grab_size_y_norm); // Handle input right away (none of the code above is relying on scrolling position) @@ -3039,13 +3044,13 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size, float bg { g.HoveredId = scrollbar_id; const float pos_y_norm = ImSaturate((g.IO.MousePos.y - (scrollbar_bb.Min.y + grab_size_y_pixels*0.5f)) / (scrollbar_height - grab_size_y_pixels)); - window->ScrollY = (float)(int)(pos_y_norm * (window->SizeContentsFit.y - window->Size.y)); + window->ScrollY = (float)(int)(pos_y_norm * (window->SizeContents.y - window->Size.y)); window->NextScrollY = window->ScrollY; } } // Normalized height of the grab - const float pos_y_norm = ImSaturate(window->ScrollY / ImMax(0.0f, window->SizeContentsFit.y - window->Size.y)); + const float pos_y_norm = ImSaturate(window->ScrollY / ImMax(0.0f, window->SizeContents.y - window->Size.y)); const ImU32 grab_col = window->Color(held ? ImGuiCol_ScrollbarGrabActive : hovered ? ImGuiCol_ScrollbarGrabHovered : ImGuiCol_ScrollbarGrab); window->DrawList->AddRectFilled( ImVec2(scrollbar_bb.Min.x, ImLerp(scrollbar_bb.Min.y, scrollbar_bb.Max.y - grab_size_y_pixels, pos_y_norm)), @@ -3095,8 +3100,6 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size, float bg window->DC.TreeDepth = 0; window->DC.StateStorage = &window->StateStorage; - // Reset contents size for auto-fitting - window->SizeContentsFit = ImVec2(0.0f, 0.0f); if (window->AutoFitFrames > 0) window->AutoFitFrames--; @@ -3677,21 +3680,21 @@ void ImGui::SetCursorPos(const ImVec2& pos) { ImGuiWindow* window = GetCurrentWindow(); window->DC.CursorPos = window->Pos + pos; - window->SizeContentsFit = ImMax(window->SizeContentsFit, pos + ImVec2(0.0f, window->ScrollY)); + window->SizeContentsCurrent = ImMax(window->SizeContentsCurrent, pos + ImVec2(0.0f, window->ScrollY)); } void ImGui::SetCursorPosX(float x) { ImGuiWindow* window = GetCurrentWindow(); window->DC.CursorPos.x = window->Pos.x + x; - window->SizeContentsFit.x = ImMax(window->SizeContentsFit.x, x); + window->SizeContentsCurrent.x = ImMax(window->SizeContentsCurrent.x, x); } void ImGui::SetCursorPosY(float y) { ImGuiWindow* window = GetCurrentWindow(); window->DC.CursorPos.y = window->Pos.y + y; - window->SizeContentsFit.y = ImMax(window->SizeContentsFit.y, y + window->ScrollY); + window->SizeContentsCurrent.y = ImMax(window->SizeContentsCurrent.y, y + window->ScrollY); } ImVec2 ImGui::GetCursorScreenPos() @@ -3706,6 +3709,18 @@ void ImGui::SetCursorScreenPos(const ImVec2& screen_pos) window->DC.CursorPos = screen_pos; } +float ImGui::GetScrollPosY() +{ + ImGuiWindow* window = GetCurrentWindow(); + return window->ScrollY; +} + +float ImGui::GetScrollMaxY() +{ + ImGuiWindow* window = GetCurrentWindow(); + return window->SizeContents.y - window->SizeFull.y; +} + void ImGui::SetScrollPosHere() { ImGuiWindow* window = GetCurrentWindow(); @@ -6413,7 +6428,7 @@ static void ItemSize(ImVec2 size, ImVec2* adjust_vertical_offset) window->DC.CursorPosPrevLine = ImVec2(window->DC.CursorPos.x + size.x, window->DC.CursorPos.y); window->DC.CursorPos = ImVec2((float)(int)(window->Pos.x + window->DC.ColumnsStartX + window->DC.ColumnsOffsetX), (float)(int)(window->DC.CursorPos.y + line_height + g.Style.ItemSpacing.y)); - window->SizeContentsFit = ImMax(window->SizeContentsFit, ImVec2(window->DC.CursorPosPrevLine.x - window->Pos.x, window->DC.CursorPos.y + window->ScrollY - window->Pos.y)); + window->SizeContentsCurrent = ImMax(window->SizeContentsCurrent, ImVec2(window->DC.CursorPosPrevLine.x - window->Pos.x, window->DC.CursorPos.y + window->ScrollY - window->Pos.y)); window->DC.PrevLineHeight = line_height; window->DC.CurrentLineHeight = 0.0f; diff --git a/imgui.h b/imgui.h index 9d96ae57..0bcc5e70 100644 --- a/imgui.h +++ b/imgui.h @@ -190,6 +190,8 @@ namespace ImGui IMGUI_API void SetWindowCollapsed(const char* name, bool collapsed, ImGuiSetCond cond = 0); // set named window collapsed state. IMGUI_API void SetWindowFocus(const char* name); // set named window to be focused / front-most + IMGUI_API float GetScrollPosY(); // get scrolling position (0..GetScrollMaxY()) + IMGUI_API float GetScrollMaxY(); // get maximum scrolling position == ContentSize.Y - WindowSize.Y IMGUI_API void SetScrollPosHere(); // adjust scrolling position to center into the current cursor position. IMGUI_API void SetKeyboardFocusHere(int offset = 0); // focus keyboard on the next widget. Use positive 'offset' to access sub components of a multiple component widget. IMGUI_API void SetStateStorage(ImGuiStorage* tree); // replace tree state storage with our own (if you want to manipulate it yourself, typically clear subsection of it). From d251204564a28ab090ef6423d48a4baaf7aa4d0d Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 8 Mar 2015 12:09:57 +0000 Subject: [PATCH 18/48] ShowTestWindow: fixed "undo" button of custom rendering applet + default size --- imgui.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/imgui.cpp b/imgui.cpp index 8e18d01f..7791730b 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -9230,6 +9230,7 @@ static void ShowExampleAppManipulatingWindowTitle(bool* opened) static void ShowExampleAppCustomRendering(bool* opened) { + ImGui::SetNextWindowSize(ImVec2(300,350), ImGuiSetCond_FirstUseEver); if (!ImGui::Begin("Example: Custom Rendering", opened)) { ImGui::End(); @@ -9244,7 +9245,7 @@ static void ShowExampleAppCustomRendering(bool* opened) static ImVector points; static bool adding_line = false; if (ImGui::Button("Clear")) points.clear(); - if (points.size() > 2) { ImGui::SameLine(); if (ImGui::Button("Undo")) points.pop_back(); } + if (points.size() >= 2) { ImGui::SameLine(); if (ImGui::Button("Undo")) { points.pop_back(); points.pop_back(); } } ImGui::Text("Left-click and drag to add lines"); ImGui::Text("Right-click to undo"); From a579d6f521cb34d35cd2524e19c27347dd4b79c8 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 8 Mar 2015 12:39:50 +0000 Subject: [PATCH 19/48] Scrollbar tidying up variable names --- imgui.cpp | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 7791730b..9fcff6b8 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -3042,19 +3042,20 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size, float bg ButtonBehaviour(scrollbar_bb, scrollbar_id, &hovered, &held, true); if (held) { + // Absolute seeking g.HoveredId = scrollbar_id; - const float pos_y_norm = ImSaturate((g.IO.MousePos.y - (scrollbar_bb.Min.y + grab_size_y_pixels*0.5f)) / (scrollbar_height - grab_size_y_pixels)); - window->ScrollY = (float)(int)(pos_y_norm * (window->SizeContents.y - window->Size.y)); + const float clicked_y_norm = ImSaturate((g.IO.MousePos.y - (scrollbar_bb.Min.y + grab_size_y_pixels*0.5f)) / (scrollbar_height - grab_size_y_pixels)); + window->ScrollY = (float)(int)(clicked_y_norm * (window->SizeContents.y - window->Size.y)); window->NextScrollY = window->ScrollY; } } - // Normalized height of the grab - const float pos_y_norm = ImSaturate(window->ScrollY / ImMax(0.0f, window->SizeContents.y - window->Size.y)); + // Render + const float scroll_y_norm = ImSaturate(window->ScrollY / ImMax(0.0f, window->SizeContents.y - window->Size.y)); const ImU32 grab_col = window->Color(held ? ImGuiCol_ScrollbarGrabActive : hovered ? ImGuiCol_ScrollbarGrabHovered : ImGuiCol_ScrollbarGrab); window->DrawList->AddRectFilled( - ImVec2(scrollbar_bb.Min.x, ImLerp(scrollbar_bb.Min.y, scrollbar_bb.Max.y - grab_size_y_pixels, pos_y_norm)), - ImVec2(scrollbar_bb.Max.x, ImLerp(scrollbar_bb.Min.y, scrollbar_bb.Max.y - grab_size_y_pixels, pos_y_norm) + grab_size_y_pixels), grab_col); + ImVec2(scrollbar_bb.Min.x, ImLerp(scrollbar_bb.Min.y, scrollbar_bb.Max.y - grab_size_y_pixels, scroll_y_norm)), + ImVec2(scrollbar_bb.Max.x, ImLerp(scrollbar_bb.Min.y, scrollbar_bb.Max.y - grab_size_y_pixels, scroll_y_norm) + grab_size_y_pixels), grab_col); } // Render resize grip From c9bfd71e1a8edcf7054dcac7779b53f2831113bc Mon Sep 17 00:00:00 2001 From: Usagi Ito Date: Sun, 8 Mar 2015 22:23:52 +0900 Subject: [PATCH 20/48] Fix the Japanese glyph range; include Punctuations ref. #156 https://github.com/ocornut/imgui/issues/156 --- imgui.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/imgui.cpp b/imgui.cpp index 7791730b..4e4d047b 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -7611,7 +7611,7 @@ const ImWchar* ImFontAtlas::GetGlyphRangesJapanese() static ImWchar ranges[10 + IM_ARRAYSIZE(offsets_from_0x4E00)*2 + 1] = { 0x0020, 0x00FF, // Basic Latin + Latin Supplement - 0x3000, 0x3000, // Ideographic Space + 0x3000, 0x303F, // Ideographic Space, Japanese Punctuations 0x3040, 0x30FF, // Hiragana, Katakana 0x31F0, 0x31FF, // Katakana Phonetic Extensions 0xFF00, 0xFFEF, // Half-width characters From afc23a5617d868f7ba84fcfd1c0e6875053fb091 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 8 Mar 2015 13:28:44 +0000 Subject: [PATCH 21/48] Tidying up & Chinese glyph range includes missing punctuation. --- imgui.cpp | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 65f08d7b..727adcf1 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -7559,8 +7559,7 @@ const ImWchar* ImFontAtlas::GetGlyphRangesChinese() static const ImWchar ranges[] = { 0x0020, 0x00FF, // Basic Latin + Latin Supplement - 0x3000, 0x3000, // Ideographic Space - 0x3040, 0x30FF, // Hiragana, Katakana + 0x3000, 0x30FF, // Punctuations, Hiragana, Katakana 0x31F0, 0x31FF, // Katakana Phonetic Extensions 0xFF00, 0xFFEF, // Half-width characters 0x4e00, 0x9FAF, // CJK Ideograms @@ -7609,11 +7608,10 @@ const ImWchar* ImFontAtlas::GetGlyphRangesJapanese() 109,2,18,23,0,0,9,61,3,0,28,41,77,27,19,17,81,5,2,14,5,83,57,252,14,154,263,14,20,8,13,6,57,39,38, }; static int ranges_unpacked = false; - static ImWchar ranges[10 + IM_ARRAYSIZE(offsets_from_0x4E00)*2 + 1] = + static ImWchar ranges[8 + IM_ARRAYSIZE(offsets_from_0x4E00)*2 + 1] = { 0x0020, 0x00FF, // Basic Latin + Latin Supplement - 0x3000, 0x303F, // Ideographic Space, Japanese Punctuations - 0x3040, 0x30FF, // Hiragana, Katakana + 0x3000, 0x30FF, // Punctuations, Hiragana, Katakana 0x31F0, 0x31FF, // Katakana Phonetic Extensions 0xFF00, 0xFFEF, // Half-width characters }; @@ -7621,7 +7619,7 @@ const ImWchar* ImFontAtlas::GetGlyphRangesJapanese() { // Unpack int codepoint = 0x4e00; - ImWchar* dst = &ranges[10]; + ImWchar* dst = &ranges[8]; for (int n = 0; n < IM_ARRAYSIZE(offsets_from_0x4E00); n++, dst += 2) dst[0] = dst[1] = (ImWchar)(codepoint += (offsets_from_0x4E00[n] + 1)); dst[0] = 0; From 32312e538ee6bcb83bca714bbf5cf4985b0f0e39 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 8 Mar 2015 15:03:55 +0000 Subject: [PATCH 22/48] Renamed style.ScrollBarWidth to style.ScrollbarWidth to be consistent with other casing. --- imgui.cpp | 21 +++++++++++---------- imgui.h | 6 +++--- 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 727adcf1..f9bedc24 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -129,6 +129,7 @@ Occasionally introducing changes that are breaking the API. The breakage are generally minor and easy to fix. Here is a change-log of API breaking changes, if you are using one of the functions listed, expect to have to fix some code. + - 2015/03/08 (1.35) - renamed style.ScrollBarWidth to style.ScrollbarWidth - 2015/02/27 (1.34) - renamed OpenNextNode(bool) to SetNextTreeNodeOpened(bool, ImGuiSetCond), kept inline redirection function. - 2015/02/27 (1.34) - renamed ImGuiSetCondition_*** to ImGuiSetCond_***, and _FirstUseThisSession becomes _Once. - 2015/02/11 (1.32) - changed text input callback ImGuiTextEditCallback return type from void-->int. reserved for future use, return 0 for now. @@ -503,8 +504,8 @@ ImGuiStyle::ImGuiStyle() WindowFillAlphaDefault = 0.70f; // Default alpha of window background, if not specified in ImGui::Begin() TreeNodeSpacing = 22.0f; // Horizontal spacing when entering a tree node ColumnsMinSpacing = 6.0f; // Minimum horizontal spacing between two columns - ScrollBarWidth = 16.0f; // Width of the vertical scroll bar - GrabMinSize = 10.0f; // Minimum width/height of a slider or scroll bar grab + ScrollbarWidth = 16.0f; // Width of the vertical scrollbar + GrabMinSize = 10.0f; // Minimum width/height of a slider or scrollbar grab Colors[ImGuiCol_Text] = ImVec4(0.90f, 0.90f, 0.90f, 1.00f); Colors[ImGuiCol_WindowBg] = ImVec4(0.00f, 0.00f, 0.00f, 1.00f); @@ -3004,7 +3005,7 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size, float bg else if ((window->Flags & ImGuiWindowFlags_Tooltip) != 0) window->DrawList->AddRectFilled(window->Pos, window->Pos+window->Size, window->Color(ImGuiCol_TooltipBg, bg_alpha), window_rounding); else if ((window->Flags & ImGuiWindowFlags_ChildWindow) != 0) - window->DrawList->AddRectFilled(window->Pos, window->Pos+window->Size-ImVec2(window->ScrollbarY?style.ScrollBarWidth:0.0f,0.0f), window->Color(ImGuiCol_ChildWindowBg, bg_alpha), window_rounding, window->ScrollbarY ? (1|8) : (0xF)); + window->DrawList->AddRectFilled(window->Pos, window->Pos+window->Size-ImVec2(window->ScrollbarY?style.ScrollbarWidth:0.0f,0.0f), window->Color(ImGuiCol_ChildWindowBg, bg_alpha), window_rounding, window->ScrollbarY ? (1|8) : (0xF)); else window->DrawList->AddRectFilled(window->Pos, window->Pos+window->Size, window->Color(ImGuiCol_WindowBg, bg_alpha), window_rounding); } @@ -3025,7 +3026,7 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size, float bg // Scrollbar if (window->ScrollbarY) { - ImGuiAabb scrollbar_bb(window->Aabb().Max.x - style.ScrollBarWidth, title_bar_aabb.Max.y+1, window->Aabb().Max.x, window->Aabb().Max.y-1); + ImGuiAabb scrollbar_bb(window->Aabb().Max.x - style.ScrollbarWidth, title_bar_aabb.Max.y+1, window->Aabb().Max.x, window->Aabb().Max.y-1); window->DrawList->AddRectFilled(scrollbar_bb.Min, scrollbar_bb.Max, window->Color(ImGuiCol_ScrollbarBg)); scrollbar_bb.Expand(ImVec2(-3,-3)); const float scrollbar_height = scrollbar_bb.GetHeight(); @@ -3132,7 +3133,7 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size, float bg const ImGuiAabb title_bar_aabb = window->TitleBarAabb(); ImVec4 clip_rect(title_bar_aabb.Min.x+0.5f+window->WindowPadding().x*0.5f, title_bar_aabb.Max.y+0.5f, window->Aabb().Max.x+0.5f-window->WindowPadding().x*0.5f, window->Aabb().Max.y-1.5f); if (window->ScrollbarY) - clip_rect.z -= style.ScrollBarWidth; + clip_rect.z -= style.ScrollbarWidth; PushClipRect(clip_rect); // Clear 'accessed' flag last thing @@ -3602,7 +3603,7 @@ ImVec2 ImGui::GetContentRegionMax() else { if (window->ScrollbarY) - mx.x -= GImGui->Style.ScrollBarWidth; + mx.x -= GImGui->Style.ScrollbarWidth; } return mx; } @@ -3618,7 +3619,7 @@ ImVec2 ImGui::GetWindowContentRegionMax() ImGuiWindow* window = GetCurrentWindow(); ImVec2 m = window->Size - window->WindowPadding(); if (window->ScrollbarY) - m.x -= GImGui->Style.ScrollBarWidth; + m.x -= GImGui->Style.ScrollbarWidth; return m; } @@ -6559,7 +6560,7 @@ float ImGui::GetColumnOffset(int column_index) const float t = window->DC.ColumnsOffsetsT[column_index]; const float min_x = window->DC.ColumnsStartX; - const float max_x = window->Size.x - (g.Style.ScrollBarWidth);// - window->WindowPadding().x; + const float max_x = window->Size.x - (g.Style.ScrollbarWidth);// - window->WindowPadding().x; const float offset = min_x + t * (max_x - min_x); return offset; } @@ -6575,7 +6576,7 @@ void ImGui::SetColumnOffset(int column_index, float offset) const ImGuiID column_id = window->DC.ColumnsSetID + ImGuiID(column_index); const float min_x = window->DC.ColumnsStartX; - const float max_x = window->Size.x - (g.Style.ScrollBarWidth);// - window->WindowPadding().x; + const float max_x = window->Size.x - (g.Style.ScrollbarWidth);// - window->WindowPadding().x; const float t = (offset - min_x) / (max_x - min_x); window->DC.StateStorage->SetFloat(column_id, t); window->DC.ColumnsOffsetsT[column_index] = t; @@ -8354,7 +8355,7 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref) ImGui::SliderFloat2("ItemInnerSpacing", (float*)&style.ItemInnerSpacing, 0.0f, 20.0f, "%.0f"); ImGui::SliderFloat2("TouchExtraPadding", (float*)&style.TouchExtraPadding, 0.0f, 10.0f, "%.0f"); ImGui::SliderFloat("TreeNodeSpacing", &style.TreeNodeSpacing, 0.0f, 20.0f, "%.0f"); - ImGui::SliderFloat("ScrollBarWidth", &style.ScrollBarWidth, 1.0f, 20.0f, "%.0f"); + ImGui::SliderFloat("ScrollBarWidth", &style.ScrollbarWidth, 1.0f, 20.0f, "%.0f"); ImGui::SliderFloat("GrabMinSize", &style.GrabMinSize, 1.0f, 20.0f, "%.0f"); ImGui::TreePop(); } diff --git a/imgui.h b/imgui.h index 0bcc5e70..9004e559 100644 --- a/imgui.h +++ b/imgui.h @@ -386,7 +386,7 @@ enum ImGuiWindowFlags_ ImGuiWindowFlags_NoTitleBar = 1 << 0, // Disable title-bar ImGuiWindowFlags_NoResize = 1 << 1, // Disable user resizing with the lower-right grip ImGuiWindowFlags_NoMove = 1 << 2, // Disable user moving the window - ImGuiWindowFlags_NoScrollbar = 1 << 3, // Disable scroll bar (window can still scroll with mouse or programatically) + ImGuiWindowFlags_NoScrollbar = 1 << 3, // Disable scrollbar (window can still scroll with mouse or programatically) ImGuiWindowFlags_NoScrollWithMouse = 1 << 4, // Disable user scrolling with mouse wheel ImGuiWindowFlags_NoCollapse = 1 << 5, // Disable user collapsing window by double-clicking on it ImGuiWindowFlags_AlwaysAutoResize = 1 << 6, // Resize every window to its content every frame @@ -534,8 +534,8 @@ struct ImGuiStyle float WindowFillAlphaDefault; // Default alpha of window background, if not specified in ImGui::Begin() float TreeNodeSpacing; // Horizontal spacing when entering a tree node float ColumnsMinSpacing; // Minimum horizontal spacing between two columns - float ScrollBarWidth; // Width of the vertical scroll bar - float GrabMinSize; // Minimum width/height of a slider or scroll bar grab + float ScrollbarWidth; // Width of the vertical scrollbar + float GrabMinSize; // Minimum width/height of a slider or scrollbar grab ImVec4 Colors[ImGuiCol_COUNT]; IMGUI_API ImGuiStyle(); From f02108085109319f0647c32efe3612fc13cca33e Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 8 Mar 2015 16:24:11 +0000 Subject: [PATCH 23/48] Scrollbar: Clicking inside the grab box doesn't modify scroll. Subsequent movement always relative. (#150). Big change, rather thoroughly tested but hope I didn't break something. --- imgui.cpp | 73 ++++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 54 insertions(+), 19 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index f9bedc24..adfe9863 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -263,7 +263,6 @@ - main: IsItemHovered() returns true even if mouse is active on another widget (e.g. dragging outside of sliders). Maybe not a sensible default? Add parameter or alternate function? - main: IsItemHovered() make it more consistent for various type of widgets, widgets with multiple components, etc. also effectively IsHovered() region sometimes differs from hot region, e.g tree nodes - main: IsItemHovered() info stored in a stack? so that 'if TreeNode() { Text; TreePop; } if IsHovered' return the hover state of the TreeNode? - - scrollbar: use relative mouse movement when first-clicking inside of scroll grab box. !- input number: very large int not reliably supported because of int<>float conversions. - input number: optional range min/max for Input*() functions - input number: holding [-]/[+] buttons could increase the step speed non-linearly (or user-controlled) @@ -290,7 +289,7 @@ - plot: add a helper e.g. Plot(char* label, float value, float time_span=2.0f) that stores values and Plot them for you - probably another function name. and/or automatically allow to plot ANY displayed value (more reliance on stable ID) - file selection widget -> build the tool in our codebase to improve model-dialog idioms - slider: allow using the [-]/[+] buttons used by InputFloat()/InputInt() - - slider: initial absolute click is imprecise. change to relative movement slider? hide mouse cursor, allow more precise input using less screen-space. + - slider: initial absolute click is imprecise. change to relative movement slider? hide mouse cursor, allow more precise input using less screen-space. same as scrollbar. - text edit: clean up the mess caused by converting UTF-8 <> wchar. the code is rather inefficient right now. - text edit: centered text for slider as input text so it matches typical positioning. - text edit: flag to disable live update of the user buffer. @@ -1047,6 +1046,7 @@ struct ImGuiState ImGuiID SliderAsInputTextId; ImGuiStorage ColorEditModeStorage; // for user selection ImGuiID ActiveComboID; + float ScrollbarClickDeltaToGrabCenter; // distance between mouse and center of grab box, normalized in parent space char Tooltip[1024]; char* PrivateClipboard; // if no custom clipboard handler is defined @@ -1096,6 +1096,7 @@ struct ImGuiState SliderAsInputTextId = 0; ActiveComboID = 0; + ScrollbarClickDeltaToGrabCenter = 0.0f; memset(Tooltip, 0, sizeof(Tooltip)); PrivateClipboard = NULL; @@ -2902,7 +2903,7 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size, float bg window->ScrollY = window->NextScrollY; window->ScrollY = ImMax(window->ScrollY, 0.0f); if (!window->Collapsed && !window->SkipItems) - window->ScrollY = ImMin(window->ScrollY, ImMax(0.0f, (float)window->SizeContents.y - window->SizeFull.y)); + window->ScrollY = ImMin(window->ScrollY, ImMax(0.0f, window->SizeContents.y - window->SizeFull.y)); window->NextScrollY = window->ScrollY; // At this point we don't have a clipping rectangle setup yet, so we can test and draw in title bar @@ -3026,37 +3027,69 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size, float bg // Scrollbar if (window->ScrollbarY) { + // Render background ImGuiAabb scrollbar_bb(window->Aabb().Max.x - style.ScrollbarWidth, title_bar_aabb.Max.y+1, window->Aabb().Max.x, window->Aabb().Max.y-1); window->DrawList->AddRectFilled(scrollbar_bb.Min, scrollbar_bb.Max, window->Color(ImGuiCol_ScrollbarBg)); scrollbar_bb.Expand(ImVec2(-3,-3)); + + // The entire piece of code below is rather confusing because: + // - The grabable box size generally represent the amount visible (vs the total scrollable amount) + // - But we maintain a minimum size in pixel to allow for the user to still aim inside. + // - We handle absolute seeking (when first clicking outside the grab) and relative manipulation (afterward or when clicking inside the grab) + // - We store values as ratio and in a form that allows the window content to change while we are holding on a scrollbar + const float scroll_max = ImMax(1.0f, window->SizeContents.y - window->Size.y); const float scrollbar_height = scrollbar_bb.GetHeight(); - - const float grab_size_y_norm = ImSaturate(window->Size.y / ImMax(window->SizeContents.y, window->Size.y)); - const float grab_size_y_pixels = ImMax(style.GrabMinSize, scrollbar_height * grab_size_y_norm); + const float grab_size_y_pixels = ImMax(style.GrabMinSize, scrollbar_height * ImSaturate(window->Size.y / ImMax(window->SizeContents.y, window->Size.y))); + const float grab_size_y_norm = grab_size_y_pixels / scrollbar_height; - // Handle input right away (none of the code above is relying on scrolling position) + // Handle input right away (none of the code of Begin() above is relying on scrolling position) bool held = false; bool hovered = false; - if (grab_size_y_pixels < scrollbar_height) + const ImGuiID scrollbar_id = window->GetID("#SCROLLY"); + const bool previously_held = (g.ActiveId == scrollbar_id); + ButtonBehaviour(scrollbar_bb, scrollbar_id, &hovered, &held, true); + + float scroll_ratio = ImSaturate(window->ScrollY / scroll_max); + float grab_pos_y_norm = scroll_ratio * (scrollbar_height - grab_size_y_pixels) / scrollbar_height; + if (held) { - const ImGuiID scrollbar_id = window->GetID("#SCROLLY"); - ButtonBehaviour(scrollbar_bb, scrollbar_id, &hovered, &held, true); - if (held) + const float clicked_y_norm = ImSaturate((g.IO.MousePos.y - scrollbar_bb.Min.y) / scrollbar_height); // Click position in scrollbar space (0.0f->1.0f) + g.HoveredId = scrollbar_id; + + bool seek_absolute = false; + if (!previously_held) { - // Absolute seeking - g.HoveredId = scrollbar_id; - const float clicked_y_norm = ImSaturate((g.IO.MousePos.y - (scrollbar_bb.Min.y + grab_size_y_pixels*0.5f)) / (scrollbar_height - grab_size_y_pixels)); - window->ScrollY = (float)(int)(clicked_y_norm * (window->SizeContents.y - window->Size.y)); - window->NextScrollY = window->ScrollY; + // On initial click calculate the distance between mouse and the center of the grab + if (clicked_y_norm >= grab_pos_y_norm && clicked_y_norm <= grab_pos_y_norm + grab_size_y_norm) + { + g.ScrollbarClickDeltaToGrabCenter = clicked_y_norm - grab_pos_y_norm - grab_size_y_norm*0.5f; + } + else + { + seek_absolute = true; + g.ScrollbarClickDeltaToGrabCenter = 0; + } } + + // Apply scroll + const float scroll_y_norm = ImSaturate((clicked_y_norm - g.ScrollbarClickDeltaToGrabCenter - grab_size_y_norm*0.5f) / (1.0f - grab_size_y_norm)); + window->ScrollY = (float)(int)(0.5f + scroll_y_norm * (window->SizeContents.y - window->Size.y)); + window->NextScrollY = window->ScrollY; + + // Update values for rendering + scroll_ratio = ImSaturate(window->ScrollY / scroll_max); + grab_pos_y_norm = scroll_ratio * (scrollbar_height - grab_size_y_pixels) / scrollbar_height; + + // Update distance to grab now that we have seeked and saturated + if (seek_absolute) + g.ScrollbarClickDeltaToGrabCenter = clicked_y_norm - grab_pos_y_norm - grab_size_y_norm*0.5f; } // Render - const float scroll_y_norm = ImSaturate(window->ScrollY / ImMax(0.0f, window->SizeContents.y - window->Size.y)); const ImU32 grab_col = window->Color(held ? ImGuiCol_ScrollbarGrabActive : hovered ? ImGuiCol_ScrollbarGrabHovered : ImGuiCol_ScrollbarGrab); window->DrawList->AddRectFilled( - ImVec2(scrollbar_bb.Min.x, ImLerp(scrollbar_bb.Min.y, scrollbar_bb.Max.y - grab_size_y_pixels, scroll_y_norm)), - ImVec2(scrollbar_bb.Max.x, ImLerp(scrollbar_bb.Min.y, scrollbar_bb.Max.y - grab_size_y_pixels, scroll_y_norm) + grab_size_y_pixels), grab_col); + ImVec2(scrollbar_bb.Min.x, ImLerp(scrollbar_bb.Min.y, scrollbar_bb.Max.y, grab_pos_y_norm)), + ImVec2(scrollbar_bb.Max.x, ImLerp(scrollbar_bb.Min.y, scrollbar_bb.Max.y, grab_pos_y_norm) + grab_size_y_pixels), grab_col); } // Render resize grip @@ -9351,6 +9384,8 @@ struct ExampleAppConsole if (ImGui::SmallButton("Add Dummy Text")) { AddLog("%d some text", Items.size()); AddLog("some more text"); AddLog("display very important message here!"); } ImGui::SameLine(); if (ImGui::SmallButton("Add Dummy Error")) AddLog("[error] something went wrong"); ImGui::SameLine(); if (ImGui::SmallButton("Clear")) ClearLog(); + //static float t = 0.0f; if (ImGui::GetTime() - t > 0.02f) { t = ImGui::GetTime(); AddLog("Spam %f", t); } + ImGui::Separator(); ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0,0)); From 6e12d314177325f1c5f0454bd9b45e915a5d574e Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 8 Mar 2015 16:37:03 +0000 Subject: [PATCH 24/48] Scrollbar: moved from Begin() into its own Scrollbar() function + tidying up --- imgui.cpp | 136 ++++++++++++++++++++++++++++-------------------------- 1 file changed, 71 insertions(+), 65 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index adfe9863..0dd8848b 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -437,6 +437,7 @@ static bool IsClipped(const ImGuiAabb& bb); static bool IsMouseHoveringBox(const ImGuiAabb& bb); static bool IsKeyPressedMap(ImGuiKey key, bool repeat = true); +static void Scrollbar(ImGuiWindow* window); static bool CloseWindowButton(bool* p_opened = NULL); static void FocusWindow(ImGuiWindow* window); static ImGuiWindow* FindHoveredWindow(ImVec2 pos, bool excluding_childs); @@ -3026,71 +3027,7 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size, float bg // Scrollbar if (window->ScrollbarY) - { - // Render background - ImGuiAabb scrollbar_bb(window->Aabb().Max.x - style.ScrollbarWidth, title_bar_aabb.Max.y+1, window->Aabb().Max.x, window->Aabb().Max.y-1); - window->DrawList->AddRectFilled(scrollbar_bb.Min, scrollbar_bb.Max, window->Color(ImGuiCol_ScrollbarBg)); - scrollbar_bb.Expand(ImVec2(-3,-3)); - - // The entire piece of code below is rather confusing because: - // - The grabable box size generally represent the amount visible (vs the total scrollable amount) - // - But we maintain a minimum size in pixel to allow for the user to still aim inside. - // - We handle absolute seeking (when first clicking outside the grab) and relative manipulation (afterward or when clicking inside the grab) - // - We store values as ratio and in a form that allows the window content to change while we are holding on a scrollbar - const float scroll_max = ImMax(1.0f, window->SizeContents.y - window->Size.y); - const float scrollbar_height = scrollbar_bb.GetHeight(); - const float grab_size_y_pixels = ImMax(style.GrabMinSize, scrollbar_height * ImSaturate(window->Size.y / ImMax(window->SizeContents.y, window->Size.y))); - const float grab_size_y_norm = grab_size_y_pixels / scrollbar_height; - - // Handle input right away (none of the code of Begin() above is relying on scrolling position) - bool held = false; - bool hovered = false; - const ImGuiID scrollbar_id = window->GetID("#SCROLLY"); - const bool previously_held = (g.ActiveId == scrollbar_id); - ButtonBehaviour(scrollbar_bb, scrollbar_id, &hovered, &held, true); - - float scroll_ratio = ImSaturate(window->ScrollY / scroll_max); - float grab_pos_y_norm = scroll_ratio * (scrollbar_height - grab_size_y_pixels) / scrollbar_height; - if (held) - { - const float clicked_y_norm = ImSaturate((g.IO.MousePos.y - scrollbar_bb.Min.y) / scrollbar_height); // Click position in scrollbar space (0.0f->1.0f) - g.HoveredId = scrollbar_id; - - bool seek_absolute = false; - if (!previously_held) - { - // On initial click calculate the distance between mouse and the center of the grab - if (clicked_y_norm >= grab_pos_y_norm && clicked_y_norm <= grab_pos_y_norm + grab_size_y_norm) - { - g.ScrollbarClickDeltaToGrabCenter = clicked_y_norm - grab_pos_y_norm - grab_size_y_norm*0.5f; - } - else - { - seek_absolute = true; - g.ScrollbarClickDeltaToGrabCenter = 0; - } - } - - // Apply scroll - const float scroll_y_norm = ImSaturate((clicked_y_norm - g.ScrollbarClickDeltaToGrabCenter - grab_size_y_norm*0.5f) / (1.0f - grab_size_y_norm)); - window->ScrollY = (float)(int)(0.5f + scroll_y_norm * (window->SizeContents.y - window->Size.y)); - window->NextScrollY = window->ScrollY; - - // Update values for rendering - scroll_ratio = ImSaturate(window->ScrollY / scroll_max); - grab_pos_y_norm = scroll_ratio * (scrollbar_height - grab_size_y_pixels) / scrollbar_height; - - // Update distance to grab now that we have seeked and saturated - if (seek_absolute) - g.ScrollbarClickDeltaToGrabCenter = clicked_y_norm - grab_pos_y_norm - grab_size_y_norm*0.5f; - } - - // Render - const ImU32 grab_col = window->Color(held ? ImGuiCol_ScrollbarGrabActive : hovered ? ImGuiCol_ScrollbarGrabHovered : ImGuiCol_ScrollbarGrab); - window->DrawList->AddRectFilled( - ImVec2(scrollbar_bb.Min.x, ImLerp(scrollbar_bb.Min.y, scrollbar_bb.Max.y, grab_pos_y_norm)), - ImVec2(scrollbar_bb.Max.x, ImLerp(scrollbar_bb.Min.y, scrollbar_bb.Max.y, grab_pos_y_norm) + grab_size_y_pixels), grab_col); - } + Scrollbar(window); // Render resize grip // (after the input handling so we don't have a frame of latency) @@ -3216,6 +3153,75 @@ void ImGui::End() g.CurrentWindow = g.CurrentWindowStack.empty() ? NULL : g.CurrentWindowStack.back(); } +// Vertical scrollbar +// The entire piece of code below is rather confusing because: +// - We handle absolute seeking (when first clicking outside the grab) and relative manipulation (afterward or when clicking inside the grab) +// - We store values as ratio and in a form that allows the window content to change while we are holding on a scrollbar +static void Scrollbar(ImGuiWindow* window) +{ + ImGuiState& g = *GImGui; + const ImGuiStyle& style = g.Style; + const ImGuiID id = window->GetID("#SCROLLY"); + + // Render background + ImGuiAabb bb(window->Aabb().Max.x - style.ScrollbarWidth, window->Pos.y + window->TitleBarHeight()+1, window->Aabb().Max.x, window->Aabb().Max.y-1); + window->DrawList->AddRectFilled(bb.Min, bb.Max, window->Color(ImGuiCol_ScrollbarBg)); + bb.Expand(ImVec2(-3,-3)); + const float scrollbar_height = bb.GetHeight(); + + // The grabable box size generally represent the amount visible (vs the total scrollable amount) + // But we maintain a minimum size in pixel to allow for the user to still aim inside. + const float grab_h_pixels = ImMax(style.GrabMinSize, scrollbar_height * ImSaturate(window->Size.y / ImMax(window->SizeContents.y, window->Size.y))); + const float grab_h_norm = grab_h_pixels / scrollbar_height; + + // Handle input right away. None of the code of Begin() is relying on scrolling position before calling Scrollbar(). + bool held = false; + bool hovered = false; + const bool previously_held = (g.ActiveId == id); + ButtonBehaviour(bb, id, &hovered, &held, true); + + const float scroll_max = ImMax(1.0f, window->SizeContents.y - window->Size.y); + float scroll_ratio = ImSaturate(window->ScrollY / scroll_max); + float grab_y_norm = scroll_ratio * (scrollbar_height - grab_h_pixels) / scrollbar_height; + if (held) + { + const float clicked_y_norm = ImSaturate((g.IO.MousePos.y - bb.Min.y) / scrollbar_height); // Click position in scrollbar space (0.0f->1.0f) + g.HoveredId = id; + + bool seek_absolute = false; + if (!previously_held) + { + // On initial click calculate the distance between mouse and the center of the grab + if (clicked_y_norm >= grab_y_norm && clicked_y_norm <= grab_y_norm + grab_h_norm) + { + g.ScrollbarClickDeltaToGrabCenter = clicked_y_norm - grab_y_norm - grab_h_norm*0.5f; + } + else + { + seek_absolute = true; + g.ScrollbarClickDeltaToGrabCenter = 0; + } + } + + // Apply scroll + const float scroll_y_norm = ImSaturate((clicked_y_norm - g.ScrollbarClickDeltaToGrabCenter - grab_h_norm*0.5f) / (1.0f - grab_h_norm)); + window->ScrollY = (float)(int)(0.5f + scroll_y_norm * (window->SizeContents.y - window->Size.y)); + window->NextScrollY = window->ScrollY; + + // Update values for rendering + scroll_ratio = ImSaturate(window->ScrollY / scroll_max); + grab_y_norm = scroll_ratio * (scrollbar_height - grab_h_pixels) / scrollbar_height; + + // Update distance to grab now that we have seeked and saturated + if (seek_absolute) + g.ScrollbarClickDeltaToGrabCenter = clicked_y_norm - grab_y_norm - grab_h_norm*0.5f; + } + + // Render + const ImU32 grab_col = window->Color(held ? ImGuiCol_ScrollbarGrabActive : hovered ? ImGuiCol_ScrollbarGrabHovered : ImGuiCol_ScrollbarGrab); + window->DrawList->AddRectFilled(ImVec2(bb.Min.x, ImLerp(bb.Min.y, bb.Max.y, grab_y_norm)), ImVec2(bb.Max.x, ImLerp(bb.Min.y, bb.Max.y, grab_y_norm) + grab_h_pixels), grab_col); +} + // Moving window to front of display (which happens to be back of our sorted list) static void FocusWindow(ImGuiWindow* window) { From 0eeb6228b9f951780aef55ab092aecb724ca876a Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 8 Mar 2015 17:23:24 +0000 Subject: [PATCH 25/48] Default clipboard handlers for Windows handle UTF-8 (the glfw ones already did that) --- imgui.cpp | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 0dd8848b..f26b7d51 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -8251,12 +8251,16 @@ static const char* GetClipboardTextFn_DefaultImpl() } if (!OpenClipboard(NULL)) return NULL; - HANDLE buf_handle = GetClipboardData(CF_TEXT); - if (buf_handle == NULL) + HANDLE wbuf_handle = GetClipboardData(CF_UNICODETEXT); + if (wbuf_handle == NULL) return NULL; - if (char* buf_global = (char*)GlobalLock(buf_handle)) - buf_local = ImStrdup(buf_global); - GlobalUnlock(buf_handle); + if (ImWchar* wbuf_global = (ImWchar*)GlobalLock(wbuf_handle)) + { + int buf_len = ImTextCountUtf8BytesFromWchar(wbuf_global, NULL) + 1; + buf_local = (char*)ImGui::MemAlloc(buf_len * sizeof(char)); + ImTextStrToUtf8(buf_local, buf_len, wbuf_global, NULL); + } + GlobalUnlock(wbuf_handle); CloseClipboard(); return buf_local; } @@ -8266,17 +8270,16 @@ static void SetClipboardTextFn_DefaultImpl(const char* text) { if (!OpenClipboard(NULL)) return; - const char* text_end = text + strlen(text); - const int buf_length = (int)(text_end - text) + 1; - HGLOBAL buf_handle = GlobalAlloc(GMEM_MOVEABLE, (SIZE_T)buf_length * sizeof(char)); - if (buf_handle == NULL) + + const int wbuf_length = ImTextCountCharsFromUtf8(text, NULL) + 1; + HGLOBAL wbuf_handle = GlobalAlloc(GMEM_MOVEABLE, (SIZE_T)wbuf_length * sizeof(ImWchar)); + if (wbuf_handle == NULL) return; - char* buf_global = (char *)GlobalLock(buf_handle); - memcpy(buf_global, text, (size_t)(text_end - text)); - buf_global[text_end - text] = 0; - GlobalUnlock(buf_handle); + ImWchar* wbuf_global = (ImWchar*)GlobalLock(wbuf_handle); + ImTextStrFromUtf8(wbuf_global, wbuf_length, text, NULL); + GlobalUnlock(wbuf_handle); EmptyClipboard(); - SetClipboardData(CF_TEXT, buf_handle); + SetClipboardData(CF_UNICODETEXT, wbuf_handle); CloseClipboard(); } From 6cd3ed58ce9b4f07352509c2b75c6d0cd0dd0406 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 8 Mar 2015 17:55:56 +0000 Subject: [PATCH 26/48] Fixed UTF-8 decoding errors leading into infnite loops (#158) --- imgui.cpp | 38 +++++++++++++++++++++----------------- 1 file changed, 21 insertions(+), 17 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index f26b7d51..582afb40 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -7731,6 +7731,7 @@ const ImFont::Glyph* ImFont::FindGlyph(unsigned short c) const // Convert UTF-8 to 32-bits character, process single character input. // Based on stb_from_utf8() from github.com/nothings/stb/ +// We handle UTF-8 decoding error by skipping forward. static int ImTextCharFromUtf8(unsigned int* out_char, const char* in_text, const char* in_text_end) { unsigned int c = (unsigned int)-1; @@ -7743,47 +7744,50 @@ static int ImTextCharFromUtf8(unsigned int* out_char, const char* in_text, const } if ((*str & 0xe0) == 0xc0) { - if (in_text_end && in_text_end - (const char*)str < 2) return -1; - if (*str < 0xc2) return -1; + *out_char = 0; + if (in_text_end && in_text_end - (const char*)str < 2) return (in_text_end - (const char*)str); // Decode error + if (*str < 0xc2) return 2; c = (unsigned int)((*str++ & 0x1f) << 6); - if ((*str & 0xc0) != 0x80) return -1; + if ((*str & 0xc0) != 0x80) return 2; c += (*str++ & 0x3f); *out_char = c; return 2; } if ((*str & 0xf0) == 0xe0) { - if (in_text_end && in_text_end - (const char*)str < 3) return -1; - if (*str == 0xe0 && (str[1] < 0xa0 || str[1] > 0xbf)) return -1; - if (*str == 0xed && str[1] > 0x9f) return -1; // str[1] < 0x80 is checked below + *out_char = 0; + if (in_text_end && in_text_end - (const char*)str < 3) return (in_text_end - (const char*)str); // Decode error + if (*str == 0xe0 && (str[1] < 0xa0 || str[1] > 0xbf)) return 3; + if (*str == 0xed && str[1] > 0x9f) return 3; // str[1] < 0x80 is checked below c = (unsigned int)((*str++ & 0x0f) << 12); - if ((*str & 0xc0) != 0x80) return -1; + if ((*str & 0xc0) != 0x80) return 3; c += (unsigned int)((*str++ & 0x3f) << 6); - if ((*str & 0xc0) != 0x80) return -1; + if ((*str & 0xc0) != 0x80) return 3; c += (*str++ & 0x3f); *out_char = c; return 3; } if ((*str & 0xf8) == 0xf0) { - if (in_text_end && in_text_end - (const char*)str < 4) return -1; - if (*str > 0xf4) return -1; - if (*str == 0xf0 && (str[1] < 0x90 || str[1] > 0xbf)) return -1; - if (*str == 0xf4 && str[1] > 0x8f) return -1; // str[1] < 0x80 is checked below + *out_char = 0; + if (in_text_end && in_text_end - (const char*)str < 4) return (in_text_end - (const char*)str); // Decode error + if (*str > 0xf4) return 4; + if (*str == 0xf0 && (str[1] < 0x90 || str[1] > 0xbf)) return 4; + if (*str == 0xf4 && str[1] > 0x8f) return 4; // str[1] < 0x80 is checked below c = (unsigned int)((*str++ & 0x07) << 18); - if ((*str & 0xc0) != 0x80) return -1; + if ((*str & 0xc0) != 0x80) return 4; c += (unsigned int)((*str++ & 0x3f) << 12); - if ((*str & 0xc0) != 0x80) return -1; + if ((*str & 0xc0) != 0x80) return 4; c += (unsigned int)((*str++ & 0x3f) << 6); - if ((*str & 0xc0) != 0x80) return -1; + if ((*str & 0xc0) != 0x80) return 4; c += (*str++ & 0x3f); // utf-8 encodings of values used in surrogate pairs are invalid - if ((c & 0xFFFFF800) == 0xD800) return -1; + if ((c & 0xFFFFF800) == 0xD800) return 4; *out_char = c; return 4; } *out_char = 0; - return 0; + return 1; } static ptrdiff_t ImTextStrFromUtf8(ImWchar* buf, size_t buf_size, const char* in_text, const char* in_text_end) From 91b4b8a0fc320db53cd981ebb9d0433c3cdcfd5d Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 8 Mar 2015 20:21:19 +0000 Subject: [PATCH 27/48] InputText() handles buffer limit correctly for multi-byte UTF-8 characters (fix #158) We now maintain the buffer len for both UTF-8 and wchar --- imgui.cpp | 133 +++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 91 insertions(+), 42 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 582afb40..1c46254e 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -461,9 +461,9 @@ static inline bool ImCharIsSpace(int c) { return c == ' ' || c == '\t' || c == static int ImTextCharToUtf8(char* buf, size_t buf_size, unsigned int in_char); // return output UTF-8 bytes count static ptrdiff_t ImTextStrToUtf8(char* buf, size_t buf_size, const ImWchar* in_text, const ImWchar* in_text_end); // return output UTF-8 bytes count static int ImTextCharFromUtf8(unsigned int* out_char, const char* in_text, const char* in_text_end); // return input UTF-8 bytes count -static ptrdiff_t ImTextStrFromUtf8(ImWchar* buf, size_t buf_size, const char* in_text, const char* in_text_end); // return input UTF-8 bytes count +static ptrdiff_t ImTextStrFromUtf8(ImWchar* buf, size_t buf_size, const char* in_text, const char* in_text_end, const char** in_remaining = NULL); // return input UTF-8 bytes count static int ImTextCountCharsFromUtf8(const char* in_text, const char* in_text_end); // return number of UTF-8 code-points (NOT bytes count) -static int ImTextCountUtf8BytesFromWchar(const ImWchar* in_text, const ImWchar* in_text_end); // return number of bytes to express string as UTF-8 code-points +static int ImTextCountUtf8BytesFromStr(const ImWchar* in_text, const ImWchar* in_text_end); // return number of bytes to express string as UTF-8 code-points //----------------------------------------------------------------------------- // Platform dependent default implementations @@ -956,8 +956,9 @@ struct ImGuiTextEditState { ImGuiID Id; // widget id owning the text state ImWchar Text[1024]; // edit buffer, we need to persist but can't guarantee the persistence of the user-provided buffer. so we copy into own buffer. - char InitialText[1024*3+1]; // backup of end-user buffer at the time of focus (in UTF-8, unconverted) - size_t BufSize; // end-user buffer size, <= 1024 (or increase above) + char InitialText[1024*4+1]; // backup of end-user buffer at the time of focus (in UTF-8, unaltered) + size_t CurLenA, CurLenW; // we need to maintain our buffer length in both UTF-8 and wchar format. + size_t BufSizeA; // end-user buffer size, <= 1024 (or increase above) float Width; // widget width float ScrollX; STB_TexteditState StbState; @@ -5268,17 +5269,38 @@ static void STB_TEXTEDIT_LAYOUTROW(StbTexteditRow* r, STB_TEXTEDIT_STRING* ob static bool is_separator(unsigned int c) { return c==',' || c==';' || c=='(' || c==')' || c=='{' || c=='}' || c=='[' || c==']' || c=='|'; } #define STB_TEXTEDIT_IS_SPACE(CH) ( ImCharIsSpace((unsigned int)CH) || is_separator((unsigned int)CH) ) -static void STB_TEXTEDIT_DELETECHARS(STB_TEXTEDIT_STRING* obj, int pos, int n) { ImWchar* dst = obj->Text+pos; const ImWchar* src = obj->Text+pos+n; while (ImWchar c = *src++) *dst++ = c; *dst = '\0'; } +static void STB_TEXTEDIT_DELETECHARS(STB_TEXTEDIT_STRING* obj, int pos, int n) +{ + ImWchar* dst = obj->Text + pos; + + // We maintain our buffer length in both UTF-8 and wchar formats + obj->CurLenA -= ImTextCountUtf8BytesFromStr(dst, dst + n); + obj->CurLenW -= n; + + // Offset remaining text + const ImWchar* src = obj->Text + pos + n; + while (ImWchar c = *src++) + *dst++ = c; + *dst = '\0'; +} + static bool STB_TEXTEDIT_INSERTCHARS(STB_TEXTEDIT_STRING* obj, int pos, const ImWchar* new_text, int new_text_len) { - const size_t text_len = ImStrlenW(obj->Text); - if ((size_t)new_text_len + text_len + 1 > obj->BufSize) + const size_t text_len = obj->CurLenW; + if ((size_t)new_text_len + text_len + 1 > IM_ARRAYSIZE(obj->Text)) + return false; + + const int new_text_len_utf8 = ImTextCountUtf8BytesFromStr(new_text, new_text + new_text_len); + if ((size_t)new_text_len_utf8 + obj->CurLenA + 1 > obj->BufSizeA) return false; if (pos != (int)text_len) memmove(obj->Text + (size_t)pos + new_text_len, obj->Text + (size_t)pos, (text_len - (size_t)pos) * sizeof(ImWchar)); memcpy(obj->Text + (size_t)pos, new_text, (size_t)new_text_len * sizeof(ImWchar)); - obj->Text[text_len + (size_t)new_text_len] = '\0'; + + obj->CurLenW += new_text_len; + obj->CurLenA += new_text_len_utf8; + obj->Text[obj->CurLenW] = '\0'; return true; } @@ -5373,11 +5395,15 @@ void ImGuiTextEditState::RenderTextScrolledClipped(ImFont* font, float font_size const char* text_start = GetTextPointerClippedA(font, font_size, buf, scroll_x, NULL); const char* text_end = GetTextPointerClippedA(font, font_size, text_start, width, &text_size); + // We need to test for the possibility of malformed UTF-8 (instead of just text_end[0] != 0) + unsigned int text_end_char = 0; + ImTextCharFromUtf8(&text_end_char, text_end, NULL); + // Draw a little clip symbol if we've got text on either left or right of the box const char symbol_c = '~'; const float symbol_w = font_size*0.40f; // FIXME: compute correct width const float clip_begin = (text_start > buf && text_start < text_end) ? symbol_w : 0.0f; - const float clip_end = (text_end[0] != '\0' && text_end > text_start) ? symbol_w : 0.0f; + const float clip_end = (text_end_char != 0 && text_end > text_start) ? symbol_w : 0.0f; // Draw text RenderText(pos+ImVec2(clip_begin,0), text_start+(clip_begin>0.0f?1:0), text_end-(clip_end>0.0f?1:0), false); @@ -5589,8 +5615,11 @@ bool ImGui::InputText(const char* label, char* buf, size_t buf_size, ImGuiInputT { // Start edition // Take a copy of the initial buffer value (both in original UTF-8 format and converted to wchar) + // From the moment we focused we are ignoring the content of 'buf' ImFormatString(edit_state.InitialText, IM_ARRAYSIZE(edit_state.InitialText), "%s", buf); - size_t buf_len = ImTextStrFromUtf8(edit_state.Text, IM_ARRAYSIZE(edit_state.Text), buf, NULL); + const char* buf_end = NULL; + edit_state.CurLenW = ImTextStrFromUtf8(edit_state.Text, IM_ARRAYSIZE(edit_state.Text), buf, NULL, &buf_end); + edit_state.CurLenA = buf_end - buf; // We can't get the result from ImFormatString() above because it is not UTF-8 aware. Here we'll cut off malformed UTF-8. edit_state.Width = w; edit_state.InputCursorScreenPos = ImVec2(-1.f,-1.f); edit_state.CursorAnimReset(); @@ -5607,9 +5636,9 @@ bool ImGui::InputText(const char* label, char* buf, size_t buf_size, ImGuiInputT { // Recycle existing cursor/selection/undo stack but clamp position // Note a single mouse click will override the cursor/position immediately by calling stb_textedit_click handler. - edit_state.StbState.cursor = ImMin(edit_state.StbState.cursor, buf_len); - edit_state.StbState.select_start = ImMin(edit_state.StbState.select_start, buf_len); - edit_state.StbState.select_end = ImMin(edit_state.StbState.select_end, buf_len); + edit_state.StbState.cursor = ImMin(edit_state.StbState.cursor, edit_state.CurLenW); + edit_state.StbState.select_start = ImMin(edit_state.StbState.select_start, edit_state.CurLenW); + edit_state.StbState.select_end = ImMin(edit_state.StbState.select_end, edit_state.CurLenW); } if (focus_requested_by_tab || (user_clicked && is_ctrl_down)) select_all = true; @@ -5638,10 +5667,10 @@ bool ImGui::InputText(const char* label, char* buf, size_t buf_size, ImGuiInputT if (g.ActiveId == id) { // Edit in progress - edit_state.BufSize = buf_size < IM_ARRAYSIZE(edit_state.Text) ? buf_size : IM_ARRAYSIZE(edit_state.Text); + edit_state.BufSizeA = buf_size; edit_state.Font = window->Font(); edit_state.FontSize = window->FontSize(); - + const float mx = g.IO.MousePos.x - frame_bb.Min.x - style.FramePadding.x; const float my = window->FontSize()*0.5f; // Flatten mouse because we are doing a single-line edit @@ -5706,7 +5735,7 @@ bool ImGui::InputText(const char* label, char* buf, size_t buf_size, ImGuiInputT if (g.IO.SetClipboardTextFn) { const int ib = edit_state.HasSelection() ? ImMin(edit_state.StbState.select_start, edit_state.StbState.select_end) : 0; - const int ie = edit_state.HasSelection() ? ImMax(edit_state.StbState.select_start, edit_state.StbState.select_end) : (int)ImStrlenW(edit_state.Text); + const int ie = edit_state.HasSelection() ? ImMax(edit_state.StbState.select_start, edit_state.StbState.select_end) : edit_state.CurLenW; ImTextStrToUtf8(text_tmp_utf8, IM_ARRAYSIZE(text_tmp_utf8), edit_state.Text+ib, edit_state.Text+ie); g.IO.SetClipboardTextFn(text_tmp_utf8); } @@ -5722,7 +5751,7 @@ bool ImGui::InputText(const char* label, char* buf, size_t buf_size, ImGuiInputT if (const char* clipboard = g.IO.GetClipboardTextFn()) { // Remove new-line from pasted buffer - size_t clipboard_len = strlen(clipboard); + const size_t clipboard_len = strlen(clipboard); ImWchar* clipboard_filtered = (ImWchar*)ImGui::MemAlloc((clipboard_len+1) * sizeof(ImWchar)); int clipboard_filtered_len = 0; for (const char* s = clipboard; *s; ) @@ -5792,22 +5821,22 @@ bool ImGui::InputText(const char* label, char* buf, size_t buf_size, ImGuiInputT callback_data.EventFlag = event_flag; callback_data.EventKey = event_key; callback_data.Buf = text_tmp_utf8; - callback_data.BufSize = edit_state.BufSize; + callback_data.BufSize = edit_state.BufSizeA; callback_data.BufDirty = false; callback_data.Flags = flags; callback_data.UserData = user_data; // We have to convert from position from wchar to UTF-8 positions - const int utf8_cursor_pos = callback_data.CursorPos = ImTextCountUtf8BytesFromWchar(edit_state.Text, edit_state.Text + edit_state.StbState.cursor); - const int utf8_selection_start = callback_data.SelectionStart = ImTextCountUtf8BytesFromWchar(edit_state.Text, edit_state.Text + edit_state.StbState.select_start); - const int utf8_selection_end = callback_data.SelectionEnd = ImTextCountUtf8BytesFromWchar(edit_state.Text, edit_state.Text + edit_state.StbState.select_end); + const int utf8_cursor_pos = callback_data.CursorPos = ImTextCountUtf8BytesFromStr(edit_state.Text, edit_state.Text + edit_state.StbState.cursor); + const int utf8_selection_start = callback_data.SelectionStart = ImTextCountUtf8BytesFromStr(edit_state.Text, edit_state.Text + edit_state.StbState.select_start); + const int utf8_selection_end = callback_data.SelectionEnd = ImTextCountUtf8BytesFromStr(edit_state.Text, edit_state.Text + edit_state.StbState.select_end); // Call user code callback(&callback_data); // Read back what user may have modified IM_ASSERT(callback_data.Buf == text_tmp_utf8); // Invalid to modify those fields - IM_ASSERT(callback_data.BufSize == edit_state.BufSize); + IM_ASSERT(callback_data.BufSize == edit_state.BufSizeA); IM_ASSERT(callback_data.Flags == flags); if (callback_data.CursorPos != utf8_cursor_pos) edit_state.StbState.cursor = ImTextCountCharsFromUtf8(callback_data.Buf, callback_data.Buf + callback_data.CursorPos); if (callback_data.SelectionStart != utf8_selection_start) edit_state.StbState.select_start = ImTextCountCharsFromUtf8(callback_data.Buf, callback_data.Buf + callback_data.SelectionStart); @@ -7745,10 +7774,10 @@ static int ImTextCharFromUtf8(unsigned int* out_char, const char* in_text, const if ((*str & 0xe0) == 0xc0) { *out_char = 0; - if (in_text_end && in_text_end - (const char*)str < 2) return (in_text_end - (const char*)str); // Decode error - if (*str < 0xc2) return 2; + if (in_text_end && in_text_end - (const char*)str < 2) return 0; + if (*str < 0xc2) return 0; c = (unsigned int)((*str++ & 0x1f) << 6); - if ((*str & 0xc0) != 0x80) return 2; + if ((*str & 0xc0) != 0x80) return 0; c += (*str++ & 0x3f); *out_char = c; return 2; @@ -7756,13 +7785,13 @@ static int ImTextCharFromUtf8(unsigned int* out_char, const char* in_text, const if ((*str & 0xf0) == 0xe0) { *out_char = 0; - if (in_text_end && in_text_end - (const char*)str < 3) return (in_text_end - (const char*)str); // Decode error - if (*str == 0xe0 && (str[1] < 0xa0 || str[1] > 0xbf)) return 3; - if (*str == 0xed && str[1] > 0x9f) return 3; // str[1] < 0x80 is checked below + if (in_text_end && in_text_end - (const char*)str < 3) return 0; + if (*str == 0xe0 && (str[1] < 0xa0 || str[1] > 0xbf)) return 0; + if (*str == 0xed && str[1] > 0x9f) return 0; // str[1] < 0x80 is checked below c = (unsigned int)((*str++ & 0x0f) << 12); - if ((*str & 0xc0) != 0x80) return 3; + if ((*str & 0xc0) != 0x80) return 0; c += (unsigned int)((*str++ & 0x3f) << 6); - if ((*str & 0xc0) != 0x80) return 3; + if ((*str & 0xc0) != 0x80) return 0; c += (*str++ & 0x3f); *out_char = c; return 3; @@ -7770,27 +7799,27 @@ static int ImTextCharFromUtf8(unsigned int* out_char, const char* in_text, const if ((*str & 0xf8) == 0xf0) { *out_char = 0; - if (in_text_end && in_text_end - (const char*)str < 4) return (in_text_end - (const char*)str); // Decode error - if (*str > 0xf4) return 4; - if (*str == 0xf0 && (str[1] < 0x90 || str[1] > 0xbf)) return 4; - if (*str == 0xf4 && str[1] > 0x8f) return 4; // str[1] < 0x80 is checked below + if (in_text_end && in_text_end - (const char*)str < 4) return 0; + if (*str > 0xf4) return 0; + if (*str == 0xf0 && (str[1] < 0x90 || str[1] > 0xbf)) return 0; + if (*str == 0xf4 && str[1] > 0x8f) return 0; // str[1] < 0x80 is checked below c = (unsigned int)((*str++ & 0x07) << 18); - if ((*str & 0xc0) != 0x80) return 4; + if ((*str & 0xc0) != 0x80) return 0; c += (unsigned int)((*str++ & 0x3f) << 12); - if ((*str & 0xc0) != 0x80) return 4; + if ((*str & 0xc0) != 0x80) return 0; c += (unsigned int)((*str++ & 0x3f) << 6); - if ((*str & 0xc0) != 0x80) return 4; + if ((*str & 0xc0) != 0x80) return 0; c += (*str++ & 0x3f); // utf-8 encodings of values used in surrogate pairs are invalid - if ((c & 0xFFFFF800) == 0xD800) return 4; + if ((c & 0xFFFFF800) == 0xD800) return 0; *out_char = c; return 4; } *out_char = 0; - return 1; + return 0; } -static ptrdiff_t ImTextStrFromUtf8(ImWchar* buf, size_t buf_size, const char* in_text, const char* in_text_end) +static ptrdiff_t ImTextStrFromUtf8(ImWchar* buf, size_t buf_size, const char* in_text, const char* in_text_end, const char** in_text_remaining) { ImWchar* buf_out = buf; ImWchar* buf_end = buf + buf_size; @@ -7798,10 +7827,14 @@ static ptrdiff_t ImTextStrFromUtf8(ImWchar* buf, size_t buf_size, const char* in { unsigned int c; in_text += ImTextCharFromUtf8(&c, in_text, in_text_end); + if (c == 0) + break; if (c < 0x10000) // FIXME: Losing characters that don't fit in 2 bytes *buf_out++ = (ImWchar)c; } *buf_out = 0; + if (in_text_remaining) + *in_text_remaining = in_text; return buf_out - buf; } @@ -7812,6 +7845,8 @@ static int ImTextCountCharsFromUtf8(const char* in_text, const char* in_text_end { unsigned int c; in_text += ImTextCharFromUtf8(&c, in_text, in_text_end); + if (c == 0) + break; if (c < 0x10000) char_count++; } @@ -7876,7 +7911,7 @@ static ptrdiff_t ImTextStrToUtf8(char* buf, size_t buf_size, const ImWchar* in_t return buf_out - buf; } -static int ImTextCountUtf8BytesFromWchar(const ImWchar* in_text, const ImWchar* in_text_end) +static int ImTextCountUtf8BytesFromStr(const ImWchar* in_text, const ImWchar* in_text_end) { int bytes_count = 0; while ((!in_text_end || in_text < in_text_end) && *in_text) @@ -7922,6 +7957,8 @@ const char* ImFont::CalcWordWrapPositionA(float scale, const char* text, const c next_s = s + 1; else next_s = s + ImTextCharFromUtf8(&c, s, text_end); + if (c == 0) + break; if (c == '\n') { @@ -8023,9 +8060,15 @@ ImVec2 ImFont::CalcTextSizeA(float size, float max_width, float wrap_width, cons // Decode and advance source (handle unlikely UTF-8 decoding failure by skipping to the next byte) unsigned int c = (unsigned int)*s; if (c < 0x80) + { s += 1; + } else + { s += ImTextCharFromUtf8(&c, s, text_end); + if (c == 0) + break; + } if (c == '\n') { @@ -8155,9 +8198,15 @@ void ImFont::RenderText(float size, ImVec2 pos, ImU32 col, const ImVec4& clip_re // Decode and advance source (handle unlikely UTF-8 decoding failure by skipping to the next byte) unsigned int c = (unsigned int)*s; if (c < 0x80) + { s += 1; + } else + { s += ImTextCharFromUtf8(&c, s, text_end); + if (c == 0) + break; + } if (c == '\n') { @@ -8260,7 +8309,7 @@ static const char* GetClipboardTextFn_DefaultImpl() return NULL; if (ImWchar* wbuf_global = (ImWchar*)GlobalLock(wbuf_handle)) { - int buf_len = ImTextCountUtf8BytesFromWchar(wbuf_global, NULL) + 1; + int buf_len = ImTextCountUtf8BytesFromStr(wbuf_global, NULL) + 1; buf_local = (char*)ImGui::MemAlloc(buf_len * sizeof(char)); ImTextStrToUtf8(buf_local, buf_len, wbuf_global, NULL); } From 545a57d25326fc804f99be03d4b51be7e6d2a6b4 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 9 Mar 2015 11:25:15 +0000 Subject: [PATCH 28/48] Examples: Refactored opengl_example into a glfw specific file that can be copied and pasted. Other examples will follow. --- examples/opengl3_example/Makefile | 3 +- examples/opengl_example/Makefile | 5 +- examples/opengl_example/imgui_impl_glfw.cpp | 236 +++++++++++++++++ examples/opengl_example/imgui_impl_glfw.h | 16 ++ examples/opengl_example/main.cpp | 249 ++---------------- .../opengl_example/opengl_example.vcxproj | 4 + .../opengl_example.vcxproj.filters | 6 + 7 files changed, 282 insertions(+), 237 deletions(-) create mode 100644 examples/opengl_example/imgui_impl_glfw.cpp create mode 100644 examples/opengl_example/imgui_impl_glfw.h diff --git a/examples/opengl3_example/Makefile b/examples/opengl3_example/Makefile index bb0a1946..fa2665f7 100644 --- a/examples/opengl3_example/Makefile +++ b/examples/opengl3_example/Makefile @@ -1,6 +1,5 @@ # -# Cross Platform Make file -# +# Cross Platform Makefile # Compatible with Ubuntu 14.04.1 and Mac OS X # # diff --git a/examples/opengl_example/Makefile b/examples/opengl_example/Makefile index 2563bdb8..966e9338 100644 --- a/examples/opengl_example/Makefile +++ b/examples/opengl_example/Makefile @@ -1,6 +1,5 @@ # -# Cross Platform Make file -# +# Cross Platform Makefile # Compatible with Ubuntu 14.04.1 and Mac OS X # # @@ -11,7 +10,7 @@ #CXX = g++ -OBJS = main.o +OBJS = main.o imgui_impl_glfw.o OBJS += ../../imgui.o UNAME_S := $(shell uname -s) diff --git a/examples/opengl_example/imgui_impl_glfw.cpp b/examples/opengl_example/imgui_impl_glfw.cpp new file mode 100644 index 00000000..fb85b6d3 --- /dev/null +++ b/examples/opengl_example/imgui_impl_glfw.cpp @@ -0,0 +1,236 @@ +// ImGui GLFW bindings +// https://github.com/ocornut/imgui + +#include +#include "imgui_impl_glfw.h" + +// GLFW +#include +#ifdef _MSC_VER +#undef APIENTRY +#define GLFW_EXPOSE_NATIVE_WIN32 +#define GLFW_EXPOSE_NATIVE_WGL +#include +#endif + +static GLFWwindow* GWindow = NULL; +static bool GMousePressed[3] = { false, false, false }; +static double GTime = 0.0f; +static bool GFontTextureLoaded; + +// This is the main rendering function that you have to implement and provide to ImGui (via setting up 'RenderDrawListsFn' in the ImGuiIO structure) +// If text or lines are blurry when integrating ImGui in your engine: +// - in your Render function, try translating your projection matrix by (0.5f,0.5f) or (0.375f,0.375f) +static void ImGui_ImplGlfw_RenderDrawLists(ImDrawList** const cmd_lists, int cmd_lists_count) +{ + if (cmd_lists_count == 0) + return; + + // We are using the OpenGL fixed pipeline to make the example code simpler to read! + // A probable faster way to render would be to collate all vertices from all cmd_lists into a single vertex buffer. + // Setup render state: alpha-blending enabled, no face culling, no depth testing, scissor enabled, vertex/texcoord/color pointers. + glPushAttrib(GL_ENABLE_BIT | GL_COLOR_BUFFER_BIT | GL_TRANSFORM_BIT); + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glDisable(GL_CULL_FACE); + glDisable(GL_DEPTH_TEST); + glEnable(GL_SCISSOR_TEST); + glEnableClientState(GL_VERTEX_ARRAY); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + glEnableClientState(GL_COLOR_ARRAY); + glEnable(GL_TEXTURE_2D); + + // Setup orthographic projection matrix + const float width = ImGui::GetIO().DisplaySize.x; + const float height = ImGui::GetIO().DisplaySize.y; + glMatrixMode(GL_PROJECTION); + glPushMatrix(); + glLoadIdentity(); + glOrtho(0.0f, width, height, 0.0f, -1.0f, +1.0f); + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); + glLoadIdentity(); + + // Render command lists + #define OFFSETOF(TYPE, ELEMENT) ((size_t)&(((TYPE *)0)->ELEMENT)) + for (int n = 0; n < cmd_lists_count; n++) + { + const ImDrawList* cmd_list = cmd_lists[n]; + const unsigned char* vtx_buffer = (const unsigned char*)&cmd_list->vtx_buffer.front(); + glVertexPointer(2, GL_FLOAT, sizeof(ImDrawVert), (void*)(vtx_buffer + OFFSETOF(ImDrawVert, pos))); + glTexCoordPointer(2, GL_FLOAT, sizeof(ImDrawVert), (void*)(vtx_buffer + OFFSETOF(ImDrawVert, uv))); + glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(ImDrawVert), (void*)(vtx_buffer + OFFSETOF(ImDrawVert, col))); + + int vtx_offset = 0; + for (size_t cmd_i = 0; cmd_i < cmd_list->commands.size(); cmd_i++) + { + const ImDrawCmd* pcmd = &cmd_list->commands[cmd_i]; + glBindTexture(GL_TEXTURE_2D, (GLuint)(intptr_t)pcmd->texture_id); + glScissor((int)pcmd->clip_rect.x, (int)(height - pcmd->clip_rect.w), (int)(pcmd->clip_rect.z - pcmd->clip_rect.x), (int)(pcmd->clip_rect.w - pcmd->clip_rect.y)); + glDrawArrays(GL_TRIANGLES, vtx_offset, pcmd->vtx_count); + vtx_offset += pcmd->vtx_count; + } + } + #undef OFFSETOF + + // Restore modified state + glDisableClientState(GL_COLOR_ARRAY); + glDisableClientState(GL_TEXTURE_COORD_ARRAY); + glDisableClientState(GL_VERTEX_ARRAY); + glMatrixMode(GL_MODELVIEW); + glPopMatrix(); + glMatrixMode(GL_PROJECTION); + glPopMatrix(); + glPopAttrib(); +} + +static const char* ImGui_ImplGlfw_GetClipboardText() +{ + return glfwGetClipboardString(GWindow); +} + +static void ImGui_ImplGlfw_SetClipboardText(const char* text) +{ + glfwSetClipboardString(GWindow, text); +} + +void ImGui_ImplGlfw_MouseButtonCallback(GLFWwindow* window, int button, int action, int mods) +{ + if (action == GLFW_PRESS && button >= 0 && button < 3) + GMousePressed[button] = true; +} + +void ImGui_ImplGlfw_ScrollCallback(GLFWwindow* window, double xoffset, double yoffset) +{ + ImGuiIO& io = ImGui::GetIO(); + io.MouseWheel += (float)yoffset; // Use fractional mouse wheel, 1.0 unit 5 lines. +} + +void ImGui_ImplGlFw_KeyCallback(GLFWwindow* window, int key, int scancode, int action, int mods) +{ + ImGuiIO& io = ImGui::GetIO(); + if (action == GLFW_PRESS) + io.KeysDown[key] = true; + if (action == GLFW_RELEASE) + io.KeysDown[key] = false; + io.KeyCtrl = (mods & GLFW_MOD_CONTROL) != 0; + io.KeyShift = (mods & GLFW_MOD_SHIFT) != 0; +} + +void ImGui_ImplGlfw_CharCallback(GLFWwindow* window, unsigned int c) +{ + ImGuiIO& io = ImGui::GetIO(); + if (c > 0 && c < 0x10000) + io.AddInputCharacter((unsigned short)c); +} + +void ImGui_ImplGlfw_LoadFontsTexture() +{ + ImGuiIO& io = ImGui::GetIO(); + + unsigned char* pixels; + int width, height; + io.Fonts->GetTexDataAsAlpha8(&pixels, &width, &height); + + GLuint tex_id; + glGenTextures(1, &tex_id); + glBindTexture(GL_TEXTURE_2D, tex_id); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, width, height, 0, GL_ALPHA, GL_UNSIGNED_BYTE, pixels); + + // Store our identifier + io.Fonts->TexID = (void *)(intptr_t)tex_id; + + GFontTextureLoaded = true; +} + +bool ImGui_ImplGlfw_Init(GLFWwindow* window, bool install_callbacks) +{ + GWindow = window; + + ImGuiIO& io = ImGui::GetIO(); + io.KeyMap[ImGuiKey_Tab] = GLFW_KEY_TAB; // Keyboard mapping. ImGui will use those indices to peek into the io.KeyDown[] array. + io.KeyMap[ImGuiKey_LeftArrow] = GLFW_KEY_LEFT; + io.KeyMap[ImGuiKey_RightArrow] = GLFW_KEY_RIGHT; + io.KeyMap[ImGuiKey_UpArrow] = GLFW_KEY_UP; + io.KeyMap[ImGuiKey_DownArrow] = GLFW_KEY_DOWN; + io.KeyMap[ImGuiKey_Home] = GLFW_KEY_HOME; + io.KeyMap[ImGuiKey_End] = GLFW_KEY_END; + io.KeyMap[ImGuiKey_Delete] = GLFW_KEY_DELETE; + io.KeyMap[ImGuiKey_Backspace] = GLFW_KEY_BACKSPACE; + io.KeyMap[ImGuiKey_Enter] = GLFW_KEY_ENTER; + io.KeyMap[ImGuiKey_Escape] = GLFW_KEY_ESCAPE; + io.KeyMap[ImGuiKey_A] = GLFW_KEY_A; + io.KeyMap[ImGuiKey_C] = GLFW_KEY_C; + io.KeyMap[ImGuiKey_V] = GLFW_KEY_V; + io.KeyMap[ImGuiKey_X] = GLFW_KEY_X; + io.KeyMap[ImGuiKey_Y] = GLFW_KEY_Y; + io.KeyMap[ImGuiKey_Z] = GLFW_KEY_Z; + + io.RenderDrawListsFn = ImGui_ImplGlfw_RenderDrawLists; + io.SetClipboardTextFn = ImGui_ImplGlfw_SetClipboardText; + io.GetClipboardTextFn = ImGui_ImplGlfw_GetClipboardText; +#ifdef _MSC_VER + io.ImeWindowHandle = glfwGetWin32Window(GWindow); +#endif + + if (install_callbacks) + { + glfwSetMouseButtonCallback(window, ImGui_ImplGlfw_MouseButtonCallback); + glfwSetScrollCallback(window, ImGui_ImplGlfw_ScrollCallback); + glfwSetKeyCallback(window, ImGui_ImplGlFw_KeyCallback); + glfwSetCharCallback(window, ImGui_ImplGlfw_CharCallback); + } + + return true; +} + +void ImGui_ImplGlfw_Shutdown() +{ + GLuint tex_id = (GLuint)ImGui::GetIO().Fonts->TexID; + if (tex_id) + { + glDeleteTextures(1, &tex_id); + ImGui::GetIO().Fonts->TexID = 0; + } + ImGui::Shutdown(); +} + +void ImGui_ImplGlfw_NewFrame() +{ + if (!GFontTextureLoaded) + ImGui_ImplGlfw_LoadFontsTexture(); + + ImGuiIO& io = ImGui::GetIO(); + + // Setup display size (every frame to accommodate for window resizing) + int w, h; + int display_w, display_h; + glfwGetWindowSize(GWindow, &w, &h); + glfwGetFramebufferSize(GWindow, &display_w, &display_h); + io.DisplaySize = ImVec2((float)display_w, (float)display_h); + + // Setup time step + double current_time = glfwGetTime(); + io.DeltaTime = GTime > 0.0 ? (float)(current_time - GTime) : (float)(1.0f/60.0f); + GTime = current_time; + + // Setup inputs + // (we already got mouse wheel, keyboard keys & characters from glfw callbacks polled in glfwPollEvents()) + double mouse_x, mouse_y; + glfwGetCursorPos(GWindow, &mouse_x, &mouse_y); + mouse_x *= (float)display_w / w; // Convert mouse coordinates to pixels + mouse_y *= (float)display_h / h; + io.MousePos = ImVec2((float)mouse_x, (float)mouse_y); // Mouse position, in pixels (set to -1,-1 if no mouse / on another screen, etc.) + + io.MouseDown[0] = GMousePressed[0] || glfwGetMouseButton(GWindow, GLFW_MOUSE_BUTTON_LEFT) != 0; // If a mouse press event came, always pass it as "mouse held this frame", so we don't miss click-release events that are shorter than 1 frame. + io.MouseDown[1] = GMousePressed[1] || glfwGetMouseButton(GWindow, GLFW_MOUSE_BUTTON_RIGHT) != 0; + io.MouseDown[2] = GMousePressed[2] || glfwGetMouseButton(GWindow, GLFW_MOUSE_BUTTON_MIDDLE) != 0; + GMousePressed[0] = false; + GMousePressed[1] = false; + GMousePressed[2] = false; + + // Start the frame + ImGui::NewFrame(); +} diff --git a/examples/opengl_example/imgui_impl_glfw.h b/examples/opengl_example/imgui_impl_glfw.h new file mode 100644 index 00000000..0b18ec77 --- /dev/null +++ b/examples/opengl_example/imgui_impl_glfw.h @@ -0,0 +1,16 @@ +// ImGui GLFW bindings +// https://github.com/ocornut/imgui + +struct GLFWwindow; + +bool ImGui_ImplGlfw_Init(GLFWwindow* window, bool install_callbacks); +void ImGui_ImplGlfw_Shutdown(); +void ImGui_ImplGlfw_LoadFontsTexture(); +void ImGui_ImplGlfw_NewFrame(); + +// GLFW callbacks (installed by default if you enable 'install_callbacks' during initialization) +// Provide here if you want to chain callbacks +void ImGui_ImplGlfw_MouseButtonCallback(GLFWwindow* window, int button, int action, int mods); +void ImGui_ImplGlfw_ScrollCallback(GLFWwindow* window, double xoffset, double yoffset); +void ImGui_ImplGlFw_KeyCallback(GLFWwindow* window, int key, int scancode, int action, int mods); +void ImGui_ImplGlfw_CharCallback(GLFWwindow* window, unsigned int c); diff --git a/examples/opengl_example/main.cpp b/examples/opengl_example/main.cpp index 4cef9290..d658f6ae 100644 --- a/examples/opengl_example/main.cpp +++ b/examples/opengl_example/main.cpp @@ -1,256 +1,41 @@ -// ImGui - standalone example application for OpenGL 2, using fixed pipeline +// ImGui - standalone example application for Glfw + OpenGL 2, using fixed pipeline -#ifdef _MSC_VER -#pragma warning (disable: 4996) // 'This function or variable may be unsafe': strcpy, strdup, sprintf, vsnprintf, sscanf, fopen -#endif -#ifdef __clang__ -#pragma clang diagnostic ignored "-Wunused-function" // warning: unused function -#endif - -#include "../../imgui.h" +#include +#include "imgui_impl_glfw.h" #include - -// GLFW #include -#ifdef _MSC_VER -#undef APIENTRY -#define GLFW_EXPOSE_NATIVE_WIN32 -#define GLFW_EXPOSE_NATIVE_WGL -#include -#endif - -static GLFWwindow* window; -static bool mousePressed[2] = { false, false }; - -#define OFFSETOF(TYPE, ELEMENT) ((size_t)&(((TYPE *)0)->ELEMENT)) - -// This is the main rendering function that you have to implement and provide to ImGui (via setting up 'RenderDrawListsFn' in the ImGuiIO structure) -// If text or lines are blurry when integrating ImGui in your engine: -// - in your Render function, try translating your projection matrix by (0.5f,0.5f) or (0.375f,0.375f) -static void ImImpl_RenderDrawLists(ImDrawList** const cmd_lists, int cmd_lists_count) -{ - if (cmd_lists_count == 0) - return; - - // We are using the OpenGL fixed pipeline to make the example code simpler to read! - // A probable faster way to render would be to collate all vertices from all cmd_lists into a single vertex buffer. - // Setup render state: alpha-blending enabled, no face culling, no depth testing, scissor enabled, vertex/texcoord/color pointers. - glPushAttrib(GL_ENABLE_BIT | GL_COLOR_BUFFER_BIT | GL_TRANSFORM_BIT); - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glDisable(GL_CULL_FACE); - glDisable(GL_DEPTH_TEST); - glEnable(GL_SCISSOR_TEST); - glEnableClientState(GL_VERTEX_ARRAY); - glEnableClientState(GL_TEXTURE_COORD_ARRAY); - glEnableClientState(GL_COLOR_ARRAY); - glEnable(GL_TEXTURE_2D); - - // Setup orthographic projection matrix - const float width = ImGui::GetIO().DisplaySize.x; - const float height = ImGui::GetIO().DisplaySize.y; - glMatrixMode(GL_PROJECTION); - glPushMatrix(); - glLoadIdentity(); - glOrtho(0.0f, width, height, 0.0f, -1.0f, +1.0f); - glMatrixMode(GL_MODELVIEW); - glPushMatrix(); - glLoadIdentity(); - - // Render command lists - for (int n = 0; n < cmd_lists_count; n++) - { - const ImDrawList* cmd_list = cmd_lists[n]; - const unsigned char* vtx_buffer = (const unsigned char*)&cmd_list->vtx_buffer.front(); - glVertexPointer(2, GL_FLOAT, sizeof(ImDrawVert), (void*)(vtx_buffer + OFFSETOF(ImDrawVert, pos))); - glTexCoordPointer(2, GL_FLOAT, sizeof(ImDrawVert), (void*)(vtx_buffer + OFFSETOF(ImDrawVert, uv))); - glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(ImDrawVert), (void*)(vtx_buffer + OFFSETOF(ImDrawVert, col))); - - int vtx_offset = 0; - for (size_t cmd_i = 0; cmd_i < cmd_list->commands.size(); cmd_i++) - { - const ImDrawCmd* pcmd = &cmd_list->commands[cmd_i]; - glBindTexture(GL_TEXTURE_2D, (GLuint)(intptr_t)pcmd->texture_id); - glScissor((int)pcmd->clip_rect.x, (int)(height - pcmd->clip_rect.w), (int)(pcmd->clip_rect.z - pcmd->clip_rect.x), (int)(pcmd->clip_rect.w - pcmd->clip_rect.y)); - glDrawArrays(GL_TRIANGLES, vtx_offset, pcmd->vtx_count); - vtx_offset += pcmd->vtx_count; - } - } - - // Restore modified state - glDisableClientState(GL_COLOR_ARRAY); - glDisableClientState(GL_TEXTURE_COORD_ARRAY); - glDisableClientState(GL_VERTEX_ARRAY); - glMatrixMode(GL_MODELVIEW); - glPopMatrix(); - glMatrixMode(GL_PROJECTION); - glPopMatrix(); - glPopAttrib(); -} - -// NB: ImGui already provide OS clipboard support for Windows so this isn't needed if you are using Windows only. -static const char* ImImpl_GetClipboardTextFn() -{ - return glfwGetClipboardString(window); -} - -static void ImImpl_SetClipboardTextFn(const char* text) -{ - glfwSetClipboardString(window, text); -} - -// GLFW callbacks -static void glfw_error_callback(int error, const char* description) -{ - fputs(description, stderr); -} - -static void glfw_mouse_button_callback(GLFWwindow* window, int button, int action, int mods) -{ - if (action == GLFW_PRESS && button >= 0 && button < 2) - mousePressed[button] = true; -} -static void glfw_scroll_callback(GLFWwindow* window, double xoffset, double yoffset) +static void error_callback(int error, const char* description) { - ImGuiIO& io = ImGui::GetIO(); - io.MouseWheel += (float)yoffset; // Use fractional mouse wheel, 1.0 unit 5 lines. + fprintf(stderr, "Error: %s\n", description); } -static void glfw_key_callback(GLFWwindow* window, int key, int scancode, int action, int mods) -{ - ImGuiIO& io = ImGui::GetIO(); - if (action == GLFW_PRESS) - io.KeysDown[key] = true; - if (action == GLFW_RELEASE) - io.KeysDown[key] = false; - io.KeyCtrl = (mods & GLFW_MOD_CONTROL) != 0; - io.KeyShift = (mods & GLFW_MOD_SHIFT) != 0; -} - -static void glfw_char_callback(GLFWwindow* window, unsigned int c) -{ - if (c > 0 && c < 0x10000) - ImGui::GetIO().AddInputCharacter((unsigned short)c); -} - -void InitGL() +int main(int argc, char** argv) { - glfwSetErrorCallback(glfw_error_callback); + glfwSetErrorCallback(error_callback); if (!glfwInit()) exit(1); - window = glfwCreateWindow(1280, 720, "ImGui OpenGL2 example", NULL, NULL); + GLFWwindow* window = glfwCreateWindow(1280, 720, "ImGui OpenGL2 example", NULL, NULL); glfwMakeContextCurrent(window); - glfwSetKeyCallback(window, glfw_key_callback); - glfwSetMouseButtonCallback(window, glfw_mouse_button_callback); - glfwSetScrollCallback(window, glfw_scroll_callback); - glfwSetCharCallback(window, glfw_char_callback); -} -void LoadFontsTexture() -{ - ImGuiIO& io = ImGui::GetIO(); + ImGui_ImplGlfw_Init(window, true); + //ImGuiIO& io = ImGui::GetIO(); //ImFont* my_font1 = io.Fonts->AddFontDefault(); //ImFont* my_font2 = io.Fonts->AddFontFromFileTTF("extra_fonts/Karla-Regular.ttf", 15.0f); //ImFont* my_font3 = io.Fonts->AddFontFromFileTTF("extra_fonts/ProggyClean.ttf", 13.0f); my_font3->DisplayOffset.y += 1; //ImFont* my_font4 = io.Fonts->AddFontFromFileTTF("extra_fonts/ProggyTiny.ttf", 10.0f); my_font4->DisplayOffset.y += 1; //ImFont* my_font5 = io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf", 18.0f, io.Fonts->GetGlyphRangesJapanese()); - - unsigned char* pixels; - int width, height; - io.Fonts->GetTexDataAsAlpha8(&pixels, &width, &height); - - GLuint tex_id; - glGenTextures(1, &tex_id); - glBindTexture(GL_TEXTURE_2D, tex_id); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, width, height, 0, GL_ALPHA, GL_UNSIGNED_BYTE, pixels); - - // Store our identifier - io.Fonts->TexID = (void *)(intptr_t)tex_id; -} - -void InitImGui() -{ - ImGuiIO& io = ImGui::GetIO(); - io.DeltaTime = 1.0f/60.0f; // Time elapsed since last frame, in seconds (in this sample app we'll override this every frame because our time step is variable) - io.KeyMap[ImGuiKey_Tab] = GLFW_KEY_TAB; // Keyboard mapping. ImGui will use those indices to peek into the io.KeyDown[] array. - io.KeyMap[ImGuiKey_LeftArrow] = GLFW_KEY_LEFT; - io.KeyMap[ImGuiKey_RightArrow] = GLFW_KEY_RIGHT; - io.KeyMap[ImGuiKey_UpArrow] = GLFW_KEY_UP; - io.KeyMap[ImGuiKey_DownArrow] = GLFW_KEY_DOWN; - io.KeyMap[ImGuiKey_Home] = GLFW_KEY_HOME; - io.KeyMap[ImGuiKey_End] = GLFW_KEY_END; - io.KeyMap[ImGuiKey_Delete] = GLFW_KEY_DELETE; - io.KeyMap[ImGuiKey_Backspace] = GLFW_KEY_BACKSPACE; - io.KeyMap[ImGuiKey_Enter] = GLFW_KEY_ENTER; - io.KeyMap[ImGuiKey_Escape] = GLFW_KEY_ESCAPE; - io.KeyMap[ImGuiKey_A] = GLFW_KEY_A; - io.KeyMap[ImGuiKey_C] = GLFW_KEY_C; - io.KeyMap[ImGuiKey_V] = GLFW_KEY_V; - io.KeyMap[ImGuiKey_X] = GLFW_KEY_X; - io.KeyMap[ImGuiKey_Y] = GLFW_KEY_Y; - io.KeyMap[ImGuiKey_Z] = GLFW_KEY_Z; - - io.RenderDrawListsFn = ImImpl_RenderDrawLists; - io.SetClipboardTextFn = ImImpl_SetClipboardTextFn; - io.GetClipboardTextFn = ImImpl_GetClipboardTextFn; -#ifdef _MSC_VER - io.ImeWindowHandle = glfwGetWin32Window(window); -#endif - - LoadFontsTexture(); -} - -void UpdateImGui() -{ - ImGuiIO& io = ImGui::GetIO(); - - // Setup resolution (every frame to accommodate for window resizing) - int w, h; - int display_w, display_h; - glfwGetWindowSize(window, &w, &h); - glfwGetFramebufferSize(window, &display_w, &display_h); - io.DisplaySize = ImVec2((float)display_w, (float)display_h); // Display size, in pixels. For clamping windows positions. - - // Setup time step - static double time = 0.0f; - const double current_time = glfwGetTime(); - io.DeltaTime = (float)(current_time - time); - time = current_time; - - // Setup inputs - // (we already got mouse wheel, keyboard keys & characters from glfw callbacks polled in glfwPollEvents()) - double mouse_x, mouse_y; - glfwGetCursorPos(window, &mouse_x, &mouse_y); - mouse_x *= (float)display_w / w; // Convert mouse coordinates to pixels - mouse_y *= (float)display_h / h; - io.MousePos = ImVec2((float)mouse_x, (float)mouse_y); // Mouse position, in pixels (set to -1,-1 if no mouse / on another screen, etc.) - io.MouseDown[0] = mousePressed[0] || glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_LEFT) != 0; // If a mouse press event came, always pass it as "mouse held this frame", so we don't miss click-release events that are shorter than 1 frame. - io.MouseDown[1] = mousePressed[1] || glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_RIGHT) != 0; - - // Start the frame - ImGui::NewFrame(); -} - -// Application code -int main(int argc, char** argv) -{ - InitGL(); - InitImGui(); + ImGui_ImplGlfw_LoadFontsTexture(); bool show_test_window = true; bool show_another_window = false; - ImVec4 clear_col = ImColor(114, 144, 154); + ImVec4 clear_color = ImColor(114, 144, 154); while (!glfwWindowShouldClose(window)) { - ImGuiIO& io = ImGui::GetIO(); - mousePressed[0] = mousePressed[1] = false; glfwPollEvents(); - UpdateImGui(); + ImGui_ImplGlfw_NewFrame(); // 1. Show a simple window // Tip: if we don't call ImGui::Begin()/ImGui::End() the widgets appears in a window automatically called "Debug" @@ -258,7 +43,7 @@ int main(int argc, char** argv) static float f; ImGui::Text("Hello, world!"); ImGui::SliderFloat("float", &f, 0.0f, 1.0f); - ImGui::ColorEdit3("clear color", (float*)&clear_col); + ImGui::ColorEdit3("clear color", (float*)&clear_color); if (ImGui::Button("Test Window")) show_test_window ^= 1; if (ImGui::Button("Another Window")) show_another_window ^= 1; ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate); @@ -280,15 +65,15 @@ int main(int argc, char** argv) } // Rendering - glViewport(0, 0, (int)io.DisplaySize.x, (int)io.DisplaySize.y); - glClearColor(clear_col.x, clear_col.y, clear_col.z, clear_col.w); + glViewport(0, 0, (int)ImGui::GetIO().DisplaySize.x, (int)ImGui::GetIO().DisplaySize.y); + glClearColor(clear_color.x, clear_color.y, clear_color.z, clear_color.w); glClear(GL_COLOR_BUFFER_BIT); ImGui::Render(); glfwSwapBuffers(window); } // Cleanup - ImGui::Shutdown(); + ImGui_ImplGlfw_Shutdown(); glfwTerminate(); return 0; diff --git a/examples/opengl_example/opengl_example.vcxproj b/examples/opengl_example/opengl_example.vcxproj index 557f0dc9..69b5df6f 100644 --- a/examples/opengl_example/opengl_example.vcxproj +++ b/examples/opengl_example/opengl_example.vcxproj @@ -39,10 +39,12 @@ $(ProjectDir)$(Configuration)\ $(ProjectDir)$(Configuration)\ + ../..;$(IncludePath) $(ProjectDir)$(Configuration)\ $(ProjectDir)$(Configuration)\ + ../..;$(IncludePath) @@ -79,11 +81,13 @@ + + diff --git a/examples/opengl_example/opengl_example.vcxproj.filters b/examples/opengl_example/opengl_example.vcxproj.filters index cf1ba241..1365a7da 100644 --- a/examples/opengl_example/opengl_example.vcxproj.filters +++ b/examples/opengl_example/opengl_example.vcxproj.filters @@ -16,6 +16,9 @@ imgui + + sources + @@ -24,5 +27,8 @@ imgui + + sources + \ No newline at end of file From d8298523915ed7c00b5e8836f298e2d8602452eb Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 9 Mar 2015 11:59:23 +0000 Subject: [PATCH 29/48] Examples: Refactored opengl3_exapmle into a glfw specific file that can be copied and pasted --- .../opengl3_example/imgui_impl_glfw_gl3.cpp | 344 ++++++++++++++++++ .../opengl3_example/imgui_impl_glfw_gl3.h | 16 + examples/opengl3_example/main.cpp | 338 +---------------- .../opengl3_example/opengl3_example.vcxproj | 4 + .../opengl3_example.vcxproj.filters | 6 + examples/opengl_example/imgui_impl_glfw.cpp | 11 +- examples/opengl_example/imgui_impl_glfw.h | 2 +- 7 files changed, 394 insertions(+), 327 deletions(-) create mode 100644 examples/opengl3_example/imgui_impl_glfw_gl3.cpp create mode 100644 examples/opengl3_example/imgui_impl_glfw_gl3.h diff --git a/examples/opengl3_example/imgui_impl_glfw_gl3.cpp b/examples/opengl3_example/imgui_impl_glfw_gl3.cpp new file mode 100644 index 00000000..8a05ed49 --- /dev/null +++ b/examples/opengl3_example/imgui_impl_glfw_gl3.cpp @@ -0,0 +1,344 @@ +// ImGui GLFW binding with OpenGL3 + shaders +// https://github.com/ocornut/imgui + +#include +#include "imgui_impl_glfw_gl3.h" + +// GL3W/GLFW +#include +#include +#ifdef _MSC_VER +#undef APIENTRY +#define GLFW_EXPOSE_NATIVE_WIN32 +#define GLFW_EXPOSE_NATIVE_WGL +#include +#endif + +static GLFWwindow* GWindow = NULL; +static bool GMousePressed[3] = { false, false, false }; +static float GMouseWheel = 0.0f; +static double GTime = 0.0f; +static bool GFontTextureLoaded = false; + +// Shader variables +static int g_shader_handle = 0, g_vert_handle = 0, g_frag_handle = 0; +static int g_texture_location = 0, g_proj_mtx_location = 0; +static int g_position_location = 0, g_uv_location = 0, g_colour_location = 0; +static size_t g_vbo_max_size = 20000; +static unsigned int g_vbo_handle = 0, g_vao_handle = 0; + +// This is the main rendering function that you have to implement and provide to ImGui (via setting up 'RenderDrawListsFn' in the ImGuiIO structure) +// If text or lines are blurry when integrating ImGui in your engine: +// - in your Render function, try translating your projection matrix by (0.5f,0.5f) or (0.375f,0.375f) +static void ImGui_ImplGlfwGL3_RenderDrawLists(ImDrawList** const cmd_lists, int cmd_lists_count) +{ + if (cmd_lists_count == 0) + return; + + // Setup render state: alpha-blending enabled, no face culling, no depth testing, scissor enabled + glEnable(GL_BLEND); + glBlendEquation(GL_FUNC_ADD); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glDisable(GL_CULL_FACE); + glDisable(GL_DEPTH_TEST); + glEnable(GL_SCISSOR_TEST); + glActiveTexture(GL_TEXTURE0); + + // Setup orthographic projection matrix + const float width = ImGui::GetIO().DisplaySize.x; + const float height = ImGui::GetIO().DisplaySize.y; + const float ortho_projection[4][4] = + { + { 2.0f/width, 0.0f, 0.0f, 0.0f }, + { 0.0f, 2.0f/-height, 0.0f, 0.0f }, + { 0.0f, 0.0f, -1.0f, 0.0f }, + { -1.0f, 1.0f, 0.0f, 1.0f }, + }; + glUseProgram(g_shader_handle); + glUniform1i(g_texture_location, 0); + glUniformMatrix4fv(g_proj_mtx_location, 1, GL_FALSE, &ortho_projection[0][0]); + + // Grow our buffer according to what we need + size_t total_vtx_count = 0; + for (int n = 0; n < cmd_lists_count; n++) + total_vtx_count += cmd_lists[n]->vtx_buffer.size(); + glBindBuffer(GL_ARRAY_BUFFER, g_vbo_handle); + size_t neededBufferSize = total_vtx_count * sizeof(ImDrawVert); + if (neededBufferSize > g_vbo_max_size) + { + g_vbo_max_size = neededBufferSize + 5000; // Grow buffer + glBufferData(GL_ARRAY_BUFFER, g_vbo_max_size, NULL, GL_STREAM_DRAW); + } + + // Copy and convert all vertices into a single contiguous buffer + unsigned char* buffer_data = (unsigned char*)glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY); + if (!buffer_data) + return; + for (int n = 0; n < cmd_lists_count; n++) + { + const ImDrawList* cmd_list = cmd_lists[n]; + memcpy(buffer_data, &cmd_list->vtx_buffer[0], cmd_list->vtx_buffer.size() * sizeof(ImDrawVert)); + buffer_data += cmd_list->vtx_buffer.size() * sizeof(ImDrawVert); + } + glUnmapBuffer(GL_ARRAY_BUFFER); + glBindBuffer(GL_ARRAY_BUFFER, 0); + glBindVertexArray(g_vao_handle); + + int cmd_offset = 0; + for (int n = 0; n < cmd_lists_count; n++) + { + const ImDrawList* cmd_list = cmd_lists[n]; + int vtx_offset = cmd_offset; + const ImDrawCmd* pcmd_end = cmd_list->commands.end(); + for (const ImDrawCmd* pcmd = cmd_list->commands.begin(); pcmd != pcmd_end; pcmd++) + { + glBindTexture(GL_TEXTURE_2D, (GLuint)(intptr_t)pcmd->texture_id); + glScissor((int)pcmd->clip_rect.x, (int)(height - pcmd->clip_rect.w), (int)(pcmd->clip_rect.z - pcmd->clip_rect.x), (int)(pcmd->clip_rect.w - pcmd->clip_rect.y)); + glDrawArrays(GL_TRIANGLES, vtx_offset, pcmd->vtx_count); + vtx_offset += pcmd->vtx_count; + } + cmd_offset = vtx_offset; + } + + // Restore modified state + glBindVertexArray(0); + glUseProgram(0); + glDisable(GL_SCISSOR_TEST); + glBindTexture(GL_TEXTURE_2D, 0); +} + +static const char* ImGui_ImplGlfwGL3_GetClipboardText() +{ + return glfwGetClipboardString(GWindow); +} + +static void ImGui_ImplGlfwGL3_SetClipboardText(const char* text) +{ + glfwSetClipboardString(GWindow, text); +} + +void ImGui_ImplGlfwGL3_MouseButtonCallback(GLFWwindow* window, int button, int action, int mods) +{ + if (action == GLFW_PRESS && button >= 0 && button < 3) + GMousePressed[button] = true; +} + +void ImGui_ImplGlfwGL3_ScrollCallback(GLFWwindow* window, double xoffset, double yoffset) +{ + GMouseWheel += (float)yoffset; // Use fractional mouse wheel, 1.0 unit 5 lines. +} + +void ImGui_ImplGlfwGL3_KeyCallback(GLFWwindow* window, int key, int scancode, int action, int mods) +{ + ImGuiIO& io = ImGui::GetIO(); + if (action == GLFW_PRESS) + io.KeysDown[key] = true; + if (action == GLFW_RELEASE) + io.KeysDown[key] = false; + io.KeyCtrl = (mods & GLFW_MOD_CONTROL) != 0; + io.KeyShift = (mods & GLFW_MOD_SHIFT) != 0; +} + +void ImGui_ImplGlfwGL3_CharCallback(GLFWwindow* window, unsigned int c) +{ + ImGuiIO& io = ImGui::GetIO(); + if (c > 0 && c < 0x10000) + io.AddInputCharacter((unsigned short)c); +} + +void ImGui_ImplGlfwGL3_LoadFontsTexture() +{ + ImGuiIO& io = ImGui::GetIO(); + + unsigned char* pixels; + int width, height; + io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); // Load as RGBA 32-bits for OpenGL3 demo because it is more likely to be compatible with user's existing shader. + + GLuint tex_id; + glGenTextures(1, &tex_id); + glBindTexture(GL_TEXTURE_2D, tex_id); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels); + + // Store our identifier + io.Fonts->TexID = (void *)(intptr_t)tex_id; + + GFontTextureLoaded = true; +} + +static void InitGL() +{ + const GLchar *vertex_shader = + "#version 330\n" + "uniform mat4 ProjMtx;\n" + "in vec2 Position;\n" + "in vec2 UV;\n" + "in vec4 Color;\n" + "out vec2 Frag_UV;\n" + "out vec4 Frag_Color;\n" + "void main()\n" + "{\n" + " Frag_UV = UV;\n" + " Frag_Color = Color;\n" + " gl_Position = ProjMtx * vec4(Position.xy,0,1);\n" + "}\n"; + + const GLchar* fragment_shader = + "#version 330\n" + "uniform sampler2D Texture;\n" + "in vec2 Frag_UV;\n" + "in vec4 Frag_Color;\n" + "out vec4 Out_Color;\n" + "void main()\n" + "{\n" + " Out_Color = Frag_Color * texture( Texture, Frag_UV.st);\n" + "}\n"; + + g_shader_handle = glCreateProgram(); + g_vert_handle = glCreateShader(GL_VERTEX_SHADER); + g_frag_handle = glCreateShader(GL_FRAGMENT_SHADER); + glShaderSource(g_vert_handle, 1, &vertex_shader, 0); + glShaderSource(g_frag_handle, 1, &fragment_shader, 0); + glCompileShader(g_vert_handle); + glCompileShader(g_frag_handle); + glAttachShader(g_shader_handle, g_vert_handle); + glAttachShader(g_shader_handle, g_frag_handle); + glLinkProgram(g_shader_handle); + + g_texture_location = glGetUniformLocation(g_shader_handle, "Texture"); + g_proj_mtx_location = glGetUniformLocation(g_shader_handle, "ProjMtx"); + g_position_location = glGetAttribLocation(g_shader_handle, "Position"); + g_uv_location = glGetAttribLocation(g_shader_handle, "UV"); + g_colour_location = glGetAttribLocation(g_shader_handle, "Color"); + + glGenBuffers(1, &g_vbo_handle); + glBindBuffer(GL_ARRAY_BUFFER, g_vbo_handle); + glBufferData(GL_ARRAY_BUFFER, g_vbo_max_size, NULL, GL_DYNAMIC_DRAW); + + glGenVertexArrays(1, &g_vao_handle); + glBindVertexArray(g_vao_handle); + glBindBuffer(GL_ARRAY_BUFFER, g_vbo_handle); + glEnableVertexAttribArray(g_position_location); + glEnableVertexAttribArray(g_uv_location); + glEnableVertexAttribArray(g_colour_location); + +#define OFFSETOF(TYPE, ELEMENT) ((size_t)&(((TYPE *)0)->ELEMENT)) + glVertexAttribPointer(g_position_location, 2, GL_FLOAT, GL_FALSE, sizeof(ImDrawVert), (GLvoid*)OFFSETOF(ImDrawVert, pos)); + glVertexAttribPointer(g_uv_location, 2, GL_FLOAT, GL_FALSE, sizeof(ImDrawVert), (GLvoid*)OFFSETOF(ImDrawVert, uv)); + glVertexAttribPointer(g_colour_location, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(ImDrawVert), (GLvoid*)OFFSETOF(ImDrawVert, col)); +#undef OFFSETOF + glBindVertexArray(0); + glBindBuffer(GL_ARRAY_BUFFER, 0); +} + +bool ImGui_ImplGlfwGL3_Init(GLFWwindow* window, bool install_callbacks) +{ + InitGL(); + + GWindow = window; + + ImGuiIO& io = ImGui::GetIO(); + io.KeyMap[ImGuiKey_Tab] = GLFW_KEY_TAB; // Keyboard mapping. ImGui will use those indices to peek into the io.KeyDown[] array. + io.KeyMap[ImGuiKey_LeftArrow] = GLFW_KEY_LEFT; + io.KeyMap[ImGuiKey_RightArrow] = GLFW_KEY_RIGHT; + io.KeyMap[ImGuiKey_UpArrow] = GLFW_KEY_UP; + io.KeyMap[ImGuiKey_DownArrow] = GLFW_KEY_DOWN; + io.KeyMap[ImGuiKey_Home] = GLFW_KEY_HOME; + io.KeyMap[ImGuiKey_End] = GLFW_KEY_END; + io.KeyMap[ImGuiKey_Delete] = GLFW_KEY_DELETE; + io.KeyMap[ImGuiKey_Backspace] = GLFW_KEY_BACKSPACE; + io.KeyMap[ImGuiKey_Enter] = GLFW_KEY_ENTER; + io.KeyMap[ImGuiKey_Escape] = GLFW_KEY_ESCAPE; + io.KeyMap[ImGuiKey_A] = GLFW_KEY_A; + io.KeyMap[ImGuiKey_C] = GLFW_KEY_C; + io.KeyMap[ImGuiKey_V] = GLFW_KEY_V; + io.KeyMap[ImGuiKey_X] = GLFW_KEY_X; + io.KeyMap[ImGuiKey_Y] = GLFW_KEY_Y; + io.KeyMap[ImGuiKey_Z] = GLFW_KEY_Z; + + io.RenderDrawListsFn = ImGui_ImplGlfwGL3_RenderDrawLists; + io.SetClipboardTextFn = ImGui_ImplGlfwGL3_SetClipboardText; + io.GetClipboardTextFn = ImGui_ImplGlfwGL3_GetClipboardText; +#ifdef _MSC_VER + io.ImeWindowHandle = glfwGetWin32Window(GWindow); +#endif + + if (install_callbacks) + { + glfwSetMouseButtonCallback(window, ImGui_ImplGlfwGL3_MouseButtonCallback); + glfwSetScrollCallback(window, ImGui_ImplGlfwGL3_ScrollCallback); + glfwSetKeyCallback(window, ImGui_ImplGlfwGL3_KeyCallback); + glfwSetCharCallback(window, ImGui_ImplGlfwGL3_CharCallback); + } + + return true; +} + +void ImGui_ImplGlfwGL3_Shutdown() +{ + if (g_vao_handle) glDeleteVertexArrays(1, &g_vao_handle); + if (g_vbo_handle) glDeleteBuffers(1, &g_vbo_handle); + g_vao_handle = 0; + g_vbo_handle = 0; + + glDetachShader(g_shader_handle, g_vert_handle); + glDeleteShader(g_vert_handle); + g_vert_handle = 0; + + glDetachShader(g_shader_handle, g_frag_handle); + glDeleteShader(g_frag_handle); + g_frag_handle = 0; + + glDeleteProgram(g_shader_handle); + g_shader_handle = 0; + + GLuint tex_id = (GLuint)ImGui::GetIO().Fonts->TexID; + if (tex_id) + { + glDeleteTextures(1, &tex_id); + ImGui::GetIO().Fonts->TexID = 0; + } + ImGui::Shutdown(); +} + +void ImGui_ImplGlfwGL3_NewFrame() +{ + if (!GFontTextureLoaded) + ImGui_ImplGlfwGL3_LoadFontsTexture(); + + ImGuiIO& io = ImGui::GetIO(); + + // Setup display size (every frame to accommodate for window resizing) + int w, h; + int display_w, display_h; + glfwGetWindowSize(GWindow, &w, &h); + glfwGetFramebufferSize(GWindow, &display_w, &display_h); + io.DisplaySize = ImVec2((float)display_w, (float)display_h); + + // Setup time step + double current_time = glfwGetTime(); + io.DeltaTime = GTime > 0.0 ? (float)(current_time - GTime) : (float)(1.0f/60.0f); + GTime = current_time; + + // Setup inputs + // (we already got mouse wheel, keyboard keys & characters from glfw callbacks polled in glfwPollEvents()) + double mouse_x, mouse_y; + glfwGetCursorPos(GWindow, &mouse_x, &mouse_y); + mouse_x *= (float)display_w / w; // Convert mouse coordinates to pixels + mouse_y *= (float)display_h / h; + io.MousePos = ImVec2((float)mouse_x, (float)mouse_y); // Mouse position, in pixels (set to -1,-1 if no mouse / on another screen, etc.) + + io.MouseDown[0] = GMousePressed[0] || glfwGetMouseButton(GWindow, GLFW_MOUSE_BUTTON_LEFT) != 0; // If a mouse press event came, always pass it as "mouse held this frame", so we don't miss click-release events that are shorter than 1 frame. + io.MouseDown[1] = GMousePressed[1] || glfwGetMouseButton(GWindow, GLFW_MOUSE_BUTTON_RIGHT) != 0; + io.MouseDown[2] = GMousePressed[2] || glfwGetMouseButton(GWindow, GLFW_MOUSE_BUTTON_MIDDLE) != 0; + GMousePressed[0] = false; + GMousePressed[1] = false; + GMousePressed[2] = false; + + io.MouseWheel = GMouseWheel; + GMouseWheel = 0.0f; + + // Start the frame + ImGui::NewFrame(); +} diff --git a/examples/opengl3_example/imgui_impl_glfw_gl3.h b/examples/opengl3_example/imgui_impl_glfw_gl3.h new file mode 100644 index 00000000..bfa5f604 --- /dev/null +++ b/examples/opengl3_example/imgui_impl_glfw_gl3.h @@ -0,0 +1,16 @@ +// ImGui GLFW binding with OpenGL3 + shaders +// https://github.com/ocornut/imgui + +struct GLFWwindow; + +bool ImGui_ImplGlfwGL3_Init(GLFWwindow* window, bool install_callbacks); +void ImGui_ImplGlfwGL3_Shutdown(); +void ImGui_ImplGlfwGL3_LoadFontsTexture(); +void ImGui_ImplGlfwGL3_NewFrame(); + +// GLFW callbacks (installed by default if you enable 'install_callbacks' during initialization) +// Provide here if you want to chain callbacks +void ImGui_ImplGlfwGL3_MouseButtonCallback(GLFWwindow* window, int button, int action, int mods); +void ImGui_ImplGlfwGL3_ScrollCallback(GLFWwindow* window, double xoffset, double yoffset); +void ImGui_ImplGlFwGL3_KeyCallback(GLFWwindow* window, int key, int scancode, int action, int mods); +void ImGui_ImplGlfwGL3_CharCallback(GLFWwindow* window, unsigned int c); diff --git a/examples/opengl3_example/main.cpp b/examples/opengl3_example/main.cpp index 88dbdda4..1665b133 100644 --- a/examples/opengl3_example/main.cpp +++ b/examples/opengl3_example/main.cpp @@ -1,165 +1,19 @@ -// ImGui - standalone example application for OpenGL 3, using programmable pipeline +// ImGui - standalone example application for Glfw + OpenGL 3, using programmable pipeline -#ifdef _MSC_VER -#pragma warning (disable: 4996) // 'This function or variable may be unsafe': strcpy, strdup, sprintf, vsnprintf, sscanf, fopen -#endif -#ifdef __clang__ -#pragma clang diagnostic ignored "-Wunused-function" // warning: unused function -#endif - -#include "../../imgui.h" +#include +#include "imgui_impl_glfw_GL3.h" #include - -// Gl3W / GLFW #include #include -#ifdef _MSC_VER -#undef APIENTRY -#define GLFW_EXPOSE_NATIVE_WIN32 -#define GLFW_EXPOSE_NATIVE_WGL -#include -#endif - -static GLFWwindow* window; -static bool mousePressed[2] = { false, false }; - -#define OFFSETOF(TYPE, ELEMENT) ((size_t)&(((TYPE *)0)->ELEMENT)) - -// Shader variables -static int shader_handle, vert_handle, frag_handle; -static int texture_location, proj_mtx_location; -static int position_location, uv_location, colour_location; -static size_t vbo_max_size = 20000; -static unsigned int vbo_handle, vao_handle; - -// This is the main rendering function that you have to implement and provide to ImGui (via setting up 'RenderDrawListsFn' in the ImGuiIO structure) -// If text or lines are blurry when integrating ImGui in your engine: -// - in your Render function, try translating your projection matrix by (0.5f,0.5f) or (0.375f,0.375f) -static void ImImpl_RenderDrawLists(ImDrawList** const cmd_lists, int cmd_lists_count) -{ - if (cmd_lists_count == 0) - return; - - // Setup render state: alpha-blending enabled, no face culling, no depth testing, scissor enabled - glEnable(GL_BLEND); - glBlendEquation(GL_FUNC_ADD); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glDisable(GL_CULL_FACE); - glDisable(GL_DEPTH_TEST); - glEnable(GL_SCISSOR_TEST); - glActiveTexture(GL_TEXTURE0); - - // Setup orthographic projection matrix - const float width = ImGui::GetIO().DisplaySize.x; - const float height = ImGui::GetIO().DisplaySize.y; - const float ortho_projection[4][4] = - { - { 2.0f/width, 0.0f, 0.0f, 0.0f }, - { 0.0f, 2.0f/-height, 0.0f, 0.0f }, - { 0.0f, 0.0f, -1.0f, 0.0f }, - { -1.0f, 1.0f, 0.0f, 1.0f }, - }; - glUseProgram(shader_handle); - glUniform1i(texture_location, 0); - glUniformMatrix4fv(proj_mtx_location, 1, GL_FALSE, &ortho_projection[0][0]); - - // Grow our buffer according to what we need - size_t total_vtx_count = 0; - for (int n = 0; n < cmd_lists_count; n++) - total_vtx_count += cmd_lists[n]->vtx_buffer.size(); - glBindBuffer(GL_ARRAY_BUFFER, vbo_handle); - size_t neededBufferSize = total_vtx_count * sizeof(ImDrawVert); - if (neededBufferSize > vbo_max_size) - { - vbo_max_size = neededBufferSize + 5000; // Grow buffer - glBufferData(GL_ARRAY_BUFFER, vbo_max_size, NULL, GL_STREAM_DRAW); - } - - // Copy and convert all vertices into a single contiguous buffer - unsigned char* buffer_data = (unsigned char*)glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY); - if (!buffer_data) - return; - for (int n = 0; n < cmd_lists_count; n++) - { - const ImDrawList* cmd_list = cmd_lists[n]; - memcpy(buffer_data, &cmd_list->vtx_buffer[0], cmd_list->vtx_buffer.size() * sizeof(ImDrawVert)); - buffer_data += cmd_list->vtx_buffer.size() * sizeof(ImDrawVert); - } - glUnmapBuffer(GL_ARRAY_BUFFER); - glBindBuffer(GL_ARRAY_BUFFER, 0); - glBindVertexArray(vao_handle); - - int cmd_offset = 0; - for (int n = 0; n < cmd_lists_count; n++) - { - const ImDrawList* cmd_list = cmd_lists[n]; - int vtx_offset = cmd_offset; - const ImDrawCmd* pcmd_end = cmd_list->commands.end(); - for (const ImDrawCmd* pcmd = cmd_list->commands.begin(); pcmd != pcmd_end; pcmd++) - { - glBindTexture(GL_TEXTURE_2D, (GLuint)(intptr_t)pcmd->texture_id); - glScissor((int)pcmd->clip_rect.x, (int)(height - pcmd->clip_rect.w), (int)(pcmd->clip_rect.z - pcmd->clip_rect.x), (int)(pcmd->clip_rect.w - pcmd->clip_rect.y)); - glDrawArrays(GL_TRIANGLES, vtx_offset, pcmd->vtx_count); - vtx_offset += pcmd->vtx_count; - } - cmd_offset = vtx_offset; - } - - // Restore modified state - glBindVertexArray(0); - glUseProgram(0); - glDisable(GL_SCISSOR_TEST); - glBindTexture(GL_TEXTURE_2D, 0); -} - -static const char* ImImpl_GetClipboardTextFn() -{ - return glfwGetClipboardString(window); -} - -static void ImImpl_SetClipboardTextFn(const char* text) -{ - glfwSetClipboardString(window, text); -} - -// GLFW callbacks to get events -static void glfw_error_callback(int error, const char* description) -{ - fputs(description, stderr); -} - -static void glfw_mouse_button_callback(GLFWwindow* window, int button, int action, int mods) -{ - if (action == GLFW_PRESS && button >= 0 && button < 2) - mousePressed[button] = true; -} - -static void glfw_scroll_callback(GLFWwindow* window, double xoffset, double yoffset) -{ - ImGuiIO& io = ImGui::GetIO(); - io.MouseWheel += (float)yoffset; // Use fractional mouse wheel, 1.0 unit 5 lines. -} - -static void glfw_key_callback(GLFWwindow* window, int key, int scancode, int action, int mods) -{ - ImGuiIO& io = ImGui::GetIO(); - if (action == GLFW_PRESS) - io.KeysDown[key] = true; - if (action == GLFW_RELEASE) - io.KeysDown[key] = false; - io.KeyCtrl = (mods & GLFW_MOD_CONTROL) != 0; - io.KeyShift = (mods & GLFW_MOD_SHIFT) != 0; -} -static void glfw_char_callback(GLFWwindow* window, unsigned int c) +static void error_callback(int error, const char* description) { - if (c > 0 && c < 0x10000) - ImGui::GetIO().AddInputCharacter((unsigned short)c); + fprintf(stderr, "Error: %s\n", description); } -void InitGL() +int main(int argc, char** argv) { - glfwSetErrorCallback(glfw_error_callback); + glfwSetErrorCallback(error_callback); if (!glfwInit()) exit(1); @@ -167,180 +21,28 @@ void InitGL() glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); - window = glfwCreateWindow(1280, 720, "ImGui OpenGL3 example", NULL, NULL); + GLFWwindow* window = glfwCreateWindow(1280, 720, "ImGui OpenGL3 example", NULL, NULL); glfwMakeContextCurrent(window); - glfwSetKeyCallback(window, glfw_key_callback); - glfwSetMouseButtonCallback(window, glfw_mouse_button_callback); - glfwSetScrollCallback(window, glfw_scroll_callback); - glfwSetCharCallback(window, glfw_char_callback); - gl3wInit(); - const GLchar *vertex_shader = - "#version 330\n" - "uniform mat4 ProjMtx;\n" - "in vec2 Position;\n" - "in vec2 UV;\n" - "in vec4 Color;\n" - "out vec2 Frag_UV;\n" - "out vec4 Frag_Color;\n" - "void main()\n" - "{\n" - " Frag_UV = UV;\n" - " Frag_Color = Color;\n" - " gl_Position = ProjMtx * vec4(Position.xy,0,1);\n" - "}\n"; - - const GLchar* fragment_shader = - "#version 330\n" - "uniform sampler2D Texture;\n" - "in vec2 Frag_UV;\n" - "in vec4 Frag_Color;\n" - "out vec4 Out_Color;\n" - "void main()\n" - "{\n" - " Out_Color = Frag_Color * texture( Texture, Frag_UV.st);\n" - "}\n"; - - shader_handle = glCreateProgram(); - vert_handle = glCreateShader(GL_VERTEX_SHADER); - frag_handle = glCreateShader(GL_FRAGMENT_SHADER); - glShaderSource(vert_handle, 1, &vertex_shader, 0); - glShaderSource(frag_handle, 1, &fragment_shader, 0); - glCompileShader(vert_handle); - glCompileShader(frag_handle); - glAttachShader(shader_handle, vert_handle); - glAttachShader(shader_handle, frag_handle); - glLinkProgram(shader_handle); - - texture_location = glGetUniformLocation(shader_handle, "Texture"); - proj_mtx_location = glGetUniformLocation(shader_handle, "ProjMtx"); - position_location = glGetAttribLocation(shader_handle, "Position"); - uv_location = glGetAttribLocation(shader_handle, "UV"); - colour_location = glGetAttribLocation(shader_handle, "Color"); - - glGenBuffers(1, &vbo_handle); - glBindBuffer(GL_ARRAY_BUFFER, vbo_handle); - glBufferData(GL_ARRAY_BUFFER, vbo_max_size, NULL, GL_DYNAMIC_DRAW); - - glGenVertexArrays(1, &vao_handle); - glBindVertexArray(vao_handle); - glBindBuffer(GL_ARRAY_BUFFER, vbo_handle); - glEnableVertexAttribArray(position_location); - glEnableVertexAttribArray(uv_location); - glEnableVertexAttribArray(colour_location); - - glVertexAttribPointer(position_location, 2, GL_FLOAT, GL_FALSE, sizeof(ImDrawVert), (GLvoid*)OFFSETOF(ImDrawVert, pos)); - glVertexAttribPointer(uv_location, 2, GL_FLOAT, GL_FALSE, sizeof(ImDrawVert), (GLvoid*)OFFSETOF(ImDrawVert, uv)); - glVertexAttribPointer(colour_location, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(ImDrawVert), (GLvoid*)OFFSETOF(ImDrawVert, col)); - glBindVertexArray(0); - glBindBuffer(GL_ARRAY_BUFFER, 0); -} - -void LoadFontsTexture() -{ - ImGuiIO& io = ImGui::GetIO(); + //ImGuiIO& io = ImGui::GetIO(); //ImFont* my_font1 = io.Fonts->AddFontDefault(); //ImFont* my_font2 = io.Fonts->AddFontFromFileTTF("extra_fonts/Karla-Regular.ttf", 15.0f); //ImFont* my_font3 = io.Fonts->AddFontFromFileTTF("extra_fonts/ProggyClean.ttf", 13.0f); my_font3->DisplayOffset.y += 1; //ImFont* my_font4 = io.Fonts->AddFontFromFileTTF("extra_fonts/ProggyTiny.ttf", 10.0f); my_font4->DisplayOffset.y += 1; //ImFont* my_font5 = io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf", 18.0f, io.Fonts->GetGlyphRangesJapanese()); - - unsigned char* pixels; - int width, height; - io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); // Load as RGBA 32-bits for OpenGL3 demo because it is more likely to be compatible with user's existing shader. - - GLuint tex_id; - glGenTextures(1, &tex_id); - glBindTexture(GL_TEXTURE_2D, tex_id); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels); - - // Store our identifier - io.Fonts->TexID = (void *)(intptr_t)tex_id; -} - -void InitImGui() -{ - ImGuiIO& io = ImGui::GetIO(); - io.DeltaTime = 1.0f / 60.0f; // Time elapsed since last frame, in seconds (in this sample app we'll override this every frame because our timestep is variable) - io.KeyMap[ImGuiKey_Tab] = GLFW_KEY_TAB; // Keyboard mapping. ImGui will use those indices to peek into the io.KeyDown[] array. - io.KeyMap[ImGuiKey_LeftArrow] = GLFW_KEY_LEFT; - io.KeyMap[ImGuiKey_RightArrow] = GLFW_KEY_RIGHT; - io.KeyMap[ImGuiKey_UpArrow] = GLFW_KEY_UP; - io.KeyMap[ImGuiKey_DownArrow] = GLFW_KEY_DOWN; - io.KeyMap[ImGuiKey_Home] = GLFW_KEY_HOME; - io.KeyMap[ImGuiKey_End] = GLFW_KEY_END; - io.KeyMap[ImGuiKey_Delete] = GLFW_KEY_DELETE; - io.KeyMap[ImGuiKey_Backspace] = GLFW_KEY_BACKSPACE; - io.KeyMap[ImGuiKey_Enter] = GLFW_KEY_ENTER; - io.KeyMap[ImGuiKey_Escape] = GLFW_KEY_ESCAPE; - io.KeyMap[ImGuiKey_A] = GLFW_KEY_A; - io.KeyMap[ImGuiKey_C] = GLFW_KEY_C; - io.KeyMap[ImGuiKey_V] = GLFW_KEY_V; - io.KeyMap[ImGuiKey_X] = GLFW_KEY_X; - io.KeyMap[ImGuiKey_Y] = GLFW_KEY_Y; - io.KeyMap[ImGuiKey_Z] = GLFW_KEY_Z; - - io.RenderDrawListsFn = ImImpl_RenderDrawLists; - io.SetClipboardTextFn = ImImpl_SetClipboardTextFn; - io.GetClipboardTextFn = ImImpl_GetClipboardTextFn; -#ifdef _MSC_VER - io.ImeWindowHandle = glfwGetWin32Window(window); -#endif - - LoadFontsTexture(); -} - -void UpdateImGui() -{ - ImGuiIO& io = ImGui::GetIO(); - - // Setup resolution (every frame to accommodate for window resizing) - int w, h; - int display_w, display_h; - glfwGetWindowSize(window, &w, &h); - glfwGetFramebufferSize(window, &display_w, &display_h); - io.DisplaySize = ImVec2((float)display_w, (float)display_h); // Display size, in pixels. For clamping windows positions. - - // Setup time step - static double time = 0.0f; - const double current_time = glfwGetTime(); - io.DeltaTime = (float)(current_time - time); - time = current_time; - - // Setup inputs - // (we already got mouse wheel, keyboard keys & characters from glfw callbacks polled in glfwPollEvents()) - double mouse_x, mouse_y; - glfwGetCursorPos(window, &mouse_x, &mouse_y); - mouse_x *= (float)display_w / w; // Convert mouse coordinates to pixels - mouse_y *= (float)display_h / h; - io.MousePos = ImVec2((float)mouse_x, (float)mouse_y); // Mouse position, in pixels (set to -1,-1 if no mouse / on another screen, etc.) - io.MouseDown[0] = mousePressed[0] || glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_LEFT) != 0; // If a mouse press event came, always pass it as "mouse held this frame", so we don't miss click-release events that are shorter than 1 frame. - io.MouseDown[1] = mousePressed[1] || glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_RIGHT) != 0; - - // Start the frame - ImGui::NewFrame(); -} - -// Application code -int main(int argc, char** argv) -{ - InitGL(); - InitImGui(); + ImGui_ImplGlfwGL3_Init(window, true); + ImGui_ImplGlfwGL3_LoadFontsTexture(); bool show_test_window = true; bool show_another_window = false; - ImVec4 clear_col = ImColor(114, 144, 154); + ImVec4 clear_color = ImColor(114, 144, 154); while (!glfwWindowShouldClose(window)) { ImGuiIO& io = ImGui::GetIO(); - io.MouseWheel = 0; - mousePressed[0] = mousePressed[1] = false; glfwPollEvents(); - UpdateImGui(); + ImGui_ImplGlfwGL3_NewFrame(); // 1. Show a simple window // Tip: if we don't call ImGui::Begin()/ImGui::End() the widgets appears in a window automatically called "Debug" @@ -348,7 +50,7 @@ int main(int argc, char** argv) static float f; ImGui::Text("Hello, world!"); ImGui::SliderFloat("float", &f, 0.0f, 1.0f); - ImGui::ColorEdit3("clear color", (float*)&clear_col); + ImGui::ColorEdit3("clear color", (float*)&clear_color); if (ImGui::Button("Test Window")) show_test_window ^= 1; if (ImGui::Button("Another Window")) show_another_window ^= 1; ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate); @@ -371,22 +73,14 @@ int main(int argc, char** argv) // Rendering glViewport(0, 0, (int)io.DisplaySize.x, (int)io.DisplaySize.y); - glClearColor(clear_col.x, clear_col.y, clear_col.z, clear_col.w); + glClearColor(clear_color.x, clear_color.y, clear_color.z, clear_color.w); glClear(GL_COLOR_BUFFER_BIT); ImGui::Render(); glfwSwapBuffers(window); } // Cleanup - if (vao_handle) glDeleteVertexArrays(1, &vao_handle); - if (vbo_handle) glDeleteBuffers(1, &vbo_handle); - glDetachShader(shader_handle, vert_handle); - glDetachShader(shader_handle, frag_handle); - glDeleteShader(vert_handle); - glDeleteShader(frag_handle); - glDeleteProgram(shader_handle); - - ImGui::Shutdown(); + ImGui_ImplGlfwGL3_Shutdown(); glfwTerminate(); return 0; diff --git a/examples/opengl3_example/opengl3_example.vcxproj b/examples/opengl3_example/opengl3_example.vcxproj index 01b4d947..60943559 100644 --- a/examples/opengl3_example/opengl3_example.vcxproj +++ b/examples/opengl3_example/opengl3_example.vcxproj @@ -39,10 +39,12 @@ $(ProjectDir)$(Configuration)\ $(ProjectDir)$(Configuration)\ + ../..;$(IncludePath) $(ProjectDir)$(Configuration)\ $(ProjectDir)$(Configuration)\ + ../..;$(IncludePath) @@ -80,11 +82,13 @@ + + diff --git a/examples/opengl3_example/opengl3_example.vcxproj.filters b/examples/opengl3_example/opengl3_example.vcxproj.filters index cb06331d..76f7fa3f 100644 --- a/examples/opengl3_example/opengl3_example.vcxproj.filters +++ b/examples/opengl3_example/opengl3_example.vcxproj.filters @@ -19,6 +19,9 @@ sources + + sources + @@ -27,5 +30,8 @@ imgui + + sources + \ No newline at end of file diff --git a/examples/opengl_example/imgui_impl_glfw.cpp b/examples/opengl_example/imgui_impl_glfw.cpp index fb85b6d3..d75f7b2c 100644 --- a/examples/opengl_example/imgui_impl_glfw.cpp +++ b/examples/opengl_example/imgui_impl_glfw.cpp @@ -1,4 +1,4 @@ -// ImGui GLFW bindings +// ImGui GLFW binding with OpenGL // https://github.com/ocornut/imgui #include @@ -15,8 +15,9 @@ static GLFWwindow* GWindow = NULL; static bool GMousePressed[3] = { false, false, false }; +static float GMouseWheel = 0.0f; static double GTime = 0.0f; -static bool GFontTextureLoaded; +static bool GFontTextureLoaded = false; // This is the main rendering function that you have to implement and provide to ImGui (via setting up 'RenderDrawListsFn' in the ImGuiIO structure) // If text or lines are blurry when integrating ImGui in your engine: @@ -102,8 +103,7 @@ void ImGui_ImplGlfw_MouseButtonCallback(GLFWwindow* window, int button, int acti void ImGui_ImplGlfw_ScrollCallback(GLFWwindow* window, double xoffset, double yoffset) { - ImGuiIO& io = ImGui::GetIO(); - io.MouseWheel += (float)yoffset; // Use fractional mouse wheel, 1.0 unit 5 lines. + GMouseWheel += (float)yoffset; // Use fractional mouse wheel, 1.0 unit 5 lines. } void ImGui_ImplGlFw_KeyCallback(GLFWwindow* window, int key, int scancode, int action, int mods) @@ -231,6 +231,9 @@ void ImGui_ImplGlfw_NewFrame() GMousePressed[1] = false; GMousePressed[2] = false; + io.MouseWheel = GMouseWheel; + GMouseWheel = 0.0f; + // Start the frame ImGui::NewFrame(); } diff --git a/examples/opengl_example/imgui_impl_glfw.h b/examples/opengl_example/imgui_impl_glfw.h index 0b18ec77..e3581e00 100644 --- a/examples/opengl_example/imgui_impl_glfw.h +++ b/examples/opengl_example/imgui_impl_glfw.h @@ -1,4 +1,4 @@ -// ImGui GLFW bindings +// ImGui GLFW binding with OpenGL // https://github.com/ocornut/imgui struct GLFWwindow; From 99ed567577ec38c7ff4925a7d5792c9f332813d5 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 9 Mar 2015 12:02:34 +0000 Subject: [PATCH 30/48] Examples: Rename global to be more consistent --- .../opengl3_example/imgui_impl_glfw_gl3.cpp | 54 +++++++++---------- examples/opengl_example/imgui_impl_glfw.cpp | 52 +++++++++--------- 2 files changed, 53 insertions(+), 53 deletions(-) diff --git a/examples/opengl3_example/imgui_impl_glfw_gl3.cpp b/examples/opengl3_example/imgui_impl_glfw_gl3.cpp index 8a05ed49..a147821c 100644 --- a/examples/opengl3_example/imgui_impl_glfw_gl3.cpp +++ b/examples/opengl3_example/imgui_impl_glfw_gl3.cpp @@ -14,13 +14,13 @@ #include #endif -static GLFWwindow* GWindow = NULL; -static bool GMousePressed[3] = { false, false, false }; -static float GMouseWheel = 0.0f; -static double GTime = 0.0f; -static bool GFontTextureLoaded = false; +static GLFWwindow* g_window = NULL; +static bool g_mouse_pressed[3] = { false, false, false }; +static float g_mouse_wheel = 0.0f; +static double g_time = 0.0f; +static bool g_font_texture_loaded = false; -// Shader variables +// Handles for OpenGL3 rendering static int g_shader_handle = 0, g_vert_handle = 0, g_frag_handle = 0; static int g_texture_location = 0, g_proj_mtx_location = 0; static int g_position_location = 0, g_uv_location = 0, g_colour_location = 0; @@ -109,23 +109,23 @@ static void ImGui_ImplGlfwGL3_RenderDrawLists(ImDrawList** const cmd_lists, int static const char* ImGui_ImplGlfwGL3_GetClipboardText() { - return glfwGetClipboardString(GWindow); + return glfwGetClipboardString(g_window); } static void ImGui_ImplGlfwGL3_SetClipboardText(const char* text) { - glfwSetClipboardString(GWindow, text); + glfwSetClipboardString(g_window, text); } void ImGui_ImplGlfwGL3_MouseButtonCallback(GLFWwindow* window, int button, int action, int mods) { if (action == GLFW_PRESS && button >= 0 && button < 3) - GMousePressed[button] = true; + g_mouse_pressed[button] = true; } void ImGui_ImplGlfwGL3_ScrollCallback(GLFWwindow* window, double xoffset, double yoffset) { - GMouseWheel += (float)yoffset; // Use fractional mouse wheel, 1.0 unit 5 lines. + g_mouse_wheel += (float)yoffset; // Use fractional mouse wheel, 1.0 unit 5 lines. } void ImGui_ImplGlfwGL3_KeyCallback(GLFWwindow* window, int key, int scancode, int action, int mods) @@ -164,7 +164,7 @@ void ImGui_ImplGlfwGL3_LoadFontsTexture() // Store our identifier io.Fonts->TexID = (void *)(intptr_t)tex_id; - GFontTextureLoaded = true; + g_font_texture_loaded = true; } static void InitGL() @@ -236,7 +236,7 @@ bool ImGui_ImplGlfwGL3_Init(GLFWwindow* window, bool install_callbacks) { InitGL(); - GWindow = window; + g_window = window; ImGuiIO& io = ImGui::GetIO(); io.KeyMap[ImGuiKey_Tab] = GLFW_KEY_TAB; // Keyboard mapping. ImGui will use those indices to peek into the io.KeyDown[] array. @@ -261,7 +261,7 @@ bool ImGui_ImplGlfwGL3_Init(GLFWwindow* window, bool install_callbacks) io.SetClipboardTextFn = ImGui_ImplGlfwGL3_SetClipboardText; io.GetClipboardTextFn = ImGui_ImplGlfwGL3_GetClipboardText; #ifdef _MSC_VER - io.ImeWindowHandle = glfwGetWin32Window(GWindow); + io.ImeWindowHandle = glfwGetWin32Window(g_window); #endif if (install_callbacks) @@ -304,7 +304,7 @@ void ImGui_ImplGlfwGL3_Shutdown() void ImGui_ImplGlfwGL3_NewFrame() { - if (!GFontTextureLoaded) + if (!g_font_texture_loaded) ImGui_ImplGlfwGL3_LoadFontsTexture(); ImGuiIO& io = ImGui::GetIO(); @@ -312,32 +312,32 @@ void ImGui_ImplGlfwGL3_NewFrame() // Setup display size (every frame to accommodate for window resizing) int w, h; int display_w, display_h; - glfwGetWindowSize(GWindow, &w, &h); - glfwGetFramebufferSize(GWindow, &display_w, &display_h); + glfwGetWindowSize(g_window, &w, &h); + glfwGetFramebufferSize(g_window, &display_w, &display_h); io.DisplaySize = ImVec2((float)display_w, (float)display_h); // Setup time step double current_time = glfwGetTime(); - io.DeltaTime = GTime > 0.0 ? (float)(current_time - GTime) : (float)(1.0f/60.0f); - GTime = current_time; + io.DeltaTime = g_time > 0.0 ? (float)(current_time - g_time) : (float)(1.0f/60.0f); + g_time = current_time; // Setup inputs // (we already got mouse wheel, keyboard keys & characters from glfw callbacks polled in glfwPollEvents()) double mouse_x, mouse_y; - glfwGetCursorPos(GWindow, &mouse_x, &mouse_y); + glfwGetCursorPos(g_window, &mouse_x, &mouse_y); mouse_x *= (float)display_w / w; // Convert mouse coordinates to pixels mouse_y *= (float)display_h / h; io.MousePos = ImVec2((float)mouse_x, (float)mouse_y); // Mouse position, in pixels (set to -1,-1 if no mouse / on another screen, etc.) - io.MouseDown[0] = GMousePressed[0] || glfwGetMouseButton(GWindow, GLFW_MOUSE_BUTTON_LEFT) != 0; // If a mouse press event came, always pass it as "mouse held this frame", so we don't miss click-release events that are shorter than 1 frame. - io.MouseDown[1] = GMousePressed[1] || glfwGetMouseButton(GWindow, GLFW_MOUSE_BUTTON_RIGHT) != 0; - io.MouseDown[2] = GMousePressed[2] || glfwGetMouseButton(GWindow, GLFW_MOUSE_BUTTON_MIDDLE) != 0; - GMousePressed[0] = false; - GMousePressed[1] = false; - GMousePressed[2] = false; + io.MouseDown[0] = g_mouse_pressed[0] || glfwGetMouseButton(g_window, GLFW_MOUSE_BUTTON_LEFT) != 0; // If a mouse press event came, always pass it as "mouse held this frame", so we don't miss click-release events that are shorter than 1 frame. + io.MouseDown[1] = g_mouse_pressed[1] || glfwGetMouseButton(g_window, GLFW_MOUSE_BUTTON_RIGHT) != 0; + io.MouseDown[2] = g_mouse_pressed[2] || glfwGetMouseButton(g_window, GLFW_MOUSE_BUTTON_MIDDLE) != 0; + g_mouse_pressed[0] = false; + g_mouse_pressed[1] = false; + g_mouse_pressed[2] = false; - io.MouseWheel = GMouseWheel; - GMouseWheel = 0.0f; + io.MouseWheel = g_mouse_wheel; + g_mouse_wheel = 0.0f; // Start the frame ImGui::NewFrame(); diff --git a/examples/opengl_example/imgui_impl_glfw.cpp b/examples/opengl_example/imgui_impl_glfw.cpp index d75f7b2c..01ba55f9 100644 --- a/examples/opengl_example/imgui_impl_glfw.cpp +++ b/examples/opengl_example/imgui_impl_glfw.cpp @@ -13,11 +13,11 @@ #include #endif -static GLFWwindow* GWindow = NULL; -static bool GMousePressed[3] = { false, false, false }; -static float GMouseWheel = 0.0f; -static double GTime = 0.0f; -static bool GFontTextureLoaded = false; +static GLFWwindow* g_window = NULL; +static bool g_mouse_pressed[3] = { false, false, false }; +static float g_mouse_wheel = 0.0f; +static double g_time = 0.0f; +static bool g_font_texture_loaded = false; // This is the main rendering function that you have to implement and provide to ImGui (via setting up 'RenderDrawListsFn' in the ImGuiIO structure) // If text or lines are blurry when integrating ImGui in your engine: @@ -87,23 +87,23 @@ static void ImGui_ImplGlfw_RenderDrawLists(ImDrawList** const cmd_lists, int cmd static const char* ImGui_ImplGlfw_GetClipboardText() { - return glfwGetClipboardString(GWindow); + return glfwGetClipboardString(g_window); } static void ImGui_ImplGlfw_SetClipboardText(const char* text) { - glfwSetClipboardString(GWindow, text); + glfwSetClipboardString(g_window, text); } void ImGui_ImplGlfw_MouseButtonCallback(GLFWwindow* window, int button, int action, int mods) { if (action == GLFW_PRESS && button >= 0 && button < 3) - GMousePressed[button] = true; + g_mouse_pressed[button] = true; } void ImGui_ImplGlfw_ScrollCallback(GLFWwindow* window, double xoffset, double yoffset) { - GMouseWheel += (float)yoffset; // Use fractional mouse wheel, 1.0 unit 5 lines. + g_mouse_wheel += (float)yoffset; // Use fractional mouse wheel, 1.0 unit 5 lines. } void ImGui_ImplGlFw_KeyCallback(GLFWwindow* window, int key, int scancode, int action, int mods) @@ -142,12 +142,12 @@ void ImGui_ImplGlfw_LoadFontsTexture() // Store our identifier io.Fonts->TexID = (void *)(intptr_t)tex_id; - GFontTextureLoaded = true; + g_font_texture_loaded = true; } bool ImGui_ImplGlfw_Init(GLFWwindow* window, bool install_callbacks) { - GWindow = window; + g_window = window; ImGuiIO& io = ImGui::GetIO(); io.KeyMap[ImGuiKey_Tab] = GLFW_KEY_TAB; // Keyboard mapping. ImGui will use those indices to peek into the io.KeyDown[] array. @@ -172,7 +172,7 @@ bool ImGui_ImplGlfw_Init(GLFWwindow* window, bool install_callbacks) io.SetClipboardTextFn = ImGui_ImplGlfw_SetClipboardText; io.GetClipboardTextFn = ImGui_ImplGlfw_GetClipboardText; #ifdef _MSC_VER - io.ImeWindowHandle = glfwGetWin32Window(GWindow); + io.ImeWindowHandle = glfwGetWin32Window(g_window); #endif if (install_callbacks) @@ -199,7 +199,7 @@ void ImGui_ImplGlfw_Shutdown() void ImGui_ImplGlfw_NewFrame() { - if (!GFontTextureLoaded) + if (!g_font_texture_loaded) ImGui_ImplGlfw_LoadFontsTexture(); ImGuiIO& io = ImGui::GetIO(); @@ -207,32 +207,32 @@ void ImGui_ImplGlfw_NewFrame() // Setup display size (every frame to accommodate for window resizing) int w, h; int display_w, display_h; - glfwGetWindowSize(GWindow, &w, &h); - glfwGetFramebufferSize(GWindow, &display_w, &display_h); + glfwGetWindowSize(g_window, &w, &h); + glfwGetFramebufferSize(g_window, &display_w, &display_h); io.DisplaySize = ImVec2((float)display_w, (float)display_h); // Setup time step double current_time = glfwGetTime(); - io.DeltaTime = GTime > 0.0 ? (float)(current_time - GTime) : (float)(1.0f/60.0f); - GTime = current_time; + io.DeltaTime = g_time > 0.0 ? (float)(current_time - g_time) : (float)(1.0f/60.0f); + g_time = current_time; // Setup inputs // (we already got mouse wheel, keyboard keys & characters from glfw callbacks polled in glfwPollEvents()) double mouse_x, mouse_y; - glfwGetCursorPos(GWindow, &mouse_x, &mouse_y); + glfwGetCursorPos(g_window, &mouse_x, &mouse_y); mouse_x *= (float)display_w / w; // Convert mouse coordinates to pixels mouse_y *= (float)display_h / h; io.MousePos = ImVec2((float)mouse_x, (float)mouse_y); // Mouse position, in pixels (set to -1,-1 if no mouse / on another screen, etc.) - io.MouseDown[0] = GMousePressed[0] || glfwGetMouseButton(GWindow, GLFW_MOUSE_BUTTON_LEFT) != 0; // If a mouse press event came, always pass it as "mouse held this frame", so we don't miss click-release events that are shorter than 1 frame. - io.MouseDown[1] = GMousePressed[1] || glfwGetMouseButton(GWindow, GLFW_MOUSE_BUTTON_RIGHT) != 0; - io.MouseDown[2] = GMousePressed[2] || glfwGetMouseButton(GWindow, GLFW_MOUSE_BUTTON_MIDDLE) != 0; - GMousePressed[0] = false; - GMousePressed[1] = false; - GMousePressed[2] = false; + io.MouseDown[0] = g_mouse_pressed[0] || glfwGetMouseButton(g_window, GLFW_MOUSE_BUTTON_LEFT) != 0; // If a mouse press event came, always pass it as "mouse held this frame", so we don't miss click-release events that are shorter than 1 frame. + io.MouseDown[1] = g_mouse_pressed[1] || glfwGetMouseButton(g_window, GLFW_MOUSE_BUTTON_RIGHT) != 0; + io.MouseDown[2] = g_mouse_pressed[2] || glfwGetMouseButton(g_window, GLFW_MOUSE_BUTTON_MIDDLE) != 0; + g_mouse_pressed[0] = false; + g_mouse_pressed[1] = false; + g_mouse_pressed[2] = false; - io.MouseWheel = GMouseWheel; - GMouseWheel = 0.0f; + io.MouseWheel = g_mouse_wheel; + g_mouse_wheel = 0.0f; // Start the frame ImGui::NewFrame(); From 4da432bd7b4cceb83fa9a03879b40237fa6af14b Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 9 Mar 2015 12:03:09 +0000 Subject: [PATCH 31/48] Examples: Makefile --- examples/opengl3_example/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/opengl3_example/Makefile b/examples/opengl3_example/Makefile index fa2665f7..c67ff83b 100644 --- a/examples/opengl3_example/Makefile +++ b/examples/opengl3_example/Makefile @@ -10,7 +10,7 @@ #CXX = g++ -OBJS = main.o +OBJS = main.o imgui_impl_glfw_gl3.o OBJS += ../../imgui.o OBJS += ../opengl_example/gl3w/GL/gl3w.o From 4f27bd6ed3aac7a7c922626f48230fed6ad48362 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 9 Mar 2015 12:11:24 +0000 Subject: [PATCH 32/48] Examples: Moved gl3w to opengl3_example directory + fixed msvc project paths --- .../gl3w/GL/gl3w.c | 0 .../gl3w/GL/gl3w.h | 0 .../gl3w/GL/glcorearb.h | 0 examples/opengl3_example/opengl3_example.vcxproj | 12 +++++++----- .../opengl3_example.vcxproj.filters | 15 ++++++++++++--- examples/opengl_example/opengl_example.vcxproj | 8 ++++---- 6 files changed, 23 insertions(+), 12 deletions(-) rename examples/{opengl_example => opengl3_example}/gl3w/GL/gl3w.c (100%) rename examples/{opengl_example => opengl3_example}/gl3w/GL/gl3w.h (100%) rename examples/{opengl_example => opengl3_example}/gl3w/GL/glcorearb.h (100%) diff --git a/examples/opengl_example/gl3w/GL/gl3w.c b/examples/opengl3_example/gl3w/GL/gl3w.c similarity index 100% rename from examples/opengl_example/gl3w/GL/gl3w.c rename to examples/opengl3_example/gl3w/GL/gl3w.c diff --git a/examples/opengl_example/gl3w/GL/gl3w.h b/examples/opengl3_example/gl3w/GL/gl3w.h similarity index 100% rename from examples/opengl_example/gl3w/GL/gl3w.h rename to examples/opengl3_example/gl3w/GL/gl3w.h diff --git a/examples/opengl_example/gl3w/GL/glcorearb.h b/examples/opengl3_example/gl3w/GL/glcorearb.h similarity index 100% rename from examples/opengl_example/gl3w/GL/glcorearb.h rename to examples/opengl3_example/gl3w/GL/glcorearb.h diff --git a/examples/opengl3_example/opengl3_example.vcxproj b/examples/opengl3_example/opengl3_example.vcxproj index 60943559..cda336d2 100644 --- a/examples/opengl3_example/opengl3_example.vcxproj +++ b/examples/opengl3_example/opengl3_example.vcxproj @@ -39,18 +39,18 @@ $(ProjectDir)$(Configuration)\ $(ProjectDir)$(Configuration)\ - ../..;$(IncludePath) + $(IncludePath) $(ProjectDir)$(Configuration)\ $(ProjectDir)$(Configuration)\ - ../..;$(IncludePath) + $(IncludePath) Level3 Disabled - $(ProjectDir)..\opengl_example\glfw\include;$(ProjectDir)..\opengl_example\glew\include;$(ProjectDir)..\opengl_example\gl3w;%(AdditionalIncludeDirectories) + $(ProjectDir)..\opengl_example\glfw\include;gl3w;..\..;%(AdditionalIncludeDirectories) true @@ -66,7 +66,7 @@ MaxSpeed true true - $(ProjectDir)..\opengl_example\glfw\include;$(ProjectDir)..\opengl_example\glew\include;$(ProjectDir)..\opengl_example\gl3w;%(AdditionalIncludeDirectories) + $(ProjectDir)..\opengl_example\glfw\include;gl3w;..\..;%(AdditionalIncludeDirectories) true @@ -81,13 +81,15 @@ - + + + diff --git a/examples/opengl3_example/opengl3_example.vcxproj.filters b/examples/opengl3_example/opengl3_example.vcxproj.filters index 76f7fa3f..1c00552d 100644 --- a/examples/opengl3_example/opengl3_example.vcxproj.filters +++ b/examples/opengl3_example/opengl3_example.vcxproj.filters @@ -8,6 +8,9 @@ {f18ab499-84e1-499f-8eff-9754361e0e52} cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + {42f99867-3108-43b8-99d0-fabefaf1f2e3} + @@ -16,12 +19,12 @@ imgui - - sources - sources + + gl3w + @@ -33,5 +36,11 @@ sources + + gl3w + + + gl3w + \ No newline at end of file diff --git a/examples/opengl_example/opengl_example.vcxproj b/examples/opengl_example/opengl_example.vcxproj index 69b5df6f..6dc90454 100644 --- a/examples/opengl_example/opengl_example.vcxproj +++ b/examples/opengl_example/opengl_example.vcxproj @@ -39,18 +39,18 @@ $(ProjectDir)$(Configuration)\ $(ProjectDir)$(Configuration)\ - ../..;$(IncludePath) + $(IncludePath) $(ProjectDir)$(Configuration)\ $(ProjectDir)$(Configuration)\ - ../..;$(IncludePath) + $(IncludePath) Level3 Disabled - $(ProjectDir)\glfw\include;$(ProjectDir)\glew\include;%(AdditionalIncludeDirectories) + $(ProjectDir)\glfw\include;..\..;%(AdditionalIncludeDirectories) true @@ -66,7 +66,7 @@ MaxSpeed true true - $(ProjectDir)\glfw\include;$(ProjectDir)\glew\include;%(AdditionalIncludeDirectories) + $(ProjectDir)\glfw\include;..\..;%(AdditionalIncludeDirectories) true From b227b0f8cd4f696b09fbebd0493171a593588d34 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 9 Mar 2015 12:16:29 +0000 Subject: [PATCH 33/48] Examples: Rename globals again --- .../opengl3_example/imgui_impl_glfw_gl3.cpp | 162 +++++++++--------- examples/opengl_example/imgui_impl_glfw.cpp | 52 +++--- 2 files changed, 107 insertions(+), 107 deletions(-) diff --git a/examples/opengl3_example/imgui_impl_glfw_gl3.cpp b/examples/opengl3_example/imgui_impl_glfw_gl3.cpp index a147821c..2c34bded 100644 --- a/examples/opengl3_example/imgui_impl_glfw_gl3.cpp +++ b/examples/opengl3_example/imgui_impl_glfw_gl3.cpp @@ -14,18 +14,18 @@ #include #endif -static GLFWwindow* g_window = NULL; -static bool g_mouse_pressed[3] = { false, false, false }; -static float g_mouse_wheel = 0.0f; -static double g_time = 0.0f; -static bool g_font_texture_loaded = false; +static GLFWwindow* g_Window = NULL; +static bool g_MousePressed[3] = { false, false, false }; +static float g_MouseWheel = 0.0f; +static double g_Time = 0.0f; +static bool g_FontTextureLoaded = false; // Handles for OpenGL3 rendering -static int g_shader_handle = 0, g_vert_handle = 0, g_frag_handle = 0; -static int g_texture_location = 0, g_proj_mtx_location = 0; -static int g_position_location = 0, g_uv_location = 0, g_colour_location = 0; -static size_t g_vbo_max_size = 20000; -static unsigned int g_vbo_handle = 0, g_vao_handle = 0; +static int g_ShaderHandle = 0, g_VertHandle = 0, g_FragHandle = 0; +static int g_AttribLocationTex = 0, g_AttribLocationProjMtx = 0; +static int g_AttribLocationPosition = 0, g_AttribLocationUV = 0, g_AttribLocationColor = 0; +static size_t g_VboMaxSize = 20000; +static unsigned int g_VboHandle = 0, g_VaoHandle = 0; // This is the main rendering function that you have to implement and provide to ImGui (via setting up 'RenderDrawListsFn' in the ImGuiIO structure) // If text or lines are blurry when integrating ImGui in your engine: @@ -54,20 +54,20 @@ static void ImGui_ImplGlfwGL3_RenderDrawLists(ImDrawList** const cmd_lists, int { 0.0f, 0.0f, -1.0f, 0.0f }, { -1.0f, 1.0f, 0.0f, 1.0f }, }; - glUseProgram(g_shader_handle); - glUniform1i(g_texture_location, 0); - glUniformMatrix4fv(g_proj_mtx_location, 1, GL_FALSE, &ortho_projection[0][0]); + glUseProgram(g_ShaderHandle); + glUniform1i(g_AttribLocationTex, 0); + glUniformMatrix4fv(g_AttribLocationProjMtx, 1, GL_FALSE, &ortho_projection[0][0]); // Grow our buffer according to what we need size_t total_vtx_count = 0; for (int n = 0; n < cmd_lists_count; n++) total_vtx_count += cmd_lists[n]->vtx_buffer.size(); - glBindBuffer(GL_ARRAY_BUFFER, g_vbo_handle); + glBindBuffer(GL_ARRAY_BUFFER, g_VboHandle); size_t neededBufferSize = total_vtx_count * sizeof(ImDrawVert); - if (neededBufferSize > g_vbo_max_size) + if (neededBufferSize > g_VboMaxSize) { - g_vbo_max_size = neededBufferSize + 5000; // Grow buffer - glBufferData(GL_ARRAY_BUFFER, g_vbo_max_size, NULL, GL_STREAM_DRAW); + g_VboMaxSize = neededBufferSize + 5000; // Grow buffer + glBufferData(GL_ARRAY_BUFFER, g_VboMaxSize, NULL, GL_STREAM_DRAW); } // Copy and convert all vertices into a single contiguous buffer @@ -82,7 +82,7 @@ static void ImGui_ImplGlfwGL3_RenderDrawLists(ImDrawList** const cmd_lists, int } glUnmapBuffer(GL_ARRAY_BUFFER); glBindBuffer(GL_ARRAY_BUFFER, 0); - glBindVertexArray(g_vao_handle); + glBindVertexArray(g_VaoHandle); int cmd_offset = 0; for (int n = 0; n < cmd_lists_count; n++) @@ -109,23 +109,23 @@ static void ImGui_ImplGlfwGL3_RenderDrawLists(ImDrawList** const cmd_lists, int static const char* ImGui_ImplGlfwGL3_GetClipboardText() { - return glfwGetClipboardString(g_window); + return glfwGetClipboardString(g_Window); } static void ImGui_ImplGlfwGL3_SetClipboardText(const char* text) { - glfwSetClipboardString(g_window, text); + glfwSetClipboardString(g_Window, text); } void ImGui_ImplGlfwGL3_MouseButtonCallback(GLFWwindow* window, int button, int action, int mods) { if (action == GLFW_PRESS && button >= 0 && button < 3) - g_mouse_pressed[button] = true; + g_MousePressed[button] = true; } void ImGui_ImplGlfwGL3_ScrollCallback(GLFWwindow* window, double xoffset, double yoffset) { - g_mouse_wheel += (float)yoffset; // Use fractional mouse wheel, 1.0 unit 5 lines. + g_MouseWheel += (float)yoffset; // Use fractional mouse wheel, 1.0 unit 5 lines. } void ImGui_ImplGlfwGL3_KeyCallback(GLFWwindow* window, int key, int scancode, int action, int mods) @@ -164,7 +164,7 @@ void ImGui_ImplGlfwGL3_LoadFontsTexture() // Store our identifier io.Fonts->TexID = (void *)(intptr_t)tex_id; - g_font_texture_loaded = true; + g_FontTextureLoaded = true; } static void InitGL() @@ -195,38 +195,38 @@ static void InitGL() " Out_Color = Frag_Color * texture( Texture, Frag_UV.st);\n" "}\n"; - g_shader_handle = glCreateProgram(); - g_vert_handle = glCreateShader(GL_VERTEX_SHADER); - g_frag_handle = glCreateShader(GL_FRAGMENT_SHADER); - glShaderSource(g_vert_handle, 1, &vertex_shader, 0); - glShaderSource(g_frag_handle, 1, &fragment_shader, 0); - glCompileShader(g_vert_handle); - glCompileShader(g_frag_handle); - glAttachShader(g_shader_handle, g_vert_handle); - glAttachShader(g_shader_handle, g_frag_handle); - glLinkProgram(g_shader_handle); - - g_texture_location = glGetUniformLocation(g_shader_handle, "Texture"); - g_proj_mtx_location = glGetUniformLocation(g_shader_handle, "ProjMtx"); - g_position_location = glGetAttribLocation(g_shader_handle, "Position"); - g_uv_location = glGetAttribLocation(g_shader_handle, "UV"); - g_colour_location = glGetAttribLocation(g_shader_handle, "Color"); - - glGenBuffers(1, &g_vbo_handle); - glBindBuffer(GL_ARRAY_BUFFER, g_vbo_handle); - glBufferData(GL_ARRAY_BUFFER, g_vbo_max_size, NULL, GL_DYNAMIC_DRAW); - - glGenVertexArrays(1, &g_vao_handle); - glBindVertexArray(g_vao_handle); - glBindBuffer(GL_ARRAY_BUFFER, g_vbo_handle); - glEnableVertexAttribArray(g_position_location); - glEnableVertexAttribArray(g_uv_location); - glEnableVertexAttribArray(g_colour_location); + g_ShaderHandle = glCreateProgram(); + g_VertHandle = glCreateShader(GL_VERTEX_SHADER); + g_FragHandle = glCreateShader(GL_FRAGMENT_SHADER); + glShaderSource(g_VertHandle, 1, &vertex_shader, 0); + glShaderSource(g_FragHandle, 1, &fragment_shader, 0); + glCompileShader(g_VertHandle); + glCompileShader(g_FragHandle); + glAttachShader(g_ShaderHandle, g_VertHandle); + glAttachShader(g_ShaderHandle, g_FragHandle); + glLinkProgram(g_ShaderHandle); + + g_AttribLocationTex = glGetUniformLocation(g_ShaderHandle, "Texture"); + g_AttribLocationProjMtx = glGetUniformLocation(g_ShaderHandle, "ProjMtx"); + g_AttribLocationPosition = glGetAttribLocation(g_ShaderHandle, "Position"); + g_AttribLocationUV = glGetAttribLocation(g_ShaderHandle, "UV"); + g_AttribLocationColor = glGetAttribLocation(g_ShaderHandle, "Color"); + + glGenBuffers(1, &g_VboHandle); + glBindBuffer(GL_ARRAY_BUFFER, g_VboHandle); + glBufferData(GL_ARRAY_BUFFER, g_VboMaxSize, NULL, GL_DYNAMIC_DRAW); + + glGenVertexArrays(1, &g_VaoHandle); + glBindVertexArray(g_VaoHandle); + glBindBuffer(GL_ARRAY_BUFFER, g_VboHandle); + glEnableVertexAttribArray(g_AttribLocationPosition); + glEnableVertexAttribArray(g_AttribLocationUV); + glEnableVertexAttribArray(g_AttribLocationColor); #define OFFSETOF(TYPE, ELEMENT) ((size_t)&(((TYPE *)0)->ELEMENT)) - glVertexAttribPointer(g_position_location, 2, GL_FLOAT, GL_FALSE, sizeof(ImDrawVert), (GLvoid*)OFFSETOF(ImDrawVert, pos)); - glVertexAttribPointer(g_uv_location, 2, GL_FLOAT, GL_FALSE, sizeof(ImDrawVert), (GLvoid*)OFFSETOF(ImDrawVert, uv)); - glVertexAttribPointer(g_colour_location, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(ImDrawVert), (GLvoid*)OFFSETOF(ImDrawVert, col)); + glVertexAttribPointer(g_AttribLocationPosition, 2, GL_FLOAT, GL_FALSE, sizeof(ImDrawVert), (GLvoid*)OFFSETOF(ImDrawVert, pos)); + glVertexAttribPointer(g_AttribLocationUV, 2, GL_FLOAT, GL_FALSE, sizeof(ImDrawVert), (GLvoid*)OFFSETOF(ImDrawVert, uv)); + glVertexAttribPointer(g_AttribLocationColor, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(ImDrawVert), (GLvoid*)OFFSETOF(ImDrawVert, col)); #undef OFFSETOF glBindVertexArray(0); glBindBuffer(GL_ARRAY_BUFFER, 0); @@ -236,7 +236,7 @@ bool ImGui_ImplGlfwGL3_Init(GLFWwindow* window, bool install_callbacks) { InitGL(); - g_window = window; + g_Window = window; ImGuiIO& io = ImGui::GetIO(); io.KeyMap[ImGuiKey_Tab] = GLFW_KEY_TAB; // Keyboard mapping. ImGui will use those indices to peek into the io.KeyDown[] array. @@ -261,7 +261,7 @@ bool ImGui_ImplGlfwGL3_Init(GLFWwindow* window, bool install_callbacks) io.SetClipboardTextFn = ImGui_ImplGlfwGL3_SetClipboardText; io.GetClipboardTextFn = ImGui_ImplGlfwGL3_GetClipboardText; #ifdef _MSC_VER - io.ImeWindowHandle = glfwGetWin32Window(g_window); + io.ImeWindowHandle = glfwGetWin32Window(g_Window); #endif if (install_callbacks) @@ -277,21 +277,21 @@ bool ImGui_ImplGlfwGL3_Init(GLFWwindow* window, bool install_callbacks) void ImGui_ImplGlfwGL3_Shutdown() { - if (g_vao_handle) glDeleteVertexArrays(1, &g_vao_handle); - if (g_vbo_handle) glDeleteBuffers(1, &g_vbo_handle); - g_vao_handle = 0; - g_vbo_handle = 0; + if (g_VaoHandle) glDeleteVertexArrays(1, &g_VaoHandle); + if (g_VboHandle) glDeleteBuffers(1, &g_VboHandle); + g_VaoHandle = 0; + g_VboHandle = 0; - glDetachShader(g_shader_handle, g_vert_handle); - glDeleteShader(g_vert_handle); - g_vert_handle = 0; + glDetachShader(g_ShaderHandle, g_VertHandle); + glDeleteShader(g_VertHandle); + g_VertHandle = 0; - glDetachShader(g_shader_handle, g_frag_handle); - glDeleteShader(g_frag_handle); - g_frag_handle = 0; + glDetachShader(g_ShaderHandle, g_FragHandle); + glDeleteShader(g_FragHandle); + g_FragHandle = 0; - glDeleteProgram(g_shader_handle); - g_shader_handle = 0; + glDeleteProgram(g_ShaderHandle); + g_ShaderHandle = 0; GLuint tex_id = (GLuint)ImGui::GetIO().Fonts->TexID; if (tex_id) @@ -304,7 +304,7 @@ void ImGui_ImplGlfwGL3_Shutdown() void ImGui_ImplGlfwGL3_NewFrame() { - if (!g_font_texture_loaded) + if (!g_FontTextureLoaded) ImGui_ImplGlfwGL3_LoadFontsTexture(); ImGuiIO& io = ImGui::GetIO(); @@ -312,32 +312,32 @@ void ImGui_ImplGlfwGL3_NewFrame() // Setup display size (every frame to accommodate for window resizing) int w, h; int display_w, display_h; - glfwGetWindowSize(g_window, &w, &h); - glfwGetFramebufferSize(g_window, &display_w, &display_h); + glfwGetWindowSize(g_Window, &w, &h); + glfwGetFramebufferSize(g_Window, &display_w, &display_h); io.DisplaySize = ImVec2((float)display_w, (float)display_h); // Setup time step double current_time = glfwGetTime(); - io.DeltaTime = g_time > 0.0 ? (float)(current_time - g_time) : (float)(1.0f/60.0f); - g_time = current_time; + io.DeltaTime = g_Time > 0.0 ? (float)(current_time - g_Time) : (float)(1.0f/60.0f); + g_Time = current_time; // Setup inputs // (we already got mouse wheel, keyboard keys & characters from glfw callbacks polled in glfwPollEvents()) double mouse_x, mouse_y; - glfwGetCursorPos(g_window, &mouse_x, &mouse_y); + glfwGetCursorPos(g_Window, &mouse_x, &mouse_y); mouse_x *= (float)display_w / w; // Convert mouse coordinates to pixels mouse_y *= (float)display_h / h; io.MousePos = ImVec2((float)mouse_x, (float)mouse_y); // Mouse position, in pixels (set to -1,-1 if no mouse / on another screen, etc.) - io.MouseDown[0] = g_mouse_pressed[0] || glfwGetMouseButton(g_window, GLFW_MOUSE_BUTTON_LEFT) != 0; // If a mouse press event came, always pass it as "mouse held this frame", so we don't miss click-release events that are shorter than 1 frame. - io.MouseDown[1] = g_mouse_pressed[1] || glfwGetMouseButton(g_window, GLFW_MOUSE_BUTTON_RIGHT) != 0; - io.MouseDown[2] = g_mouse_pressed[2] || glfwGetMouseButton(g_window, GLFW_MOUSE_BUTTON_MIDDLE) != 0; - g_mouse_pressed[0] = false; - g_mouse_pressed[1] = false; - g_mouse_pressed[2] = false; + io.MouseDown[0] = g_MousePressed[0] || glfwGetMouseButton(g_Window, GLFW_MOUSE_BUTTON_LEFT) != 0; // If a mouse press event came, always pass it as "mouse held this frame", so we don't miss click-release events that are shorter than 1 frame. + io.MouseDown[1] = g_MousePressed[1] || glfwGetMouseButton(g_Window, GLFW_MOUSE_BUTTON_RIGHT) != 0; + io.MouseDown[2] = g_MousePressed[2] || glfwGetMouseButton(g_Window, GLFW_MOUSE_BUTTON_MIDDLE) != 0; + g_MousePressed[0] = false; + g_MousePressed[1] = false; + g_MousePressed[2] = false; - io.MouseWheel = g_mouse_wheel; - g_mouse_wheel = 0.0f; + io.MouseWheel = g_MouseWheel; + g_MouseWheel = 0.0f; // Start the frame ImGui::NewFrame(); diff --git a/examples/opengl_example/imgui_impl_glfw.cpp b/examples/opengl_example/imgui_impl_glfw.cpp index 01ba55f9..bcea31e1 100644 --- a/examples/opengl_example/imgui_impl_glfw.cpp +++ b/examples/opengl_example/imgui_impl_glfw.cpp @@ -13,11 +13,11 @@ #include #endif -static GLFWwindow* g_window = NULL; -static bool g_mouse_pressed[3] = { false, false, false }; -static float g_mouse_wheel = 0.0f; -static double g_time = 0.0f; -static bool g_font_texture_loaded = false; +static GLFWwindow* g_Window = NULL; +static bool g_MousePressed[3] = { false, false, false }; +static float g_MouseWheel = 0.0f; +static double g_Time = 0.0f; +static bool g_FontTextureLoaded = false; // This is the main rendering function that you have to implement and provide to ImGui (via setting up 'RenderDrawListsFn' in the ImGuiIO structure) // If text or lines are blurry when integrating ImGui in your engine: @@ -87,23 +87,23 @@ static void ImGui_ImplGlfw_RenderDrawLists(ImDrawList** const cmd_lists, int cmd static const char* ImGui_ImplGlfw_GetClipboardText() { - return glfwGetClipboardString(g_window); + return glfwGetClipboardString(g_Window); } static void ImGui_ImplGlfw_SetClipboardText(const char* text) { - glfwSetClipboardString(g_window, text); + glfwSetClipboardString(g_Window, text); } void ImGui_ImplGlfw_MouseButtonCallback(GLFWwindow* window, int button, int action, int mods) { if (action == GLFW_PRESS && button >= 0 && button < 3) - g_mouse_pressed[button] = true; + g_MousePressed[button] = true; } void ImGui_ImplGlfw_ScrollCallback(GLFWwindow* window, double xoffset, double yoffset) { - g_mouse_wheel += (float)yoffset; // Use fractional mouse wheel, 1.0 unit 5 lines. + g_MouseWheel += (float)yoffset; // Use fractional mouse wheel, 1.0 unit 5 lines. } void ImGui_ImplGlFw_KeyCallback(GLFWwindow* window, int key, int scancode, int action, int mods) @@ -142,12 +142,12 @@ void ImGui_ImplGlfw_LoadFontsTexture() // Store our identifier io.Fonts->TexID = (void *)(intptr_t)tex_id; - g_font_texture_loaded = true; + g_FontTextureLoaded = true; } bool ImGui_ImplGlfw_Init(GLFWwindow* window, bool install_callbacks) { - g_window = window; + g_Window = window; ImGuiIO& io = ImGui::GetIO(); io.KeyMap[ImGuiKey_Tab] = GLFW_KEY_TAB; // Keyboard mapping. ImGui will use those indices to peek into the io.KeyDown[] array. @@ -172,7 +172,7 @@ bool ImGui_ImplGlfw_Init(GLFWwindow* window, bool install_callbacks) io.SetClipboardTextFn = ImGui_ImplGlfw_SetClipboardText; io.GetClipboardTextFn = ImGui_ImplGlfw_GetClipboardText; #ifdef _MSC_VER - io.ImeWindowHandle = glfwGetWin32Window(g_window); + io.ImeWindowHandle = glfwGetWin32Window(g_Window); #endif if (install_callbacks) @@ -199,7 +199,7 @@ void ImGui_ImplGlfw_Shutdown() void ImGui_ImplGlfw_NewFrame() { - if (!g_font_texture_loaded) + if (!g_FontTextureLoaded) ImGui_ImplGlfw_LoadFontsTexture(); ImGuiIO& io = ImGui::GetIO(); @@ -207,32 +207,32 @@ void ImGui_ImplGlfw_NewFrame() // Setup display size (every frame to accommodate for window resizing) int w, h; int display_w, display_h; - glfwGetWindowSize(g_window, &w, &h); - glfwGetFramebufferSize(g_window, &display_w, &display_h); + glfwGetWindowSize(g_Window, &w, &h); + glfwGetFramebufferSize(g_Window, &display_w, &display_h); io.DisplaySize = ImVec2((float)display_w, (float)display_h); // Setup time step double current_time = glfwGetTime(); - io.DeltaTime = g_time > 0.0 ? (float)(current_time - g_time) : (float)(1.0f/60.0f); - g_time = current_time; + io.DeltaTime = g_Time > 0.0 ? (float)(current_time - g_Time) : (float)(1.0f/60.0f); + g_Time = current_time; // Setup inputs // (we already got mouse wheel, keyboard keys & characters from glfw callbacks polled in glfwPollEvents()) double mouse_x, mouse_y; - glfwGetCursorPos(g_window, &mouse_x, &mouse_y); + glfwGetCursorPos(g_Window, &mouse_x, &mouse_y); mouse_x *= (float)display_w / w; // Convert mouse coordinates to pixels mouse_y *= (float)display_h / h; io.MousePos = ImVec2((float)mouse_x, (float)mouse_y); // Mouse position, in pixels (set to -1,-1 if no mouse / on another screen, etc.) - io.MouseDown[0] = g_mouse_pressed[0] || glfwGetMouseButton(g_window, GLFW_MOUSE_BUTTON_LEFT) != 0; // If a mouse press event came, always pass it as "mouse held this frame", so we don't miss click-release events that are shorter than 1 frame. - io.MouseDown[1] = g_mouse_pressed[1] || glfwGetMouseButton(g_window, GLFW_MOUSE_BUTTON_RIGHT) != 0; - io.MouseDown[2] = g_mouse_pressed[2] || glfwGetMouseButton(g_window, GLFW_MOUSE_BUTTON_MIDDLE) != 0; - g_mouse_pressed[0] = false; - g_mouse_pressed[1] = false; - g_mouse_pressed[2] = false; + io.MouseDown[0] = g_MousePressed[0] || glfwGetMouseButton(g_Window, GLFW_MOUSE_BUTTON_LEFT) != 0; // If a mouse press event came, always pass it as "mouse held this frame", so we don't miss click-release events that are shorter than 1 frame. + io.MouseDown[1] = g_MousePressed[1] || glfwGetMouseButton(g_Window, GLFW_MOUSE_BUTTON_RIGHT) != 0; + io.MouseDown[2] = g_MousePressed[2] || glfwGetMouseButton(g_Window, GLFW_MOUSE_BUTTON_MIDDLE) != 0; + g_MousePressed[0] = false; + g_MousePressed[1] = false; + g_MousePressed[2] = false; - io.MouseWheel = g_mouse_wheel; - g_mouse_wheel = 0.0f; + io.MouseWheel = g_MouseWheel; + g_MouseWheel = 0.0f; // Start the frame ImGui::NewFrame(); From b87ec205a9484cc6099e5b9173b6a4edafdaa66f Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 9 Mar 2015 13:02:32 +0000 Subject: [PATCH 34/48] Examples: shallow tweaks to match upcoming other examples. --- examples/opengl3_example/imgui_impl_glfw_gl3.cpp | 12 +++++------- examples/opengl3_example/imgui_impl_glfw_gl3.h | 2 +- examples/opengl3_example/main.cpp | 9 +++++---- examples/opengl_example/imgui_impl_glfw.cpp | 10 +++++----- examples/opengl_example/imgui_impl_glfw.h | 2 +- examples/opengl_example/main.cpp | 6 ++++-- 6 files changed, 21 insertions(+), 20 deletions(-) diff --git a/examples/opengl3_example/imgui_impl_glfw_gl3.cpp b/examples/opengl3_example/imgui_impl_glfw_gl3.cpp index 2c34bded..cbe9f60c 100644 --- a/examples/opengl3_example/imgui_impl_glfw_gl3.cpp +++ b/examples/opengl3_example/imgui_impl_glfw_gl3.cpp @@ -14,13 +14,12 @@ #include #endif +// Data static GLFWwindow* g_Window = NULL; +static double g_Time = 0.0f; static bool g_MousePressed[3] = { false, false, false }; static float g_MouseWheel = 0.0f; -static double g_Time = 0.0f; static bool g_FontTextureLoaded = false; - -// Handles for OpenGL3 rendering static int g_ShaderHandle = 0, g_VertHandle = 0, g_FragHandle = 0; static int g_AttribLocationTex = 0, g_AttribLocationProjMtx = 0; static int g_AttribLocationPosition = 0, g_AttribLocationUV = 0, g_AttribLocationColor = 0; @@ -146,7 +145,7 @@ void ImGui_ImplGlfwGL3_CharCallback(GLFWwindow* window, unsigned int c) io.AddInputCharacter((unsigned short)c); } -void ImGui_ImplGlfwGL3_LoadFontsTexture() +void ImGui_ImplGlfwGL3_InitFontsTexture() { ImGuiIO& io = ImGui::GetIO(); @@ -293,8 +292,7 @@ void ImGui_ImplGlfwGL3_Shutdown() glDeleteProgram(g_ShaderHandle); g_ShaderHandle = 0; - GLuint tex_id = (GLuint)ImGui::GetIO().Fonts->TexID; - if (tex_id) + if (GLuint tex_id = (GLuint)ImGui::GetIO().Fonts->TexID) { glDeleteTextures(1, &tex_id); ImGui::GetIO().Fonts->TexID = 0; @@ -305,7 +303,7 @@ void ImGui_ImplGlfwGL3_Shutdown() void ImGui_ImplGlfwGL3_NewFrame() { if (!g_FontTextureLoaded) - ImGui_ImplGlfwGL3_LoadFontsTexture(); + ImGui_ImplGlfwGL3_InitFontsTexture(); ImGuiIO& io = ImGui::GetIO(); diff --git a/examples/opengl3_example/imgui_impl_glfw_gl3.h b/examples/opengl3_example/imgui_impl_glfw_gl3.h index bfa5f604..d3d1d817 100644 --- a/examples/opengl3_example/imgui_impl_glfw_gl3.h +++ b/examples/opengl3_example/imgui_impl_glfw_gl3.h @@ -4,8 +4,8 @@ struct GLFWwindow; bool ImGui_ImplGlfwGL3_Init(GLFWwindow* window, bool install_callbacks); +void ImGui_ImplGlfwGL3_InitFontsTexture(); void ImGui_ImplGlfwGL3_Shutdown(); -void ImGui_ImplGlfwGL3_LoadFontsTexture(); void ImGui_ImplGlfwGL3_NewFrame(); // GLFW callbacks (installed by default if you enable 'install_callbacks' during initialization) diff --git a/examples/opengl3_example/main.cpp b/examples/opengl3_example/main.cpp index 1665b133..16d3a716 100644 --- a/examples/opengl3_example/main.cpp +++ b/examples/opengl3_example/main.cpp @@ -13,31 +13,32 @@ static void error_callback(int error, const char* description) int main(int argc, char** argv) { + // Setup window glfwSetErrorCallback(error_callback); if (!glfwInit()) exit(1); - glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); - GLFWwindow* window = glfwCreateWindow(1280, 720, "ImGui OpenGL3 example", NULL, NULL); glfwMakeContextCurrent(window); gl3wInit(); + // Setup ImGui binding + ImGui_ImplGlfwGL3_Init(window, true); //ImGuiIO& io = ImGui::GetIO(); //ImFont* my_font1 = io.Fonts->AddFontDefault(); //ImFont* my_font2 = io.Fonts->AddFontFromFileTTF("extra_fonts/Karla-Regular.ttf", 15.0f); //ImFont* my_font3 = io.Fonts->AddFontFromFileTTF("extra_fonts/ProggyClean.ttf", 13.0f); my_font3->DisplayOffset.y += 1; //ImFont* my_font4 = io.Fonts->AddFontFromFileTTF("extra_fonts/ProggyTiny.ttf", 10.0f); my_font4->DisplayOffset.y += 1; //ImFont* my_font5 = io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf", 18.0f, io.Fonts->GetGlyphRangesJapanese()); - ImGui_ImplGlfwGL3_Init(window, true); - ImGui_ImplGlfwGL3_LoadFontsTexture(); + ImGui_ImplGlfwGL3_InitFontsTexture(); bool show_test_window = true; bool show_another_window = false; ImVec4 clear_color = ImColor(114, 144, 154); + // Main loop while (!glfwWindowShouldClose(window)) { ImGuiIO& io = ImGui::GetIO(); diff --git a/examples/opengl_example/imgui_impl_glfw.cpp b/examples/opengl_example/imgui_impl_glfw.cpp index bcea31e1..6bf07d8a 100644 --- a/examples/opengl_example/imgui_impl_glfw.cpp +++ b/examples/opengl_example/imgui_impl_glfw.cpp @@ -13,10 +13,11 @@ #include #endif +// Data static GLFWwindow* g_Window = NULL; +static double g_Time = 0.0f; static bool g_MousePressed[3] = { false, false, false }; static float g_MouseWheel = 0.0f; -static double g_Time = 0.0f; static bool g_FontTextureLoaded = false; // This is the main rendering function that you have to implement and provide to ImGui (via setting up 'RenderDrawListsFn' in the ImGuiIO structure) @@ -124,7 +125,7 @@ void ImGui_ImplGlfw_CharCallback(GLFWwindow* window, unsigned int c) io.AddInputCharacter((unsigned short)c); } -void ImGui_ImplGlfw_LoadFontsTexture() +void ImGui_ImplGlfw_InitFontsTexture() { ImGuiIO& io = ImGui::GetIO(); @@ -188,8 +189,7 @@ bool ImGui_ImplGlfw_Init(GLFWwindow* window, bool install_callbacks) void ImGui_ImplGlfw_Shutdown() { - GLuint tex_id = (GLuint)ImGui::GetIO().Fonts->TexID; - if (tex_id) + if (GLuint tex_id = (GLuint)ImGui::GetIO().Fonts->TexID) { glDeleteTextures(1, &tex_id); ImGui::GetIO().Fonts->TexID = 0; @@ -200,7 +200,7 @@ void ImGui_ImplGlfw_Shutdown() void ImGui_ImplGlfw_NewFrame() { if (!g_FontTextureLoaded) - ImGui_ImplGlfw_LoadFontsTexture(); + ImGui_ImplGlfw_InitFontsTexture(); ImGuiIO& io = ImGui::GetIO(); diff --git a/examples/opengl_example/imgui_impl_glfw.h b/examples/opengl_example/imgui_impl_glfw.h index e3581e00..455b542a 100644 --- a/examples/opengl_example/imgui_impl_glfw.h +++ b/examples/opengl_example/imgui_impl_glfw.h @@ -4,8 +4,8 @@ struct GLFWwindow; bool ImGui_ImplGlfw_Init(GLFWwindow* window, bool install_callbacks); +void ImGui_ImplGlfw_InitFontsTexture(); void ImGui_ImplGlfw_Shutdown(); -void ImGui_ImplGlfw_LoadFontsTexture(); void ImGui_ImplGlfw_NewFrame(); // GLFW callbacks (installed by default if you enable 'install_callbacks' during initialization) diff --git a/examples/opengl_example/main.cpp b/examples/opengl_example/main.cpp index d658f6ae..1dd7839b 100644 --- a/examples/opengl_example/main.cpp +++ b/examples/opengl_example/main.cpp @@ -12,13 +12,14 @@ static void error_callback(int error, const char* description) int main(int argc, char** argv) { + // Setup window glfwSetErrorCallback(error_callback); if (!glfwInit()) exit(1); - GLFWwindow* window = glfwCreateWindow(1280, 720, "ImGui OpenGL2 example", NULL, NULL); glfwMakeContextCurrent(window); + // Setup ImGui binding ImGui_ImplGlfw_Init(window, true); //ImGuiIO& io = ImGui::GetIO(); //ImFont* my_font1 = io.Fonts->AddFontDefault(); @@ -26,12 +27,13 @@ int main(int argc, char** argv) //ImFont* my_font3 = io.Fonts->AddFontFromFileTTF("extra_fonts/ProggyClean.ttf", 13.0f); my_font3->DisplayOffset.y += 1; //ImFont* my_font4 = io.Fonts->AddFontFromFileTTF("extra_fonts/ProggyTiny.ttf", 10.0f); my_font4->DisplayOffset.y += 1; //ImFont* my_font5 = io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf", 18.0f, io.Fonts->GetGlyphRangesJapanese()); - ImGui_ImplGlfw_LoadFontsTexture(); + ImGui_ImplGlfw_InitFontsTexture(); bool show_test_window = true; bool show_another_window = false; ImVec4 clear_color = ImColor(114, 144, 154); + // Main loop while (!glfwWindowShouldClose(window)) { glfwPollEvents(); From 73974250975fa4bbed5e9ef5f2ff46ddd38b5459 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 9 Mar 2015 13:03:46 +0000 Subject: [PATCH 35/48] Examples: Refactored directx9_example to be eaasier to copy & paste into user application. --- .../directx9_example/directx9_example.vcxproj | 6 +- .../directx9_example.vcxproj.filters | 6 + examples/directx9_example/imgui_impl_dx9.cpp | 262 ++++++++++++++ examples/directx9_example/imgui_impl_dx9.h | 16 + examples/directx9_example/main.cpp | 338 +++--------------- 5 files changed, 337 insertions(+), 291 deletions(-) create mode 100644 examples/directx9_example/imgui_impl_dx9.cpp create mode 100644 examples/directx9_example/imgui_impl_dx9.h diff --git a/examples/directx9_example/directx9_example.vcxproj b/examples/directx9_example/directx9_example.vcxproj index 548f1d3d..3b638b7b 100644 --- a/examples/directx9_example/directx9_example.vcxproj +++ b/examples/directx9_example/directx9_example.vcxproj @@ -48,7 +48,7 @@ Level3 Disabled - $(DXSDK_DIR)Include;%(AdditionalIncludeDirectories) + ..\..;$(DXSDK_DIR)Include;%(AdditionalIncludeDirectories) true @@ -63,7 +63,7 @@ MaxSpeed true true - $(DXSDK_DIR)Include;%(AdditionalIncludeDirectories) + ..\..;$(DXSDK_DIR)Include;%(AdditionalIncludeDirectories) true @@ -76,11 +76,13 @@ + + diff --git a/examples/directx9_example/directx9_example.vcxproj.filters b/examples/directx9_example/directx9_example.vcxproj.filters index 06afcb03..13e1f412 100644 --- a/examples/directx9_example/directx9_example.vcxproj.filters +++ b/examples/directx9_example/directx9_example.vcxproj.filters @@ -16,6 +16,9 @@ imgui + + sources + @@ -24,5 +27,8 @@ imgui + + sources + \ No newline at end of file diff --git a/examples/directx9_example/imgui_impl_dx9.cpp b/examples/directx9_example/imgui_impl_dx9.cpp new file mode 100644 index 00000000..9e0a342f --- /dev/null +++ b/examples/directx9_example/imgui_impl_dx9.cpp @@ -0,0 +1,262 @@ +// ImGui Win32 + DirectX9 binding +// https://github.com/ocornut/imgui + +#include +#include "imgui_impl_dx9.h" + +// DirectX +#include +#define DIRECTINPUT_VERSION 0x0800 +#include + +// Data +static INT64 g_Time = 0; +static INT64 g_TicksPerSecond = 0; +static bool g_FontTextureLoaded = false; +static LPDIRECT3DDEVICE9 g_pd3dDevice = NULL; +static LPDIRECT3DVERTEXBUFFER9 g_pVB = NULL; + +struct CUSTOMVERTEX +{ + D3DXVECTOR3 pos; + D3DCOLOR col; + D3DXVECTOR2 uv; +}; +#define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZ|D3DFVF_DIFFUSE|D3DFVF_TEX1) + +// This is the main rendering function that you have to implement and provide to ImGui (via setting up 'RenderDrawListsFn' in the ImGuiIO structure) +// If text or lines are blurry when integrating ImGui in your engine: +// - in your Render function, try translating your projection matrix by (0.5f,0.5f) or (0.375f,0.375f) +static void ImGui_ImplDX9_RenderDrawLists(ImDrawList** const cmd_lists, int cmd_lists_count) +{ + size_t total_vtx_count = 0; + for (int n = 0; n < cmd_lists_count; n++) + total_vtx_count += cmd_lists[n]->vtx_buffer.size(); + if (total_vtx_count == 0) + return; + + // Copy and convert all vertices into a single contiguous buffer + CUSTOMVERTEX* vtx_dst; + if (g_pVB->Lock(0, (UINT)total_vtx_count, (void**)&vtx_dst, D3DLOCK_DISCARD) < 0) + return; + for (int n = 0; n < cmd_lists_count; n++) + { + const ImDrawList* cmd_list = cmd_lists[n]; + const ImDrawVert* vtx_src = &cmd_list->vtx_buffer[0]; + for (size_t i = 0; i < cmd_list->vtx_buffer.size(); i++) + { + vtx_dst->pos.x = vtx_src->pos.x; + vtx_dst->pos.y = vtx_src->pos.y; + vtx_dst->pos.z = 0.0f; + vtx_dst->col = (vtx_src->col & 0xFF00FF00) | ((vtx_src->col & 0xFF0000)>>16) | ((vtx_src->col & 0xFF) << 16); // RGBA --> ARGB for DirectX9 + vtx_dst->uv.x = vtx_src->uv.x; + vtx_dst->uv.y = vtx_src->uv.y; + vtx_dst++; + vtx_src++; + } + } + g_pVB->Unlock(); + + g_pd3dDevice->SetStreamSource( 0, g_pVB, 0, sizeof( CUSTOMVERTEX ) ); + g_pd3dDevice->SetFVF( D3DFVF_CUSTOMVERTEX ); + + // Setup render state: alpha-blending, no face culling, no depth testing + g_pd3dDevice->SetRenderState( D3DRS_CULLMODE, D3DCULL_NONE ); + g_pd3dDevice->SetRenderState( D3DRS_LIGHTING, false ); + g_pd3dDevice->SetRenderState( D3DRS_ZENABLE, false ); + g_pd3dDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, true ); + g_pd3dDevice->SetRenderState( D3DRS_BLENDOP, D3DBLENDOP_ADD ); + g_pd3dDevice->SetRenderState( D3DRS_ALPHATESTENABLE, false ); + g_pd3dDevice->SetRenderState( D3DRS_SRCBLEND, D3DBLEND_SRCALPHA ); + g_pd3dDevice->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA ); + g_pd3dDevice->SetRenderState( D3DRS_SCISSORTESTENABLE, true ); + g_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_SELECTARG1 ); + g_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_DIFFUSE ); + g_pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAOP, D3DTOP_MODULATE ); + g_pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE ); + g_pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE ); + g_pd3dDevice->SetSamplerState( 0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR ); + g_pd3dDevice->SetSamplerState( 0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR ); + + // Setup orthographic projection matrix + D3DXMATRIXA16 mat; + D3DXMatrixIdentity(&mat); + g_pd3dDevice->SetTransform(D3DTS_WORLD, &mat); + g_pd3dDevice->SetTransform(D3DTS_VIEW, &mat); + D3DXMatrixOrthoOffCenterLH(&mat, 0.5f, ImGui::GetIO().DisplaySize.x+0.5f, ImGui::GetIO().DisplaySize.y+0.5f, 0.5f, -1.0f, +1.0f); + g_pd3dDevice->SetTransform(D3DTS_PROJECTION, &mat); + + // Render command lists + int vtx_offset = 0; + for (int n = 0; n < cmd_lists_count; n++) + { + // Render command list + const ImDrawList* cmd_list = cmd_lists[n]; + for (size_t cmd_i = 0; cmd_i < cmd_list->commands.size(); cmd_i++) + { + const ImDrawCmd* pcmd = &cmd_list->commands[cmd_i]; + const RECT r = { (LONG)pcmd->clip_rect.x, (LONG)pcmd->clip_rect.y, (LONG)pcmd->clip_rect.z, (LONG)pcmd->clip_rect.w }; + g_pd3dDevice->SetTexture( 0, (LPDIRECT3DTEXTURE9)pcmd->texture_id ); + g_pd3dDevice->SetScissorRect(&r); + g_pd3dDevice->DrawPrimitive(D3DPT_TRIANGLELIST, vtx_offset, pcmd->vtx_count/3); + vtx_offset += pcmd->vtx_count; + } + } +} + +LRESULT ImGui_ImplDX9_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + ImGuiIO& io = ImGui::GetIO(); + switch (msg) + { + case WM_LBUTTONDOWN: + io.MouseDown[0] = true; + return true; + case WM_LBUTTONUP: + io.MouseDown[0] = false; + return true; + case WM_RBUTTONDOWN: + io.MouseDown[1] = true; + return true; + case WM_RBUTTONUP: + io.MouseDown[1] = false; + return true; + case WM_MOUSEWHEEL: + io.MouseWheel += GET_WHEEL_DELTA_WPARAM(wParam) > 0 ? +1.0f : -1.0f; + return true; + case WM_MOUSEMOVE: + io.MousePos.x = (signed short)(lParam); + io.MousePos.y = (signed short)(lParam >> 16); + return true; + case WM_KEYDOWN: + if (wParam >= 0 && wParam < 256) + io.KeysDown[wParam] = 1; + return true; + case WM_KEYUP: + if (wParam >= 0 && wParam < 256) + io.KeysDown[wParam] = 0; + return true; + case WM_CHAR: + // You can also use ToAscii()+GetKeyboardState() to retrieve characters. + if (wParam > 0 && wParam < 0x10000) + io.AddInputCharacter((unsigned short)wParam); + return true; + } + return 0; +} + +void ImGui_ImplDX9_InitFontsTexture() +{ + ImGuiIO& io = ImGui::GetIO(); + + // Build + unsigned char* pixels; + int width, height, bytes_per_pixel; + io.Fonts->GetTexDataAsAlpha8(&pixels, &width, &height, &bytes_per_pixel); + + // Create DX9 texture + LPDIRECT3DTEXTURE9 pTexture = NULL; + if (D3DXCreateTexture(g_pd3dDevice, width, height, 1, D3DUSAGE_DYNAMIC, D3DFMT_A8, D3DPOOL_DEFAULT, &pTexture) < 0) + { + IM_ASSERT(0); + return; + } + D3DLOCKED_RECT tex_locked_rect; + if (pTexture->LockRect(0, &tex_locked_rect, NULL, 0) != D3D_OK) + { + IM_ASSERT(0); + return; + } + 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)); + pTexture->UnlockRect(0); + + // Store our identifier + io.Fonts->TexID = (void *)pTexture; + g_FontTextureLoaded = true; +} + +bool ImGui_ImplDX9_Init(void* hwnd, IDirect3DDevice9* device, bool install_callbacks) +{ + g_pd3dDevice = device; + if (!QueryPerformanceFrequency((LARGE_INTEGER *)&g_TicksPerSecond)) + return false; + if (!QueryPerformanceCounter((LARGE_INTEGER *)&g_Time)) + return false; + + // FIXME + RECT rect; + GetClientRect((HWND)hwnd, &rect); + int display_w = (int)(rect.right - rect.left); + int display_h = (int)(rect.bottom - rect.top); + + ImGuiIO& io = ImGui::GetIO(); + io.DisplaySize = ImVec2((float)display_w, (float)display_h); // Display size, in pixels. For clamping windows positions. + io.KeyMap[ImGuiKey_Tab] = VK_TAB; // Keyboard mapping. ImGui will use those indices to peek into the io.KeyDown[] array that we will update during the application lifetime. + io.KeyMap[ImGuiKey_LeftArrow] = VK_LEFT; + io.KeyMap[ImGuiKey_RightArrow] = VK_RIGHT; + io.KeyMap[ImGuiKey_UpArrow] = VK_UP; + io.KeyMap[ImGuiKey_DownArrow] = VK_UP; + io.KeyMap[ImGuiKey_Home] = VK_HOME; + io.KeyMap[ImGuiKey_End] = VK_END; + io.KeyMap[ImGuiKey_Delete] = VK_DELETE; + io.KeyMap[ImGuiKey_Backspace] = VK_BACK; + io.KeyMap[ImGuiKey_Enter] = VK_RETURN; + io.KeyMap[ImGuiKey_Escape] = VK_ESCAPE; + 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'; + + io.RenderDrawListsFn = ImGui_ImplDX9_RenderDrawLists; + io.ImeWindowHandle = hwnd; + + // Create the vertex buffer + if (g_pd3dDevice->CreateVertexBuffer(10000 * sizeof(CUSTOMVERTEX), D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY, D3DFVF_CUSTOMVERTEX, D3DPOOL_DEFAULT, &g_pVB, NULL) < 0) + return false; + + return true; +} + +void ImGui_ImplDX9_Shutdown() +{ + if (g_pVB) + { + g_pVB->Release(); + g_pVB = NULL; + } + if (LPDIRECT3DTEXTURE9 tex = (LPDIRECT3DTEXTURE9)ImGui::GetIO().Fonts->TexID) + { + tex->Release(); + ImGui::GetIO().Fonts->TexID = 0; + } + + ImGui::Shutdown(); +} + +void ImGui_ImplDX9_NewFrame() +{ + if (!g_FontTextureLoaded) + ImGui_ImplDX9_InitFontsTexture(); + + ImGuiIO& io = ImGui::GetIO(); + + // Setup time step + INT64 current_time; + 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.KeysDown : filled by WM_KEYDOWN/WM_KEYUP events + // io.MousePos : filled by WM_MOUSEMOVE events + // io.MouseDown : filled by WM_*BUTTON* events + // io.MouseWheel : filled by WM_MOUSEWHEEL events + + // Start the frame + ImGui::NewFrame(); +} diff --git a/examples/directx9_example/imgui_impl_dx9.h b/examples/directx9_example/imgui_impl_dx9.h new file mode 100644 index 00000000..327ec25d --- /dev/null +++ b/examples/directx9_example/imgui_impl_dx9.h @@ -0,0 +1,16 @@ +// ImGui Win32 + DirectX9 binding +// https://github.com/ocornut/imgui + +struct IDirect3DDevice9; + +bool ImGui_ImplDX9_Init(void* hwnd, IDirect3DDevice9* device, bool install_callbacks); +void ImGui_ImplDX9_InitFontsTexture(); +void ImGui_ImplDX9_Shutdown(); +void ImGui_ImplDX9_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. +// Commented out to avoid dragging dependencies on types. You can copy the extern declaration in your code. +/* +extern LRESULT ImGui_ImplDX9_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); +*/ diff --git a/examples/directx9_example/main.cpp b/examples/directx9_example/main.cpp index 4b73328c..6bfd91e7 100644 --- a/examples/directx9_example/main.cpp +++ b/examples/directx9_example/main.cpp @@ -1,112 +1,44 @@ // ImGui - standalone example application for DirectX 9 +// TODO: Allow resizing the application window. #include -#include "../../imgui.h" - -// DirectX 9 +#include +#include "imgui_impl_dx9.h" #include #define DIRECTINPUT_VERSION 0x0800 #include -#pragma warning (disable: 4996) // 'This function or variable may be unsafe': strdup - -static HWND hWnd; -static LPDIRECT3D9 g_pD3D = NULL; // Used to create the D3DDevice -static LPDIRECT3DDEVICE9 g_pd3dDevice = NULL; // Our rendering device -static LPDIRECT3DVERTEXBUFFER9 g_pVB = NULL; // Buffer to hold vertices -struct CUSTOMVERTEX -{ - D3DXVECTOR3 pos; - D3DCOLOR col; - D3DXVECTOR2 uv; -}; -#define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZ|D3DFVF_DIFFUSE|D3DFVF_TEX1) - -// This is the main rendering function that you have to implement and provide to ImGui (via setting up 'RenderDrawListsFn' in the ImGuiIO structure) -// If text or lines are blurry when integrating ImGui in your engine: -// - in your Render function, try translating your projection matrix by (0.5f,0.5f) or (0.375f,0.375f) -static void ImImpl_RenderDrawLists(ImDrawList** const cmd_lists, int cmd_lists_count) +extern LRESULT ImGui_ImplDX9_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); +LRESULT WINAPI WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { - size_t total_vtx_count = 0; - for (int n = 0; n < cmd_lists_count; n++) - total_vtx_count += cmd_lists[n]->vtx_buffer.size(); - if (total_vtx_count == 0) - return; + if (ImGui_ImplDX9_WndProcHandler(hWnd, msg, wParam, lParam)) + return true; - // Copy and convert all vertices into a single contiguous buffer - CUSTOMVERTEX* vtx_dst; - if (g_pVB->Lock(0, (UINT)total_vtx_count, (void**)&vtx_dst, D3DLOCK_DISCARD) < 0) - return; - for (int n = 0; n < cmd_lists_count; n++) + switch (msg) { - const ImDrawList* cmd_list = cmd_lists[n]; - const ImDrawVert* vtx_src = &cmd_list->vtx_buffer[0]; - for (size_t i = 0; i < cmd_list->vtx_buffer.size(); i++) - { - vtx_dst->pos.x = vtx_src->pos.x; - vtx_dst->pos.y = vtx_src->pos.y; - vtx_dst->pos.z = 0.0f; - vtx_dst->col = (vtx_src->col & 0xFF00FF00) | ((vtx_src->col & 0xFF0000)>>16) | ((vtx_src->col & 0xFF) << 16); // RGBA --> ARGB for DirectX9 - vtx_dst->uv.x = vtx_src->uv.x; - vtx_dst->uv.y = vtx_src->uv.y; - vtx_dst++; - vtx_src++; - } + case WM_DESTROY: + PostQuitMessage(0); + return 0; } - g_pVB->Unlock(); - - g_pd3dDevice->SetStreamSource( 0, g_pVB, 0, sizeof( CUSTOMVERTEX ) ); - g_pd3dDevice->SetFVF( D3DFVF_CUSTOMVERTEX ); + return DefWindowProc(hWnd, msg, wParam, lParam); +} - // Setup render state: alpha-blending, no face culling, no depth testing - g_pd3dDevice->SetRenderState( D3DRS_CULLMODE, D3DCULL_NONE ); - g_pd3dDevice->SetRenderState( D3DRS_LIGHTING, false ); - g_pd3dDevice->SetRenderState( D3DRS_ZENABLE, false ); - g_pd3dDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, true ); - g_pd3dDevice->SetRenderState( D3DRS_BLENDOP, D3DBLENDOP_ADD ); - g_pd3dDevice->SetRenderState( D3DRS_ALPHATESTENABLE, false ); - g_pd3dDevice->SetRenderState( D3DRS_SRCBLEND, D3DBLEND_SRCALPHA ); - g_pd3dDevice->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA ); - g_pd3dDevice->SetRenderState( D3DRS_SCISSORTESTENABLE, true ); - g_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_SELECTARG1 ); - g_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_DIFFUSE ); - g_pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAOP, D3DTOP_MODULATE ); - g_pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE ); - g_pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE ); - g_pd3dDevice->SetSamplerState( 0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR ); - g_pd3dDevice->SetSamplerState( 0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR ); +int main(int argc, char** argv) +{ + // Register the window class + WNDCLASSEX wc = { sizeof(WNDCLASSEX), CS_CLASSDC, WndProc, 0L, 0L, GetModuleHandle(NULL), NULL, LoadCursor(NULL, IDC_ARROW), NULL, NULL, L"ImGui Example", NULL }; + RegisterClassEx(&wc); - // Setup orthographic projection matrix - D3DXMATRIXA16 mat; - D3DXMatrixIdentity(&mat); - g_pd3dDevice->SetTransform(D3DTS_WORLD, &mat); - g_pd3dDevice->SetTransform(D3DTS_VIEW, &mat); - D3DXMatrixOrthoOffCenterLH(&mat, 0.5f, ImGui::GetIO().DisplaySize.x+0.5f, ImGui::GetIO().DisplaySize.y+0.5f, 0.5f, -1.0f, +1.0f); - g_pd3dDevice->SetTransform(D3DTS_PROJECTION, &mat); + // Create the application's window + HWND hwnd = CreateWindow(L"ImGui Example", L"ImGui DirectX9 Example", WS_OVERLAPPEDWINDOW, 100, 100, 1280, 800, NULL, NULL, wc.hInstance, NULL); - // Render command lists - int vtx_offset = 0; - for (int n = 0; n < cmd_lists_count; n++) + // Initialize Direct3D + LPDIRECT3D9 pD3D; + if ((pD3D = Direct3DCreate9(D3D_SDK_VERSION)) == NULL) { - // Render command list - const ImDrawList* cmd_list = cmd_lists[n]; - for (size_t cmd_i = 0; cmd_i < cmd_list->commands.size(); cmd_i++) - { - const ImDrawCmd* pcmd = &cmd_list->commands[cmd_i]; - const RECT r = { (LONG)pcmd->clip_rect.x, (LONG)pcmd->clip_rect.y, (LONG)pcmd->clip_rect.z, (LONG)pcmd->clip_rect.w }; - g_pd3dDevice->SetTexture( 0, (LPDIRECT3DTEXTURE9)pcmd->texture_id ); - g_pd3dDevice->SetScissorRect(&r); - g_pd3dDevice->DrawPrimitive(D3DPT_TRIANGLELIST, vtx_offset, pcmd->vtx_count/3); - vtx_offset += pcmd->vtx_count; - } + UnregisterClass(L"ImGui Example", wc.hInstance); + return 0; } -} - -HRESULT InitDeviceD3D(HWND hWnd) -{ - if (NULL == (g_pD3D = Direct3DCreate9(D3D_SDK_VERSION))) - return E_FAIL; - D3DPRESENT_PARAMETERS d3dpp; ZeroMemory(&d3dpp, sizeof(d3dpp)); d3dpp.Windowed = TRUE; @@ -117,207 +49,32 @@ HRESULT InitDeviceD3D(HWND hWnd) d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE; // Create the D3DDevice - if (g_pD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd, D3DCREATE_HARDWARE_VERTEXPROCESSING, &d3dpp, &g_pd3dDevice) < 0) - return E_FAIL; - - return S_OK; -} - -void CleanupDevice() -{ - // InitImGui - if (g_pVB) g_pVB->Release(); - - // InitDeviceD3D - if (LPDIRECT3DTEXTURE9 tex = (LPDIRECT3DTEXTURE9)ImGui::GetIO().Fonts->TexID) - tex->Release(); - if (g_pd3dDevice) g_pd3dDevice->Release(); - if (g_pD3D) g_pD3D->Release(); -} - -LRESULT WINAPI WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) -{ - ImGuiIO& io = ImGui::GetIO(); - switch (msg) + LPDIRECT3DDEVICE9 pd3dDevice = NULL; + if (pD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hwnd, D3DCREATE_HARDWARE_VERTEXPROCESSING, &d3dpp, &pd3dDevice) < 0) { - case WM_LBUTTONDOWN: - io.MouseDown[0] = true; - return true; - case WM_LBUTTONUP: - io.MouseDown[0] = false; - return true; - case WM_RBUTTONDOWN: - io.MouseDown[1] = true; - return true; - case WM_RBUTTONUP: - io.MouseDown[1] = false; - return true; - case WM_MOUSEWHEEL: - io.MouseWheel += GET_WHEEL_DELTA_WPARAM(wParam) > 0 ? +1.0f : -1.0f; - return true; - case WM_MOUSEMOVE: - // Mouse position, in pixels (set to -1,-1 if no mouse / on another screen, etc.) - io.MousePos.x = (signed short)(lParam); - io.MousePos.y = (signed short)(lParam >> 16); - return true; - case WM_KEYDOWN: - if (wParam >= 0 && wParam < 256) - io.KeysDown[wParam] = 1; - return true; - case WM_KEYUP: - if (wParam >= 0 && wParam < 256) - io.KeysDown[wParam] = 0; - return true; - case WM_CHAR: - // You can also use ToAscii()+GetKeyboardState() to retrieve characters. - if (wParam > 0 && wParam < 0x10000) - io.AddInputCharacter((unsigned short)wParam); - return true; - case WM_DESTROY: - CleanupDevice(); - PostQuitMessage(0); + pD3D->Release(); + UnregisterClass(L"ImGui Example", wc.hInstance); return 0; } - return DefWindowProc(hWnd, msg, wParam, lParam); -} -void LoadFontsTexture() -{ - // Load one or more font - ImGuiIO& io = ImGui::GetIO(); + ShowWindow(hwnd, SW_SHOWDEFAULT); + UpdateWindow(hwnd); + + // ImGui + ImGui_ImplDX9_Init(hwnd, pd3dDevice, true); + //ImGuiIO& io = ImGui::GetIO(); //ImFont* my_font1 = io.Fonts->AddFontDefault(); //ImFont* my_font2 = io.Fonts->AddFontFromFileTTF("extra_fonts/Karla-Regular.ttf", 15.0f); //ImFont* my_font3 = io.Fonts->AddFontFromFileTTF("extra_fonts/ProggyClean.ttf", 13.0f); my_font3->DisplayOffset.y += 1; //ImFont* my_font4 = io.Fonts->AddFontFromFileTTF("extra_fonts/ProggyTiny.ttf", 10.0f); my_font4->DisplayOffset.y += 1; //ImFont* my_font5 = io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf", 18.0f, io.Fonts->GetGlyphRangesJapanese()); - - // Build - unsigned char* pixels; - int width, height, bytes_per_pixel; - io.Fonts->GetTexDataAsAlpha8(&pixels, &width, &height, &bytes_per_pixel); - - // Create texture - LPDIRECT3DTEXTURE9 pTexture = NULL; - if (D3DXCreateTexture(g_pd3dDevice, width, height, 1, D3DUSAGE_DYNAMIC, D3DFMT_A8, D3DPOOL_DEFAULT, &pTexture) < 0) - { - IM_ASSERT(0); - return; - } - - // Copy pixels - D3DLOCKED_RECT tex_locked_rect; - if (pTexture->LockRect(0, &tex_locked_rect, NULL, 0) != D3D_OK) - { - IM_ASSERT(0); - return; - } - 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)); - pTexture->UnlockRect(0); - - // Store our identifier - io.Fonts->TexID = (void *)pTexture; -} - -void InitImGui() -{ - RECT rect; - GetClientRect(hWnd, &rect); - int display_w = (int)(rect.right - rect.left); - int display_h = (int)(rect.bottom - rect.top); - - ImGuiIO& io = ImGui::GetIO(); - io.DisplaySize = ImVec2((float)display_w, (float)display_h); // Display size, in pixels. For clamping windows positions. - io.DeltaTime = 1.0f/60.0f; // Time elapsed since last frame, in seconds (in this sample app we'll override this every frame because our time step is variable) - io.KeyMap[ImGuiKey_Tab] = VK_TAB; // Keyboard mapping. ImGui will use those indices to peek into the io.KeyDown[] array that we will update during the application lifetime. - io.KeyMap[ImGuiKey_LeftArrow] = VK_LEFT; - io.KeyMap[ImGuiKey_RightArrow] = VK_RIGHT; - io.KeyMap[ImGuiKey_UpArrow] = VK_UP; - io.KeyMap[ImGuiKey_DownArrow] = VK_UP; - io.KeyMap[ImGuiKey_Home] = VK_HOME; - io.KeyMap[ImGuiKey_End] = VK_END; - io.KeyMap[ImGuiKey_Delete] = VK_DELETE; - io.KeyMap[ImGuiKey_Backspace] = VK_BACK; - io.KeyMap[ImGuiKey_Enter] = VK_RETURN; - io.KeyMap[ImGuiKey_Escape] = VK_ESCAPE; - 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'; - - io.RenderDrawListsFn = ImImpl_RenderDrawLists; - io.ImeWindowHandle = hWnd; - - // Create the vertex buffer - if (g_pd3dDevice->CreateVertexBuffer(10000 * sizeof(CUSTOMVERTEX), D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY, D3DFVF_CUSTOMVERTEX, D3DPOOL_DEFAULT, &g_pVB, NULL) < 0) - { - IM_ASSERT(0); - return; - } - - LoadFontsTexture(); -} - -INT64 ticks_per_second = 0; -INT64 last_time = 0; - -void UpdateImGui() -{ - ImGuiIO& io = ImGui::GetIO(); - - // Setup time step - INT64 current_time; - QueryPerformanceCounter((LARGE_INTEGER *)¤t_time); - io.DeltaTime = (float)(current_time - last_time) / ticks_per_second; - last_time = current_time; - - // Read keyboard modifiers inputs - io.KeyCtrl = (GetKeyState(VK_CONTROL) & 0x8000) != 0; - io.KeyShift = (GetKeyState(VK_SHIFT) & 0x8000) != 0; - // io.KeysDown : filled by WM_KEYDOWN/WM_KEYUP events - // io.MousePos : filled by WM_MOUSEMOVE events - // io.MouseDown : filled by WM_*BUTTON* events - // io.MouseWheel : filled by WM_MOUSEWHEEL events - - // Start the frame - ImGui::NewFrame(); -} - -int main(int argc, char** argv) -{ - // Register the window class - WNDCLASSEX wc = { sizeof(WNDCLASSEX), CS_CLASSDC, WndProc, 0L, 0L, GetModuleHandle(NULL), NULL, LoadCursor(NULL, IDC_ARROW), NULL, NULL, L"ImGui Example", NULL }; - RegisterClassEx(&wc); - - // Create the application's window - hWnd = CreateWindow(L"ImGui Example", L"ImGui DirectX9 Example", WS_OVERLAPPEDWINDOW, 100, 100, 1280, 800, NULL, NULL, wc.hInstance, NULL); - - if (!QueryPerformanceFrequency((LARGE_INTEGER *)&ticks_per_second)) - return 1; - if (!QueryPerformanceCounter((LARGE_INTEGER *)&last_time)) - return 1; - - // Initialize Direct3D - if (InitDeviceD3D(hWnd) < 0) - { - CleanupDevice(); - UnregisterClass(L"ImGui Example", wc.hInstance); - return 1; - } - - // Show the window - ShowWindow(hWnd, SW_SHOWDEFAULT); - UpdateWindow(hWnd); - - InitImGui(); + ImGui_ImplDX9_InitFontsTexture(); bool show_test_window = true; bool show_another_window = false; ImVec4 clear_col = ImColor(114, 144, 154); - // Enter the message loop + // Main loop MSG msg; ZeroMemory(&msg, sizeof(msg)); while (msg.message != WM_QUIT) @@ -328,7 +85,7 @@ int main(int argc, char** argv) DispatchMessage(&msg); continue; } - UpdateImGui(); + ImGui_ImplDX9_NewFrame(); // 1. Show a simple window // Tip: if we don't call ImGui::Begin()/ImGui::End() the widgets appears in a window automatically called "Debug" @@ -358,21 +115,24 @@ int main(int argc, char** argv) } // Rendering - g_pd3dDevice->SetRenderState(D3DRS_ZENABLE, false); - g_pd3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, false); - g_pd3dDevice->SetRenderState(D3DRS_SCISSORTESTENABLE, false); + pd3dDevice->SetRenderState(D3DRS_ZENABLE, false); + pd3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, false); + pd3dDevice->SetRenderState(D3DRS_SCISSORTESTENABLE, false); D3DCOLOR clear_col_dx = D3DCOLOR_RGBA((int)(clear_col.x*255.0f), (int)(clear_col.y*255.0f), (int)(clear_col.z*255.0f), (int)(clear_col.w*255.0f)); - g_pd3dDevice->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, clear_col_dx, 1.0f, 0); - if (g_pd3dDevice->BeginScene() >= 0) + pd3dDevice->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, clear_col_dx, 1.0f, 0); + if (pd3dDevice->BeginScene() >= 0) { ImGui::Render(); - g_pd3dDevice->EndScene(); + pd3dDevice->EndScene(); } - g_pd3dDevice->Present(NULL, NULL, NULL, NULL); + pd3dDevice->Present(NULL, NULL, NULL, NULL); } - ImGui::Shutdown(); + ImGui_ImplDX9_Shutdown(); + if (pd3dDevice) pd3dDevice->Release(); + if (pD3D) pD3D->Release(); UnregisterClass(L"ImGui Example", wc.hInstance); + return 0; } From a3f3793cb628797dbed48600f6bf80b8fd749326 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 9 Mar 2015 13:05:18 +0000 Subject: [PATCH 36/48] Examples: Tweaks. --- examples/directx9_example/imgui_impl_dx9.cpp | 2 +- examples/directx9_example/imgui_impl_dx9.h | 2 +- examples/directx9_example/main.cpp | 2 +- examples/opengl3_example/imgui_impl_glfw_gl3.h | 3 ++- examples/opengl_example/imgui_impl_glfw.h | 3 ++- 5 files changed, 7 insertions(+), 5 deletions(-) diff --git a/examples/directx9_example/imgui_impl_dx9.cpp b/examples/directx9_example/imgui_impl_dx9.cpp index 9e0a342f..370bcb12 100644 --- a/examples/directx9_example/imgui_impl_dx9.cpp +++ b/examples/directx9_example/imgui_impl_dx9.cpp @@ -176,7 +176,7 @@ void ImGui_ImplDX9_InitFontsTexture() g_FontTextureLoaded = true; } -bool ImGui_ImplDX9_Init(void* hwnd, IDirect3DDevice9* device, bool install_callbacks) +bool ImGui_ImplDX9_Init(void* hwnd, IDirect3DDevice9* device) { g_pd3dDevice = device; if (!QueryPerformanceFrequency((LARGE_INTEGER *)&g_TicksPerSecond)) diff --git a/examples/directx9_example/imgui_impl_dx9.h b/examples/directx9_example/imgui_impl_dx9.h index 327ec25d..6574e3f7 100644 --- a/examples/directx9_example/imgui_impl_dx9.h +++ b/examples/directx9_example/imgui_impl_dx9.h @@ -3,7 +3,7 @@ struct IDirect3DDevice9; -bool ImGui_ImplDX9_Init(void* hwnd, IDirect3DDevice9* device, bool install_callbacks); +bool ImGui_ImplDX9_Init(void* hwnd, IDirect3DDevice9* device); void ImGui_ImplDX9_InitFontsTexture(); void ImGui_ImplDX9_Shutdown(); void ImGui_ImplDX9_NewFrame(); diff --git a/examples/directx9_example/main.cpp b/examples/directx9_example/main.cpp index 6bfd91e7..65069805 100644 --- a/examples/directx9_example/main.cpp +++ b/examples/directx9_example/main.cpp @@ -61,7 +61,7 @@ int main(int argc, char** argv) UpdateWindow(hwnd); // ImGui - ImGui_ImplDX9_Init(hwnd, pd3dDevice, true); + ImGui_ImplDX9_Init(hwnd, pd3dDevice); //ImGuiIO& io = ImGui::GetIO(); //ImFont* my_font1 = io.Fonts->AddFontDefault(); //ImFont* my_font2 = io.Fonts->AddFontFromFileTTF("extra_fonts/Karla-Regular.ttf", 15.0f); diff --git a/examples/opengl3_example/imgui_impl_glfw_gl3.h b/examples/opengl3_example/imgui_impl_glfw_gl3.h index d3d1d817..16d5d532 100644 --- a/examples/opengl3_example/imgui_impl_glfw_gl3.h +++ b/examples/opengl3_example/imgui_impl_glfw_gl3.h @@ -9,7 +9,8 @@ void ImGui_ImplGlfwGL3_Shutdown(); void ImGui_ImplGlfwGL3_NewFrame(); // GLFW callbacks (installed by default if you enable 'install_callbacks' during initialization) -// Provide here if you want to chain callbacks +// Provided here if you want to chain callbacks. +// You can also handle inputs yourself and use those as a reference. void ImGui_ImplGlfwGL3_MouseButtonCallback(GLFWwindow* window, int button, int action, int mods); void ImGui_ImplGlfwGL3_ScrollCallback(GLFWwindow* window, double xoffset, double yoffset); void ImGui_ImplGlFwGL3_KeyCallback(GLFWwindow* window, int key, int scancode, int action, int mods); diff --git a/examples/opengl_example/imgui_impl_glfw.h b/examples/opengl_example/imgui_impl_glfw.h index 455b542a..53909fa6 100644 --- a/examples/opengl_example/imgui_impl_glfw.h +++ b/examples/opengl_example/imgui_impl_glfw.h @@ -9,7 +9,8 @@ void ImGui_ImplGlfw_Shutdown(); void ImGui_ImplGlfw_NewFrame(); // GLFW callbacks (installed by default if you enable 'install_callbacks' during initialization) -// Provide here if you want to chain callbacks +// Provided here if you want to chain callbacks. +// You can also handle inputs yourself and use those as a reference. void ImGui_ImplGlfw_MouseButtonCallback(GLFWwindow* window, int button, int action, int mods); void ImGui_ImplGlfw_ScrollCallback(GLFWwindow* window, double xoffset, double yoffset); void ImGui_ImplGlFw_KeyCallback(GLFWwindow* window, int key, int scancode, int action, int mods); From 2dd92e3eed4f4ffb833808261cf255e45b3414cf Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 9 Mar 2015 13:08:27 +0000 Subject: [PATCH 37/48] Examples: Clang/Linux warning fixes. --- examples/opengl3_example/main.cpp | 2 +- examples/opengl_example/imgui_impl_glfw.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/opengl3_example/main.cpp b/examples/opengl3_example/main.cpp index 16d3a716..d773ec3d 100644 --- a/examples/opengl3_example/main.cpp +++ b/examples/opengl3_example/main.cpp @@ -1,7 +1,7 @@ // ImGui - standalone example application for Glfw + OpenGL 3, using programmable pipeline #include -#include "imgui_impl_glfw_GL3.h" +#include "imgui_impl_glfw_gl3.h" #include #include #include diff --git a/examples/opengl_example/imgui_impl_glfw.cpp b/examples/opengl_example/imgui_impl_glfw.cpp index 6bf07d8a..aa7de29b 100644 --- a/examples/opengl_example/imgui_impl_glfw.cpp +++ b/examples/opengl_example/imgui_impl_glfw.cpp @@ -189,7 +189,7 @@ bool ImGui_ImplGlfw_Init(GLFWwindow* window, bool install_callbacks) void ImGui_ImplGlfw_Shutdown() { - if (GLuint tex_id = (GLuint)ImGui::GetIO().Fonts->TexID) + if (GLuint tex_id = (GLuint)(intptr_t)ImGui::GetIO().Fonts->TexID) { glDeleteTextures(1, &tex_id); ImGui::GetIO().Fonts->TexID = 0; From 3f86554457befcb7e3f8fee92c168cc5b57b3f97 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 9 Mar 2015 13:22:32 +0000 Subject: [PATCH 38/48] Examples: Makefile fixes. --- examples/opengl3_example/Makefile | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/examples/opengl3_example/Makefile b/examples/opengl3_example/Makefile index c67ff83b..208d279f 100644 --- a/examples/opengl3_example/Makefile +++ b/examples/opengl3_example/Makefile @@ -10,9 +10,8 @@ #CXX = g++ -OBJS = main.o imgui_impl_glfw_gl3.o +OBJS = main.o imgui_impl_glfw_gl3.o gl3w/GL/gl3w.o OBJS += ../../imgui.o -OBJS += ../opengl_example/gl3w/GL/gl3w.o UNAME_S := $(shell uname -s) @@ -21,7 +20,7 @@ ifeq ($(UNAME_S), Linux) #LINUX ECHO_MESSAGE = "Linux" LIBS = `pkg-config --static --libs glfw3` - CXXFLAGS = -I../../ -I../opengl_example/gl3w `pkg-config --cflags glfw3` + CXXFLAGS = -I../../ -Igl3w `pkg-config --cflags glfw3` CXXFLAGS += -Wall CFLAGS = $(CXXFLAGS) endif @@ -32,7 +31,7 @@ ifeq ($(UNAME_S), Darwin) #APPLE LIBS += -L/usr/local/lib LIBS += -lglfw3 - CXXFLAGS = -I../../ -I../opengl_example/gl3w -I/usr/local/Cellar/glew/1.10.0/include -I/usr/local/include + CXXFLAGS = -I../../ -Igl3w -I/usr/local/Cellar/glew/1.10.0/include -I/usr/local/include CXXFLAGS += -Wall # CXXFLAGS += -D__APPLE__ CFLAGS = $(CXXFLAGS) From 567184dc9fd6376511449577105859eb8303fea7 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 9 Mar 2015 13:38:23 +0000 Subject: [PATCH 39/48] Examples: Clang warning fix. --- examples/opengl3_example/imgui_impl_glfw_gl3.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/examples/opengl3_example/imgui_impl_glfw_gl3.cpp b/examples/opengl3_example/imgui_impl_glfw_gl3.cpp index cbe9f60c..92def5ed 100644 --- a/examples/opengl3_example/imgui_impl_glfw_gl3.cpp +++ b/examples/opengl3_example/imgui_impl_glfw_gl3.cpp @@ -233,9 +233,8 @@ static void InitGL() bool ImGui_ImplGlfwGL3_Init(GLFWwindow* window, bool install_callbacks) { - InitGL(); - g_Window = window; + InitGL(); ImGuiIO& io = ImGui::GetIO(); io.KeyMap[ImGuiKey_Tab] = GLFW_KEY_TAB; // Keyboard mapping. ImGui will use those indices to peek into the io.KeyDown[] array. @@ -292,7 +291,7 @@ void ImGui_ImplGlfwGL3_Shutdown() glDeleteProgram(g_ShaderHandle); g_ShaderHandle = 0; - if (GLuint tex_id = (GLuint)ImGui::GetIO().Fonts->TexID) + if (GLuint tex_id = (GLuint)(intptr_t)ImGui::GetIO().Fonts->TexID) { glDeleteTextures(1, &tex_id); ImGui::GetIO().Fonts->TexID = 0; From b4165c43ff4962e4cfc781987eebdf15ffb74c95 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 9 Mar 2015 13:45:23 +0000 Subject: [PATCH 40/48] Examples: Refactored directx11_example to be easier to copy & paste into user application. --- .../directx11_example.vcxproj | 6 +- .../directx11_example.vcxproj.filters | 6 + .../directx11_example/imgui_impl_dx11.cpp | 447 ++++++++++++++++ examples/directx11_example/imgui_impl_dx11.h | 17 + examples/directx11_example/main.cpp | 484 ++---------------- examples/directx9_example/imgui_impl_dx9.cpp | 3 +- examples/directx9_example/main.cpp | 8 +- 7 files changed, 512 insertions(+), 459 deletions(-) create mode 100644 examples/directx11_example/imgui_impl_dx11.cpp create mode 100644 examples/directx11_example/imgui_impl_dx11.h diff --git a/examples/directx11_example/directx11_example.vcxproj b/examples/directx11_example/directx11_example.vcxproj index ec95e4ab..beddb330 100644 --- a/examples/directx11_example/directx11_example.vcxproj +++ b/examples/directx11_example/directx11_example.vcxproj @@ -48,7 +48,7 @@ Level3 Disabled - $(DXSDK_DIR)/Include;%(AdditionalIncludeDirectories) + ..\..;$(DXSDK_DIR)/Include;%(AdditionalIncludeDirectories) true @@ -63,7 +63,7 @@ MaxSpeed true true - $(DXSDK_DIR)/Include;%(AdditionalIncludeDirectories) + ..\..;$(DXSDK_DIR)/Include;%(AdditionalIncludeDirectories) true @@ -77,9 +77,11 @@ + + diff --git a/examples/directx11_example/directx11_example.vcxproj.filters b/examples/directx11_example/directx11_example.vcxproj.filters index ab9c654e..fca4dcfd 100644 --- a/examples/directx11_example/directx11_example.vcxproj.filters +++ b/examples/directx11_example/directx11_example.vcxproj.filters @@ -15,6 +15,9 @@ imgui + + sources + @@ -23,5 +26,8 @@ sources + + sources + \ No newline at end of file diff --git a/examples/directx11_example/imgui_impl_dx11.cpp b/examples/directx11_example/imgui_impl_dx11.cpp new file mode 100644 index 00000000..bc693a47 --- /dev/null +++ b/examples/directx11_example/imgui_impl_dx11.cpp @@ -0,0 +1,447 @@ +// ImGui Win32 + DirectX11 binding +// https://github.com/ocornut/imgui + +#include +#include "imgui_impl_dx11.h" + +// DirectX +#include +#include +#define DIRECTINPUT_VERSION 0x0800 +#include + +// Data +static INT64 g_Time = 0; +static INT64 g_TicksPerSecond = 0; +static bool g_FontTextureLoaded = false; + +static ID3D11Device* g_pd3dDevice = NULL; +static ID3D11DeviceContext* g_pd3dDeviceContext = NULL; +static ID3D11Buffer* g_pVB = NULL; +static ID3D10Blob * g_pVertexShaderBlob = NULL; +static ID3D11VertexShader* g_pVertexShader = NULL; +static ID3D11InputLayout* g_pInputLayout = NULL; +static ID3D11Buffer* g_pVertexConstantBuffer = NULL; +static ID3D10Blob * g_pPixelShaderBlob = NULL; +static ID3D11PixelShader* g_pPixelShader = NULL; +static ID3D11SamplerState* g_pFontSampler = NULL; +static ID3D11BlendState* g_blendState = NULL; + +struct CUSTOMVERTEX +{ + float pos[2]; + float uv[2]; + unsigned int col; +}; + +struct VERTEX_CONSTANT_BUFFER +{ + float mvp[4][4]; +}; + +// This is the main rendering function that you have to implement and provide to ImGui (via setting up 'RenderDrawListsFn' in the ImGuiIO structure) +// If text or lines are blurry when integrating ImGui in your engine: +// - in your Render function, try translating your projection matrix by (0.5f,0.5f) or (0.375f,0.375f) +static void ImGui_ImplDX11_RenderDrawLists(ImDrawList** const cmd_lists, int cmd_lists_count) +{ + // Copy and convert all vertices into a single contiguous buffer + D3D11_MAPPED_SUBRESOURCE mappedResource; + if (g_pd3dDeviceContext->Map(g_pVB, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource) != S_OK) + return; + CUSTOMVERTEX* vtx_dst = (CUSTOMVERTEX*)mappedResource.pData; + for (int n = 0; n < cmd_lists_count; n++) + { + const ImDrawList* cmd_list = cmd_lists[n]; + const ImDrawVert* vtx_src = &cmd_list->vtx_buffer[0]; + for (size_t i = 0; i < cmd_list->vtx_buffer.size(); i++) + { + vtx_dst->pos[0] = vtx_src->pos.x; + vtx_dst->pos[1] = vtx_src->pos.y; + vtx_dst->uv[0] = vtx_src->uv.x; + vtx_dst->uv[1] = vtx_src->uv.y; + vtx_dst->col = vtx_src->col; + vtx_dst++; + vtx_src++; + } + } + g_pd3dDeviceContext->Unmap(g_pVB, 0); + + // Setup orthographic projection matrix into our constant buffer + { + D3D11_MAPPED_SUBRESOURCE mappedResource; + if (g_pd3dDeviceContext->Map(g_pVertexConstantBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource) != S_OK) + return; + + VERTEX_CONSTANT_BUFFER* pConstantBuffer = (VERTEX_CONSTANT_BUFFER*)mappedResource.pData; + const float L = 0.0f; + const float R = ImGui::GetIO().DisplaySize.x; + const float B = ImGui::GetIO().DisplaySize.y; + const float T = 0.0f; + const float mvp[4][4] = + { + { 2.0f/(R-L), 0.0f, 0.0f, 0.0f}, + { 0.0f, 2.0f/(T-B), 0.0f, 0.0f,}, + { 0.0f, 0.0f, 0.5f, 0.0f }, + { (R+L)/(L-R), (T+B)/(B-T), 0.5f, 1.0f }, + }; + memcpy(&pConstantBuffer->mvp, mvp, sizeof(mvp)); + g_pd3dDeviceContext->Unmap(g_pVertexConstantBuffer, 0); + } + + // Setup viewport + { + D3D11_VIEWPORT vp; + memset(&vp, 0, sizeof(D3D11_VIEWPORT)); + vp.Width = ImGui::GetIO().DisplaySize.x; + vp.Height = ImGui::GetIO().DisplaySize.y; + vp.MinDepth = 0.0f; + vp.MaxDepth = 1.0f; + vp.TopLeftX = 0; + vp.TopLeftY = 0; + g_pd3dDeviceContext->RSSetViewports(1, &vp); + } + + // Bind shader and vertex buffers + unsigned int stride = sizeof(CUSTOMVERTEX); + unsigned int offset = 0; + g_pd3dDeviceContext->IASetInputLayout(g_pInputLayout); + g_pd3dDeviceContext->IASetVertexBuffers(0, 1, &g_pVB, &stride, &offset); + g_pd3dDeviceContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); + g_pd3dDeviceContext->VSSetShader(g_pVertexShader, NULL, 0); + g_pd3dDeviceContext->VSSetConstantBuffers(0, 1, &g_pVertexConstantBuffer); + g_pd3dDeviceContext->PSSetShader(g_pPixelShader, NULL, 0); + g_pd3dDeviceContext->PSSetSamplers(0, 1, &g_pFontSampler); + + // Setup render state + const float blendFactor[4] = { 0.f, 0.f, 0.f, 0.f }; + g_pd3dDeviceContext->OMSetBlendState(g_blendState, blendFactor, 0xffffffff); + + // Render command lists + int vtx_offset = 0; + for (int n = 0; n < cmd_lists_count; n++) + { + const ImDrawList* cmd_list = cmd_lists[n]; + for (size_t cmd_i = 0; cmd_i < cmd_list->commands.size(); cmd_i++) + { + const ImDrawCmd* pcmd = &cmd_list->commands[cmd_i]; + const D3D11_RECT r = { (LONG)pcmd->clip_rect.x, (LONG)pcmd->clip_rect.y, (LONG)pcmd->clip_rect.z, (LONG)pcmd->clip_rect.w }; + g_pd3dDeviceContext->PSSetShaderResources(0, 1, (ID3D11ShaderResourceView**)&pcmd->texture_id); + g_pd3dDeviceContext->RSSetScissorRects(1, &r); + g_pd3dDeviceContext->Draw(pcmd->vtx_count, vtx_offset); + vtx_offset += pcmd->vtx_count; + } + } + + // Restore modified state + g_pd3dDeviceContext->IASetInputLayout(NULL); + g_pd3dDeviceContext->PSSetShader(NULL, NULL, 0); + g_pd3dDeviceContext->VSSetShader(NULL, NULL, 0); +} + +LRESULT ImGui_ImplDX11_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + ImGuiIO& io = ImGui::GetIO(); + switch (msg) + { + case WM_LBUTTONDOWN: + io.MouseDown[0] = true; + return true; + case WM_LBUTTONUP: + io.MouseDown[0] = false; + return true; + case WM_RBUTTONDOWN: + io.MouseDown[1] = true; + return true; + case WM_RBUTTONUP: + io.MouseDown[1] = false; + return true; + case WM_MOUSEWHEEL: + io.MouseWheel += GET_WHEEL_DELTA_WPARAM(wParam) > 0 ? +1.0f : -1.0f; + return true; + case WM_MOUSEMOVE: + io.MousePos.x = (signed short)(lParam); + io.MousePos.y = (signed short)(lParam >> 16); + return true; + case WM_KEYDOWN: + if (wParam >= 0 && wParam < 256) + io.KeysDown[wParam] = 1; + return true; + case WM_KEYUP: + if (wParam >= 0 && wParam < 256) + io.KeysDown[wParam] = 0; + return true; + case WM_CHAR: + // You can also use ToAscii()+GetKeyboardState() to retrieve characters. + if (wParam > 0 && wParam < 0x10000) + io.AddInputCharacter((unsigned short)wParam); + return true; + } + return 0; +} + +void ImGui_ImplDX11_InitFontsTexture() +{ + ImGuiIO& io = ImGui::GetIO(); + + // Build + unsigned char* pixels; + int width, height; + io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); + + // Create DX11 texture + D3D11_TEXTURE2D_DESC texDesc; + ZeroMemory(&texDesc, sizeof(texDesc)); + texDesc.Width = width; + texDesc.Height = height; + texDesc.MipLevels = 1; + texDesc.ArraySize = 1; + texDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; + texDesc.SampleDesc.Count = 1; + texDesc.Usage = D3D11_USAGE_DEFAULT; + texDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE; + texDesc.CPUAccessFlags = 0; + + ID3D11Texture2D *pTexture = NULL; + D3D11_SUBRESOURCE_DATA subResource; + subResource.pSysMem = pixels; + subResource.SysMemPitch = texDesc.Width * 4; + subResource.SysMemSlicePitch = 0; + g_pd3dDevice->CreateTexture2D(&texDesc, &subResource, &pTexture); + + // Create texture view + D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc; + ZeroMemory(&srvDesc, sizeof(srvDesc)); + srvDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; + srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D; + srvDesc.Texture2D.MipLevels = texDesc.MipLevels; + srvDesc.Texture2D.MostDetailedMip = 0; + ID3D11ShaderResourceView* font_texture_view = NULL; + g_pd3dDevice->CreateShaderResourceView(pTexture, &srvDesc, &font_texture_view); + pTexture->Release(); + + // Store our identifier + io.Fonts->TexID = (void *)font_texture_view; + + // Create texture sampler + D3D11_SAMPLER_DESC samplerDesc; + ZeroMemory(&samplerDesc, sizeof(samplerDesc)); + samplerDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR; + samplerDesc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP; + samplerDesc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP; + samplerDesc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP; + samplerDesc.MipLODBias = 0.f; + samplerDesc.ComparisonFunc = D3D11_COMPARISON_ALWAYS; + samplerDesc.MinLOD = 0.f; + samplerDesc.MaxLOD = 0.f; + g_pd3dDevice->CreateSamplerState(&samplerDesc, &g_pFontSampler); +} + +static bool InitDirect3DState() +{ + // Create the vertex shader + { + static const char* vertexShader = + "cbuffer vertexBuffer : register(c0) \ + {\ + float4x4 ProjectionMatrix; \ + };\ + struct VS_INPUT\ + {\ + float2 pos : POSITION;\ + float4 col : COLOR0;\ + float2 uv : TEXCOORD0;\ + };\ + \ + struct PS_INPUT\ + {\ + float4 pos : SV_POSITION;\ + float4 col : COLOR0;\ + float2 uv : TEXCOORD0;\ + };\ + \ + PS_INPUT main(VS_INPUT input)\ + {\ + PS_INPUT output;\ + output.pos = mul( ProjectionMatrix, float4(input.pos.xy, 0.f, 1.f));\ + output.col = input.col;\ + output.uv = input.uv;\ + return output;\ + }"; + + D3DCompile(vertexShader, strlen(vertexShader), NULL, NULL, NULL, "main", "vs_5_0", 0, 0, &g_pVertexShaderBlob, NULL); + if (g_pVertexShaderBlob == NULL) // NB: Pass ID3D10Blob* pErrorBlob to D3DCompile() to get error showing in (const char*)pErrorBlob->GetBufferPointer(). Make sure to Release() the blob! + return false; + if (g_pd3dDevice->CreateVertexShader((DWORD*)g_pVertexShaderBlob->GetBufferPointer(), g_pVertexShaderBlob->GetBufferSize(), NULL, &g_pVertexShader) != S_OK) + return false; + + // Create the input layout + D3D11_INPUT_ELEMENT_DESC localLayout[] = { + { "POSITION", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, (size_t)(&((CUSTOMVERTEX*)0)->pos), D3D11_INPUT_PER_VERTEX_DATA, 0 }, + { "COLOR", 0, DXGI_FORMAT_R8G8B8A8_UNORM, 0, (size_t)(&((CUSTOMVERTEX*)0)->col), D3D11_INPUT_PER_VERTEX_DATA, 0 }, + { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, (size_t)(&((CUSTOMVERTEX*)0)->uv), D3D11_INPUT_PER_VERTEX_DATA, 0 }, + }; + + if (g_pd3dDevice->CreateInputLayout(localLayout, 3, g_pVertexShaderBlob->GetBufferPointer(), g_pVertexShaderBlob->GetBufferSize(), &g_pInputLayout) != S_OK) + return false; + + // Create the constant buffer + { + D3D11_BUFFER_DESC cbDesc; + cbDesc.ByteWidth = sizeof(VERTEX_CONSTANT_BUFFER); + cbDesc.Usage = D3D11_USAGE_DYNAMIC; + cbDesc.BindFlags = D3D11_BIND_CONSTANT_BUFFER; + cbDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; + cbDesc.MiscFlags = 0; + g_pd3dDevice->CreateBuffer(&cbDesc, NULL, &g_pVertexConstantBuffer); + } + } + + // Create the pixel shader + { + static const char* pixelShader = + "struct PS_INPUT\ + {\ + float4 pos : SV_POSITION;\ + float4 col : COLOR0;\ + float2 uv : TEXCOORD0;\ + };\ + sampler sampler0;\ + Texture2D texture0;\ + \ + float4 main(PS_INPUT input) : SV_Target\ + {\ + float4 out_col = input.col * texture0.Sample(sampler0, input.uv); \ + return out_col; \ + }"; + + D3DCompile(pixelShader, strlen(pixelShader), NULL, NULL, NULL, "main", "ps_5_0", 0, 0, &g_pPixelShaderBlob, NULL); + if (g_pPixelShaderBlob == NULL) // NB: Pass ID3D10Blob* pErrorBlob to D3DCompile() to get error showing in (const char*)pErrorBlob->GetBufferPointer(). Make sure to Release() the blob! + return false; + if (g_pd3dDevice->CreatePixelShader((DWORD*)g_pPixelShaderBlob->GetBufferPointer(), g_pPixelShaderBlob->GetBufferSize(), NULL, &g_pPixelShader) != S_OK) + return false; + } + + // Create the blending setup + { + D3D11_BLEND_DESC desc; + ZeroMemory(&desc, sizeof(desc)); + desc.AlphaToCoverageEnable = false; + desc.RenderTarget[0].BlendEnable = true; + desc.RenderTarget[0].SrcBlend = D3D11_BLEND_SRC_ALPHA; + desc.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC_ALPHA; + desc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD; + desc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_INV_SRC_ALPHA; + desc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ZERO; + desc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD; + desc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL; + g_pd3dDevice->CreateBlendState(&desc, &g_blendState); + } + + // Create the vertex buffer + { + D3D11_BUFFER_DESC bufferDesc; + memset(&bufferDesc, 0, sizeof(D3D11_BUFFER_DESC)); + bufferDesc.Usage = D3D11_USAGE_DYNAMIC; + bufferDesc.ByteWidth = 100000 * sizeof(CUSTOMVERTEX); // Maybe we should handle that more dynamically? + bufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER; + bufferDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; + bufferDesc.MiscFlags = 0; + if (g_pd3dDevice->CreateBuffer(&bufferDesc, NULL, &g_pVB) < 0) + return false; + } + + return true; +} + +bool ImGui_ImplDX11_Init(void* hwnd, ID3D11Device* device, ID3D11DeviceContext* device_context) +{ + g_pd3dDevice = device; + g_pd3dDeviceContext = device_context; + + if (!InitDirect3DState()) + { + IM_ASSERT(0); + return false; + } + + if (!QueryPerformanceFrequency((LARGE_INTEGER *)&g_TicksPerSecond)) + return false; + if (!QueryPerformanceCounter((LARGE_INTEGER *)&g_Time)) + return false; + + // FIXME: resizing + RECT rect; + GetClientRect((HWND)hwnd, &rect); + int display_w = (int)(rect.right - rect.left); + int display_h = (int)(rect.bottom - rect.top); + + ImGuiIO& io = ImGui::GetIO(); + io.DisplaySize = ImVec2((float)display_w, (float)display_h); // Display size, in pixels. For clamping windows positions. + io.KeyMap[ImGuiKey_Tab] = VK_TAB; // Keyboard mapping. ImGui will use those indices to peek into the io.KeyDown[] array that we will update during the application lifetime. + io.KeyMap[ImGuiKey_LeftArrow] = VK_LEFT; + io.KeyMap[ImGuiKey_RightArrow] = VK_RIGHT; + io.KeyMap[ImGuiKey_UpArrow] = VK_UP; + io.KeyMap[ImGuiKey_DownArrow] = VK_UP; + io.KeyMap[ImGuiKey_Home] = VK_HOME; + io.KeyMap[ImGuiKey_End] = VK_END; + io.KeyMap[ImGuiKey_Delete] = VK_DELETE; + io.KeyMap[ImGuiKey_Backspace] = VK_BACK; + io.KeyMap[ImGuiKey_Enter] = VK_RETURN; + io.KeyMap[ImGuiKey_Escape] = VK_ESCAPE; + 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'; + + io.RenderDrawListsFn = ImGui_ImplDX11_RenderDrawLists; + io.ImeWindowHandle = hwnd; + + return true; +} + +void ImGui_ImplDX11_Shutdown() +{ + if (g_pd3dDeviceContext) g_pd3dDeviceContext->ClearState(); + + if (g_pFontSampler) g_pFontSampler->Release(); + if (ID3D11ShaderResourceView* font_texture_view = (ID3D11ShaderResourceView*)ImGui::GetIO().Fonts->TexID) + font_texture_view->Release(); + if (g_pVB) g_pVB->Release(); + + if (g_blendState) g_blendState->Release(); + if (g_pPixelShader) g_pPixelShader->Release(); + if (g_pPixelShaderBlob) g_pPixelShaderBlob->Release(); + if (g_pVertexConstantBuffer) g_pVertexConstantBuffer->Release(); + if (g_pInputLayout) g_pInputLayout->Release(); + if (g_pVertexShader) g_pVertexShader->Release(); + if (g_pVertexShaderBlob) g_pVertexShaderBlob->Release(); + + ImGui::Shutdown(); +} + +void ImGui_ImplDX11_NewFrame() +{ + if (!g_FontTextureLoaded) + ImGui_ImplDX11_InitFontsTexture(); + + ImGuiIO& io = ImGui::GetIO(); + + // Setup time step + INT64 current_time; + 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.KeysDown : filled by WM_KEYDOWN/WM_KEYUP events + // io.MousePos : filled by WM_MOUSEMOVE events + // io.MouseDown : filled by WM_*BUTTON* events + // io.MouseWheel : filled by WM_MOUSEWHEEL events + + // Start the frame + ImGui::NewFrame(); +} diff --git a/examples/directx11_example/imgui_impl_dx11.h b/examples/directx11_example/imgui_impl_dx11.h new file mode 100644 index 00000000..aa33edb2 --- /dev/null +++ b/examples/directx11_example/imgui_impl_dx11.h @@ -0,0 +1,17 @@ +// ImGui Win32 + DirectX11 binding +// https://github.com/ocornut/imgui + +struct ID3D11Device; +struct ID3D11DeviceContext; + +bool ImGui_ImplDX11_Init(void* hwnd, ID3D11Device* device, ID3D11DeviceContext* device_context); +void ImGui_ImplDX11_InitFontsTexture(); +void ImGui_ImplDX11_Shutdown(); +void ImGui_ImplDX11_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. +// Commented out to avoid dragging dependencies on types. You can copy the extern declaration in your code. +/* +extern LRESULT ImGui_ImplDX11_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); +*/ diff --git a/examples/directx11_example/main.cpp b/examples/directx11_example/main.cpp index a7f7a993..75c77064 100644 --- a/examples/directx11_example/main.cpp +++ b/examples/directx11_example/main.cpp @@ -1,147 +1,18 @@ // ImGui - standalone example application for DirectX 11 +// TODO: Allow resizing the application window. -#include -#include "../../imgui.h" - -// DirectX 11 +#include +#include "imgui_impl_dx11.h" #include #include #define DIRECTINPUT_VERSION 0x0800 #include -#pragma warning (disable: 4996) // 'This function or variable may be unsafe': strdup - -static HWND hWnd; +// Data static ID3D11Device* g_pd3dDevice = NULL; -static ID3D11DeviceContext* g_pd3dDeviceImmediateContext = NULL; +static ID3D11DeviceContext* g_pd3dDeviceContext = NULL; static IDXGISwapChain* g_pSwapChain = NULL; -static ID3D11Buffer* g_pVB = NULL; -static ID3D11RenderTargetView* g_mainRenderTargetView; - -static ID3D10Blob * g_pVertexShaderBlob = NULL; -static ID3D11VertexShader* g_pVertexShader = NULL; -static ID3D11InputLayout* g_pInputLayout = NULL; -static ID3D11Buffer* g_pVertexConstantBuffer = NULL; - -static ID3D10Blob * g_pPixelShaderBlob = NULL; -static ID3D11PixelShader* g_pPixelShader = NULL; - -static ID3D11SamplerState* g_pFontSampler = NULL; -static ID3D11BlendState* g_blendState = NULL; - -struct CUSTOMVERTEX -{ - float pos[2]; - float uv[2]; - unsigned int col; -}; - -struct VERTEX_CONSTANT_BUFFER -{ - float mvp[4][4]; -}; - -// This is the main rendering function that you have to implement and provide to ImGui (via setting up 'RenderDrawListsFn' in the ImGuiIO structure) -// If text or lines are blurry when integrating ImGui in your engine: -// - in your Render function, try translating your projection matrix by (0.5f,0.5f) or (0.375f,0.375f) -static void ImImpl_RenderDrawLists(ImDrawList** const cmd_lists, int cmd_lists_count) -{ - // Copy and convert all vertices into a single contiguous buffer - D3D11_MAPPED_SUBRESOURCE mappedResource; - if (g_pd3dDeviceImmediateContext->Map(g_pVB, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource) != S_OK) - return; - CUSTOMVERTEX* vtx_dst = (CUSTOMVERTEX*)mappedResource.pData; - for (int n = 0; n < cmd_lists_count; n++) - { - const ImDrawList* cmd_list = cmd_lists[n]; - const ImDrawVert* vtx_src = &cmd_list->vtx_buffer[0]; - for (size_t i = 0; i < cmd_list->vtx_buffer.size(); i++) - { - vtx_dst->pos[0] = vtx_src->pos.x; - vtx_dst->pos[1] = vtx_src->pos.y; - vtx_dst->uv[0] = vtx_src->uv.x; - vtx_dst->uv[1] = vtx_src->uv.y; - vtx_dst->col = vtx_src->col; - vtx_dst++; - vtx_src++; - } - } - g_pd3dDeviceImmediateContext->Unmap(g_pVB, 0); - - // Setup orthographic projection matrix into our constant buffer - { - D3D11_MAPPED_SUBRESOURCE mappedResource; - if (g_pd3dDeviceImmediateContext->Map(g_pVertexConstantBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource) != S_OK) - return; - - VERTEX_CONSTANT_BUFFER* pConstantBuffer = (VERTEX_CONSTANT_BUFFER*)mappedResource.pData; - const float L = 0.0f; - const float R = ImGui::GetIO().DisplaySize.x; - const float B = ImGui::GetIO().DisplaySize.y; - const float T = 0.0f; - const float mvp[4][4] = - { - { 2.0f/(R-L), 0.0f, 0.0f, 0.0f}, - { 0.0f, 2.0f/(T-B), 0.0f, 0.0f,}, - { 0.0f, 0.0f, 0.5f, 0.0f }, - { (R+L)/(L-R), (T+B)/(B-T), 0.5f, 1.0f }, - }; - memcpy(&pConstantBuffer->mvp, mvp, sizeof(mvp)); - g_pd3dDeviceImmediateContext->Unmap(g_pVertexConstantBuffer, 0); - } - - // Setup viewport - { - D3D11_VIEWPORT vp; - memset(&vp, 0, sizeof(D3D11_VIEWPORT)); - vp.Width = ImGui::GetIO().DisplaySize.x; - vp.Height = ImGui::GetIO().DisplaySize.y; - vp.MinDepth = 0.0f; - vp.MaxDepth = 1.0f; - vp.TopLeftX = 0; - vp.TopLeftY = 0; - g_pd3dDeviceImmediateContext->RSSetViewports(1, &vp); - } - - // Bind shader and vertex buffers - unsigned int stride = sizeof(CUSTOMVERTEX); - unsigned int offset = 0; - g_pd3dDeviceImmediateContext->IASetInputLayout(g_pInputLayout); - g_pd3dDeviceImmediateContext->IASetVertexBuffers(0, 1, &g_pVB, &stride, &offset); - g_pd3dDeviceImmediateContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); - - g_pd3dDeviceImmediateContext->VSSetShader(g_pVertexShader, NULL, 0); - g_pd3dDeviceImmediateContext->VSSetConstantBuffers(0, 1, &g_pVertexConstantBuffer); - - g_pd3dDeviceImmediateContext->PSSetShader(g_pPixelShader, NULL, 0); - g_pd3dDeviceImmediateContext->PSSetSamplers(0, 1, &g_pFontSampler); - - // Setup render state - const float blendFactor[4] = { 0.f, 0.f, 0.f, 0.f }; - g_pd3dDeviceImmediateContext->OMSetBlendState(g_blendState, blendFactor, 0xffffffff); - - // Render command lists - int vtx_offset = 0; - for (int n = 0; n < cmd_lists_count; n++) - { - // Render command list - const ImDrawList* cmd_list = cmd_lists[n]; - for (size_t cmd_i = 0; cmd_i < cmd_list->commands.size(); cmd_i++) - { - const ImDrawCmd* pcmd = &cmd_list->commands[cmd_i]; - const D3D11_RECT r = { (LONG)pcmd->clip_rect.x, (LONG)pcmd->clip_rect.y, (LONG)pcmd->clip_rect.z, (LONG)pcmd->clip_rect.w }; - g_pd3dDeviceImmediateContext->PSSetShaderResources(0, 1, (ID3D11ShaderResourceView**)&pcmd->texture_id); - g_pd3dDeviceImmediateContext->RSSetScissorRects(1, &r); - g_pd3dDeviceImmediateContext->Draw(pcmd->vtx_count, vtx_offset); - vtx_offset += pcmd->vtx_count; - } - } - - // Restore modified state - g_pd3dDeviceImmediateContext->IASetInputLayout(NULL); - g_pd3dDeviceImmediateContext->PSSetShader(NULL, NULL, 0); - g_pd3dDeviceImmediateContext->VSSetShader(NULL, NULL, 0); -} +static ID3D11RenderTargetView* g_mainRenderTargetView = NULL; HRESULT InitDeviceD3D(HWND hWnd) { @@ -170,7 +41,7 @@ HRESULT InitDeviceD3D(HWND hWnd) #endif D3D_FEATURE_LEVEL featureLevel; const D3D_FEATURE_LEVEL featureLevelArray[1] = { D3D_FEATURE_LEVEL_11_0, }; - if (D3D11CreateDeviceAndSwapChain(NULL, D3D_DRIVER_TYPE_HARDWARE, NULL, createDeviceFlags, featureLevelArray, 1, D3D11_SDK_VERSION, &sd, &g_pSwapChain, &g_pd3dDevice, &featureLevel, &g_pd3dDeviceImmediateContext) != S_OK) + if (D3D11CreateDeviceAndSwapChain(NULL, D3D_DRIVER_TYPE_HARDWARE, NULL, createDeviceFlags, featureLevelArray, 1, D3D11_SDK_VERSION, &sd, &g_pSwapChain, &g_pd3dDevice, &featureLevel, &g_pd3dDeviceContext) != S_OK) return E_FAIL; // Setup rasterizer @@ -190,7 +61,7 @@ HRESULT InitDeviceD3D(HWND hWnd) ID3D11RasterizerState* pRState = NULL; g_pd3dDevice->CreateRasterizerState(&RSDesc, &pRState); - g_pd3dDeviceImmediateContext->RSSetState(pRState); + g_pd3dDeviceContext->RSSetState(pRState); pRState->Release(); } @@ -203,356 +74,70 @@ HRESULT InitDeviceD3D(HWND hWnd) render_target_view_desc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D; g_pSwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (LPVOID*)&pBackBuffer); g_pd3dDevice->CreateRenderTargetView(pBackBuffer, &render_target_view_desc, &g_mainRenderTargetView); - g_pd3dDeviceImmediateContext->OMSetRenderTargets(1, &g_mainRenderTargetView, NULL); + g_pd3dDeviceContext->OMSetRenderTargets(1, &g_mainRenderTargetView, NULL); pBackBuffer->Release(); } - // Create the vertex shader - { - static const char* vertexShader = - "cbuffer vertexBuffer : register(c0) \ - {\ - float4x4 ProjectionMatrix; \ - };\ - struct VS_INPUT\ - {\ - float2 pos : POSITION;\ - float4 col : COLOR0;\ - float2 uv : TEXCOORD0;\ - };\ - \ - struct PS_INPUT\ - {\ - float4 pos : SV_POSITION;\ - float4 col : COLOR0;\ - float2 uv : TEXCOORD0;\ - };\ - \ - PS_INPUT main(VS_INPUT input)\ - {\ - PS_INPUT output;\ - output.pos = mul( ProjectionMatrix, float4(input.pos.xy, 0.f, 1.f));\ - output.col = input.col;\ - output.uv = input.uv;\ - return output;\ - }"; - - D3DCompile(vertexShader, strlen(vertexShader), NULL, NULL, NULL, "main", "vs_5_0", 0, 0, &g_pVertexShaderBlob, NULL); - if (g_pVertexShaderBlob == NULL) // NB: Pass ID3D10Blob* pErrorBlob to D3DCompile() to get error showing in (const char*)pErrorBlob->GetBufferPointer(). Make sure to Release() the blob! - return E_FAIL; - if (g_pd3dDevice->CreateVertexShader((DWORD*)g_pVertexShaderBlob->GetBufferPointer(), g_pVertexShaderBlob->GetBufferSize(), NULL, &g_pVertexShader) != S_OK) - return E_FAIL; - - // Create the input layout - D3D11_INPUT_ELEMENT_DESC localLayout[] = { - { "POSITION", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, (size_t)(&((CUSTOMVERTEX*)0)->pos), D3D11_INPUT_PER_VERTEX_DATA, 0 }, - { "COLOR", 0, DXGI_FORMAT_R8G8B8A8_UNORM, 0, (size_t)(&((CUSTOMVERTEX*)0)->col), D3D11_INPUT_PER_VERTEX_DATA, 0 }, - { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, (size_t)(&((CUSTOMVERTEX*)0)->uv), D3D11_INPUT_PER_VERTEX_DATA, 0 }, - }; - - if (g_pd3dDevice->CreateInputLayout(localLayout, 3, g_pVertexShaderBlob->GetBufferPointer(), g_pVertexShaderBlob->GetBufferSize(), &g_pInputLayout) != S_OK) - return E_FAIL; - - // Create the constant buffer - { - D3D11_BUFFER_DESC cbDesc; - cbDesc.ByteWidth = sizeof(VERTEX_CONSTANT_BUFFER); - cbDesc.Usage = D3D11_USAGE_DYNAMIC; - cbDesc.BindFlags = D3D11_BIND_CONSTANT_BUFFER; - cbDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; - cbDesc.MiscFlags = 0; - g_pd3dDevice->CreateBuffer(&cbDesc, NULL, &g_pVertexConstantBuffer); - } - } - - // Create the pixel shader - { - static const char* pixelShader = - "struct PS_INPUT\ - {\ - float4 pos : SV_POSITION;\ - float4 col : COLOR0;\ - float2 uv : TEXCOORD0;\ - };\ - sampler sampler0;\ - Texture2D texture0;\ - \ - float4 main(PS_INPUT input) : SV_Target\ - {\ - float4 out_col = input.col * texture0.Sample(sampler0, input.uv); \ - return out_col; \ - }"; - - D3DCompile(pixelShader, strlen(pixelShader), NULL, NULL, NULL, "main", "ps_5_0", 0, 0, &g_pPixelShaderBlob, NULL); - if (g_pPixelShaderBlob == NULL) // NB: Pass ID3D10Blob* pErrorBlob to D3DCompile() to get error showing in (const char*)pErrorBlob->GetBufferPointer(). Make sure to Release() the blob! - return E_FAIL; - if (g_pd3dDevice->CreatePixelShader((DWORD*)g_pPixelShaderBlob->GetBufferPointer(), g_pPixelShaderBlob->GetBufferSize(), NULL, &g_pPixelShader) != S_OK) - return E_FAIL; - } - - // Create the blending setup - { - D3D11_BLEND_DESC desc; - ZeroMemory(&desc, sizeof(desc)); - desc.AlphaToCoverageEnable = false; - desc.RenderTarget[0].BlendEnable = true; - desc.RenderTarget[0].SrcBlend = D3D11_BLEND_SRC_ALPHA; - desc.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC_ALPHA; - desc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD; - desc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_INV_SRC_ALPHA; - desc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ZERO; - desc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD; - desc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL; - g_pd3dDevice->CreateBlendState(&desc, &g_blendState); - } - return S_OK; } -void CleanupDevice() +void CleanupDeviceD3D() { - if (g_pd3dDeviceImmediateContext) g_pd3dDeviceImmediateContext->ClearState(); - - // InitImGui - if (g_pFontSampler) g_pFontSampler->Release(); - if (ID3D11ShaderResourceView* font_texture_view = (ID3D11ShaderResourceView*)ImGui::GetIO().Fonts->TexID) - font_texture_view->Release(); - if (g_pVB) g_pVB->Release(); - - // InitDeviceD3D - if (g_blendState) g_blendState->Release(); - if (g_pPixelShader) g_pPixelShader->Release(); - if (g_pPixelShaderBlob) g_pPixelShaderBlob->Release(); - if (g_pVertexConstantBuffer) g_pVertexConstantBuffer->Release(); - if (g_pInputLayout) g_pInputLayout->Release(); - if (g_pVertexShader) g_pVertexShader->Release(); - if (g_pVertexShaderBlob) g_pVertexShaderBlob->Release(); if (g_mainRenderTargetView) g_mainRenderTargetView->Release(); if (g_pSwapChain) g_pSwapChain->Release(); - if (g_pd3dDeviceImmediateContext) g_pd3dDeviceImmediateContext->Release(); + if (g_pd3dDeviceContext) g_pd3dDeviceContext->Release(); if (g_pd3dDevice) g_pd3dDevice->Release(); } +extern LRESULT ImGui_ImplDX11_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); LRESULT WINAPI WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { - ImGuiIO& io = ImGui::GetIO(); + if (ImGui_ImplDX11_WndProcHandler(hWnd, msg, wParam, lParam)) + return true; + switch (msg) { - case WM_LBUTTONDOWN: - io.MouseDown[0] = true; - return true; - case WM_LBUTTONUP: - io.MouseDown[0] = false; - return true; - case WM_RBUTTONDOWN: - io.MouseDown[1] = true; - return true; - case WM_RBUTTONUP: - io.MouseDown[1] = false; - return true; - case WM_MOUSEWHEEL: - io.MouseWheel += GET_WHEEL_DELTA_WPARAM(wParam) > 0 ? +1.0f : -1.0f; - return true; - case WM_MOUSEMOVE: - // Mouse position, in pixels (set to -1,-1 if no mouse / on another screen, etc.) - io.MousePos.x = (signed short)(lParam); - io.MousePos.y = (signed short)(lParam >> 16); - return true; - case WM_KEYDOWN: - if (wParam >= 0 && wParam < 256) - io.KeysDown[wParam] = 1; - return true; - case WM_KEYUP: - if (wParam >= 0 && wParam < 256) - io.KeysDown[wParam] = 0; - return true; - case WM_CHAR: - // You can also use ToAscii()+GetKeyboardState() to retrieve characters. - if (wParam > 0 && wParam < 0x10000) - io.AddInputCharacter((unsigned short)wParam); - return true; case WM_DESTROY: - CleanupDevice(); PostQuitMessage(0); return 0; } return DefWindowProc(hWnd, msg, wParam, lParam); } -void LoadFontsTexture() -{ - // Load one or more font - ImGuiIO& io = ImGui::GetIO(); - //ImFont* my_font1 = io.Fonts->AddFontDefault(); - //ImFont* my_font2 = io.Fonts->AddFontFromFileTTF("extra_fonts/Karla-Regular.ttf", 15.0f); - //ImFont* my_font3 = io.Fonts->AddFontFromFileTTF("extra_fonts/ProggyClean.ttf", 13.0f); my_font3->DisplayOffset.y += 1; - //ImFont* my_font4 = io.Fonts->AddFontFromFileTTF("extra_fonts/ProggyTiny.ttf", 10.0f); my_font4->DisplayOffset.y += 1; - //ImFont* my_font5 = io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf", 18.0f, io.Fonts->GetGlyphRangesJapanese()); - - // Build - unsigned char* pixels; - int width, height; - io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); - - // Create texture - D3D11_TEXTURE2D_DESC desc; - ZeroMemory(&desc, sizeof(desc)); - desc.Width = width; - desc.Height = height; - desc.MipLevels = 1; - desc.ArraySize = 1; - desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; - desc.SampleDesc.Count = 1; - desc.Usage = D3D11_USAGE_DEFAULT; - desc.BindFlags = D3D11_BIND_SHADER_RESOURCE; - desc.CPUAccessFlags = 0; - - ID3D11Texture2D *pTexture = NULL; - D3D11_SUBRESOURCE_DATA subResource; - subResource.pSysMem = pixels; - subResource.SysMemPitch = desc.Width * 4; - subResource.SysMemSlicePitch = 0; - g_pd3dDevice->CreateTexture2D(&desc, &subResource, &pTexture); - - // Create texture view - D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc; - ZeroMemory(&srvDesc, sizeof(srvDesc)); - srvDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; - srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D; - srvDesc.Texture2D.MipLevels = desc.MipLevels; - srvDesc.Texture2D.MostDetailedMip = 0; - ID3D11ShaderResourceView* font_texture_view = NULL; - g_pd3dDevice->CreateShaderResourceView(pTexture, &srvDesc, &font_texture_view); - pTexture->Release(); - - // Store our identifier - io.Fonts->TexID = (void *)font_texture_view; -} - -void InitImGui() -{ - RECT rect; - GetClientRect(hWnd, &rect); - int display_w = (int)(rect.right - rect.left); - int display_h = (int)(rect.bottom - rect.top); - - ImGuiIO& io = ImGui::GetIO(); - io.DisplaySize = ImVec2((float)display_w, (float)display_h); // Display size, in pixels. For clamping windows positions. - io.DeltaTime = 1.0f/60.0f; // Time elapsed since last frame, in seconds (in this sample app we'll override this every frame because our time step is variable) - io.KeyMap[ImGuiKey_Tab] = VK_TAB; // Keyboard mapping. ImGui will use those indices to peek into the io.KeyDown[] array that we will update during the application lifetime. - io.KeyMap[ImGuiKey_LeftArrow] = VK_LEFT; - io.KeyMap[ImGuiKey_RightArrow] = VK_RIGHT; - io.KeyMap[ImGuiKey_UpArrow] = VK_UP; - io.KeyMap[ImGuiKey_DownArrow] = VK_UP; - io.KeyMap[ImGuiKey_Home] = VK_HOME; - io.KeyMap[ImGuiKey_End] = VK_END; - io.KeyMap[ImGuiKey_Delete] = VK_DELETE; - io.KeyMap[ImGuiKey_Backspace] = VK_BACK; - io.KeyMap[ImGuiKey_Enter] = VK_RETURN; - io.KeyMap[ImGuiKey_Escape] = VK_ESCAPE; - 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'; - - io.RenderDrawListsFn = ImImpl_RenderDrawLists; - io.ImeWindowHandle = hWnd; - - // Create the vertex buffer - { - D3D11_BUFFER_DESC bufferDesc; - memset(&bufferDesc, 0, sizeof(D3D11_BUFFER_DESC)); - bufferDesc.Usage = D3D11_USAGE_DYNAMIC; - bufferDesc.ByteWidth = 100000 * sizeof(CUSTOMVERTEX); // Maybe we should handle that more dynamically? - bufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER; - bufferDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; - bufferDesc.MiscFlags = 0; - if (g_pd3dDevice->CreateBuffer(&bufferDesc, NULL, &g_pVB) < 0) - { - IM_ASSERT(0); - return; - } - } - - // Load fonts - LoadFontsTexture(); - - // Create texture sampler - { - D3D11_SAMPLER_DESC desc; - ZeroMemory(&desc, sizeof(desc)); - desc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR; - desc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP; - desc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP; - desc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP; - desc.MipLODBias = 0.f; - desc.ComparisonFunc = D3D11_COMPARISON_ALWAYS; - desc.MinLOD = 0.f; - desc.MaxLOD = 0.f; - g_pd3dDevice->CreateSamplerState(&desc, &g_pFontSampler); - } -} - -INT64 ticks_per_second = 0; -INT64 last_time = 0; - -void UpdateImGui() -{ - ImGuiIO& io = ImGui::GetIO(); - - // Setup time step - INT64 current_time; - QueryPerformanceCounter((LARGE_INTEGER *)¤t_time); - io.DeltaTime = (float)(current_time - last_time) / ticks_per_second; - last_time = current_time; - - // Read keyboard modifiers inputs - io.KeyCtrl = (GetKeyState(VK_CONTROL) & 0x8000) != 0; - io.KeyShift = (GetKeyState(VK_SHIFT) & 0x8000) != 0; - // io.KeysDown : filled by WM_KEYDOWN/WM_KEYUP events - // io.MousePos : filled by WM_MOUSEMOVE events - // io.MouseDown : filled by WM_*BUTTON* events - // io.MouseWheel : filled by WM_MOUSEWHEEL events - - // Start the frame - ImGui::NewFrame(); -} - int main(int argc, char** argv) { - // Register the window class + // Create application window WNDCLASSEX wc = { sizeof(WNDCLASSEX), CS_CLASSDC, WndProc, 0L, 0L, GetModuleHandle(NULL), NULL, LoadCursor(NULL, IDC_ARROW), NULL, NULL, L"ImGui Example", NULL }; RegisterClassEx(&wc); - - // Create the application's window - hWnd = CreateWindow(L"ImGui Example", L"ImGui DirectX11 Example", WS_OVERLAPPEDWINDOW, 100, 100, 1280, 800, NULL, NULL, wc.hInstance, NULL); - - if (!QueryPerformanceFrequency((LARGE_INTEGER *)&ticks_per_second)) - return 1; - if (!QueryPerformanceCounter((LARGE_INTEGER *)&last_time)) - return 1; + HWND hwnd = CreateWindow(L"ImGui Example", L"ImGui DirectX11 Example", WS_OVERLAPPEDWINDOW, 100, 100, 1280, 800, NULL, NULL, wc.hInstance, NULL); // Initialize Direct3D - if (InitDeviceD3D(hWnd) < 0) + if (InitDeviceD3D(hwnd) < 0) { - CleanupDevice(); + CleanupDeviceD3D(); UnregisterClass(L"ImGui Example", wc.hInstance); return 1; } // Show the window - ShowWindow(hWnd, SW_SHOWDEFAULT); - UpdateWindow(hWnd); + ShowWindow(hwnd, SW_SHOWDEFAULT); + UpdateWindow(hwnd); - InitImGui(); + // Setup ImGui binding + ImGui_ImplDX11_Init(hwnd, g_pd3dDevice, g_pd3dDeviceContext); + //ImGuiIO& io = ImGui::GetIO(); + //ImFont* my_font1 = io.Fonts->AddFontDefault(); + //ImFont* my_font2 = io.Fonts->AddFontFromFileTTF("extra_fonts/Karla-Regular.ttf", 15.0f); + //ImFont* my_font3 = io.Fonts->AddFontFromFileTTF("extra_fonts/ProggyClean.ttf", 13.0f); my_font3->DisplayOffset.y += 1; + //ImFont* my_font4 = io.Fonts->AddFontFromFileTTF("extra_fonts/ProggyTiny.ttf", 10.0f); my_font4->DisplayOffset.y += 1; + //ImFont* my_font5 = io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf", 18.0f, io.Fonts->GetGlyphRangesJapanese()); + ImGui_ImplDX11_InitFontsTexture(); bool show_test_window = true; bool show_another_window = false; ImVec4 clear_col = ImColor(114, 144, 154); - // Enter the message loop + // Main loop MSG msg; ZeroMemory(&msg, sizeof(msg)); while (msg.message != WM_QUIT) @@ -563,7 +148,7 @@ int main(int argc, char** argv) DispatchMessage(&msg); continue; } - UpdateImGui(); + ImGui_ImplDX11_NewFrame(); // 1. Show a simple window // Tip: if we don't call ImGui::Begin()/ImGui::End() the widgets appears in a window automatically called "Debug" @@ -593,12 +178,13 @@ int main(int argc, char** argv) } // Rendering - g_pd3dDeviceImmediateContext->ClearRenderTargetView(g_mainRenderTargetView, (float*)&clear_col); + g_pd3dDeviceContext->ClearRenderTargetView(g_mainRenderTargetView, (float*)&clear_col); ImGui::Render(); g_pSwapChain->Present(0, 0); } - ImGui::Shutdown(); + ImGui_ImplDX11_Shutdown(); + CleanupDeviceD3D(); UnregisterClass(L"ImGui Example", wc.hInstance); return 0; diff --git a/examples/directx9_example/imgui_impl_dx9.cpp b/examples/directx9_example/imgui_impl_dx9.cpp index 370bcb12..ccddbe05 100644 --- a/examples/directx9_example/imgui_impl_dx9.cpp +++ b/examples/directx9_example/imgui_impl_dx9.cpp @@ -90,7 +90,6 @@ static void ImGui_ImplDX9_RenderDrawLists(ImDrawList** const cmd_lists, int cmd_ int vtx_offset = 0; for (int n = 0; n < cmd_lists_count; n++) { - // Render command list const ImDrawList* cmd_list = cmd_lists[n]; for (size_t cmd_i = 0; cmd_i < cmd_list->commands.size(); cmd_i++) { @@ -184,7 +183,7 @@ bool ImGui_ImplDX9_Init(void* hwnd, IDirect3DDevice9* device) if (!QueryPerformanceCounter((LARGE_INTEGER *)&g_Time)) return false; - // FIXME + // FIXME: resizing RECT rect; GetClientRect((HWND)hwnd, &rect); int display_w = (int)(rect.right - rect.left); diff --git a/examples/directx9_example/main.cpp b/examples/directx9_example/main.cpp index 65069805..9224be50 100644 --- a/examples/directx9_example/main.cpp +++ b/examples/directx9_example/main.cpp @@ -1,7 +1,6 @@ // ImGui - standalone example application for DirectX 9 // TODO: Allow resizing the application window. -#include #include #include "imgui_impl_dx9.h" #include @@ -25,11 +24,9 @@ LRESULT WINAPI WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) int main(int argc, char** argv) { - // Register the window class + // Create application window WNDCLASSEX wc = { sizeof(WNDCLASSEX), CS_CLASSDC, WndProc, 0L, 0L, GetModuleHandle(NULL), NULL, LoadCursor(NULL, IDC_ARROW), NULL, NULL, L"ImGui Example", NULL }; RegisterClassEx(&wc); - - // Create the application's window HWND hwnd = CreateWindow(L"ImGui Example", L"ImGui DirectX9 Example", WS_OVERLAPPEDWINDOW, 100, 100, 1280, 800, NULL, NULL, wc.hInstance, NULL); // Initialize Direct3D @@ -60,7 +57,7 @@ int main(int argc, char** argv) ShowWindow(hwnd, SW_SHOWDEFAULT); UpdateWindow(hwnd); - // ImGui + // Setup ImGui binding ImGui_ImplDX9_Init(hwnd, pd3dDevice); //ImGuiIO& io = ImGui::GetIO(); //ImFont* my_font1 = io.Fonts->AddFontDefault(); @@ -129,7 +126,6 @@ int main(int argc, char** argv) } ImGui_ImplDX9_Shutdown(); - if (pd3dDevice) pd3dDevice->Release(); if (pD3D) pD3D->Release(); UnregisterClass(L"ImGui Example", wc.hInstance); From 25765e4bfc02b632f6221dd254fd283d17d5158b Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 9 Mar 2015 13:49:52 +0000 Subject: [PATCH 41/48] Examples: Fixed readme file. --- examples/README.txt | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/examples/README.txt b/examples/README.txt index 6ad61da0..b7aaaa24 100644 --- a/examples/README.txt +++ b/examples/README.txt @@ -1,16 +1,15 @@ directx9_example/ - DirectX9 example application (Windows). + DirectX9 example (Windows only). directx11_example/ - DirectX11 example (Windows). + DirectX11 example (Windows only). opengl_example/ - OpenGL exemple, using fixed pipeline (Windows/OSX/Linux etc., using glfw+glew) + OpenGL example, using GLFW + fixed pipeline. This is simple and should work for all OpenGL enabled applications. opengl3_example/ - OpenGL exemple, using programmable pipeline (Windows/OSX/Linux etc., using glfw+glew) + OpenGL exemple, using GLFW/GL3W + programmable pipeline. This uses more modern calls and custom shaders. - I don't think there is an advantage using this over the "simpler example, but it is provided for information. - \ No newline at end of file + I don't think there is an advantage using this over the simpler example, but it is provided for reference. From 866fa95aaad79b1912fa8ed5f94e10d7921cdee3 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 9 Mar 2015 14:13:29 +0000 Subject: [PATCH 42/48] Examples: DirectX9 example application handle window resizing. --- .../directx11_example/imgui_impl_dx11.cpp | 16 ++--- examples/directx9_example/imgui_impl_dx9.cpp | 38 ++++++++---- examples/directx9_example/imgui_impl_dx9.h | 4 ++ examples/directx9_example/main.cpp | 59 +++++++++++-------- 4 files changed, 76 insertions(+), 41 deletions(-) diff --git a/examples/directx11_example/imgui_impl_dx11.cpp b/examples/directx11_example/imgui_impl_dx11.cpp index bc693a47..c2e90ae5 100644 --- a/examples/directx11_example/imgui_impl_dx11.cpp +++ b/examples/directx11_example/imgui_impl_dx11.cpp @@ -15,6 +15,7 @@ static INT64 g_Time = 0; static INT64 g_TicksPerSecond = 0; static bool g_FontTextureLoaded = false; +static HWND g_hWnd = 0; static ID3D11Device* g_pd3dDevice = NULL; static ID3D11DeviceContext* g_pd3dDeviceContext = NULL; static ID3D11Buffer* g_pVB = NULL; @@ -355,6 +356,7 @@ static bool InitDirect3DState() bool ImGui_ImplDX11_Init(void* hwnd, ID3D11Device* device, ID3D11DeviceContext* device_context) { + g_hWnd = (HWND)hwnd; g_pd3dDevice = device; g_pd3dDeviceContext = device_context; @@ -369,14 +371,7 @@ bool ImGui_ImplDX11_Init(void* hwnd, ID3D11Device* device, ID3D11DeviceContex if (!QueryPerformanceCounter((LARGE_INTEGER *)&g_Time)) return false; - // FIXME: resizing - RECT rect; - GetClientRect((HWND)hwnd, &rect); - int display_w = (int)(rect.right - rect.left); - int display_h = (int)(rect.bottom - rect.top); - ImGuiIO& io = ImGui::GetIO(); - io.DisplaySize = ImVec2((float)display_w, (float)display_h); // Display size, in pixels. For clamping windows positions. io.KeyMap[ImGuiKey_Tab] = VK_TAB; // Keyboard mapping. ImGui will use those indices to peek into the io.KeyDown[] array that we will update during the application lifetime. io.KeyMap[ImGuiKey_LeftArrow] = VK_LEFT; io.KeyMap[ImGuiKey_RightArrow] = VK_RIGHT; @@ -396,7 +391,7 @@ bool ImGui_ImplDX11_Init(void* hwnd, ID3D11Device* device, ID3D11DeviceContex io.KeyMap[ImGuiKey_Z] = 'Z'; io.RenderDrawListsFn = ImGui_ImplDX11_RenderDrawLists; - io.ImeWindowHandle = hwnd; + io.ImeWindowHandle = g_hWnd; return true; } @@ -428,6 +423,11 @@ void ImGui_ImplDX11_NewFrame() ImGuiIO& io = ImGui::GetIO(); + // Setup display size (every frame to accommodate for window resizing) + RECT rect; + GetClientRect(g_hWnd, &rect); + io.DisplaySize = ImVec2((float)(rect.right - rect.left), (float)(rect.bottom - rect.top)); + // Setup time step INT64 current_time; QueryPerformanceCounter((LARGE_INTEGER *)¤t_time); diff --git a/examples/directx9_example/imgui_impl_dx9.cpp b/examples/directx9_example/imgui_impl_dx9.cpp index ccddbe05..c69a8d2e 100644 --- a/examples/directx9_example/imgui_impl_dx9.cpp +++ b/examples/directx9_example/imgui_impl_dx9.cpp @@ -10,6 +10,7 @@ #include // Data +static HWND g_hWnd = 0; static INT64 g_Time = 0; static INT64 g_TicksPerSecond = 0; static bool g_FontTextureLoaded = false; @@ -177,20 +178,15 @@ void ImGui_ImplDX9_InitFontsTexture() bool ImGui_ImplDX9_Init(void* hwnd, IDirect3DDevice9* device) { + g_hWnd = (HWND)hwnd; g_pd3dDevice = device; + if (!QueryPerformanceFrequency((LARGE_INTEGER *)&g_TicksPerSecond)) return false; if (!QueryPerformanceCounter((LARGE_INTEGER *)&g_Time)) return false; - // FIXME: resizing - RECT rect; - GetClientRect((HWND)hwnd, &rect); - int display_w = (int)(rect.right - rect.left); - int display_h = (int)(rect.bottom - rect.top); - ImGuiIO& io = ImGui::GetIO(); - io.DisplaySize = ImVec2((float)display_w, (float)display_h); // Display size, in pixels. For clamping windows positions. io.KeyMap[ImGuiKey_Tab] = VK_TAB; // Keyboard mapping. ImGui will use those indices to peek into the io.KeyDown[] array that we will update during the application lifetime. io.KeyMap[ImGuiKey_LeftArrow] = VK_LEFT; io.KeyMap[ImGuiKey_RightArrow] = VK_RIGHT; @@ -210,17 +206,18 @@ bool ImGui_ImplDX9_Init(void* hwnd, IDirect3DDevice9* device) io.KeyMap[ImGuiKey_Z] = 'Z'; io.RenderDrawListsFn = ImGui_ImplDX9_RenderDrawLists; - io.ImeWindowHandle = hwnd; + io.ImeWindowHandle = g_hWnd; - // Create the vertex buffer if (g_pd3dDevice->CreateVertexBuffer(10000 * sizeof(CUSTOMVERTEX), D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY, D3DFVF_CUSTOMVERTEX, D3DPOOL_DEFAULT, &g_pVB, NULL) < 0) return false; return true; } -void ImGui_ImplDX9_Shutdown() +void ImGui_ImplDX9_InvalidateDeviceObjects() { + if (!g_pd3dDevice) + return; if (g_pVB) { g_pVB->Release(); @@ -231,8 +228,24 @@ void ImGui_ImplDX9_Shutdown() tex->Release(); ImGui::GetIO().Fonts->TexID = 0; } +} +void ImGui_ImplDX9_CreateDeviceObjects() +{ + if (!g_pd3dDevice) + return; + if (g_pd3dDevice->CreateVertexBuffer(10000 * sizeof(CUSTOMVERTEX), D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY, D3DFVF_CUSTOMVERTEX, D3DPOOL_DEFAULT, &g_pVB, NULL) < 0) + return; + + ImGui_ImplDX9_InitFontsTexture(); +} + +void ImGui_ImplDX9_Shutdown() +{ + ImGui_ImplDX9_InvalidateDeviceObjects(); ImGui::Shutdown(); + g_pd3dDevice = NULL; + g_hWnd = 0; } void ImGui_ImplDX9_NewFrame() @@ -242,6 +255,11 @@ void ImGui_ImplDX9_NewFrame() ImGuiIO& io = ImGui::GetIO(); + // Setup display size (every frame to accommodate for window resizing) + RECT rect; + GetClientRect(g_hWnd, &rect); + io.DisplaySize = ImVec2((float)(rect.right - rect.left), (float)(rect.bottom - rect.top)); + // Setup time step INT64 current_time; QueryPerformanceCounter((LARGE_INTEGER *)¤t_time); diff --git a/examples/directx9_example/imgui_impl_dx9.h b/examples/directx9_example/imgui_impl_dx9.h index 6574e3f7..1822bee8 100644 --- a/examples/directx9_example/imgui_impl_dx9.h +++ b/examples/directx9_example/imgui_impl_dx9.h @@ -8,6 +8,10 @@ void ImGui_ImplDX9_InitFontsTexture(); void ImGui_ImplDX9_Shutdown(); void ImGui_ImplDX9_NewFrame(); +// Use if you want to reset your rendering device without losing ImGui state. +void ImGui_ImplDX9_InvalidateDeviceObjects(); +void ImGui_ImplDX9_CreateDeviceObjects(); + // 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. // Commented out to avoid dragging dependencies on types. You can copy the extern declaration in your code. diff --git a/examples/directx9_example/main.cpp b/examples/directx9_example/main.cpp index 9224be50..2f2a6188 100644 --- a/examples/directx9_example/main.cpp +++ b/examples/directx9_example/main.cpp @@ -1,5 +1,4 @@ // ImGui - standalone example application for DirectX 9 -// TODO: Allow resizing the application window. #include #include "imgui_impl_dx9.h" @@ -7,6 +6,10 @@ #define DIRECTINPUT_VERSION 0x0800 #include +// Data +static LPDIRECT3DDEVICE9 g_pd3dDevice = NULL; +static D3DPRESENT_PARAMETERS g_d3dpp; + extern LRESULT ImGui_ImplDX9_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); LRESULT WINAPI WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { @@ -15,6 +18,18 @@ LRESULT WINAPI WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) switch (msg) { + case WM_SIZE: + if (g_pd3dDevice != NULL && wParam != SIZE_MINIMIZED) + { + ImGui_ImplDX9_InvalidateDeviceObjects(); + g_d3dpp.BackBufferWidth = LOWORD(lParam); + g_d3dpp.BackBufferHeight = HIWORD(lParam); + HRESULT hr = g_pd3dDevice->Reset(&g_d3dpp); + if (hr == D3DERR_INVALIDCALL) + IM_ASSERT(0); + ImGui_ImplDX9_CreateDeviceObjects(); + } + return 0; case WM_DESTROY: PostQuitMessage(0); return 0; @@ -36,29 +51,24 @@ int main(int argc, char** argv) UnregisterClass(L"ImGui Example", wc.hInstance); return 0; } - D3DPRESENT_PARAMETERS d3dpp; - ZeroMemory(&d3dpp, sizeof(d3dpp)); - d3dpp.Windowed = TRUE; - d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD; - d3dpp.BackBufferFormat = D3DFMT_UNKNOWN; - d3dpp.EnableAutoDepthStencil = TRUE; - d3dpp.AutoDepthStencilFormat = D3DFMT_D16; - d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE; + ZeroMemory(&g_d3dpp, sizeof(g_d3dpp)); + g_d3dpp.Windowed = TRUE; + g_d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD; + g_d3dpp.BackBufferFormat = D3DFMT_UNKNOWN; + g_d3dpp.EnableAutoDepthStencil = TRUE; + g_d3dpp.AutoDepthStencilFormat = D3DFMT_D16; + g_d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE; // Create the D3DDevice - LPDIRECT3DDEVICE9 pd3dDevice = NULL; - if (pD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hwnd, D3DCREATE_HARDWARE_VERTEXPROCESSING, &d3dpp, &pd3dDevice) < 0) + if (pD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hwnd, D3DCREATE_HARDWARE_VERTEXPROCESSING, &g_d3dpp, &g_pd3dDevice) < 0) { pD3D->Release(); UnregisterClass(L"ImGui Example", wc.hInstance); return 0; } - ShowWindow(hwnd, SW_SHOWDEFAULT); - UpdateWindow(hwnd); - // Setup ImGui binding - ImGui_ImplDX9_Init(hwnd, pd3dDevice); + ImGui_ImplDX9_Init(hwnd, g_pd3dDevice); //ImGuiIO& io = ImGui::GetIO(); //ImFont* my_font1 = io.Fonts->AddFontDefault(); //ImFont* my_font2 = io.Fonts->AddFontFromFileTTF("extra_fonts/Karla-Regular.ttf", 15.0f); @@ -67,6 +77,9 @@ int main(int argc, char** argv) //ImFont* my_font5 = io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf", 18.0f, io.Fonts->GetGlyphRangesJapanese()); ImGui_ImplDX9_InitFontsTexture(); + ShowWindow(hwnd, SW_SHOWDEFAULT); + UpdateWindow(hwnd); + bool show_test_window = true; bool show_another_window = false; ImVec4 clear_col = ImColor(114, 144, 154); @@ -112,21 +125,21 @@ int main(int argc, char** argv) } // Rendering - pd3dDevice->SetRenderState(D3DRS_ZENABLE, false); - pd3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, false); - pd3dDevice->SetRenderState(D3DRS_SCISSORTESTENABLE, false); + g_pd3dDevice->SetRenderState(D3DRS_ZENABLE, false); + g_pd3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, false); + g_pd3dDevice->SetRenderState(D3DRS_SCISSORTESTENABLE, false); D3DCOLOR clear_col_dx = D3DCOLOR_RGBA((int)(clear_col.x*255.0f), (int)(clear_col.y*255.0f), (int)(clear_col.z*255.0f), (int)(clear_col.w*255.0f)); - pd3dDevice->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, clear_col_dx, 1.0f, 0); - if (pd3dDevice->BeginScene() >= 0) + g_pd3dDevice->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, clear_col_dx, 1.0f, 0); + if (g_pd3dDevice->BeginScene() >= 0) { ImGui::Render(); - pd3dDevice->EndScene(); + g_pd3dDevice->EndScene(); } - pd3dDevice->Present(NULL, NULL, NULL, NULL); + g_pd3dDevice->Present(NULL, NULL, NULL, NULL); } ImGui_ImplDX9_Shutdown(); - if (pd3dDevice) pd3dDevice->Release(); + if (g_pd3dDevice) g_pd3dDevice->Release(); if (pD3D) pD3D->Release(); UnregisterClass(L"ImGui Example", wc.hInstance); From 66a5837ba8f05090c02e12bba8a8e71dce6ddb8e Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 9 Mar 2015 14:51:10 +0000 Subject: [PATCH 43/48] Examples: DirectX11 example application handles window resizing. --- .../directx11_example/imgui_impl_dx11.cpp | 145 ++++++++++-------- examples/directx11_example/imgui_impl_dx11.h | 5 +- examples/directx11_example/main.cpp | 59 ++++--- 3 files changed, 121 insertions(+), 88 deletions(-) diff --git a/examples/directx11_example/imgui_impl_dx11.cpp b/examples/directx11_example/imgui_impl_dx11.cpp index c2e90ae5..ffcb7cdb 100644 --- a/examples/directx11_example/imgui_impl_dx11.cpp +++ b/examples/directx11_example/imgui_impl_dx11.cpp @@ -13,7 +13,6 @@ // Data static INT64 g_Time = 0; static INT64 g_TicksPerSecond = 0; -static bool g_FontTextureLoaded = false; static HWND g_hWnd = 0; static ID3D11Device* g_pd3dDevice = NULL; @@ -26,6 +25,7 @@ static ID3D11Buffer* g_pVertexConstantBuffer = NULL; static ID3D10Blob * g_pPixelShaderBlob = NULL; static ID3D11PixelShader* g_pPixelShader = NULL; static ID3D11SamplerState* g_pFontSampler = NULL; +static ID3D11ShaderResourceView*g_pFontTextureView = NULL; static ID3D11BlendState* g_blendState = NULL; struct CUSTOMVERTEX @@ -180,7 +180,7 @@ LRESULT ImGui_ImplDX11_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM return 0; } -void ImGui_ImplDX11_InitFontsTexture() +static void ImGui_ImplDX11_InitFontsTexture() { ImGuiIO& io = ImGui::GetIO(); @@ -190,55 +190,63 @@ void ImGui_ImplDX11_InitFontsTexture() io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); // Create DX11 texture - D3D11_TEXTURE2D_DESC texDesc; - ZeroMemory(&texDesc, sizeof(texDesc)); - texDesc.Width = width; - texDesc.Height = height; - texDesc.MipLevels = 1; - texDesc.ArraySize = 1; - texDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; - texDesc.SampleDesc.Count = 1; - texDesc.Usage = D3D11_USAGE_DEFAULT; - texDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE; - texDesc.CPUAccessFlags = 0; - - ID3D11Texture2D *pTexture = NULL; - D3D11_SUBRESOURCE_DATA subResource; - subResource.pSysMem = pixels; - subResource.SysMemPitch = texDesc.Width * 4; - subResource.SysMemSlicePitch = 0; - g_pd3dDevice->CreateTexture2D(&texDesc, &subResource, &pTexture); - - // Create texture view - D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc; - ZeroMemory(&srvDesc, sizeof(srvDesc)); - srvDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; - srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D; - srvDesc.Texture2D.MipLevels = texDesc.MipLevels; - srvDesc.Texture2D.MostDetailedMip = 0; - ID3D11ShaderResourceView* font_texture_view = NULL; - g_pd3dDevice->CreateShaderResourceView(pTexture, &srvDesc, &font_texture_view); - pTexture->Release(); + { + D3D11_TEXTURE2D_DESC texDesc; + ZeroMemory(&texDesc, sizeof(texDesc)); + texDesc.Width = width; + texDesc.Height = height; + texDesc.MipLevels = 1; + texDesc.ArraySize = 1; + texDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; + texDesc.SampleDesc.Count = 1; + texDesc.Usage = D3D11_USAGE_DEFAULT; + texDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE; + texDesc.CPUAccessFlags = 0; + + ID3D11Texture2D *pTexture = NULL; + D3D11_SUBRESOURCE_DATA subResource; + subResource.pSysMem = pixels; + subResource.SysMemPitch = texDesc.Width * 4; + subResource.SysMemSlicePitch = 0; + g_pd3dDevice->CreateTexture2D(&texDesc, &subResource, &pTexture); + + // Create texture view + D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc; + ZeroMemory(&srvDesc, sizeof(srvDesc)); + srvDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; + srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D; + srvDesc.Texture2D.MipLevels = texDesc.MipLevels; + srvDesc.Texture2D.MostDetailedMip = 0; + g_pd3dDevice->CreateShaderResourceView(pTexture, &srvDesc, &g_pFontTextureView); + pTexture->Release(); + } // Store our identifier - io.Fonts->TexID = (void *)font_texture_view; + io.Fonts->TexID = (void *)g_pFontTextureView; // Create texture sampler - D3D11_SAMPLER_DESC samplerDesc; - ZeroMemory(&samplerDesc, sizeof(samplerDesc)); - samplerDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR; - samplerDesc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP; - samplerDesc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP; - samplerDesc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP; - samplerDesc.MipLODBias = 0.f; - samplerDesc.ComparisonFunc = D3D11_COMPARISON_ALWAYS; - samplerDesc.MinLOD = 0.f; - samplerDesc.MaxLOD = 0.f; - g_pd3dDevice->CreateSamplerState(&samplerDesc, &g_pFontSampler); + { + D3D11_SAMPLER_DESC samplerDesc; + ZeroMemory(&samplerDesc, sizeof(samplerDesc)); + samplerDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR; + samplerDesc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP; + samplerDesc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP; + samplerDesc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP; + samplerDesc.MipLODBias = 0.f; + samplerDesc.ComparisonFunc = D3D11_COMPARISON_ALWAYS; + samplerDesc.MinLOD = 0.f; + samplerDesc.MaxLOD = 0.f; + g_pd3dDevice->CreateSamplerState(&samplerDesc, &g_pFontSampler); + } } -static bool InitDirect3DState() +bool ImGui_ImplDX11_CreateDeviceObjects() { + if (!g_pd3dDevice) + return false; + if (g_pVB) + ImGui_ImplDX11_InvalidateDeviceObjects(); + // Create the vertex shader { static const char* vertexShader = @@ -351,21 +359,35 @@ static bool InitDirect3DState() return false; } + ImGui_ImplDX11_InitFontsTexture(); + return true; } +void ImGui_ImplDX11_InvalidateDeviceObjects() +{ + if (!g_pd3dDevice) + return; + + if (g_pFontSampler) { g_pFontSampler->Release(); g_pFontSampler = NULL; } + if (g_pFontTextureView) { g_pFontTextureView->Release(); ImGui::GetIO().Fonts->TexID = 0; } + if (g_pVB) { g_pVB->Release(); g_pVB = NULL; } + + if (g_blendState) { g_blendState->Release(); g_blendState = NULL; } + if (g_pPixelShader) { g_pPixelShader->Release(); g_pPixelShader = NULL; } + if (g_pPixelShaderBlob) { g_pPixelShaderBlob->Release(); g_pPixelShaderBlob = NULL; } + if (g_pVertexConstantBuffer) { g_pVertexConstantBuffer->Release(); g_pVertexConstantBuffer = NULL; } + if (g_pInputLayout) { g_pInputLayout->Release(); g_pInputLayout = NULL; } + if (g_pVertexShader) { g_pVertexShader->Release(); g_pVertexShader = NULL; } + if (g_pVertexShaderBlob) { g_pVertexShaderBlob->Release(); g_pVertexShaderBlob = NULL; } +} + bool ImGui_ImplDX11_Init(void* hwnd, ID3D11Device* device, ID3D11DeviceContext* device_context) { g_hWnd = (HWND)hwnd; g_pd3dDevice = device; g_pd3dDeviceContext = device_context; - if (!InitDirect3DState()) - { - IM_ASSERT(0); - return false; - } - if (!QueryPerformanceFrequency((LARGE_INTEGER *)&g_TicksPerSecond)) return false; if (!QueryPerformanceCounter((LARGE_INTEGER *)&g_Time)) @@ -398,28 +420,17 @@ bool ImGui_ImplDX11_Init(void* hwnd, ID3D11Device* device, ID3D11DeviceContex void ImGui_ImplDX11_Shutdown() { - if (g_pd3dDeviceContext) g_pd3dDeviceContext->ClearState(); - - if (g_pFontSampler) g_pFontSampler->Release(); - if (ID3D11ShaderResourceView* font_texture_view = (ID3D11ShaderResourceView*)ImGui::GetIO().Fonts->TexID) - font_texture_view->Release(); - if (g_pVB) g_pVB->Release(); - - if (g_blendState) g_blendState->Release(); - if (g_pPixelShader) g_pPixelShader->Release(); - if (g_pPixelShaderBlob) g_pPixelShaderBlob->Release(); - if (g_pVertexConstantBuffer) g_pVertexConstantBuffer->Release(); - if (g_pInputLayout) g_pInputLayout->Release(); - if (g_pVertexShader) g_pVertexShader->Release(); - if (g_pVertexShaderBlob) g_pVertexShaderBlob->Release(); - + ImGui_ImplDX11_InvalidateDeviceObjects(); ImGui::Shutdown(); + g_pd3dDevice = NULL; + g_pd3dDeviceContext = NULL; + g_hWnd = (HWND)0; } void ImGui_ImplDX11_NewFrame() { - if (!g_FontTextureLoaded) - ImGui_ImplDX11_InitFontsTexture(); + if (!g_pVB) + ImGui_ImplDX11_CreateDeviceObjects(); ImGuiIO& io = ImGui::GetIO(); diff --git a/examples/directx11_example/imgui_impl_dx11.h b/examples/directx11_example/imgui_impl_dx11.h index aa33edb2..c920d0b9 100644 --- a/examples/directx11_example/imgui_impl_dx11.h +++ b/examples/directx11_example/imgui_impl_dx11.h @@ -5,10 +5,13 @@ struct ID3D11Device; struct ID3D11DeviceContext; bool ImGui_ImplDX11_Init(void* hwnd, ID3D11Device* device, ID3D11DeviceContext* device_context); -void ImGui_ImplDX11_InitFontsTexture(); void ImGui_ImplDX11_Shutdown(); void ImGui_ImplDX11_NewFrame(); +// Use if you want to reset your rendering device without losing ImGui state. +void ImGui_ImplDX11_InvalidateDeviceObjects(); +bool ImGui_ImplDX11_CreateDeviceObjects(); + // 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. // Commented out to avoid dragging dependencies on types. You can copy the extern declaration in your code. diff --git a/examples/directx11_example/main.cpp b/examples/directx11_example/main.cpp index 75c77064..0620245b 100644 --- a/examples/directx11_example/main.cpp +++ b/examples/directx11_example/main.cpp @@ -1,5 +1,4 @@ // ImGui - standalone example application for DirectX 11 -// TODO: Allow resizing the application window. #include #include "imgui_impl_dx11.h" @@ -14,7 +13,29 @@ static ID3D11DeviceContext* g_pd3dDeviceContext = NULL; static IDXGISwapChain* g_pSwapChain = NULL; static ID3D11RenderTargetView* g_mainRenderTargetView = NULL; -HRESULT InitDeviceD3D(HWND hWnd) +void CreateRenderTarget() +{ + DXGI_SWAP_CHAIN_DESC sd; + g_pSwapChain->GetDesc(&sd); + + // Create the render target + ID3D11Texture2D* pBackBuffer; + D3D11_RENDER_TARGET_VIEW_DESC render_target_view_desc; + ZeroMemory(&render_target_view_desc, sizeof(render_target_view_desc)); + render_target_view_desc.Format = sd.BufferDesc.Format; + render_target_view_desc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D; + g_pSwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (LPVOID*)&pBackBuffer); + g_pd3dDevice->CreateRenderTargetView(pBackBuffer, &render_target_view_desc, &g_mainRenderTargetView); + g_pd3dDeviceContext->OMSetRenderTargets(1, &g_mainRenderTargetView, NULL); + pBackBuffer->Release(); +} + +void CleanupRenderTarget() +{ + if (g_mainRenderTargetView) { g_mainRenderTargetView->Release(); g_mainRenderTargetView = NULL; } +} + +HRESULT CreateDeviceD3D(HWND hWnd) { // Setup swap chain DXGI_SWAP_CHAIN_DESC sd; @@ -65,28 +86,17 @@ HRESULT InitDeviceD3D(HWND hWnd) pRState->Release(); } - // Create the render target - { - ID3D11Texture2D* pBackBuffer; - D3D11_RENDER_TARGET_VIEW_DESC render_target_view_desc; - ZeroMemory(&render_target_view_desc, sizeof(render_target_view_desc)); - render_target_view_desc.Format = sd.BufferDesc.Format; - render_target_view_desc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D; - g_pSwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (LPVOID*)&pBackBuffer); - g_pd3dDevice->CreateRenderTargetView(pBackBuffer, &render_target_view_desc, &g_mainRenderTargetView); - g_pd3dDeviceContext->OMSetRenderTargets(1, &g_mainRenderTargetView, NULL); - pBackBuffer->Release(); - } + CreateRenderTarget(); return S_OK; } void CleanupDeviceD3D() { - if (g_mainRenderTargetView) g_mainRenderTargetView->Release(); - if (g_pSwapChain) g_pSwapChain->Release(); - if (g_pd3dDeviceContext) g_pd3dDeviceContext->Release(); - if (g_pd3dDevice) g_pd3dDevice->Release(); + CleanupRenderTarget(); + if (g_pSwapChain) { g_pSwapChain->Release(); g_pSwapChain = NULL; } + if (g_pd3dDeviceContext) { g_pd3dDeviceContext->Release(); g_pd3dDeviceContext = NULL; } + if (g_pd3dDevice) { g_pd3dDevice->Release(); g_pd3dDevice = NULL; } } extern LRESULT ImGui_ImplDX11_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); @@ -97,6 +107,16 @@ LRESULT WINAPI WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) switch (msg) { + case WM_SIZE: + if (g_pd3dDevice != NULL && wParam != SIZE_MINIMIZED) + { + ImGui_ImplDX11_InvalidateDeviceObjects(); + CleanupRenderTarget(); + g_pSwapChain->ResizeBuffers(0, (UINT)LOWORD(lParam), (UINT)HIWORD(lParam), DXGI_FORMAT_UNKNOWN, 0); + CreateRenderTarget(); + ImGui_ImplDX11_CreateDeviceObjects(); + } + return 0; case WM_DESTROY: PostQuitMessage(0); return 0; @@ -112,7 +132,7 @@ int main(int argc, char** argv) HWND hwnd = CreateWindow(L"ImGui Example", L"ImGui DirectX11 Example", WS_OVERLAPPEDWINDOW, 100, 100, 1280, 800, NULL, NULL, wc.hInstance, NULL); // Initialize Direct3D - if (InitDeviceD3D(hwnd) < 0) + if (CreateDeviceD3D(hwnd) < 0) { CleanupDeviceD3D(); UnregisterClass(L"ImGui Example", wc.hInstance); @@ -131,7 +151,6 @@ int main(int argc, char** argv) //ImFont* my_font3 = io.Fonts->AddFontFromFileTTF("extra_fonts/ProggyClean.ttf", 13.0f); my_font3->DisplayOffset.y += 1; //ImFont* my_font4 = io.Fonts->AddFontFromFileTTF("extra_fonts/ProggyTiny.ttf", 10.0f); my_font4->DisplayOffset.y += 1; //ImFont* my_font5 = io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf", 18.0f, io.Fonts->GetGlyphRangesJapanese()); - ImGui_ImplDX11_InitFontsTexture(); bool show_test_window = true; bool show_another_window = false; From f9c833b4a5fce38c489dd018df3d3f1b51096d7d Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 9 Mar 2015 14:55:46 +0000 Subject: [PATCH 44/48] Examples: DirectX9 example cleanup to match DirectX11 structure. --- .../directx11_example/imgui_impl_dx11.cpp | 4 +- examples/directx9_example/imgui_impl_dx9.cpp | 104 +++++++++--------- examples/directx9_example/imgui_impl_dx9.h | 3 +- examples/directx9_example/main.cpp | 1 - 4 files changed, 55 insertions(+), 57 deletions(-) diff --git a/examples/directx11_example/imgui_impl_dx11.cpp b/examples/directx11_example/imgui_impl_dx11.cpp index ffcb7cdb..a2cbd0da 100644 --- a/examples/directx11_example/imgui_impl_dx11.cpp +++ b/examples/directx11_example/imgui_impl_dx11.cpp @@ -180,7 +180,7 @@ LRESULT ImGui_ImplDX11_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM return 0; } -static void ImGui_ImplDX11_InitFontsTexture() +static void ImGui_ImplDX11_CreateFontsTexture() { ImGuiIO& io = ImGui::GetIO(); @@ -359,7 +359,7 @@ bool ImGui_ImplDX11_CreateDeviceObjects() return false; } - ImGui_ImplDX11_InitFontsTexture(); + ImGui_ImplDX11_CreateFontsTexture(); return true; } diff --git a/examples/directx9_example/imgui_impl_dx9.cpp b/examples/directx9_example/imgui_impl_dx9.cpp index c69a8d2e..259102af 100644 --- a/examples/directx9_example/imgui_impl_dx9.cpp +++ b/examples/directx9_example/imgui_impl_dx9.cpp @@ -13,7 +13,6 @@ static HWND g_hWnd = 0; static INT64 g_Time = 0; static INT64 g_TicksPerSecond = 0; -static bool g_FontTextureLoaded = false; static LPDIRECT3DDEVICE9 g_pd3dDevice = NULL; static LPDIRECT3DVERTEXBUFFER9 g_pVB = NULL; @@ -145,37 +144,6 @@ LRESULT ImGui_ImplDX9_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM return 0; } -void ImGui_ImplDX9_InitFontsTexture() -{ - ImGuiIO& io = ImGui::GetIO(); - - // Build - unsigned char* pixels; - int width, height, bytes_per_pixel; - io.Fonts->GetTexDataAsAlpha8(&pixels, &width, &height, &bytes_per_pixel); - - // Create DX9 texture - LPDIRECT3DTEXTURE9 pTexture = NULL; - if (D3DXCreateTexture(g_pd3dDevice, width, height, 1, D3DUSAGE_DYNAMIC, D3DFMT_A8, D3DPOOL_DEFAULT, &pTexture) < 0) - { - IM_ASSERT(0); - return; - } - D3DLOCKED_RECT tex_locked_rect; - if (pTexture->LockRect(0, &tex_locked_rect, NULL, 0) != D3D_OK) - { - IM_ASSERT(0); - return; - } - 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)); - pTexture->UnlockRect(0); - - // Store our identifier - io.Fonts->TexID = (void *)pTexture; - g_FontTextureLoaded = true; -} - bool ImGui_ImplDX9_Init(void* hwnd, IDirect3DDevice9* device) { g_hWnd = (HWND)hwnd; @@ -214,6 +182,56 @@ bool ImGui_ImplDX9_Init(void* hwnd, IDirect3DDevice9* device) return true; } +void ImGui_ImplDX9_Shutdown() +{ + ImGui_ImplDX9_InvalidateDeviceObjects(); + ImGui::Shutdown(); + g_pd3dDevice = NULL; + g_hWnd = 0; +} + +static void ImGui_ImplDX9_CreateFontsTexture() +{ + ImGuiIO& io = ImGui::GetIO(); + + // Build + unsigned char* pixels; + int width, height, bytes_per_pixel; + io.Fonts->GetTexDataAsAlpha8(&pixels, &width, &height, &bytes_per_pixel); + + // Create DX9 texture + LPDIRECT3DTEXTURE9 pTexture = NULL; + if (D3DXCreateTexture(g_pd3dDevice, width, height, 1, D3DUSAGE_DYNAMIC, D3DFMT_A8, D3DPOOL_DEFAULT, &pTexture) < 0) + { + IM_ASSERT(0); + return; + } + D3DLOCKED_RECT tex_locked_rect; + if (pTexture->LockRect(0, &tex_locked_rect, NULL, 0) != D3D_OK) + { + IM_ASSERT(0); + return; + } + 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)); + pTexture->UnlockRect(0); + + // Store our identifier + io.Fonts->TexID = (void *)pTexture; +} + +bool ImGui_ImplDX9_CreateDeviceObjects() +{ + if (!g_pd3dDevice) + return false; + + if (g_pd3dDevice->CreateVertexBuffer(10000 * sizeof(CUSTOMVERTEX), D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY, D3DFVF_CUSTOMVERTEX, D3DPOOL_DEFAULT, &g_pVB, NULL) < 0) + return false; + + ImGui_ImplDX9_CreateFontsTexture(); + return true; +} + void ImGui_ImplDX9_InvalidateDeviceObjects() { if (!g_pd3dDevice) @@ -230,28 +248,10 @@ void ImGui_ImplDX9_InvalidateDeviceObjects() } } -void ImGui_ImplDX9_CreateDeviceObjects() -{ - if (!g_pd3dDevice) - return; - if (g_pd3dDevice->CreateVertexBuffer(10000 * sizeof(CUSTOMVERTEX), D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY, D3DFVF_CUSTOMVERTEX, D3DPOOL_DEFAULT, &g_pVB, NULL) < 0) - return; - - ImGui_ImplDX9_InitFontsTexture(); -} - -void ImGui_ImplDX9_Shutdown() -{ - ImGui_ImplDX9_InvalidateDeviceObjects(); - ImGui::Shutdown(); - g_pd3dDevice = NULL; - g_hWnd = 0; -} - void ImGui_ImplDX9_NewFrame() { - if (!g_FontTextureLoaded) - ImGui_ImplDX9_InitFontsTexture(); + if (!g_pVB) + ImGui_ImplDX9_CreateDeviceObjects(); ImGuiIO& io = ImGui::GetIO(); diff --git a/examples/directx9_example/imgui_impl_dx9.h b/examples/directx9_example/imgui_impl_dx9.h index 1822bee8..0f53b3d5 100644 --- a/examples/directx9_example/imgui_impl_dx9.h +++ b/examples/directx9_example/imgui_impl_dx9.h @@ -4,13 +4,12 @@ struct IDirect3DDevice9; bool ImGui_ImplDX9_Init(void* hwnd, IDirect3DDevice9* device); -void ImGui_ImplDX9_InitFontsTexture(); void ImGui_ImplDX9_Shutdown(); void ImGui_ImplDX9_NewFrame(); // Use if you want to reset your rendering device without losing ImGui state. void ImGui_ImplDX9_InvalidateDeviceObjects(); -void ImGui_ImplDX9_CreateDeviceObjects(); +bool ImGui_ImplDX9_CreateDeviceObjects(); // 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. diff --git a/examples/directx9_example/main.cpp b/examples/directx9_example/main.cpp index 2f2a6188..75892ffb 100644 --- a/examples/directx9_example/main.cpp +++ b/examples/directx9_example/main.cpp @@ -75,7 +75,6 @@ int main(int argc, char** argv) //ImFont* my_font3 = io.Fonts->AddFontFromFileTTF("extra_fonts/ProggyClean.ttf", 13.0f); my_font3->DisplayOffset.y += 1; //ImFont* my_font4 = io.Fonts->AddFontFromFileTTF("extra_fonts/ProggyTiny.ttf", 10.0f); my_font4->DisplayOffset.y += 1; //ImFont* my_font5 = io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf", 18.0f, io.Fonts->GetGlyphRangesJapanese()); - ImGui_ImplDX9_InitFontsTexture(); ShowWindow(hwnd, SW_SHOWDEFAULT); UpdateWindow(hwnd); From 5879f3f5ac86845c2b93b9701c3cb636f9890d77 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 9 Mar 2015 15:02:22 +0000 Subject: [PATCH 45/48] Examples: OpenGL 2/3 examples cleanup to match DirectX9/11 structure. --- .../opengl3_example/imgui_impl_glfw_gl3.cpp | 29 +++++++-------- .../opengl3_example/imgui_impl_glfw_gl3.h | 5 ++- examples/opengl3_example/main.cpp | 1 - examples/opengl_example/imgui_impl_glfw.cpp | 35 +++++++++++-------- examples/opengl_example/imgui_impl_glfw.h | 5 ++- examples/opengl_example/main.cpp | 1 - 6 files changed, 44 insertions(+), 32 deletions(-) diff --git a/examples/opengl3_example/imgui_impl_glfw_gl3.cpp b/examples/opengl3_example/imgui_impl_glfw_gl3.cpp index 92def5ed..1c883441 100644 --- a/examples/opengl3_example/imgui_impl_glfw_gl3.cpp +++ b/examples/opengl3_example/imgui_impl_glfw_gl3.cpp @@ -19,7 +19,7 @@ static GLFWwindow* g_Window = NULL; static double g_Time = 0.0f; static bool g_MousePressed[3] = { false, false, false }; static float g_MouseWheel = 0.0f; -static bool g_FontTextureLoaded = false; +static GLuint g_FontTexture = 0; static int g_ShaderHandle = 0, g_VertHandle = 0, g_FragHandle = 0; static int g_AttribLocationTex = 0, g_AttribLocationProjMtx = 0; static int g_AttribLocationPosition = 0, g_AttribLocationUV = 0, g_AttribLocationColor = 0; @@ -145,7 +145,7 @@ void ImGui_ImplGlfwGL3_CharCallback(GLFWwindow* window, unsigned int c) io.AddInputCharacter((unsigned short)c); } -void ImGui_ImplGlfwGL3_InitFontsTexture() +void ImGui_ImplGlfwGL3_CreateFontsTexture() { ImGuiIO& io = ImGui::GetIO(); @@ -153,20 +153,17 @@ void ImGui_ImplGlfwGL3_InitFontsTexture() int width, height; io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); // Load as RGBA 32-bits for OpenGL3 demo because it is more likely to be compatible with user's existing shader. - GLuint tex_id; - glGenTextures(1, &tex_id); - glBindTexture(GL_TEXTURE_2D, tex_id); + glGenTextures(1, &g_FontTexture); + glBindTexture(GL_TEXTURE_2D, g_FontTexture); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels); // Store our identifier - io.Fonts->TexID = (void *)(intptr_t)tex_id; - - g_FontTextureLoaded = true; + io.Fonts->TexID = (void *)(intptr_t)g_FontTexture; } -static void InitGL() +bool ImGui_ImplGlfwGL3_CreateDeviceObjects() { const GLchar *vertex_shader = "#version 330\n" @@ -229,12 +226,15 @@ static void InitGL() #undef OFFSETOF glBindVertexArray(0); glBindBuffer(GL_ARRAY_BUFFER, 0); + + ImGui_ImplGlfwGL3_CreateFontsTexture(); + + return true; } bool ImGui_ImplGlfwGL3_Init(GLFWwindow* window, bool install_callbacks) { g_Window = window; - InitGL(); ImGuiIO& io = ImGui::GetIO(); io.KeyMap[ImGuiKey_Tab] = GLFW_KEY_TAB; // Keyboard mapping. ImGui will use those indices to peek into the io.KeyDown[] array. @@ -291,18 +291,19 @@ void ImGui_ImplGlfwGL3_Shutdown() glDeleteProgram(g_ShaderHandle); g_ShaderHandle = 0; - if (GLuint tex_id = (GLuint)(intptr_t)ImGui::GetIO().Fonts->TexID) + if (g_FontTexture) { - glDeleteTextures(1, &tex_id); + glDeleteTextures(1, &g_FontTexture); ImGui::GetIO().Fonts->TexID = 0; + g_FontTexture = 0; } ImGui::Shutdown(); } void ImGui_ImplGlfwGL3_NewFrame() { - if (!g_FontTextureLoaded) - ImGui_ImplGlfwGL3_InitFontsTexture(); + if (!g_FontTexture) + ImGui_ImplGlfwGL3_CreateDeviceObjects(); ImGuiIO& io = ImGui::GetIO(); diff --git a/examples/opengl3_example/imgui_impl_glfw_gl3.h b/examples/opengl3_example/imgui_impl_glfw_gl3.h index 16d5d532..7b181577 100644 --- a/examples/opengl3_example/imgui_impl_glfw_gl3.h +++ b/examples/opengl3_example/imgui_impl_glfw_gl3.h @@ -4,10 +4,13 @@ struct GLFWwindow; bool ImGui_ImplGlfwGL3_Init(GLFWwindow* window, bool install_callbacks); -void ImGui_ImplGlfwGL3_InitFontsTexture(); void ImGui_ImplGlfwGL3_Shutdown(); void ImGui_ImplGlfwGL3_NewFrame(); +// Use if you want to reset your rendering device without losing ImGui state. +void ImGui_ImplGlfwGL3_InvalidateDeviceObjects(); +bool ImGui_ImplGlfwGL3_CreateDeviceObjects(); + // GLFW callbacks (installed by default if you enable 'install_callbacks' during initialization) // Provided here if you want to chain callbacks. // You can also handle inputs yourself and use those as a reference. diff --git a/examples/opengl3_example/main.cpp b/examples/opengl3_example/main.cpp index d773ec3d..9651970b 100644 --- a/examples/opengl3_example/main.cpp +++ b/examples/opengl3_example/main.cpp @@ -32,7 +32,6 @@ int main(int argc, char** argv) //ImFont* my_font3 = io.Fonts->AddFontFromFileTTF("extra_fonts/ProggyClean.ttf", 13.0f); my_font3->DisplayOffset.y += 1; //ImFont* my_font4 = io.Fonts->AddFontFromFileTTF("extra_fonts/ProggyTiny.ttf", 10.0f); my_font4->DisplayOffset.y += 1; //ImFont* my_font5 = io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf", 18.0f, io.Fonts->GetGlyphRangesJapanese()); - ImGui_ImplGlfwGL3_InitFontsTexture(); bool show_test_window = true; bool show_another_window = false; diff --git a/examples/opengl_example/imgui_impl_glfw.cpp b/examples/opengl_example/imgui_impl_glfw.cpp index aa7de29b..f3273948 100644 --- a/examples/opengl_example/imgui_impl_glfw.cpp +++ b/examples/opengl_example/imgui_impl_glfw.cpp @@ -18,7 +18,7 @@ static GLFWwindow* g_Window = NULL; static double g_Time = 0.0f; static bool g_MousePressed[3] = { false, false, false }; static float g_MouseWheel = 0.0f; -static bool g_FontTextureLoaded = false; +static GLuint g_FontTexture = 0; // This is the main rendering function that you have to implement and provide to ImGui (via setting up 'RenderDrawListsFn' in the ImGuiIO structure) // If text or lines are blurry when integrating ImGui in your engine: @@ -125,25 +125,36 @@ void ImGui_ImplGlfw_CharCallback(GLFWwindow* window, unsigned int c) io.AddInputCharacter((unsigned short)c); } -void ImGui_ImplGlfw_InitFontsTexture() +bool ImGui_ImplGlfw_CreateDeviceObjects() { ImGuiIO& io = ImGui::GetIO(); + // Build texture unsigned char* pixels; int width, height; io.Fonts->GetTexDataAsAlpha8(&pixels, &width, &height); - GLuint tex_id; - glGenTextures(1, &tex_id); - glBindTexture(GL_TEXTURE_2D, tex_id); + // Create texture + glGenTextures(1, &g_FontTexture); + glBindTexture(GL_TEXTURE_2D, g_FontTexture); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, width, height, 0, GL_ALPHA, GL_UNSIGNED_BYTE, pixels); // Store our identifier - io.Fonts->TexID = (void *)(intptr_t)tex_id; + io.Fonts->TexID = (void *)(intptr_t)g_FontTexture; - g_FontTextureLoaded = true; + return true; +} + +void ImGui_ImplGlfw_InvalidateDeviceObjects() +{ + if (g_FontTexture) + { + glDeleteTextures(1, &g_FontTexture); + ImGui::GetIO().Fonts->TexID = 0; + g_FontTexture = 0; + } } bool ImGui_ImplGlfw_Init(GLFWwindow* window, bool install_callbacks) @@ -189,18 +200,14 @@ bool ImGui_ImplGlfw_Init(GLFWwindow* window, bool install_callbacks) void ImGui_ImplGlfw_Shutdown() { - if (GLuint tex_id = (GLuint)(intptr_t)ImGui::GetIO().Fonts->TexID) - { - glDeleteTextures(1, &tex_id); - ImGui::GetIO().Fonts->TexID = 0; - } + ImGui_ImplGlfw_InvalidateDeviceObjects(); ImGui::Shutdown(); } void ImGui_ImplGlfw_NewFrame() { - if (!g_FontTextureLoaded) - ImGui_ImplGlfw_InitFontsTexture(); + if (!g_FontTexture) + ImGui_ImplGlfw_CreateDeviceObjects(); ImGuiIO& io = ImGui::GetIO(); diff --git a/examples/opengl_example/imgui_impl_glfw.h b/examples/opengl_example/imgui_impl_glfw.h index 53909fa6..502d837f 100644 --- a/examples/opengl_example/imgui_impl_glfw.h +++ b/examples/opengl_example/imgui_impl_glfw.h @@ -4,10 +4,13 @@ struct GLFWwindow; bool ImGui_ImplGlfw_Init(GLFWwindow* window, bool install_callbacks); -void ImGui_ImplGlfw_InitFontsTexture(); void ImGui_ImplGlfw_Shutdown(); void ImGui_ImplGlfw_NewFrame(); +// Use if you want to reset your rendering device without losing ImGui state. +void ImGui_ImplGlfw_InvalidateDeviceObjects(); +bool ImGui_ImplGlfw_CreateDeviceObjects(); + // GLFW callbacks (installed by default if you enable 'install_callbacks' during initialization) // Provided here if you want to chain callbacks. // You can also handle inputs yourself and use those as a reference. diff --git a/examples/opengl_example/main.cpp b/examples/opengl_example/main.cpp index 1dd7839b..c9d303d0 100644 --- a/examples/opengl_example/main.cpp +++ b/examples/opengl_example/main.cpp @@ -27,7 +27,6 @@ int main(int argc, char** argv) //ImFont* my_font3 = io.Fonts->AddFontFromFileTTF("extra_fonts/ProggyClean.ttf", 13.0f); my_font3->DisplayOffset.y += 1; //ImFont* my_font4 = io.Fonts->AddFontFromFileTTF("extra_fonts/ProggyTiny.ttf", 10.0f); my_font4->DisplayOffset.y += 1; //ImFont* my_font5 = io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf", 18.0f, io.Fonts->GetGlyphRangesJapanese()); - ImGui_ImplGlfw_InitFontsTexture(); bool show_test_window = true; bool show_another_window = false; From db5fc8a26558c5728690a177a14254b721480c05 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 9 Mar 2015 15:09:24 +0000 Subject: [PATCH 46/48] Examples: README direct the user to the opengl_example --- examples/README.txt | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/examples/README.txt b/examples/README.txt index b7aaaa24..e6ce70c9 100644 --- a/examples/README.txt +++ b/examples/README.txt @@ -1,15 +1,18 @@ -directx9_example/ - DirectX9 example (Windows only). - -directx11_example/ - DirectX11 example (Windows only). - opengl_example/ OpenGL example, using GLFW + fixed pipeline. This is simple and should work for all OpenGL enabled applications. + Prefer following this example since it is the shortest one! opengl3_example/ OpenGL exemple, using GLFW/GL3W + programmable pipeline. This uses more modern calls and custom shaders. I don't think there is an advantage using this over the simpler example, but it is provided for reference. + +directx9_example/ + DirectX9 example, Windows only. + +directx11_example/ + DirectX11 example, Windows only. + This is quite long and tedious, because: DirectX11. + From d5b7b8398f658224f1695b61ea067570e197e8ac Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 9 Mar 2015 15:26:58 +0000 Subject: [PATCH 47/48] Examples: reference implementations honors drawlist user callbacks. --- .../directx11_example/imgui_impl_dx11.cpp | 15 +++++++--- examples/directx9_example/imgui_impl_dx9.cpp | 15 +++++++--- .../opengl3_example/imgui_impl_glfw_gl3.cpp | 30 +++++++++++-------- examples/opengl_example/imgui_impl_glfw.cpp | 30 +++++++++++-------- 4 files changed, 58 insertions(+), 32 deletions(-) diff --git a/examples/directx11_example/imgui_impl_dx11.cpp b/examples/directx11_example/imgui_impl_dx11.cpp index a2cbd0da..727b5eeb 100644 --- a/examples/directx11_example/imgui_impl_dx11.cpp +++ b/examples/directx11_example/imgui_impl_dx11.cpp @@ -125,10 +125,17 @@ static void ImGui_ImplDX11_RenderDrawLists(ImDrawList** const cmd_lists, int cmd for (size_t cmd_i = 0; cmd_i < cmd_list->commands.size(); cmd_i++) { const ImDrawCmd* pcmd = &cmd_list->commands[cmd_i]; - const D3D11_RECT r = { (LONG)pcmd->clip_rect.x, (LONG)pcmd->clip_rect.y, (LONG)pcmd->clip_rect.z, (LONG)pcmd->clip_rect.w }; - g_pd3dDeviceContext->PSSetShaderResources(0, 1, (ID3D11ShaderResourceView**)&pcmd->texture_id); - g_pd3dDeviceContext->RSSetScissorRects(1, &r); - g_pd3dDeviceContext->Draw(pcmd->vtx_count, vtx_offset); + if (pcmd->user_callback) + { + pcmd->user_callback(cmd_list, pcmd); + } + else + { + const D3D11_RECT r = { (LONG)pcmd->clip_rect.x, (LONG)pcmd->clip_rect.y, (LONG)pcmd->clip_rect.z, (LONG)pcmd->clip_rect.w }; + g_pd3dDeviceContext->PSSetShaderResources(0, 1, (ID3D11ShaderResourceView**)&pcmd->texture_id); + g_pd3dDeviceContext->RSSetScissorRects(1, &r); + g_pd3dDeviceContext->Draw(pcmd->vtx_count, vtx_offset); + } vtx_offset += pcmd->vtx_count; } } diff --git a/examples/directx9_example/imgui_impl_dx9.cpp b/examples/directx9_example/imgui_impl_dx9.cpp index 259102af..e47ddea9 100644 --- a/examples/directx9_example/imgui_impl_dx9.cpp +++ b/examples/directx9_example/imgui_impl_dx9.cpp @@ -94,10 +94,17 @@ static void ImGui_ImplDX9_RenderDrawLists(ImDrawList** const cmd_lists, int cmd_ for (size_t cmd_i = 0; cmd_i < cmd_list->commands.size(); cmd_i++) { const ImDrawCmd* pcmd = &cmd_list->commands[cmd_i]; - const RECT r = { (LONG)pcmd->clip_rect.x, (LONG)pcmd->clip_rect.y, (LONG)pcmd->clip_rect.z, (LONG)pcmd->clip_rect.w }; - g_pd3dDevice->SetTexture( 0, (LPDIRECT3DTEXTURE9)pcmd->texture_id ); - g_pd3dDevice->SetScissorRect(&r); - g_pd3dDevice->DrawPrimitive(D3DPT_TRIANGLELIST, vtx_offset, pcmd->vtx_count/3); + if (pcmd->user_callback) + { + pcmd->user_callback(cmd_list, pcmd); + } + else + { + const RECT r = { (LONG)pcmd->clip_rect.x, (LONG)pcmd->clip_rect.y, (LONG)pcmd->clip_rect.z, (LONG)pcmd->clip_rect.w }; + g_pd3dDevice->SetTexture( 0, (LPDIRECT3DTEXTURE9)pcmd->texture_id ); + g_pd3dDevice->SetScissorRect(&r); + g_pd3dDevice->DrawPrimitive(D3DPT_TRIANGLELIST, vtx_offset, pcmd->vtx_count/3); + } vtx_offset += pcmd->vtx_count; } } diff --git a/examples/opengl3_example/imgui_impl_glfw_gl3.cpp b/examples/opengl3_example/imgui_impl_glfw_gl3.cpp index 1c883441..adc2d673 100644 --- a/examples/opengl3_example/imgui_impl_glfw_gl3.cpp +++ b/examples/opengl3_example/imgui_impl_glfw_gl3.cpp @@ -91,9 +91,16 @@ static void ImGui_ImplGlfwGL3_RenderDrawLists(ImDrawList** const cmd_lists, int const ImDrawCmd* pcmd_end = cmd_list->commands.end(); for (const ImDrawCmd* pcmd = cmd_list->commands.begin(); pcmd != pcmd_end; pcmd++) { - glBindTexture(GL_TEXTURE_2D, (GLuint)(intptr_t)pcmd->texture_id); - glScissor((int)pcmd->clip_rect.x, (int)(height - pcmd->clip_rect.w), (int)(pcmd->clip_rect.z - pcmd->clip_rect.x), (int)(pcmd->clip_rect.w - pcmd->clip_rect.y)); - glDrawArrays(GL_TRIANGLES, vtx_offset, pcmd->vtx_count); + if (pcmd->user_callback) + { + pcmd->user_callback(cmd_list, pcmd); + } + else + { + glBindTexture(GL_TEXTURE_2D, (GLuint)(intptr_t)pcmd->texture_id); + glScissor((int)pcmd->clip_rect.x, (int)(height - pcmd->clip_rect.w), (int)(pcmd->clip_rect.z - pcmd->clip_rect.x), (int)(pcmd->clip_rect.w - pcmd->clip_rect.y)); + glDrawArrays(GL_TRIANGLES, vtx_offset, pcmd->vtx_count); + } vtx_offset += pcmd->vtx_count; } cmd_offset = vtx_offset; @@ -323,16 +330,15 @@ void ImGui_ImplGlfwGL3_NewFrame() // (we already got mouse wheel, keyboard keys & characters from glfw callbacks polled in glfwPollEvents()) double mouse_x, mouse_y; glfwGetCursorPos(g_Window, &mouse_x, &mouse_y); - mouse_x *= (float)display_w / w; // Convert mouse coordinates to pixels + mouse_x *= (float)display_w / w; // Convert mouse coordinates to pixels mouse_y *= (float)display_h / h; - io.MousePos = ImVec2((float)mouse_x, (float)mouse_y); // Mouse position, in pixels (set to -1,-1 if no mouse / on another screen, etc.) - - io.MouseDown[0] = g_MousePressed[0] || glfwGetMouseButton(g_Window, GLFW_MOUSE_BUTTON_LEFT) != 0; // If a mouse press event came, always pass it as "mouse held this frame", so we don't miss click-release events that are shorter than 1 frame. - io.MouseDown[1] = g_MousePressed[1] || glfwGetMouseButton(g_Window, GLFW_MOUSE_BUTTON_RIGHT) != 0; - io.MouseDown[2] = g_MousePressed[2] || glfwGetMouseButton(g_Window, GLFW_MOUSE_BUTTON_MIDDLE) != 0; - g_MousePressed[0] = false; - g_MousePressed[1] = false; - g_MousePressed[2] = false; + io.MousePos = ImVec2((float)mouse_x, (float)mouse_y); // Mouse position, in pixels (set to -1,-1 if no mouse / on another screen, etc.) + + for (int i = 0; i < 3; i++) + { + io.MouseDown[i] = g_MousePressed[i] || glfwGetMouseButton(g_Window, i) != 0; // If a mouse press event came, always pass it as "mouse held this frame", so we don't miss click-release events that are shorter than 1 frame. + g_MousePressed[i] = false; + } io.MouseWheel = g_MouseWheel; g_MouseWheel = 0.0f; diff --git a/examples/opengl_example/imgui_impl_glfw.cpp b/examples/opengl_example/imgui_impl_glfw.cpp index f3273948..2be01de0 100644 --- a/examples/opengl_example/imgui_impl_glfw.cpp +++ b/examples/opengl_example/imgui_impl_glfw.cpp @@ -67,9 +67,16 @@ static void ImGui_ImplGlfw_RenderDrawLists(ImDrawList** const cmd_lists, int cmd for (size_t cmd_i = 0; cmd_i < cmd_list->commands.size(); cmd_i++) { const ImDrawCmd* pcmd = &cmd_list->commands[cmd_i]; - glBindTexture(GL_TEXTURE_2D, (GLuint)(intptr_t)pcmd->texture_id); - glScissor((int)pcmd->clip_rect.x, (int)(height - pcmd->clip_rect.w), (int)(pcmd->clip_rect.z - pcmd->clip_rect.x), (int)(pcmd->clip_rect.w - pcmd->clip_rect.y)); - glDrawArrays(GL_TRIANGLES, vtx_offset, pcmd->vtx_count); + if (pcmd->user_callback) + { + pcmd->user_callback(cmd_list, pcmd); + } + else + { + glBindTexture(GL_TEXTURE_2D, (GLuint)(intptr_t)pcmd->texture_id); + glScissor((int)pcmd->clip_rect.x, (int)(height - pcmd->clip_rect.w), (int)(pcmd->clip_rect.z - pcmd->clip_rect.x), (int)(pcmd->clip_rect.w - pcmd->clip_rect.y)); + glDrawArrays(GL_TRIANGLES, vtx_offset, pcmd->vtx_count); + } vtx_offset += pcmd->vtx_count; } } @@ -227,16 +234,15 @@ void ImGui_ImplGlfw_NewFrame() // (we already got mouse wheel, keyboard keys & characters from glfw callbacks polled in glfwPollEvents()) double mouse_x, mouse_y; glfwGetCursorPos(g_Window, &mouse_x, &mouse_y); - mouse_x *= (float)display_w / w; // Convert mouse coordinates to pixels + mouse_x *= (float)display_w / w; // Convert mouse coordinates to pixels mouse_y *= (float)display_h / h; - io.MousePos = ImVec2((float)mouse_x, (float)mouse_y); // Mouse position, in pixels (set to -1,-1 if no mouse / on another screen, etc.) - - io.MouseDown[0] = g_MousePressed[0] || glfwGetMouseButton(g_Window, GLFW_MOUSE_BUTTON_LEFT) != 0; // If a mouse press event came, always pass it as "mouse held this frame", so we don't miss click-release events that are shorter than 1 frame. - io.MouseDown[1] = g_MousePressed[1] || glfwGetMouseButton(g_Window, GLFW_MOUSE_BUTTON_RIGHT) != 0; - io.MouseDown[2] = g_MousePressed[2] || glfwGetMouseButton(g_Window, GLFW_MOUSE_BUTTON_MIDDLE) != 0; - g_MousePressed[0] = false; - g_MousePressed[1] = false; - g_MousePressed[2] = false; + io.MousePos = ImVec2((float)mouse_x, (float)mouse_y); // Mouse position, in pixels (set to -1,-1 if no mouse / on another screen, etc.) + + for (int i = 0; i < 3; i++) + { + io.MouseDown[i] = g_MousePressed[i] || glfwGetMouseButton(g_Window, i) != 0; // If a mouse press event came, always pass it as "mouse held this frame", so we don't miss click-release events that are shorter than 1 frame. + g_MousePressed[i] = false; + } io.MouseWheel = g_MouseWheel; g_MouseWheel = 0.0f; From d440a13b7e9289582ccb871073124f69b1497753 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 9 Mar 2015 17:30:22 +0000 Subject: [PATCH 48/48] Version number --- imgui.cpp | 2 +- imgui.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 1c46254e..6cb7be3e 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1,4 +1,4 @@ -// ImGui library v1.35 wip +// ImGui library v1.35 // See ImGui::ShowTestWindow() for sample code. // Read 'Programmer guide' below for notes on how to setup ImGui in your codebase. // Get latest version at https://github.com/ocornut/imgui diff --git a/imgui.h b/imgui.h index 9004e559..f4f36f18 100644 --- a/imgui.h +++ b/imgui.h @@ -1,4 +1,4 @@ -// ImGui library v1.35 wip +// ImGui library v1.35 // See .cpp file for documentation. // See ImGui::ShowTestWindow() for sample code. // Read 'Programmer guide' in .cpp for notes on how to setup ImGui in your codebase.