Browse Source

ImDrawList: Fixed issues with channels split/merge. Functional without manually adding a draw cmd. + Removed unnecessary parameter to Channe

ocornut 10 years ago
parent
commit
77b82ecad7
3 changed files with 40 additions and 27 deletions
  1. 1 1
      imgui.cpp
  2. 7 4
      imgui.h
  3. 32 22
      imgui_draw.cpp

+ 1 - 1
imgui.cpp

@@ -8566,7 +8566,7 @@ void ImGui::Columns(int columns_count, const char* id, bool border)
             ItemSize(ImVec2(0,0));   // Advance to column 0
             ItemSize(ImVec2(0,0));   // Advance to column 0
         ImGui::PopItemWidth();
         ImGui::PopItemWidth();
         PopClipRect();
         PopClipRect();
-        window->DrawList->ChannelsMerge(window->DC.ColumnsCount);
+        window->DrawList->ChannelsMerge();
 
 
         window->DC.ColumnsCellMaxY = ImMax(window->DC.ColumnsCellMaxY, window->DC.CursorPos.y);
         window->DC.ColumnsCellMaxY = ImMax(window->DC.ColumnsCellMaxY, window->DC.CursorPos.y);
         window->DC.CursorPos.y = window->DC.ColumnsCellMaxY;
         window->DC.CursorPos.y = window->DC.ColumnsCellMaxY;

+ 7 - 4
imgui.h

@@ -1015,6 +1015,8 @@ struct ImDrawCmd
     ImTextureID     TextureId;              // User-provided texture ID. Set by user in ImfontAtlas::SetTexID() for fonts or passed to Image*() functions. Ignore if never using images or multiple fonts atlas.
     ImTextureID     TextureId;              // User-provided texture ID. Set by user in ImfontAtlas::SetTexID() for fonts or passed to Image*() functions. Ignore if never using images or multiple fonts atlas.
     ImDrawCallback  UserCallback;           // If != NULL, call the function instead of rendering the vertices. clip_rect and texture_id will be set normally.
     ImDrawCallback  UserCallback;           // If != NULL, call the function instead of rendering the vertices. clip_rect and texture_id will be set normally.
     void*           UserCallbackData;       // The draw callback code can access this.
     void*           UserCallbackData;       // The draw callback code can access this.
+
+    ImDrawCmd() { ElemCount = 0; ClipRect.x = ClipRect.y = -8192.0f; ClipRect.z = ClipRect.w = +8192.0f; TextureId = NULL; UserCallback = NULL; UserCallbackData = NULL; }
 };
 };
 
 
 // Vertex index (override with, e.g. '#define ImDrawIdx unsigned int' in ImConfig)
 // Vertex index (override with, e.g. '#define ImDrawIdx unsigned int' in ImConfig)
@@ -1066,8 +1068,9 @@ struct ImDrawList
     ImVector<ImVec4>        _ClipRectStack;     // [Internal]
     ImVector<ImVec4>        _ClipRectStack;     // [Internal]
     ImVector<ImTextureID>   _TextureIdStack;    // [Internal]
     ImVector<ImTextureID>   _TextureIdStack;    // [Internal]
     ImVector<ImVec2>        _Path;              // [Internal] current path building
     ImVector<ImVec2>        _Path;              // [Internal] current path building
-    int                     _ChannelCurrent;    // [Internal] current channel number (0)
-    ImVector<ImDrawChannel> _Channels;          // [Internal] draw channels for columns API
+    int                     _ChannelsCurrent;   // [Internal] current channel number (0)
+    int                     _ChannelsCount;     // [Internal] number of active channels (1+)
+    ImVector<ImDrawChannel> _Channels;          // [Internal] draw channels for columns API (not resized down so _ChannelsCount may be smaller than _Channels.Size)
 
 
     ImDrawList() { _OwnerName = NULL; Clear(); }
     ImDrawList() { _OwnerName = NULL; Clear(); }
     ~ImDrawList() { ClearFreeMemory(); }
     ~ImDrawList() { ClearFreeMemory(); }
