Skip to content

Commit c6960cd

Browse files
committed
LeaveLocalSpace(): Search for ImDrawCallback_ImCanvas after m_DrawListFirstCommandIndex (proposed fix for thedmd#282)
Analysis of the bug thedmd#282 when using this repro: https://github.com/pthom/node_window_clipping_issue/tree/suspend_resume_issue2 At the 4th call of LeaveLocalSpace(), we have: this = {ImGuiEx::Canvas *} m_DrawList = {ImDrawList *} mDrawList is of size 4 CmdBuffer = {ImVector<ImDrawCmd>} its elements at index 2 Size = {int} 4 has UserCallback == {ImDrawCallback_ImCanvas} Capacity = {int} 8 Data = {ImDrawCmd *} m_ExpectedChannel = {int} 0 m_DrawListFirstCommandIndex = {int} 2 m_DrawListCommadBufferSize = {int} 1 m_DrawListStartVertexIndex = {int} 8 We have m_DrawListFirstCommandIndex = 2, however, the tests in the original code will test only at index 0 and 1! if (m_DrawList->CmdBuffer.size() > m_DrawListCommadBufferSize && m_DrawList->CmdBuffer[m_DrawListCommadBufferSize].UserCallback == ImDrawCallback_ImCanvas) m_DrawList->CmdBuffer.erase(m_DrawList->CmdBuffer.Data + m_DrawListCommadBufferSize); else if (m_DrawList->CmdBuffer.size() >= m_DrawListCommadBufferSize && m_DrawList->CmdBuffer[m_DrawListCommadBufferSize - 1].UserCallback == ImDrawCallback_ImCanvas) m_DrawList->CmdBuffer.erase(m_DrawList->CmdBuffer.Data + m_DrawListCommadBufferSize - 1); // Proposed solution: test all commands from index >= m_DrawListFirstCommandIndex // and remove the one with UserCallback == ImDrawCallback_ImCanvas // (based on the original code, it seems there can be only one) int idxCommand_ImDrawCallback_ImCanvas = -1; for (int i = m_DrawListFirstCommandIndex; i < m_DrawList->CmdBuffer.size(); ++i) { auto & command = m_DrawList->CmdBuffer[i]; if (command.UserCallback == ImDrawCallback_ImCanvas) { idxCommand_ImDrawCallback_ImCanvas = i; break; } } if (idxCommand_ImDrawCallback_ImCanvas >= 0) m_DrawList->CmdBuffer.erase(m_DrawList->CmdBuffer.Data + idxCommand_ImDrawCallback_ImCanvas);
1 parent a0b68cb commit c6960cd

File tree

1 file changed

+43
-0
lines changed

1 file changed

+43
-0
lines changed

Diff for: imgui_canvas.cpp

+43
Original file line numberDiff line numberDiff line change
@@ -557,10 +557,53 @@ void ImGuiEx::Canvas::LeaveLocalSpace()
557557
// Remove sentinel draw command if present
558558
if (m_DrawListCommadBufferSize > 0)
559559
{
560+
/*
561+
Analysis of the bug https://github.com/thedmd/imgui-node-editor/issues/282
562+
when using this repro: https://github.com/pthom/node_window_clipping_issue/tree/suspend_resume_issue2
563+
564+
At the 4th call of LeaveLocalSpace(), we have:
565+
566+
this = {ImGuiEx::Canvas *}
567+
m_DrawList = {ImDrawList *} mDrawList is of size 4
568+
CmdBuffer = {ImVector<ImDrawCmd>} its elements at index 2
569+
Size = {int} 4 has UserCallback == {ImDrawCallback_ImCanvas}
570+
Capacity = {int} 8
571+
Data = {ImDrawCmd *}
572+
m_ExpectedChannel = {int} 0
573+
m_DrawListFirstCommandIndex = {int} 2
574+
m_DrawListCommadBufferSize = {int} 1
575+
m_DrawListStartVertexIndex = {int} 8
576+
577+
We have m_DrawListFirstCommandIndex = 2, however, the tests in the original code will test only at index 0 and 1!
578+
if (m_DrawList->CmdBuffer.size() > m_DrawListCommadBufferSize && m_DrawList->CmdBuffer[m_DrawListCommadBufferSize].UserCallback == ImDrawCallback_ImCanvas)
579+
m_DrawList->CmdBuffer.erase(m_DrawList->CmdBuffer.Data + m_DrawListCommadBufferSize);
580+
else if (m_DrawList->CmdBuffer.size() >= m_DrawListCommadBufferSize && m_DrawList->CmdBuffer[m_DrawListCommadBufferSize - 1].UserCallback == ImDrawCallback_ImCanvas)
581+
m_DrawList->CmdBuffer.erase(m_DrawList->CmdBuffer.Data + m_DrawListCommadBufferSize - 1);
582+
583+
584+
*/
585+
586+
// Original tests; this test will fail because it tests at index 0 and 1
560587
if (m_DrawList->CmdBuffer.size() > m_DrawListCommadBufferSize && m_DrawList->CmdBuffer[m_DrawListCommadBufferSize].UserCallback == ImDrawCallback_ImCanvas)
561588
m_DrawList->CmdBuffer.erase(m_DrawList->CmdBuffer.Data + m_DrawListCommadBufferSize);
562589
else if (m_DrawList->CmdBuffer.size() >= m_DrawListCommadBufferSize && m_DrawList->CmdBuffer[m_DrawListCommadBufferSize - 1].UserCallback == ImDrawCallback_ImCanvas)
563590
m_DrawList->CmdBuffer.erase(m_DrawList->CmdBuffer.Data + m_DrawListCommadBufferSize - 1);
591+
592+
// Proposed solution: test all commands from index >= m_DrawListFirstCommandIndex
593+
// and remove the one with UserCallback == ImDrawCallback_ImCanvas
594+
// (based on the original code, it seems there can be only one)
595+
int idxCommand_ImDrawCallback_ImCanvas = -1;
596+
for (int i = m_DrawListFirstCommandIndex; i < m_DrawList->CmdBuffer.size(); ++i)
597+
{
598+
auto & command = m_DrawList->CmdBuffer[i];
599+
if (command.UserCallback == ImDrawCallback_ImCanvas)
600+
{
601+
idxCommand_ImDrawCallback_ImCanvas = i;
602+
break;
603+
}
604+
}
605+
if (idxCommand_ImDrawCallback_ImCanvas >= 0)
606+
m_DrawList->CmdBuffer.erase(m_DrawList->CmdBuffer.Data + idxCommand_ImDrawCallback_ImCanvas);
564607
}
565608

566609
auto& fringeScale = ImFringeScaleRef(m_DrawList);

0 commit comments

Comments
 (0)