Browse Source

Merge remote-tracking branch 'origin' into 2015-04-indexed-rendering

Conflicts:
	examples/directx11_example/imgui_impl_dx11.cpp
	imgui.cpp
ocornut 10 years ago
parent
commit
43cb4038c6

+ 1 - 2
examples/directx11_example/imgui_impl_dx11.cpp

@@ -52,8 +52,7 @@ static void ImGui_ImplDX11_RenderDrawLists(ImDrawList** const cmd_lists, int cmd
     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];
-        memcpy(vtx_dst, vtx_src, cmd_list->vtx_buffer.size() * sizeof(ImDrawVert));
+        memcpy(vtx_dst, &cmd_list->vtx_buffer[0], cmd_list->vtx_buffer.size() * sizeof(ImDrawVert));
         memcpy(idx_dst, &cmd_list->idx_buffer[0], cmd_list->idx_buffer.size() * sizeof(ImDrawIdx));
         vtx_dst += cmd_list->vtx_buffer.size();
         idx_dst += cmd_list->idx_buffer.size();

+ 6 - 4
examples/opengl3_example/imgui_impl_glfw_gl3.cpp

@@ -135,16 +135,18 @@ void ImGui_ImplGlfwGL3_ScrollCallback(GLFWwindow*, double /*xoffset*/, double yo
     g_MouseWheel += (float)yoffset; // Use fractional mouse wheel, 1.0 unit 5 lines.
 }
 
-void ImGui_ImplGlfwGL3_KeyCallback(GLFWwindow*, int key, int, int action, int mods)
+void ImGui_ImplGlfwGL3_KeyCallback(GLFWwindow* window, int key, int, 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;
-    io.KeyAlt = (mods & GLFW_MOD_ALT) != 0;
+
+    (void)mods; // Modifiers are not reliable across systems
+    io.KeyCtrl = glfwGetKey(window, GLFW_KEY_LEFT_CONTROL) == GLFW_PRESS || glfwGetKey(window, GLFW_KEY_RIGHT_CONTROL) == GLFW_PRESS;
+    io.KeyShift = glfwGetKey(window, GLFW_KEY_LEFT_SHIFT) == GLFW_PRESS || glfwGetKey(window, GLFW_KEY_RIGHT_SHIFT) == GLFW_PRESS;
+    io.KeyAlt = glfwGetKey(window, GLFW_KEY_LEFT_ALT) == GLFW_PRESS || glfwGetKey(window, GLFW_KEY_RIGHT_ALT) == GLFW_PRESS;
 }
 
 void ImGui_ImplGlfwGL3_CharCallback(GLFWwindow*, unsigned int c)

+ 6 - 4
examples/opengl_example/imgui_impl_glfw.cpp

@@ -116,16 +116,18 @@ void ImGui_ImplGlfw_ScrollCallback(GLFWwindow*, double /*xoffset*/, double yoffs
     g_MouseWheel += (float)yoffset; // Use fractional mouse wheel, 1.0 unit 5 lines.
 }
 
-void ImGui_ImplGlFw_KeyCallback(GLFWwindow*, int key, int, int action, int mods)
+void ImGui_ImplGlFw_KeyCallback(GLFWwindow* window, int key, int, 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;
-    io.KeyAlt = (mods & GLFW_MOD_ALT) != 0;
+
+    (void)mods; // Modifiers are not reliable across systems
+    io.KeyCtrl = glfwGetKey(window, GLFW_KEY_LEFT_CONTROL) == GLFW_PRESS || glfwGetKey(window, GLFW_KEY_RIGHT_CONTROL) == GLFW_PRESS;
+    io.KeyShift = glfwGetKey(window, GLFW_KEY_LEFT_SHIFT) == GLFW_PRESS || glfwGetKey(window, GLFW_KEY_RIGHT_SHIFT) == GLFW_PRESS;
+    io.KeyAlt = glfwGetKey(window, GLFW_KEY_LEFT_ALT) == GLFW_PRESS || glfwGetKey(window, GLFW_KEY_RIGHT_ALT) == GLFW_PRESS;
 }
 
 void ImGui_ImplGlfw_CharCallback(GLFWwindow*, unsigned int c)

+ 330 - 0
extra_fonts/binary_to_compressed_c.cpp