@@ -1105,8 +1108,8 @@ struct ImDrawList
     // Advanced
     // Advanced
     IMGUI_API void  AddCallback(ImDrawCallback callback, void* callback_data);  // Your rendering function must check for 'UserCallback' in ImDrawCmd and call the function instead of rendering triangles.
     IMGUI_API void  AddCallback(ImDrawCallback callback, void* callback_data);  // Your rendering function must check for 'UserCallback' in ImDrawCmd and call the function instead of rendering triangles.
     IMGUI_API void  AddDrawCmd();                                               // This is useful if you need to forcefully create a new draw call (to allow for dependent rendering / blending). Otherwise primitives are merged into the same draw-call as much as possible
     IMGUI_API void  AddDrawCmd();                                               // This is useful if you need to forcefully create a new draw call (to allow for dependent rendering / blending). Otherwise primitives are merged into the same draw-call as much as possible
-    IMGUI_API void  ChannelsSplit(int channel_count);
-    IMGUI_API void  ChannelsMerge(int channel_count);
+    IMGUI_API void  ChannelsSplit(int channels_count);
+    IMGUI_API void  ChannelsMerge();
     IMGUI_API void  ChannelsSetCurrent(int idx);
     IMGUI_API void  ChannelsSetCurrent(int idx);
 
 
     // Internal helpers
     // Internal helpers

+ 32 - 22
imgui_draw.cpp

@@ -85,7 +85,7 @@ using namespace IMGUI_STB_NAMESPACE;
 // ImDrawList
 // ImDrawList
 //-----------------------------------------------------------------------------
 //-----------------------------------------------------------------------------
 
 
-static ImVec4 GNullClipRect(-9999.0f,-9999.0f, +9999.0f, +9999.0f);
+static ImVec4 GNullClipRect(-8192.0f, -8192.0f, +8192.0f, +8192.0f); // Large values that are easy to encode in a few bits+shift
 
 
 void ImDrawList::Clear()
 void ImDrawList::Clear()
 {
 {
@@ -98,7 +98,8 @@ void ImDrawList::Clear()
     _ClipRectStack.resize(0);
     _ClipRectStack.resize(0);
     _TextureIdStack.resize(0);
     _TextureIdStack.resize(0);
     _Path.resize(0);
     _Path.resize(0);
-    _ChannelCurrent = 0;
+    _ChannelsCurrent = 0;
+    _ChannelsCount = 1;
     // NB: Do not clear channels so our allocations are re-used after the first frame.
     // NB: Do not clear channels so our allocations are re-used after the first frame.
 }
 }
 
 
@@ -113,7 +114,8 @@ void ImDrawList::ClearFreeMemory()
     _ClipRectStack.clear();
     _ClipRectStack.clear();
     _TextureIdStack.clear();
     _TextureIdStack.clear();
     _Path.clear();
     _Path.clear();
