|
@@ -383,13 +383,19 @@ void ImDrawListSharedData::SetCircleSegmentMaxError(float max_error)
|
|
}
|
|
}
|
|
|
|
|
|
// Initialize before use in a new frame. We always have a command ready in the buffer.
|
|
// Initialize before use in a new frame. We always have a command ready in the buffer.
|
|
-void ImDrawList::ResetForNewFrame()
|
|
|
|
|
|
+void ImDrawList::_ResetForNewFrame()
|
|
{
|
|
{
|
|
|
|
+ // Verify that the ImDrawCmd fields we want to memcmp() are contiguous in memory.
|
|
|
|
+ // (those should be IM_STATIC_ASSERT() in theory but with our pre C++11 setup the whole check doesn't compile with GCC)
|
|
|
|
+ IM_ASSERT(IM_OFFSETOF(ImDrawCmd, ClipRect) == 0);
|
|
|
|
+ IM_ASSERT(IM_OFFSETOF(ImDrawCmd, TextureId) == sizeof(ImVec4));
|
|
|
|
+ IM_ASSERT(IM_OFFSETOF(ImDrawCmd, VtxOffset) == sizeof(ImVec4) + sizeof(ImTextureID));
|
|
|
|
+
|
|
CmdBuffer.resize(0);
|
|
CmdBuffer.resize(0);
|
|
IdxBuffer.resize(0);
|
|
IdxBuffer.resize(0);
|
|
VtxBuffer.resize(0);
|
|
VtxBuffer.resize(0);
|
|
Flags = _Data->InitialFlags;
|
|
Flags = _Data->InitialFlags;
|
|
- _VtxCurrentOffset = 0;
|
|
|
|
|
|
+ memset(&_CmdHeader, 0, sizeof(_CmdHeader));
|
|
_VtxCurrentIdx = 0;
|
|
_VtxCurrentIdx = 0;
|
|
_VtxWritePtr = NULL;
|
|
_VtxWritePtr = NULL;
|
|
_IdxWritePtr = NULL;
|
|
_IdxWritePtr = NULL;
|
|
@@ -400,13 +406,12 @@ void ImDrawList::ResetForNewFrame()
|
|
CmdBuffer.push_back(ImDrawCmd());
|
|
CmdBuffer.push_back(ImDrawCmd());
|
|
}
|
|
}
|
|
|
|
|
|
-void ImDrawList::ClearFreeMemory()
|
|
|
|
|
|
+void ImDrawList::_ClearFreeMemory()
|
|
{
|
|
{
|
|
CmdBuffer.clear();
|
|
CmdBuffer.clear();
|
|
IdxBuffer.clear();
|
|
IdxBuffer.clear();
|
|
VtxBuffer.clear();
|
|
VtxBuffer.clear();
|
|
Flags = ImDrawListFlags_None;
|
|
Flags = ImDrawListFlags_None;
|
|
- _VtxCurrentOffset = 0;
|
|
|
|
_VtxCurrentIdx = 0;
|
|
_VtxCurrentIdx = 0;
|
|
_VtxWritePtr = NULL;
|
|
_VtxWritePtr = NULL;
|
|
_IdxWritePtr = NULL;
|
|
_IdxWritePtr = NULL;
|
|
@@ -426,26 +431,34 @@ ImDrawList* ImDrawList::CloneOutput() const
|
|
return dst;
|
|
return dst;
|
|
}
|
|
}
|
|
|
|
|
|
-// Using macros because C++ is a terrible language, we want guaranteed inline, no code in header, and no overhead in Debug builds
|
|
|
|
-#define GetCurrentClipRect() (_ClipRectStack.Size ? _ClipRectStack.Data[_ClipRectStack.Size-1] : _Data->ClipRectFullscreen)
|
|
|
|
-#define GetCurrentTextureId() (_TextureIdStack.Size ? _TextureIdStack.Data[_TextureIdStack.Size-1] : (ImTextureID)NULL)
|
|
|
|
-
|
|
|
|
void ImDrawList::AddDrawCmd()
|
|
void ImDrawList::AddDrawCmd()
|
|
{
|
|
{
|
|
ImDrawCmd draw_cmd;
|
|
ImDrawCmd draw_cmd;
|
|
- draw_cmd.ClipRect = GetCurrentClipRect();
|
|
|
|
- draw_cmd.TextureId = GetCurrentTextureId();
|
|
|
|
- draw_cmd.VtxOffset = _VtxCurrentOffset;
|
|
|
|
|
|
+ draw_cmd.ClipRect = _CmdHeader.ClipRect; // Same as calling ImDrawCmd_HeaderCopy()
|
|
|
|
+ draw_cmd.TextureId = _CmdHeader.TextureId;
|
|
|
|
+ draw_cmd.VtxOffset = _CmdHeader.VtxOffset;
|
|
draw_cmd.IdxOffset = IdxBuffer.Size;
|
|
draw_cmd.IdxOffset = IdxBuffer.Size;
|
|
|
|
|
|
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);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+// Pop trailing draw command (used before merging or presenting to user)
|
|
|
|
+// Note that this leaves the ImDrawList in a state unfit for further commands, as most code assume that CmdBuffer.Size > 0 && CmdBuffer.back().UserCallback == NULL
|
|
|
|
+void ImDrawList::_PopUnusedDrawCmd()
|
|
|
|
+{
|
|
|
|
+ if (CmdBuffer.Size == 0)
|
|
|
|
+ return;
|
|
|
|
+ ImDrawCmd* curr_cmd = &CmdBuffer.Data[CmdBuffer.Size - 1];
|
|
|
|
+ if (curr_cmd->ElemCount == 0 && curr_cmd->UserCallback == NULL)
|
|
|
|
+ CmdBuffer.pop_back();
|
|
|
|
+}
|
|
|
|
+
|
|
void ImDrawList::AddCallback(ImDrawCallback callback, void* callback_data)
|
|
void ImDrawList::AddCallback(ImDrawCallback callback, void* callback_data)
|
|
{
|
|
{
|
|
ImDrawCmd* curr_cmd = &CmdBuffer.Data[CmdBuffer.Size - 1];
|
|
ImDrawCmd* curr_cmd = &CmdBuffer.Data[CmdBuffer.Size - 1];
|
|
- if (curr_cmd->ElemCount != 0 || curr_cmd->UserCallback != NULL)
|
|
|
|
|
|
+ IM_ASSERT(curr_cmd->UserCallback == NULL);
|
|
|
|
+ if (curr_cmd->ElemCount != 0)
|
|
{
|
|
{
|
|
AddDrawCmd();
|
|
AddDrawCmd();
|
|
curr_cmd = &CmdBuffer.Data[CmdBuffer.Size - 1];
|
|
curr_cmd = &CmdBuffer.Data[CmdBuffer.Size - 1];
|
|
@@ -456,68 +469,79 @@ void ImDrawList::AddCallback(ImDrawCallback callback, void* callback_data)
|
|
AddDrawCmd(); // Force a new command after us (see comment below)
|
|
AddDrawCmd(); // Force a new command after us (see comment below)
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+// Compare ClipRect, TextureId and VtxOffset with a single memcmp()
|
|
|
|
+#define ImDrawCmd_HeaderSize (IM_OFFSETOF(ImDrawCmd, VtxOffset) + sizeof(unsigned int))
|
|
|
|
+#define ImDrawCmd_HeaderCompare(CMD_LHS, CMD_RHS) (memcmp(CMD_LHS, CMD_RHS, ImDrawCmd_HeaderSize)) // Compare ClipRect, TextureId, VtxOffset
|
|
|
|
+#define ImDrawCmd_HeaderCopy(CMD_DST, CMD_SRC) (memcpy(CMD_DST, CMD_SRC, ImDrawCmd_HeaderSize)) // Copy ClipRect, TextureId, VtxOffset
|
|
|
|
+
|
|
// Our scheme may appears a bit unusual, basically we want the most-common calls AddLine AddRect etc. to not have to perform any check so we always have a command ready in the stack.
|
|
// Our scheme may appears a bit unusual, basically we want the most-common calls AddLine AddRect etc. to not have to perform any check so we always have a command ready in the stack.
|
|
// The cost of figuring out if a new command has to be added or if we can merge is paid in those Update** functions only.
|
|
// The cost of figuring out if a new command has to be added or if we can merge is paid in those Update** functions only.
|
|
-void ImDrawList::UpdateClipRect()
|
|
|
|
|
|
+void ImDrawList::_OnChangedClipRect()
|
|
{
|
|
{
|
|
// If current command is used with different settings we need to add a new command
|
|
// If current command is used with different settings we need to add a new command
|
|
- const ImVec4 curr_clip_rect = GetCurrentClipRect();
|
|
|
|
ImDrawCmd* curr_cmd = &CmdBuffer.Data[CmdBuffer.Size - 1];
|
|
ImDrawCmd* curr_cmd = &CmdBuffer.Data[CmdBuffer.Size - 1];
|
|
- if ((curr_cmd->ElemCount != 0 && memcmp(&curr_cmd->ClipRect, &curr_clip_rect, sizeof(ImVec4)) != 0) || curr_cmd->UserCallback != NULL)
|
|
|
|
|
|
+ if (curr_cmd->ElemCount != 0 && memcmp(&curr_cmd->ClipRect, &_CmdHeader.ClipRect, sizeof(ImVec4)) != 0)
|
|
{
|
|
{
|
|
AddDrawCmd();
|
|
AddDrawCmd();
|
|
return;
|
|
return;
|
|
}
|
|
}
|
|
|
|
+ IM_ASSERT(curr_cmd->UserCallback == NULL);
|
|
|
|
|
|
// Try to merge with previous command if it matches, else use current command
|
|
// Try to merge with previous command if it matches, else use current command
|
|
- if (curr_cmd->ElemCount == 0 && CmdBuffer.Size > 1)
|
|
|
|
|
|
+ ImDrawCmd* prev_cmd = curr_cmd - 1;
|
|
|
|
+ if (curr_cmd->ElemCount == 0 && CmdBuffer.Size > 1 && ImDrawCmd_HeaderCompare(&_CmdHeader, prev_cmd) == 0 && prev_cmd->UserCallback == NULL)
|
|
{
|
|
{
|
|
- ImDrawCmd* prev_cmd = curr_cmd - 1;
|
|
|
|
- if (memcmp(&prev_cmd->ClipRect, &curr_clip_rect, sizeof(ImVec4)) == 0 && prev_cmd->VtxOffset == _VtxCurrentOffset && prev_cmd->TextureId == GetCurrentTextureId() && prev_cmd->UserCallback == NULL)
|
|
|
|
- {
|
|
|
|
- CmdBuffer.pop_back();
|
|
|
|
- return;
|
|
|
|
- }
|
|
|
|
|
|
+ CmdBuffer.pop_back();
|
|
|
|
+ return;
|
|
}
|
|
}
|
|
|
|
|
|
- curr_cmd->ClipRect = curr_clip_rect;
|
|
|
|
|
|
+ curr_cmd->ClipRect = _CmdHeader.ClipRect;
|
|
}
|
|
}
|
|
|
|
|
|
-void ImDrawList::UpdateTextureID()
|
|
|
|
|
|
+void ImDrawList::_OnChangedTextureID()
|
|
{
|
|
{
|
|
// If current command is used with different settings we need to add a new command
|
|
// If current command is used with different settings we need to add a new command
|
|
- const ImTextureID curr_texture_id = GetCurrentTextureId();
|
|
|
|
ImDrawCmd* curr_cmd = &CmdBuffer.Data[CmdBuffer.Size - 1];
|
|
ImDrawCmd* curr_cmd = &CmdBuffer.Data[CmdBuffer.Size - 1];
|
|
- if (!curr_cmd || (curr_cmd->ElemCount != 0 && curr_cmd->TextureId != curr_texture_id) || curr_cmd->UserCallback != NULL)
|
|
|
|
|
|
+ if (curr_cmd->ElemCount != 0 && curr_cmd->TextureId != _CmdHeader.TextureId)
|
|
{
|
|
{
|
|
AddDrawCmd();
|
|
AddDrawCmd();
|
|
return;
|
|
return;
|
|
}
|
|
}
|
|
|
|
+ IM_ASSERT(curr_cmd->UserCallback == NULL);
|
|
|
|
|
|
// Try to merge with previous command if it matches, else use current command
|
|
// Try to merge with previous command if it matches, else use current command
|
|
- if (curr_cmd->ElemCount == 0 && CmdBuffer.Size > 1)
|
|
|
|
|
|
+ ImDrawCmd* prev_cmd = curr_cmd - 1;
|
|
|
|
+ if (curr_cmd->ElemCount == 0 && CmdBuffer.Size > 1 && ImDrawCmd_HeaderCompare(&_CmdHeader, prev_cmd) == 0 && prev_cmd->UserCallback == NULL)
|
|
{
|
|
{
|
|
- ImDrawCmd* prev_cmd = curr_cmd - 1;
|
|
|
|
- if (prev_cmd->TextureId == curr_texture_id && memcmp(&prev_cmd->ClipRect, &GetCurrentClipRect(), sizeof(ImVec4)) == 0 && prev_cmd->VtxOffset == _VtxCurrentOffset && prev_cmd->UserCallback == NULL)
|
|
|
|
- {
|
|
|
|
- CmdBuffer.pop_back();
|
|
|
|
- return;
|
|
|
|
- }
|
|
|
|
|
|
+ CmdBuffer.pop_back();
|
|
|
|
+ return;
|
|
}
|
|
}
|
|
|
|
|
|
- curr_cmd->TextureId = curr_texture_id;
|
|
|
|
|
|
+ curr_cmd->TextureId = _CmdHeader.TextureId;
|
|
}
|
|
}
|
|
|
|
|
|
-#undef GetCurrentClipRect
|
|
|
|
-#undef GetCurrentTextureId
|
|
|
|
|
|
+void ImDrawList::_OnChangedVtxOffset()
|
|
|
|
+{
|
|
|
|
+ // We don't need to compare curr_cmd->VtxOffset != _CmdHeader.VtxOffset because we know it'll be different at the time we call this.
|
|
|
|
+ _VtxCurrentIdx = 0;
|
|
|
|
+ ImDrawCmd* curr_cmd = &CmdBuffer.Data[CmdBuffer.Size - 1];
|
|
|
|
+ IM_ASSERT(curr_cmd->VtxOffset != _CmdHeader.VtxOffset);
|
|
|
|
+ if (curr_cmd->ElemCount != 0)
|
|
|
|
+ {
|
|
|
|
+ AddDrawCmd();
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+ IM_ASSERT(curr_cmd->UserCallback == NULL);
|
|
|
|
+ curr_cmd->VtxOffset = _CmdHeader.VtxOffset;
|
|
|
|
+}
|
|
|
|
|
|
// Render-level scissoring. This is passed down to your render function but not used for CPU-side coarse clipping. Prefer using higher-level ImGui::PushClipRect() to affect logic (hit-testing and widget culling)
|
|
// Render-level scissoring. This is passed down to your render function but not used for CPU-side coarse clipping. Prefer using higher-level ImGui::PushClipRect() to affect logic (hit-testing and widget culling)
|
|
void ImDrawList::PushClipRect(ImVec2 cr_min, ImVec2 cr_max, bool intersect_with_current_clip_rect)
|
|
void ImDrawList::PushClipRect(ImVec2 cr_min, ImVec2 cr_max, bool intersect_with_current_clip_rect)
|
|
{
|
|
{
|
|
ImVec4 cr(cr_min.x, cr_min.y, cr_max.x, cr_max.y);
|
|
ImVec4 cr(cr_min.x, cr_min.y, cr_max.x, cr_max.y);
|
|
- if (intersect_with_current_clip_rect && _ClipRectStack.Size)
|
|
|
|
|
|
+ if (intersect_with_current_clip_rect)
|
|
{
|
|
{
|
|
- ImVec4 current = _ClipRectStack.Data[_ClipRectStack.Size-1];
|
|
|
|
|
|
+ ImVec4 current = _CmdHeader.ClipRect;
|
|
if (cr.x < current.x) cr.x = current.x;
|
|
if (cr.x < current.x) cr.x = current.x;
|
|
if (cr.y < current.y) cr.y = current.y;
|
|
if (cr.y < current.y) cr.y = current.y;
|
|
if (cr.z > current.z) cr.z = current.z;
|
|
if (cr.z > current.z) cr.z = current.z;
|
|
@@ -527,7 +551,8 @@ void ImDrawList::PushClipRect(ImVec2 cr_min, ImVec2 cr_max, bool intersect_with_
|
|
cr.w = ImMax(cr.y, cr.w);
|
|
cr.w = ImMax(cr.y, cr.w);
|
|
|
|
|
|
_ClipRectStack.push_back(cr);
|
|
_ClipRectStack.push_back(cr);
|
|
- UpdateClipRect();
|
|
|
|
|
|
+ _CmdHeader.ClipRect = cr;
|
|
|
|
+ _OnChangedClipRect();
|
|
}
|
|
}
|
|
|
|
|
|
void ImDrawList::PushClipRectFullScreen()
|
|
void ImDrawList::PushClipRectFullScreen()
|
|
@@ -537,22 +562,23 @@ void ImDrawList::PushClipRectFullScreen()
|
|
|
|
|
|
void ImDrawList::PopClipRect()
|
|
void ImDrawList::PopClipRect()
|
|
{
|
|
{
|
|
- IM_ASSERT(_ClipRectStack.Size > 0);
|
|
|
|
_ClipRectStack.pop_back();
|
|
_ClipRectStack.pop_back();
|
|
- UpdateClipRect();
|
|
|
|
|
|
+ _CmdHeader.ClipRect = (_ClipRectStack.Size == 0) ? _Data->ClipRectFullscreen : _ClipRectStack.Data[_ClipRectStack.Size - 1];
|
|
|
|
+ _OnChangedClipRect();
|
|
}
|
|
}
|
|
|
|
|
|
void ImDrawList::PushTextureID(ImTextureID texture_id)
|
|
void ImDrawList::PushTextureID(ImTextureID texture_id)
|
|
{
|
|
{
|
|
_TextureIdStack.push_back(texture_id);
|
|
_TextureIdStack.push_back(texture_id);
|
|
- UpdateTextureID();
|
|
|
|
|
|
+ _CmdHeader.TextureId = texture_id;
|
|
|
|
+ _OnChangedTextureID();
|
|
}
|
|
}
|
|
|
|
|
|
void ImDrawList::PopTextureID()
|
|
void ImDrawList::PopTextureID()
|
|
{
|
|
{
|
|
- IM_ASSERT(_TextureIdStack.Size > 0);
|
|
|
|
_TextureIdStack.pop_back();
|
|
_TextureIdStack.pop_back();
|
|
- UpdateTextureID();
|
|
|
|
|
|
+ _CmdHeader.TextureId = (_TextureIdStack.Size == 0) ? (ImTextureID)NULL : _TextureIdStack.Data[_TextureIdStack.Size - 1];
|
|
|
|
+ _OnChangedTextureID();
|
|
}
|
|
}
|
|
|
|
|
|
// Reserve space for a number of vertices and indices.
|
|
// Reserve space for a number of vertices and indices.
|
|
@@ -564,9 +590,8 @@ void ImDrawList::PrimReserve(int idx_count, int vtx_count)
|
|
IM_ASSERT_PARANOID(idx_count >= 0 && vtx_count >= 0);
|
|
IM_ASSERT_PARANOID(idx_count >= 0 && vtx_count >= 0);
|
|
if (sizeof(ImDrawIdx) == 2 && (_VtxCurrentIdx + vtx_count >= (1 << 16)) && (Flags & ImDrawListFlags_AllowVtxOffset))
|
|
if (sizeof(ImDrawIdx) == 2 && (_VtxCurrentIdx + vtx_count >= (1 << 16)) && (Flags & ImDrawListFlags_AllowVtxOffset))
|
|
{
|
|
{
|
|
- _VtxCurrentOffset = VtxBuffer.Size;
|
|
|
|
- _VtxCurrentIdx = 0;
|
|
|
|
- AddDrawCmd();
|
|
|
|
|
|
+ _CmdHeader.VtxOffset = VtxBuffer.Size;
|
|
|
|
+ _OnChangedVtxOffset();
|
|
}
|
|
}
|
|
|
|
|
|
ImDrawCmd* draw_cmd = &CmdBuffer.Data[CmdBuffer.Size - 1];
|
|
ImDrawCmd* draw_cmd = &CmdBuffer.Data[CmdBuffer.Size - 1];
|
|
@@ -1241,9 +1266,9 @@ void ImDrawList::AddText(const ImFont* font, float font_size, const ImVec2& pos,
|
|
if (font_size == 0.0f)
|
|
if (font_size == 0.0f)
|
|
font_size = _Data->FontSize;
|
|
font_size = _Data->FontSize;
|
|
|
|
|
|
- IM_ASSERT(font->ContainerAtlas->TexID == _TextureIdStack.back()); // Use high-level ImGui::PushFont() or low-level ImDrawList::PushTextureId() to change font.
|
|
|
|
|
|
+ IM_ASSERT(font->ContainerAtlas->TexID == _CmdHeader.TextureId); // Use high-level ImGui::PushFont() or low-level ImDrawList::PushTextureId() to change font.
|
|
|
|
|
|
- ImVec4 clip_rect = _ClipRectStack.back();
|
|
|
|
|
|
+ ImVec4 clip_rect = _CmdHeader.ClipRect;
|
|
if (cpu_fine_clip_rect)
|
|
if (cpu_fine_clip_rect)
|
|
{
|
|
{
|
|
clip_rect.x = ImMax(clip_rect.x, cpu_fine_clip_rect->x);
|
|
clip_rect.x = ImMax(clip_rect.x, cpu_fine_clip_rect->x);
|
|
@@ -1264,7 +1289,7 @@ void ImDrawList::AddImage(ImTextureID user_texture_id, const ImVec2& p_min, cons
|
|
if ((col & IM_COL32_A_MASK) == 0)
|
|
if ((col & IM_COL32_A_MASK) == 0)
|
|
return;
|
|
return;
|
|
|
|
|
|
- const bool push_texture_id = _TextureIdStack.empty() || user_texture_id != _TextureIdStack.back();
|
|
|
|
|
|
+ const bool push_texture_id = user_texture_id != _CmdHeader.TextureId;
|
|
if (push_texture_id)
|
|
if (push_texture_id)
|
|
PushTextureID(user_texture_id);
|
|
PushTextureID(user_texture_id);
|
|
|
|
|
|
@@ -1280,7 +1305,7 @@ void ImDrawList::AddImageQuad(ImTextureID user_texture_id, const ImVec2& p1, con
|
|
if ((col & IM_COL32_A_MASK) == 0)
|
|
if ((col & IM_COL32_A_MASK) == 0)
|
|
return;
|
|
return;
|
|
|
|
|
|
- const bool push_texture_id = _TextureIdStack.empty() || user_texture_id != _TextureIdStack.back();
|
|
|
|
|
|
+ const bool push_texture_id = user_texture_id != _CmdHeader.TextureId;
|
|
if (push_texture_id)
|
|
if (push_texture_id)
|
|
PushTextureID(user_texture_id);
|
|
PushTextureID(user_texture_id);
|
|
|
|
|
|
@@ -1363,27 +1388,20 @@ void ImDrawListSplitter::Split(ImDrawList* draw_list, int channels_count)
|
|
if (_Channels[i]._CmdBuffer.Size == 0)
|
|
if (_Channels[i]._CmdBuffer.Size == 0)
|
|
{
|
|
{
|
|
ImDrawCmd draw_cmd;
|
|
ImDrawCmd draw_cmd;
|
|
- draw_cmd.ClipRect = draw_list->_ClipRectStack.back();
|
|
|
|
- draw_cmd.TextureId = draw_list->_TextureIdStack.back();
|
|
|
|
|
|
+ ImDrawCmd_HeaderCopy(&draw_cmd, &draw_list->_CmdHeader); // Copy ClipRect, TextureId, VtxOffset
|
|
_Channels[i]._CmdBuffer.push_back(draw_cmd);
|
|
_Channels[i]._CmdBuffer.push_back(draw_cmd);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
-static inline bool CanMergeDrawCommands(ImDrawCmd* a, ImDrawCmd* b)
|
|
|
|
-{
|
|
|
|
- return memcmp(&a->ClipRect, &b->ClipRect, sizeof(a->ClipRect)) == 0 && a->TextureId == b->TextureId && a->VtxOffset == b->VtxOffset && !a->UserCallback && !b->UserCallback;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
void ImDrawListSplitter::Merge(ImDrawList* draw_list)
|
|
void ImDrawListSplitter::Merge(ImDrawList* draw_list)
|
|
{
|
|
{
|
|
- // 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.
|
|
if (_Count <= 1)
|
|
if (_Count <= 1)
|
|
return;
|
|
return;
|
|
|
|
|
|
SetCurrentChannel(draw_list, 0);
|
|
SetCurrentChannel(draw_list, 0);
|
|
- if (draw_list->CmdBuffer.Size != 0 && draw_list->CmdBuffer.back().ElemCount == 0)
|
|
|
|
- draw_list->CmdBuffer.pop_back();
|
|
|
|
|
|
+ draw_list->_PopUnusedDrawCmd();
|
|
|
|
|
|
// Calculate our final buffer sizes. Also fix the incorrect IdxOffset values in each command.
|
|
// Calculate our final buffer sizes. Also fix the incorrect IdxOffset values in each command.
|
|
int new_cmd_buffer_count = 0;
|
|
int new_cmd_buffer_count = 0;
|
|
@@ -1393,14 +1411,21 @@ void ImDrawListSplitter::Merge(ImDrawList* draw_list)
|
|
for (int i = 1; i < _Count; i++)
|
|
for (int i = 1; i < _Count; i++)
|
|
{
|
|
{
|
|
ImDrawChannel& ch = _Channels[i];
|
|
ImDrawChannel& ch = _Channels[i];
|
|
|
|
+
|
|
|
|
+ // Equivalent of PopUnusedDrawCmd() for this channel's cmdbuffer and except we don't need to test for UserCallback.
|
|
if (ch._CmdBuffer.Size > 0 && ch._CmdBuffer.back().ElemCount == 0)
|
|
if (ch._CmdBuffer.Size > 0 && ch._CmdBuffer.back().ElemCount == 0)
|
|
ch._CmdBuffer.pop_back();
|
|
ch._CmdBuffer.pop_back();
|
|
- if (ch._CmdBuffer.Size > 0 && last_cmd != NULL && CanMergeDrawCommands(last_cmd, &ch._CmdBuffer[0]))
|
|
|
|
|
|
+
|
|
|
|
+ if (ch._CmdBuffer.Size > 0 && last_cmd != NULL)
|
|
{
|
|
{
|
|
- // Merge previous channel last draw command with current channel first draw command if matching.
|
|
|
|
- last_cmd->ElemCount += ch._CmdBuffer[0].ElemCount;
|
|
|
|
- idx_offset += ch._CmdBuffer[0].ElemCount;
|
|
|
|
- ch._CmdBuffer.erase(ch._CmdBuffer.Data); // FIXME-OPT: Improve for multiple merges.
|
|
|
|
|
|
+ ImDrawCmd* next_cmd = &ch._CmdBuffer[0];
|
|
|
|
+ if (ImDrawCmd_HeaderCompare(last_cmd, next_cmd) == 0 && last_cmd->UserCallback == NULL && next_cmd->UserCallback == NULL)
|
|
|
|
+ {
|
|
|
|
+ // Merge previous channel last draw command with current channel first draw command if matching.
|
|
|
|
+ last_cmd->ElemCount += next_cmd->ElemCount;
|
|
|
|
+ idx_offset += next_cmd->ElemCount;
|
|
|
|
+ ch._CmdBuffer.erase(ch._CmdBuffer.Data); // FIXME-OPT: Improve for multiple merges.
|
|
|
|
+ }
|
|
}
|
|
}
|
|
if (ch._CmdBuffer.Size > 0)
|
|
if (ch._CmdBuffer.Size > 0)
|
|
last_cmd = &ch._CmdBuffer.back();
|
|
last_cmd = &ch._CmdBuffer.back();
|
|
@@ -1425,8 +1450,18 @@ void ImDrawListSplitter::Merge(ImDrawList* draw_list)
|
|
if (int sz = ch._IdxBuffer.Size) { memcpy(idx_write, ch._IdxBuffer.Data, sz * sizeof(ImDrawIdx)); idx_write += sz; }
|
|
if (int sz = ch._IdxBuffer.Size) { memcpy(idx_write, ch._IdxBuffer.Data, sz * sizeof(ImDrawIdx)); idx_write += sz; }
|
|
}
|
|
}
|
|
draw_list->_IdxWritePtr = idx_write;
|
|
draw_list->_IdxWritePtr = idx_write;
|
|
- draw_list->UpdateClipRect(); // We call this instead of AddDrawCmd(), so that empty channels won't produce an extra draw call.
|
|
|
|
- draw_list->UpdateTextureID();
|
|
|
|
|
|
+
|
|
|
|
+ // Ensure there's always a non-callback draw command trailing the command-buffer
|
|
|
|
+ if (draw_list->CmdBuffer.Size == 0 || draw_list->CmdBuffer.back().UserCallback != NULL)
|
|
|
|
+ draw_list->AddDrawCmd();
|
|
|
|
+
|
|
|
|
+ // If current command is used with different settings we need to add a new command
|
|
|
|
+ ImDrawCmd* curr_cmd = &draw_list->CmdBuffer.Data[draw_list->CmdBuffer.Size - 1];
|
|
|
|
+ if (curr_cmd->ElemCount == 0)
|
|
|
|
+ ImDrawCmd_HeaderCopy(curr_cmd, &draw_list->_CmdHeader); // Copy ClipRect, TextureId, VtxOffset
|
|
|
|
+ else if (ImDrawCmd_HeaderCompare(curr_cmd, &draw_list->_CmdHeader) != 0)
|
|
|
|
+ draw_list->AddDrawCmd();
|
|
|
|
+
|
|
_Count = 1;
|
|
_Count = 1;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -1435,6 +1470,7 @@ void ImDrawListSplitter::SetCurrentChannel(ImDrawList* draw_list, int idx)
|
|
IM_ASSERT(idx >= 0 && idx < _Count);
|
|
IM_ASSERT(idx >= 0 && idx < _Count);
|
|
if (_Current == idx)
|
|
if (_Current == idx)
|
|
return;
|
|
return;
|
|
|
|
+
|
|
// Overwrite ImVector (12/16 bytes), four times. This is merely a silly optimization instead of doing .swap()
|
|
// Overwrite ImVector (12/16 bytes), four times. This is merely a silly optimization instead of doing .swap()
|
|
memcpy(&_Channels.Data[_Current]._CmdBuffer, &draw_list->CmdBuffer, sizeof(draw_list->CmdBuffer));
|
|
memcpy(&_Channels.Data[_Current]._CmdBuffer, &draw_list->CmdBuffer, sizeof(draw_list->CmdBuffer));
|
|
memcpy(&_Channels.Data[_Current]._IdxBuffer, &draw_list->IdxBuffer, sizeof(draw_list->IdxBuffer));
|
|
memcpy(&_Channels.Data[_Current]._IdxBuffer, &draw_list->IdxBuffer, sizeof(draw_list->IdxBuffer));
|
|
@@ -1442,6 +1478,13 @@ void ImDrawListSplitter::SetCurrentChannel(ImDrawList* draw_list, int idx)
|
|
memcpy(&draw_list->CmdBuffer, &_Channels.Data[idx]._CmdBuffer, sizeof(draw_list->CmdBuffer));
|
|
memcpy(&draw_list->CmdBuffer, &_Channels.Data[idx]._CmdBuffer, sizeof(draw_list->CmdBuffer));
|
|
memcpy(&draw_list->IdxBuffer, &_Channels.Data[idx]._IdxBuffer, sizeof(draw_list->IdxBuffer));
|
|
memcpy(&draw_list->IdxBuffer, &_Channels.Data[idx]._IdxBuffer, sizeof(draw_list->IdxBuffer));
|
|
draw_list->_IdxWritePtr = draw_list->IdxBuffer.Data + draw_list->IdxBuffer.Size;
|
|
draw_list->_IdxWritePtr = draw_list->IdxBuffer.Data + draw_list->IdxBuffer.Size;
|
|
|
|
+
|
|
|
|
+ // If current command is used with different settings we need to add a new command
|
|
|
|
+ ImDrawCmd* curr_cmd = &draw_list->CmdBuffer.Data[draw_list->CmdBuffer.Size - 1];
|
|
|
|
+ if (curr_cmd->ElemCount == 0)
|
|
|
|
+ ImDrawCmd_HeaderCopy(curr_cmd, &draw_list->_CmdHeader); // Copy ClipRect, TextureId, VtxOffset
|
|
|
|
+ else if (ImDrawCmd_HeaderCompare(curr_cmd, &draw_list->_CmdHeader) != 0)
|
|
|
|
+ draw_list->AddDrawCmd();
|
|
}
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//-----------------------------------------------------------------------------
|