@@ -0,0 +1,330 @@
+// ImGui - binary_to_compressed_c.cpp
+// Helper tool to turn a file into a C array.
+// The data is first compressed with stb_compress() to reduce source code size a little.
+// Useful if you want to embed fonts into your code.
+// Note that the output array is likely to be bigger than the binary file..
+// Load compressed TTF fonts with ImGui::GetIO().Fonts->AddFontFromMemoryCompressedTTF()
+
+#define _CRT_SECURE_NO_WARNINGS
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <assert.h>
+
+const int COLUMNS = 12;
+
+// stb_compress* from stb.h - declaration
+typedef unsigned int stb_uint;
+typedef unsigned char stb_uchar;
+stb_uint stb_compress(stb_uchar *out,stb_uchar *in,stb_uint len);
+
+static bool binary_to_compressed_c(const char* filename, const char* symbol);
+
+int main(int argc, char** argv)
+{
+    if (argc < 3)
+    {
+        printf("Syntax: %s <inputfile> <symbolname>\n", argv[0]);
+        return 0;
+    }
+
+    binary_to_compressed_c(argv[1], argv[2]);
+    return 1;
+}
+
+bool binary_to_compressed_c(const char* filename, const char* symbol)
+{
+    // Read file
+    FILE* f = fopen(filename, "rb");
+    if (!f) return false;
+    int data_sz;
+    if (fseek(f, 0, SEEK_END) || (data_sz = (int)ftell(f)) == -1 || fseek(f, 0, SEEK_SET)) { fclose(f); return false; }
+    char* data = new char[data_sz+4];
+    if (fread(data, 1, data_sz, f) != (size_t)data_sz) { fclose(f); delete[] data; return false; }
+    memset((void *)(((char*)data) + data_sz), 0, 4);
+    fclose(f);
+
+    // Compress
+    int maxlen = data_sz + 512 + (data_sz >> 2) + sizeof(int); // total guess
+    char* compressed = new char[maxlen];
+    int compressed_sz = stb_compress((stb_uchar*)compressed, (stb_uchar*)data, data_sz);
+    memset(compressed + compressed_sz, 0, maxlen - compressed_sz);
+
+    // Output
+    FILE* out = stdout;
+    fprintf(out, "// File: '%s' (%d bytes)\n", filename, (int)data_sz);
+    fprintf(out, "// Exported using binary_to_compressed_c\n");
+    fprintf(out, "static const unsigned int %s_compressed_size = %d;\n", symbol, (int)compressed_sz);
+    fprintf(out, "static const unsigned int %s_compressed_data[%d/4] =\n{", symbol, (int)((compressed_sz+3)/4)*4);
+    int column = 0;
+    for (int i = 0; i < compressed_sz; i += 4)
+    {
+        unsigned int d = *(unsigned int*)(compressed + i);
+        if ((column++ % COLUMNS) == 0)
+            fprintf(out, "\n    0x%08x, ", d);
+        else
+            fprintf(out, "0x%08x, ", d);
+    }
+    fprintf(out, "\n};\n\n");
+
+    // Cleanup
+    delete[] data;
+    delete[] compressed;
+    return true;
+}
+
+// stb_compress* from stb.h - definition
+
+////////////////////           compressor         ///////////////////////
+
+static stb_uint stb_adler32(stb_uint adler32, stb_uchar *buffer, stb_uint buflen)
+{
+    const unsigned long ADLER_MOD = 65521;
+    unsigned long s1 = adler32 & 0xffff, s2 = adler32 >> 16;
+    unsigned long blocklen, i;
+
+    blocklen = buflen % 5552;
+    while (buflen) {
+        for (i=0; i + 7 < blocklen; i += 8) {
+            s1 += buffer[0], s2 += s1;
+            s1 += buffer[1], s2 += s1;
+            s1 += buffer[2], s2 += s1;
+            s1 += buffer[3], s2 += s1;
+            s1 += buffer[4], s2 += s1;
+            s1 += buffer[5], s2 += s1;
+            s1 += buffer[6], s2 += s1;
+            s1 += buffer[7], s2 += s1;
+
+            buffer += 8;
+        }
+
+        for (; i < blocklen; ++i)
+            s1 += *buffer++, s2 += s1;
+
+        s1 %= ADLER_MOD, s2 %= ADLER_MOD;
+        buflen -= blocklen;
+        blocklen = 5552;
+    }
+    return (s2 << 16) + s1;
+}
+
+static unsigned int stb_matchlen(stb_uchar *m1, stb_uchar *m2, stb_uint maxlen)
+{
+    stb_uint i;
+    for (i=0; i < maxlen; ++i)
+        if (m1[i] != m2[i]) return i;
+    return i;
+}
+
+// simple implementation that just takes the source data in a big block
+
+static stb_uchar *stb__out;
+static FILE      *stb__outfile;
+static stb_uint   stb__outbytes;
+
+static void stb__write(unsigned char v)
+{
+    fputc(v, stb__outfile);
+    ++stb__outbytes;
+}
+
+#define stb_out(v)    (stb__out ? *stb__out++ = (stb_uchar) (v) : stb__write((stb_uchar) (v)))
+
+static void stb_out2(stb_uint v)
+{
+    stb_out(v >> 8);
+    stb_out(v);
+}
+
+static void stb_out3(stb_uint v) { stb_out(v >> 16); stb_out(v >> 8); stb_out(v); }
+static void stb_out4(stb_uint v) { stb_out(v >> 24); stb_out(v >> 16);
+stb_out(v >> 8 ); stb_out(v);                  }
+
+static void outliterals(stb_uchar *in, int numlit)
+{
+    while (numlit > 65536) {
+        outliterals(in,65536);
+        in     += 65536;
+        numlit -= 65536;
+    }
+
+    if      (numlit ==     0)    ;
+    else if (numlit <=    32)    stb_out (0x000020 + numlit-1);
+    else if (numlit <=  2048)    stb_out2(0x000800 + numlit-1);
+    else /*  numlit <= 65536) */ stb_out3(0x070000 + numlit-1);
+
+    if (stb__out) {
+        memcpy(stb__out,in,numlit);
+        stb__out += numlit;
+    } else
+        fwrite(in, 1, numlit, stb__outfile);
+}
+
+static int stb__window = 0x40000; // 256K
+
+static int stb_not_crap(int best, int dist)
+{
+    return   ((best > 2  &&  dist <= 0x00100)     
+        || (best > 5  &&  dist <= 0x04000)
+        || (best > 7  &&  dist <= 0x80000));
+}
+
+static  stb_uint stb__hashsize = 32768;
+
+// note that you can play with the hashing functions all you
+// want without needing to change the decompressor
+#define stb__hc(q,h,c)      (((h) << 7) + ((h) >> 25) + q[c])
+#define stb__hc2(q,h,c,d)   (((h) << 14) + ((h) >> 18) + (q[c] << 7) + q[d])
+#define stb__hc3(q,c,d,e)   ((q[c] << 14) + (q[d] << 7) + q[e])
+
+static unsigned int stb__running_adler;
+
+static int stb_compress_chunk(stb_uchar *history,
+    stb_uchar *start,
+    stb_uchar *end,
+    int length,
+    int *pending_literals,
+    stb_uchar **chash,
+    stb_uint mask)
+{
+    (void)history;
+    int window = stb__window;
+    stb_uint match_max;
+    stb_uchar *lit_start = start - *pending_literals;
+    stb_uchar *q = start;
+
+#define STB__SCRAMBLE(h)   (((h) + ((h) >> 16)) & mask)
+
+    // stop short of the end so we don't scan off the end doing
+    // the hashing; this means we won't compress the last few bytes
+    // unless they were part of something longer
+    while (q < start+length && q+12 < end) {
+        int m;
+        stb_uint h1,h2,h3,h4, h;
+        stb_uchar *t;
+        int best = 2, dist=0;
+
+        if (q+65536 > end)
+            match_max = end-q;
+        else
+            match_max = 65536;
+
+#define stb__nc(b,d)  ((d) <= window && ((b) > 9 || stb_not_crap(b,d)))
+
+#define STB__TRY(t,p)  /* avoid retrying a match we already tried */ \
+    if (p ? dist != q-t : 1)                             \
+    if ((m = stb_matchlen(t, q, match_max)) > best)     \
+    if (stb__nc(m,q-(t)))                                \
+    best = m, dist = q - (t)
+
+        // rather than search for all matches, only try 4 candidate locations,
+        // chosen based on 4 different hash functions of different lengths.
+        // this strategy is inspired by LZO; hashing is unrolled here using the
+        // 'hc' macro
+        h = stb__hc3(q,0, 1, 2); h1 = STB__SCRAMBLE(h);
+        t = chash[h1]; if (t) STB__TRY(t,0);
+        h = stb__hc2(q,h, 3, 4); h2 = STB__SCRAMBLE(h);
+        h = stb__hc2(q,h, 5, 6);        t = chash[h2]; if (t) STB__TRY(t,1);
+        h = stb__hc2(q,h, 7, 8); h3 = STB__SCRAMBLE(h);
+        h = stb__hc2(q,h, 9,10);        t = chash[h3]; if (t) STB__TRY(t,1);
+        h = stb__hc2(q,h,11,12); h4 = STB__SCRAMBLE(h);
+        t = chash[h4]; if (t) STB__TRY(t,1);
+
+        // because we use a shared hash table, can only update it
+        // _after_ we've probed all of them
+        chash[h1] = chash[h2] = chash[h3] = chash[h4] = q;
+
+        if (best > 2)
+            assert(dist > 0);
+
+        // see if our best match qualifies
+        if (best < 3) { // fast path literals
+            ++q;
+        } else if (best > 2  &&  best <= 0x80    &&  dist <= 0x100) {
+            outliterals(lit_start, q-lit_start); lit_start = (q += best);
+            stb_out(0x80 + best-1);
+            stb_out(dist-1);
+        } else if (best > 5  &&  best <= 0x100   &&  dist <= 0x4000) {
+            outliterals(lit_start, q-lit_start); lit_start = (q += best);
+            stb_out2(0x4000 + dist-1);       
+            stb_out(best-1);
+        } else if (best > 7  &&  best <= 0x100   &&  dist <= 0x80000) {
+            outliterals(lit_start, q-lit_start); lit_start = (q += best);
+            stb_out3(0x180000 + dist-1);     
+            stb_out(best-1);
+        } else if (best > 8  &&  best <= 0x10000 &&  dist <= 0x80000) {
+            outliterals(lit_start, q-lit_start); lit_start = (q += best);
+            stb_out3(0x100000 + dist-1);     
+            stb_out2(best-1);
+        } else if (best > 9                      &&  dist <= 0x1000000) {
+            if (best > 65536) best = 65536;
+            outliterals(lit_start, q-lit_start); lit_start = (q += best);
+            if (best <= 0x100) {
+                stb_out(0x06);
+                stb_out3(dist-1);
+                stb_out(best-1);
+            } else {
+                stb_out(0x04);
+                stb_out3(dist-1);
+                stb_out2(best-1);
+            }
+        } else {  // fallback literals if no match was a balanced tradeoff
+            ++q;
+        }
+    }
+
+    // if we didn't get all the way, add the rest to literals
+    if (q-start < length)
+        q = start+length;
+
+    // the literals are everything from lit_start to q
+    *pending_literals = (q - lit_start);
+
+    stb__running_adler = stb_adler32(stb__running_adler, start, q - start);
+    return q - start;
+}
+
+static int stb_compress_inner(stb_uchar *input, stb_uint length)
+{
+    int literals = 0;
+    stb_uint len,i;
+
+    stb_uchar **chash;
+    chash = (stb_uchar**) malloc(stb__hashsize * sizeof(stb_uchar*));
+    if (chash == NULL) return 0; // failure
+    for (i=0; i < stb__hashsize; ++i)
+        chash[i] = NULL;
+
+    // stream signature
+    stb_out(0x57); stb_out(0xbc);
+    stb_out2(0);
+
+    stb_out4(0);       // 64-bit length requires 32-bit leading 0
+    stb_out4(length);
+    stb_out4(stb__window);
+
+    stb__running_adler = 1;
+
+    len = stb_compress_chunk(input, input, input+length, length, &literals, chash, stb__hashsize-1);
+    assert(len == length);
+
+    outliterals(input+length - literals, literals);
+
+    free(chash);
+
+    stb_out2(0x05fa); // end opcode
+
+    stb_out4(stb__running_adler);
+
+    return 1; // success
+}
+
+stb_uint stb_compress(stb_uchar *out, stb_uchar *input, stb_uint length)
+{
+    stb__out = out;
+    stb__outfile = NULL;
+
+    stb_compress_inner(input, length);
+
+    return stb__out - out;
+}