-    _ChannelCurrent = 0;
+    _ChannelsCurrent = 0;
+    _ChannelsCount = 1;
     for (int i = 0; i < _Channels.Size; i++)
     for (int i = 0; i < _Channels.Size; i++)
     {
     {
         if (i == 0) memset(&_Channels[0], 0, sizeof(_Channels[0]));  // channel 0 is a copy of CmdBuffer/IdxBuffer, don't destruct again
         if (i == 0) memset(&_Channels[0], 0, sizeof(_Channels[0]));  // channel 0 is a copy of CmdBuffer/IdxBuffer, don't destruct again
@@ -126,11 +128,8 @@ void ImDrawList::ClearFreeMemory()
 void ImDrawList::AddDrawCmd()
 void ImDrawList::AddDrawCmd()
 {
 {
     ImDrawCmd draw_cmd;
     ImDrawCmd draw_cmd;
-    draw_cmd.ElemCount = 0;
     draw_cmd.ClipRect = _ClipRectStack.Size ? _ClipRectStack.back() : GNullClipRect;
     draw_cmd.ClipRect = _ClipRectStack.Size ? _ClipRectStack.back() : GNullClipRect;
     draw_cmd.TextureId = _TextureIdStack.Size ? _TextureIdStack.back() : NULL;
     draw_cmd.TextureId = _TextureIdStack.Size ? _TextureIdStack.back() : NULL;
-    draw_cmd.UserCallback = NULL;
-    draw_cmd.UserCallbackData = NULL;
 
 
     IM_ASSERT(draw_cmd.ClipRect.x <= draw_cmd.ClipRect.z && draw_cmd.ClipRect.y <= draw_cmd.ClipRect.w);
     IM_ASSERT(draw_cmd.ClipRect.x <= draw_cmd.ClipRect.z && draw_cmd.ClipRect.y <= draw_cmd.ClipRect.w);
     CmdBuffer.push_back(draw_cmd);
     CmdBuffer.push_back(draw_cmd);
@@ -151,24 +150,34 @@ void ImDrawList::AddCallback(ImDrawCallback callback, void* callback_data)
     AddDrawCmd();
     AddDrawCmd();
 }
 }
 
 
-void ImDrawList::ChannelsSplit(int channel_count)
+void ImDrawList::ChannelsSplit(int channels_count)
 {
 {
-    IM_ASSERT(_ChannelCurrent == 0);
+    IM_ASSERT(_ChannelsCurrent == 0 && _ChannelsCount == 1);
     int old_channels_count = _Channels.Size;
     int old_channels_count = _Channels.Size;
-    if (old_channels_count < channel_count)
-        _Channels.resize(channel_count);
-    for (int i = 0; i < channel_count; i++)
+    if (old_channels_count < channels_count)
+        _Channels.resize(channels_count);
+    _ChannelsCount = channels_count;
+    for (int i = 0; i < channels_count; i++)
+    {
         if (i >= old_channels_count)
         if (i >= old_channels_count)
             new(&_Channels[i]) ImDrawChannel();
             new(&_Channels[i]) ImDrawChannel();
-        else
+        else if (i > 0)
             _Channels[i].CmdBuffer.resize(0), _Channels[i].IdxBuffer.resize(0);
             _Channels[i].CmdBuffer.resize(0), _Channels[i].IdxBuffer.resize(0);
+        if (_Channels[i].CmdBuffer.Size == 0)
+        {
+            ImDrawCmd draw_cmd;
+            draw_cmd.ClipRect = _ClipRectStack.back();
+            draw_cmd.TextureId = _TextureIdStack.back();
+            _Channels[i].CmdBuffer.push_back(draw_cmd);
+        }
+    }
 }
 }
 
 
-void ImDrawList::ChannelsMerge(int channel_count)
+void ImDrawList::ChannelsMerge()
 {
 {
     // Note that we never use or rely on channels.Size because it is merely a buffer that we never shrink back to 0 to keep all sub-buffers ready for use.
     // Note that we never use or rely on channels.Size because it is merely a buffer that we never shrink back to 0 to keep all sub-buffers ready for use.
     // This is why this function takes 'channel_count' as a parameter of how many channels to merge (the user knows)
     // This is why this function takes 'channel_count' as a parameter of how many channels to merge (the user knows)
-    if (channel_count < 2)
+    if (_ChannelsCount <= 1)
         return;
         return;
 
 
     ChannelsSetCurrent(0);
     ChannelsSetCurrent(0);
@@ -176,7 +185,7 @@ void ImDrawList::ChannelsMerge(int channel_count)
         CmdBuffer.pop_back();
         CmdBuffer.pop_back();
 
 
     int new_cmd_buffer_count = 0, new_idx_buffer_count = 0;
     int new_cmd_buffer_count = 0, new_idx_buffer_count = 0;
-    for (int i = 1; i < channel_count; i++)
+    for (int i = 1; i < _ChannelsCount; i++)
     {
     {
         ImDrawChannel& ch = _Channels[i];
         ImDrawChannel& ch = _Channels[i];
         if (ch.CmdBuffer.Size && ch.CmdBuffer.back().ElemCount == 0)
         if (ch.CmdBuffer.Size && ch.CmdBuffer.back().ElemCount == 0)
@@ -189,23 +198,24 @@ void ImDrawList::ChannelsMerge(int channel_count)
 
 
     ImDrawCmd* cmd_write = CmdBuffer.Data + CmdBuffer.Size - new_cmd_buffer_count;
     ImDrawCmd* cmd_write = CmdBuffer.Data + CmdBuffer.Size - new_cmd_buffer_count;
     _IdxWritePtr = IdxBuffer.Data + IdxBuffer.Size - new_idx_buffer_count;
     _IdxWritePtr = IdxBuffer.Data + IdxBuffer.Size - new_idx_buffer_count;
-    for (int i = 1; i < channel_count; i++)
+    for (int i = 1; i < _ChannelsCount; i++)
     {
     {
         ImDrawChannel& ch = _Channels[i];
         ImDrawChannel& ch = _Channels[i];
         if (int sz = ch.CmdBuffer.Size) { memcpy(cmd_write, ch.CmdBuffer.Data, sz * sizeof(ImDrawCmd)); cmd_write += sz; }
         if (int sz = ch.CmdBuffer.Size) { memcpy(cmd_write, ch.CmdBuffer.Data, sz * sizeof(ImDrawCmd)); cmd_write += sz; }
         if (int sz = ch.IdxBuffer.Size) { memcpy(_IdxWritePtr, ch.IdxBuffer.Data, sz * sizeof(ImDrawIdx)); _IdxWritePtr += sz; }
         if (int sz = ch.IdxBuffer.Size) { memcpy(_IdxWritePtr, ch.IdxBuffer.Data, sz * sizeof(ImDrawIdx)); _IdxWritePtr += sz; }
     }
     }
     AddDrawCmd();
     AddDrawCmd();
+    _ChannelsCount = 1;
 }
 }
 
 
 void ImDrawList::ChannelsSetCurrent(int idx)
 void ImDrawList::ChannelsSetCurrent(int idx)
 {
 {
-    if (_ChannelCurrent == idx) return;
-    memcpy(&_Channels.Data[_ChannelCurrent].CmdBuffer, &CmdBuffer, sizeof(CmdBuffer));
-    memcpy(&_Channels.Data[_ChannelCurrent].IdxBuffer, &IdxBuffer, sizeof(IdxBuffer));
-    _ChannelCurrent = idx;
-    memcpy(&CmdBuffer, &_Channels.Data[_ChannelCurrent].CmdBuffer, sizeof(CmdBuffer));
-    memcpy(&IdxBuffer, &_Channels.Data[_ChannelCurrent].IdxBuffer, sizeof(IdxBuffer));
+    if (_ChannelsCurrent == idx) return;
+    memcpy(&_Channels.Data[_ChannelsCurrent].CmdBuffer, &CmdBuffer, sizeof(CmdBuffer)); // copy 12 bytes, four times
+    memcpy(&_Channels.Data[_ChannelsCurrent].IdxBuffer, &IdxBuffer, sizeof(IdxBuffer));
+    _ChannelsCurrent = idx;
+    memcpy(&CmdBuffer, &_Channels.Data[_ChannelsCurrent].CmdBuffer, sizeof(CmdBuffer));
+    memcpy(&IdxBuffer, &_Channels.Data[_ChannelsCurrent].IdxBuffer, sizeof(IdxBuffer));
     _IdxWritePtr = IdxBuffer.Data + IdxBuffer.Size;
     _IdxWritePtr = IdxBuffer.Data + IdxBuffer.Size;
 }
 }