+ 142 - 64
imgui.cpp

@@ -1,4 +1,4 @@
-// ImGui library v1.38 WIP
+// ImGui library v1.38 WIP
 // 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
@@ -135,6 +135,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/04/13 (1.38) - renamed IsClipped() to IsRectClipped(). Kept inline redirection function (will obsolete).
  - 2015/04/09 (1.38) - renamed ImDrawList::AddArc() to ImDrawList::AddArcFast() for compatibility with future API
  - 2015/04/03 (1.38) - removed ImGuiCol_CheckHovered, ImGuiCol_CheckActive, replaced with the more general ImGuiCol_FrameBgHovered, ImGuiCol_FrameBgActive.
  - 2014/04/03 (1.38) - removed support for passing -FLT_MAX..+FLT_MAX as the range for a SliderFloat(). Use DragFloat() or Inputfloat() instead.
@@ -491,7 +492,7 @@ static bool         ItemAdd(const ImRect& bb, const ImGuiID* id);
 static void         ItemSize(ImVec2 size, float text_offset_y = 0.0f);
 static void         ItemSize(const ImRect& bb, float text_offset_y = 0.0f);
 static void         PushColumnClipRect(int column_index = -1);
-static bool         IsClipped(const ImRect& bb);
+static bool         IsClippedEx(const ImRect& bb, bool clip_even_when_logged);
 
 static bool         IsMouseHoveringRect(const ImRect& bb);
 static bool         IsKeyPressedMap(ImGuiKey key, bool repeat = true);
@@ -1108,10 +1109,11 @@ struct ImGuiState
     ImGuiWindow*            FocusedWindow;                      // Will catch keyboard inputs
     ImGuiWindow*            HoveredWindow;                      // Will catch mouse inputs
     ImGuiWindow*            HoveredRootWindow;                  // Will catch mouse inputs (for focus/move only)
-    ImGuiID                 HoveredId;
-    ImGuiID                 ActiveId;
+    ImGuiID                 HoveredId;                          // Hovered widget
+    ImGuiID                 ActiveId;                           // Active widget
     ImGuiID                 ActiveIdPreviousFrame;
     bool                    ActiveIdIsAlive;
+    bool                    ActiveIdIsJustActivated;            // Set when 
     bool                    ActiveIdIsFocusedOnly;              // Set only by active widget. Denote focus but no active interaction.
     ImGuiWindow*            MovedWindow;                        // Track the child window we clicked on to move a window. Only valid if ActiveID is the "#MOVE" identifier of a window.
     float                   SettingsDirtyTimer;
@@ -1144,6 +1146,7 @@ struct ImGuiState
     ImGuiID                 ScalarAsInputTextId;                // Temporary text input when CTRL+clicking on a slider, etc.
     ImGuiStorage            ColorEditModeStorage;               // for user selection
     ImGuiID                 ActiveComboID;
+    float                   DragCurrentValue;                   // current dragged value, always float, not rounded by end-user precision settings
     ImVec2                  DragLastMouseDelta;
     float                   DragSpeedScaleSlow;
     float                   DragSpeedScaleFast;
@@ -1182,6 +1185,7 @@ struct ImGuiState
         ActiveId = 0;
         ActiveIdPreviousFrame = 0;
         ActiveIdIsAlive = false;
+        ActiveIdIsJustActivated = false;
         ActiveIdIsFocusedOnly = false;
         MovedWindow = NULL;
         SettingsDirtyTimer = 0.0f;
@@ -1199,6 +1203,7 @@ struct ImGuiState
 
         ScalarAsInputTextId = 0;
         ActiveComboID = 0;
+        DragCurrentValue = 0.0f;
         DragLastMouseDelta = ImVec2(0.0f, 0.0f);
         DragSpeedScaleSlow = 0.01f;
         DragSpeedScaleFast = 10.0f;
@@ -1271,7 +1276,7 @@ public:
     ImGuiWindow(const char* name);
     ~ImGuiWindow();
 
-    ImGuiID     GetID(const char* str);
+    ImGuiID     GetID(const char* str, const char* str_end = NULL);
     ImGuiID     GetID(const void* ptr);
 
     bool        FocusItemRegister(bool is_active, bool tab_stop = true);      // Return true if focus is requested
@@ -1314,6 +1319,7 @@ static void SetActiveId(ImGuiID id)
     ImGuiState& g = *GImGui;
     g.ActiveId = id; 
     g.ActiveIdIsFocusedOnly = false;
+    g.ActiveIdIsJustActivated = true;
 }
 
 static void RegisterAliveId(ImGuiID id)
@@ -1616,10 +1622,10 @@ ImGuiWindow::~ImGuiWindow()
     Name = NULL;
 }
 
-ImGuiID ImGuiWindow::GetID(const char* str)
+ImGuiID ImGuiWindow::GetID(const char* str, const char* str_end)
 {
     ImGuiID seed = IDStack.back();
-    const ImGuiID id = ImHash(str, 0, seed);
+    const ImGuiID id = ImHash(str, str_end ? str_end - str : 0, seed);
     RegisterAliveId(id);
     return id;
 }
@@ -1936,6 +1942,7 @@ void ImGui::NewFrame()
         SetActiveId(0);
     g.ActiveIdPreviousFrame = g.ActiveId;
     g.ActiveIdIsAlive = false;
+    g.ActiveIdIsJustActivated = false;
     if (!g.ActiveId)
         g.MovedWindow = NULL;
 
@@ -2694,6 +2701,14 @@ ImVec2 ImGui::GetMouseDragDelta(int button, float lock_threshold)
     return ImVec2(0.0f, 0.0f);
 }
 
+void ImGui::ResetMouseDragDelta(int button)
+{
+    ImGuiState& g = *GImGui;
+    IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown));
+    // NB: We don't need to reset g.IO.MouseDragMaxDistanceSqr
+    g.IO.MouseClickedPos[button] = g.IO.MousePos;
+}
+
 ImGuiMouseCursor ImGui::GetMouseCursor()
 {
     return GImGui->MouseCursor;
@@ -2733,6 +2748,13 @@ bool ImGui::IsAnyItemActive()
     return g.ActiveId != 0;
 }
 
+bool ImGui::IsItemVisible()
+{
+    ImGuiWindow* window = GetCurrentWindow();
+    ImRect r(window->ClipRectStack.back());
+    return r.Overlaps(window->DC.LastItemRect);
+}
+
 ImVec2 ImGui::GetItemRectMin()
 {
     ImGuiWindow* window = GetCurrentWindow();
@@ -4232,7 +4254,7 @@ void ImGui::TextUnformatted(const char* text, const char* text_end)
                 while (line < text_end)
                 {
                     const char* line_end = strchr(line, '\n');
-                    if (IsClipped(line_rect))
+                    if (IsClippedEx(line_rect, false))
                         break;
 
                     const ImVec2 line_size = CalcTextSize(line, line_end, false);
@@ -4943,6 +4965,12 @@ void ImGui::PushID(const char* str_id)
     window->IDStack.push_back(window->GetID(str_id));
 }
 
+void ImGui::PushID(const char* str_id_begin, const char* str_id_end)
+{
+    ImGuiWindow* window = GetCurrentWindow();
+    window->IDStack.push_back(window->GetID(str_id_begin, str_id_end));
+}
+
 void ImGui::PushID(const void* ptr_id)
 {
     ImGuiWindow* window = GetCurrentWindow();
@@ -4968,6 +4996,12 @@ ImGuiID ImGui::GetID(const char* str_id)
     return window->GetID(str_id);
 }
 
+ImGuiID ImGui::GetID(const char* str_id_begin, const char* str_id_end)
+{
+    ImGuiWindow* window = GetCurrentWindow();
+    return window->GetID(str_id_begin, str_id_end);
+}
+
 ImGuiID ImGui::GetID(const void* ptr_id)
 {
     ImGuiWindow* window = GetCurrentWindow();
@@ -5056,7 +5090,7 @@ static bool SliderFloatAsInputText(const char* label, float* v, ImGuiID id, int
 }
 
 // Parse display precision back from the display format string
-static void ParseFormat(const char* fmt, int& decimal_precision)
+static inline void ParseFormat(const char* fmt, int& decimal_precision)
 {
     while ((fmt = strchr(fmt, '%')) != NULL)
     {
@@ -5074,6 +5108,21 @@ static void ParseFormat(const char* fmt, int& decimal_precision)
     }
 }
 
+static inline float RoundScalar(float value, int decimal_precision)
+{
+    // Round past decimal precision
+    //    0: 1, 1: 0.1, 2: 0.01, etc.
+    // So when our value is 1.99999 with a precision of 0.001 we'll end up rounding to 2.0
+    // FIXME: Investigate better rounding methods
+    const float min_step = 1.0f / powf(10.0f, (float)decimal_precision);
+    const float remainder = fmodf(value, min_step);
+    if (remainder <= min_step*0.5f)
+        value -= remainder;
+    else
+        value += (min_step - remainder);
+    return value;
+}
+
 static bool SliderBehavior(const ImRect& frame_bb, const ImRect& slider_bb, ImGuiID id, float* v, float v_min, float v_max, float power, int decimal_precision, bool horizontal)
 {
     ImGuiState& g = *GImGui;
@@ -5152,14 +5201,7 @@ static bool SliderBehavior(const ImRect& frame_bb, const ImRect& slider_bb, ImGu
             }
 
             // Round past decimal precision
-            //    0->1, 1->0.1, 2->0.01, etc.
-            // So when our value is 1.99999 with a precision of 0.001 we'll end up rounding to 2.0
-            const float min_step = 1.0f / powf(10.0f, (float)decimal_precision);
-            const float remainder = fmodf(new_value, min_step);
-            if (remainder <= min_step*0.5f)
-                new_value -= remainder;
-            else
-                new_value += (min_step - remainder);
+            new_value = RoundScalar(new_value, decimal_precision);
 
             if (*v != new_value)
             {
@@ -5465,7 +5507,7 @@ bool ImGui::SliderInt4(const char* label, int v[4], int v_min, int v_max, const
 }
 
 // FIXME-WIP: Work in progress. May change API / behavior.
-static bool DragScalarBehavior(const ImRect& frame_bb, ImGuiID id, float* v, float v_step, float v_min, float v_max)
+static bool DragScalarBehavior(const ImRect& frame_bb, ImGuiID id, float* v, float v_speed, float v_min, float v_max, int decimal_precision, float power)
 {
     ImGuiState& g = *GImGui;
     ImGuiWindow* window = GetCurrentWindow();
@@ -5482,23 +5524,52 @@ static bool DragScalarBehavior(const ImRect& frame_bb, ImGuiID id, float* v, flo
     {
         if (g.IO.MouseDown[0])
         {
-            const ImVec2 mouse_drag_delta = ImGui::GetMouseDragDelta(0);
+            if (g.ActiveIdIsJustActivated)
+            {
+                // Lock current value on click
+                g.DragCurrentValue = *v;
+                g.DragLastMouseDelta = ImVec2(0.f, 0.f);
+            }
 
+            const ImVec2 mouse_drag_delta = ImGui::GetMouseDragDelta(0, 1.0f);
             if (fabsf(mouse_drag_delta.x - g.DragLastMouseDelta.x) > 0.0f)
             {
-                float step = v_step;
+                float speed = v_speed;
                 if (g.IO.KeyShift && g.DragSpeedScaleFast >= 0.0f)
-                    step = v_step * g.DragSpeedScaleFast;
+                    speed = v_speed * g.DragSpeedScaleFast;
                 if (g.IO.KeyAlt && g.DragSpeedScaleSlow >= 0.0f)
-                    step = v_step * g.DragSpeedScaleSlow;
+                    speed = v_speed * g.DragSpeedScaleSlow;
 
-                *v += (mouse_drag_delta.x - g.DragLastMouseDelta.x) * step;
+                float v_cur = g.DragCurrentValue;
+                float delta = (mouse_drag_delta.x - g.DragLastMouseDelta.x) * speed;
+                if (fabsf(power - 1.0f) > 0.001f)
+                {
+                    // Logarithmic curve on both side of 0.0
+                    float v0_abs = v_cur >= 0.0f ? v_cur : -v_cur;
+                    float v0_sign = v_cur >= 0.0f ? 1.0f : -1.0f;
+                    float v1 = powf(v0_abs, 1.0f / power) + (delta * v0_sign);
+                    float v1_abs = v1 >= 0.0f ? v1 : -v1;
+                    float v1_sign = v1 >= 0.0f ? 1.0f : -1.0f;          // Crossed sign line
+                    v_cur = powf(v1_abs, power) * v0_sign * v1_sign;    // Reapply sign
+                }
+                else
+                {
+                    v_cur += delta;
+                }
+                g.DragLastMouseDelta.x = mouse_drag_delta.x;
 
+                // Clamp
                 if (v_min < v_max)
-                    *v = ImClamp(*v, v_min, v_max);
+                    v_cur = ImClamp(v_cur, v_min, v_max);
+                g.DragCurrentValue = v_cur;
 
-                g.DragLastMouseDelta.x = mouse_drag_delta.x;
-                value_changed = true;
+                // Round to user desired precision, then apply
+                v_cur = RoundScalar(v_cur, decimal_precision);
+                if (*v != v_cur)
+                {
+                    *v = v_cur;
+                    value_changed = true;
+                }
             }
         }
         else
@@ -5510,7 +5581,7 @@ static bool DragScalarBehavior(const ImRect& frame_bb, ImGuiID id, float* v, flo
     return value_changed;
 }
 
-bool ImGui::DragFloat(const char* label, float *v, float v_step, float v_min, float v_max, const char* display_format)
+bool ImGui::DragFloat(const char* label, float *v, float v_speed, float v_min, float v_max, const char* display_format, float power)
 {
     ImGuiState& g = *GImGui;
     ImGuiWindow* window = GetCurrentWindow();
@@ -5549,7 +5620,6 @@ bool ImGui::DragFloat(const char* label, float *v, float v_step, float v_min, fl
     {
         SetActiveId(id);
         FocusWindow(window);
-        g.DragLastMouseDelta = ImVec2(0.f, 0.f);
 
         if (tab_focus_requested || g.IO.KeyCtrl || g.IO.MouseDoubleClicked[0])
         {
@@ -5563,7 +5633,7 @@ bool ImGui::DragFloat(const char* label, float *v, float v_step, float v_min, fl
     ItemSize(total_bb, style.FramePadding.y);
 
     // Actual drag behavior
-    const bool value_changed = DragScalarBehavior(frame_bb, id, v, v_step, v_min, v_max);
+    const bool value_changed = DragScalarBehavior(frame_bb, id, v, v_speed, v_min, v_max, decimal_precision, power);
 
     // Display value using user-provided display format so user can add prefix/suffix/decorations to the value.
     char value_buf[64];
@@ -5577,12 +5647,13 @@ bool ImGui::DragFloat(const char* label, float *v, float v_step, float v_min, fl
     return value_changed;
 }
 
-bool ImGui::DragInt(const char* label, int* v, int v_step, int v_min, int v_max, const char* display_format)
+// NB: v_speed is float to allow adjusting the drag speed with more precision
+bool ImGui::DragInt(const char* label, int* v, float v_speed, int v_min, int v_max, const char* display_format)
 {
     if (!display_format)
         display_format = "%.0f";
     float v_f = (float)*v;
-    bool value_changed = ImGui::DragFloat(label, &v_f, (float)v_step, (float)v_min, (float)v_max, display_format);
+    bool value_changed = ImGui::DragFloat(label, &v_f, v_speed, (float)v_min, (float)v_max, display_format);
     *v = (int)v_f;
     return value_changed;
 }
@@ -7030,7 +7101,7 @@ bool ImGui::ColorEdit4(const char* label, float col[4], bool alpha)
                     ImGui::SameLine(0, (int)style.ItemInnerSpacing.x);
                 if (n + 1 == components)
                     ImGui::PushItemWidth(w_item_last);
-                value_changed |= ImGui::DragInt(ids[n], &i[n], 1, 0, 255, fmt[n]);
+                value_changed |= ImGui::DragInt(ids[n], &i[n], 1.0f, 0, 255, fmt[n]);
             }
             ImGui::PopItemWidth();
             ImGui::PopItemWidth();
@@ -7180,20 +7251,23 @@ static inline void ItemSize(const ImRect& bb, float text_offset_y)
     ItemSize(bb.GetSize(), text_offset_y); 
 }
 
-static bool IsClipped(const ImRect& bb)
+static bool IsClippedEx(const ImRect& bb, bool clip_even_when_logged)
 {
     ImGuiState& g = *GImGui;
     ImGuiWindow* window = GetCurrentWindow();
 
-    if (!bb.Overlaps(ImRect(window->ClipRectStack.back())) && !g.LogEnabled)
-        return true;
+    if (!bb.Overlaps(ImRect(window->ClipRectStack.back())))
+    {
+        if (clip_even_when_logged || !g.LogEnabled)
+            return true;
+    }
     return false;
 }
 
-bool ImGui::IsClipped(const ImVec2& item_size)
+bool ImGui::IsRectClipped(const ImVec2& size)
 {
     ImGuiWindow* window = GetCurrentWindow();
-    return IsClipped(ImRect(window->DC.CursorPos, window->DC.CursorPos + item_size));
+    return IsClippedEx(ImRect(window->DC.CursorPos, window->DC.CursorPos + size), true);
 }
 
 static bool ItemAdd(const ImRect& bb, const ImGuiID* id)
@@ -7201,10 +7275,13 @@ static bool ItemAdd(const ImRect& bb, const ImGuiID* id)
     ImGuiWindow* window = GetCurrentWindow();
     window->DC.LastItemID = id ? *id : 0;
     window->DC.LastItemRect = bb;
-    if (IsClipped(bb))
+    if (IsClippedEx(bb, false))
     {
-        window->DC.LastItemHoveredAndUsable = window->DC.LastItemHoveredRect = false;
-        return false;
+        if (!id || *id != GImGui->ActiveId)
+        {
+            window->DC.LastItemHoveredAndUsable = window->DC.LastItemHoveredRect = false;
+            return false;
+        }
     }
 
     // This is a sensible default, but widgets are free to override it after calling ItemAdd()
@@ -7433,7 +7510,7 @@ void ImGui::Columns(int columns_count, const char* id, bool border)
             const ImGuiID column_id = window->DC.ColumnsSetID + ImGuiID(i);
             const ImRect column_rect(ImVec2(x-4,y1),ImVec2(x+4,y2));
 
-            if (IsClipped(column_rect))
+            if (IsClippedEx(column_rect, false))
                 continue;
 
             bool hovered, held;
@@ -8138,18 +8215,10 @@ static unsigned int stb_decompress(unsigned char *output, unsigned char *i, unsi
 // Load embedded ProggyClean.ttf at size 13
 ImFont* ImFontAtlas::AddFontDefault()
 {
-    // Get compressed data
     unsigned int ttf_compressed_size;
     const void* ttf_compressed;
     GetDefaultCompressedFontDataTTF(&ttf_compressed, &ttf_compressed_size);
-
-    // Decompress
-    const size_t buf_decompressed_size = stb_decompress_length((unsigned char*)ttf_compressed);
-    unsigned char* buf_decompressed = (unsigned char *)ImGui::MemAlloc(buf_decompressed_size);
-    stb_decompress(buf_decompressed, (unsigned char*)ttf_compressed, ttf_compressed_size);
-
-    // Add
-    ImFont* font = AddFontFromMemoryTTF(buf_decompressed, buf_decompressed_size, 13.0f, GetGlyphRangesDefault(), 0);
+    ImFont* font = AddFontFromMemoryCompressedTTF(ttf_compressed, ttf_compressed_size, 13.0f, GetGlyphRangesDefault(), 0);
     font->DisplayOffset.y += 1;
     return font;
 }
@@ -8164,13 +8233,12 @@ ImFont* ImFontAtlas::AddFontFromFileTTF(const char* filename, float size_pixels,
         return NULL;
     }
 
-    // Add
     ImFont* font = AddFontFromMemoryTTF(data, data_size, size_pixels, glyph_ranges, font_no);
     return font;
 }
 
 // NB: ownership of 'data' is given to ImFontAtlas which will clear it.
-ImFont* ImFontAtlas::AddFontFromMemoryTTF(void* in_ttf_data, size_t in_ttf_data_size, float size_pixels, const ImWchar* glyph_ranges, int font_no)
+ImFont* ImFontAtlas::AddFontFromMemoryTTF(void* in_ttf_data, unsigned int in_ttf_data_size, float size_pixels, const ImWchar* glyph_ranges, int font_no)
 {
     // Create new font
     ImFont* font = (ImFont*)ImGui::MemAlloc(sizeof(ImFont));
@@ -8194,6 +8262,18 @@ ImFont* ImFontAtlas::AddFontFromMemoryTTF(void* in_ttf_data, size_t in_ttf_data_
     return font;
 }
 
+ImFont* ImFontAtlas::AddFontFromMemoryCompressedTTF(const void* in_compressed_ttf_data, unsigned int in_compressed_ttf_data_size, float size_pixels, const ImWchar* glyph_ranges, int font_no)
+{
+    // Decompress
+    const size_t buf_decompressed_size = stb_decompress_length((unsigned char*)in_compressed_ttf_data);
+    unsigned char* buf_decompressed = (unsigned char *)ImGui::MemAlloc(buf_decompressed_size);
+    stb_decompress(buf_decompressed, (unsigned char*)in_compressed_ttf_data, in_compressed_ttf_data_size);
+
+    // Add
+    ImFont* font = AddFontFromMemoryTTF(buf_decompressed, buf_decompressed_size, size_pixels, glyph_ranges, font_no);
+    return font;
+}
+
 bool    ImFontAtlas::Build()
 {
     IM_ASSERT(InputData.size() > 0);
@@ -10235,7 +10315,7 @@ void ImGui::ShowTestWindow(bool* opened)
         ImGui::Spacing();
 
         // Scrolling columns
-		/*
+        /*
         ImGui::Text("Scrolling:");
         ImGui::BeginChild("##header", ImVec2(0, ImGui::GetTextLineHeightWithSpacing()+ImGui::GetStyle().ItemSpacing.y));
         ImGui::Columns(3);
@@ -10258,7 +10338,7 @@ void ImGui::ShowTestWindow(bool* opened)
 
         ImGui::Separator();
         ImGui::Spacing();
-		*/
+        */
 
         // Create multiple items in a same cell before switching to next column
         ImGui::Text("Mixed items:");
@@ -10947,16 +11027,9 @@ static void ShowExampleAppLongText(bool* opened)
 //-----------------------------------------------------------------------------
 // FONT DATA
 //-----------------------------------------------------------------------------
-
-//-----------------------------------------------------------------------------
-// ProggyClean.ttf
-// Copyright (c) 2004, 2005 Tristan Grimmer
-// MIT license (see License.txt in http://www.upperbounds.net/download/ProggyClean.ttf.zip)
-// Download and more information at http://upperbounds.net
-//-----------------------------------------------------------------------------
 // Compressed with stb_compress() then converted to a C array.
-// Decompressor from stb.h (public domain) by Sean Barrett
-// https://github.com/nothings/stb/blob/master/stb.h
+// Use the program in extra_fonts/binary_to_compressed_c.cpp to create the array from a TTF file.
+// Decompressor from stb.h (public domain) by Sean Barrett https://github.com/nothings/stb/blob/master/stb.h
 //-----------------------------------------------------------------------------
 
 static unsigned int stb_decompress_length(unsigned char *input)
@@ -10965,7 +11038,6 @@ static unsigned int stb_decompress_length(unsigned char *input)
 }
 
 static unsigned char *stb__barrier, *stb__barrier2, *stb__barrier3, *stb__barrier4;
-
 static unsigned char *stb__dout;
 static void stb__match(unsigned char *data, unsigned int length)
 {
@@ -11071,6 +11143,12 @@ static unsigned int stb_decompress(unsigned char *output, unsigned char *i, unsi
     }
 }
 
+//-----------------------------------------------------------------------------
+// ProggyClean.ttf
+// Copyright (c) 2004, 2005 Tristan Grimmer
+// MIT license (see License.txt in http://www.upperbounds.net/download/ProggyClean.ttf.zip)
+// Download and more information at http://upperbounds.net
+//-----------------------------------------------------------------------------
 static const unsigned int proggy_clean_ttf_compressed_size = 9583;
 static const unsigned int proggy_clean_ttf_compressed_data[9584/4] =
 {

+ 12 - 6
imgui.h

@@ -260,10 +260,12 @@ namespace ImGui
     // If you are creating widgets in a loop you most likely want to push a unique identifier so ImGui can differentiate them
     // You can also use "##extra" within your widget name to distinguish them from each others (see 'Programmer Guide')
     IMGUI_API void          PushID(const char* str_id);                                         // push identifier into the ID stack. IDs are hash of the *entire* stack!
+    IMGUI_API void          PushID(const char* str_id_begin, const char* str_id_end);
     IMGUI_API void          PushID(const void* ptr_id);
     IMGUI_API void          PushID(const int int_id);
     IMGUI_API void          PopID();
     IMGUI_API ImGuiID       GetID(const char* str_id);                                          // calculate unique ID (hash of whole ID stack + given parameter). useful if you want to query into ImGuiStorage yourself. otherwise rarely needed
+    IMGUI_API ImGuiID       GetID(const char* str_id_begin, const char* str_id_end);
     IMGUI_API ImGuiID       GetID(const void* ptr_id);
 
     // Widgets
@@ -316,8 +318,8 @@ namespace ImGui
 
     // Widgets: Drags (tip: ctrl+click on a drag box to input text)
     // ImGui 1.38+ work-in-progress, may change name or API.
-    IMGUI_API bool          DragFloat(const char* label, float* v, float v_step = 1.0f, float v_min = 0.0f, float v_max = 0.0f, const char* display_format = "%.3f");   // If v_max >= v_max we have no bound
-    IMGUI_API bool          DragInt(const char* label, int* v, int v_step = 1, int v_min = 0, int v_max = 0, const char* display_format = "%.0f");                // If v_max >= v_max we have no bound
+    IMGUI_API bool          DragFloat(const char* label, float* v, float v_speed = 1.0f, float v_min = 0.0f, float v_max = 0.0f, const char* display_format = "%.3f", float power = 1.0f);  // If v_max >= v_max we have no bound
+    IMGUI_API bool          DragInt(const char* label, int* v, float v_speed = 1.0f, int v_min = 0, int v_max = 0, const char* display_format = "%.0f");                                    // If v_max >= v_max we have no bound
 
     // Widgets: Input
     IMGUI_API bool          InputText(const char* label, char* buf, size_t buf_size, ImGuiInputTextFlags flags = 0, ImGuiTextEditCallback callback = NULL, void* user_data = NULL);
@@ -371,13 +373,14 @@ namespace ImGui
     IMGUI_API bool          IsItemHoveredRect();                                                // was the last item hovered by mouse? even if another item is active while we are hovering this
     IMGUI_API bool          IsItemActive();                                                     // was the last item active? (e.g. button being held, text field being edited- items that don't interact will always return false)
     IMGUI_API bool          IsAnyItemActive();                                                  // 
-    IMGUI_API ImVec2        GetItemRectMin();                                                   // get bounding rect of last item
+    IMGUI_API bool          IsItemVisible();
+    IMGUI_API ImVec2        GetItemRectMin();                                                   // get bounding rect of last item in screen space
     IMGUI_API ImVec2        GetItemRectMax();                                                   // "
     IMGUI_API ImVec2        GetItemRectSize();                                                  // "
     IMGUI_API bool          IsWindowFocused();                                                  // is current window focused (differentiate child windows from each others)
     IMGUI_API bool          IsRootWindowFocused();                                              // is current root window focused
     IMGUI_API bool          IsRootWindowOrAnyChildFocused();                                    // is current root window or any of its child (including current window) focused
-    IMGUI_API bool          IsClipped(const ImVec2& item_size);                                 // to perform coarse clipping on user's side (as an optimization)
+    IMGUI_API bool          IsRectClipped(const ImVec2& size);                                  // test if rectangle of given size starting from cursor pos is out of clipping region. to perform coarse clipping on user's side (as an optimization)
     IMGUI_API bool          IsKeyPressed(int key_index, bool repeat = true);                    // key_index into the keys_down[512] array, imgui doesn't know the semantic of each entry
     IMGUI_API bool          IsMouseClicked(int button, bool repeat = false);
     IMGUI_API bool          IsMouseDoubleClicked(int button);
@@ -388,6 +391,7 @@ namespace ImGui
     IMGUI_API bool          IsPosHoveringAnyWindow(const ImVec2& pos);                          // is given position hovering any active imgui window
     IMGUI_API ImVec2        GetMousePos();                                                      // shortcut to ImGui::GetIO().MousePos provided by user, to be consistent with other calls
     IMGUI_API ImVec2        GetMouseDragDelta(int button = 0, float lock_threshold = -1.0f);    // dragging amount since clicking, also see: GetItemActiveDragDelta(). if lock_threshold < -1.0f uses io.MouseDraggingThreshold
+    IMGUI_API void          ResetMouseDragDelta(int button = 0);
     IMGUI_API ImGuiMouseCursor GetMouseCursor();                                                // get desired cursor type, reset in ImGui::NewFrame(), this updated during the frame. valid before Render(). If you use software rendering by setting io.MouseDrawCursor ImGui will render those for you
     IMGUI_API void          SetMouseCursor(ImGuiMouseCursor type);                              // set desired cursor type
     IMGUI_API float         GetTime();
@@ -416,6 +420,7 @@ namespace ImGui
     static inline bool      GetWindowIsFocused() { return ImGui::IsWindowFocused(); }   // OBSOLETE
     static inline ImVec2    GetItemBoxMin() { return GetItemRectMin(); }    // OBSOLETE
     static inline ImVec2    GetItemBoxMax() { return GetItemRectMax(); }    // OBSOLETE
+    static inline bool      IsClipped(const ImVec2& size) { return IsRectClipped(size); }   // OBSOLETE
     static inline bool      IsMouseHoveringBox(const ImVec2& rect_min, const ImVec2& rect_max) { return IsMouseHoveringRect(rect_min, rect_max); }  // OBSOLETE
 
 } // namespace ImGui
@@ -948,14 +953,15 @@ struct ImDrawList
 //  2. Call GetTexDataAsAlpha8() or GetTexDataAsRGBA32() to build and retrieve pixels data.
 //  3. Upload the pixels data into a texture within your graphics system.
 //  4. Call SetTexID(my_tex_id); and pass the pointer/identifier to your texture. This value will be passed back to you during rendering to identify the texture.
-//  5. Call ClearPixelsData() to free textures memory on the heap.
+//  5. Call ClearTexData() to free textures memory on the heap.
 struct ImFontAtlas
 {
     IMGUI_API ImFontAtlas();
     IMGUI_API ~ImFontAtlas();
     IMGUI_API ImFont*           AddFontDefault();
     IMGUI_API ImFont*           AddFontFromFileTTF(const char* filename, float size_pixels, const ImWchar* glyph_ranges = NULL, int font_no = 0);
-    IMGUI_API ImFont*           AddFontFromMemoryTTF(void* in_ttf_data, size_t in_ttf_data_size, float size_pixels, const ImWchar* glyph_ranges = NULL, int font_no = 0); // Pass ownership of 'in_ttf_data' memory.
+    IMGUI_API ImFont*           AddFontFromMemoryTTF(void* in_ttf_data, unsigned int in_ttf_data_size, float size_pixels, const ImWchar* glyph_ranges = NULL, int font_no = 0); // Pass ownership of 'in_ttf_data' memory, will be deleted after build
+    IMGUI_API ImFont*           AddFontFromMemoryCompressedTTF(const void* in_compressed_ttf_data, unsigned int in_compressed_ttf_data_size, float size_pixels, const ImWchar* glyph_ranges = NULL, int font_no = 0); // 'in_compressed_ttf_data' untouched and still owned by caller. compress with binary_to_compressed_c.
     IMGUI_API void              ClearTexData();             // Saves RAM once the texture has been copied to graphics memory.
     IMGUI_API void              Clear();