| 1717 | } |
| 1718 | |
| 1719 | void ImDrawListSplitter::Merge(ImDrawList* draw_list) |
| 1720 | { |
| 1721 | // 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. |
| 1722 | if (_Count <= 1) |
| 1723 | return; |
| 1724 | |
| 1725 | SetCurrentChannel(draw_list, 0); |
| 1726 | draw_list->_PopUnusedDrawCmd(); |
| 1727 | |
| 1728 | // Calculate our final buffer sizes. Also fix the incorrect IdxOffset values in each command. |
| 1729 | int new_cmd_buffer_count = 0; |
| 1730 | int new_idx_buffer_count = 0; |
| 1731 | ImDrawCmd* last_cmd = (_Count > 0 && draw_list->CmdBuffer.Size > 0) ? &draw_list->CmdBuffer.back() : NULL; |
| 1732 | int idx_offset = last_cmd ? last_cmd->IdxOffset + last_cmd->ElemCount : 0; |
| 1733 | for (int i = 1; i < _Count; i++) |
| 1734 | { |
| 1735 | ImDrawChannel& ch = _Channels[i]; |
| 1736 | if (ch._CmdBuffer.Size > 0 && ch._CmdBuffer.back().ElemCount == 0 && ch._CmdBuffer.back().UserCallback == NULL) // Equivalent of PopUnusedDrawCmd() |
| 1737 | ch._CmdBuffer.pop_back(); |
| 1738 | |
| 1739 | if (ch._CmdBuffer.Size > 0 && last_cmd != NULL) |
| 1740 | { |
| 1741 | // Do not include ImDrawCmd_AreSequentialIdxOffset() in the compare as we rebuild IdxOffset values ourselves. |
| 1742 | // Manipulating IdxOffset (e.g. by reordering draw commands like done by RenderDimmedBackgroundBehindWindow()) is not supported within a splitter. |
| 1743 | ImDrawCmd* next_cmd = &ch._CmdBuffer[0]; |
| 1744 | if (ImDrawCmd_HeaderCompare(last_cmd, next_cmd) == 0 && last_cmd->UserCallback == NULL && next_cmd->UserCallback == NULL) |
| 1745 | { |
| 1746 | // Merge previous channel last draw command with current channel first draw command if matching. |
| 1747 | last_cmd->ElemCount += next_cmd->ElemCount; |
| 1748 | idx_offset += next_cmd->ElemCount; |
| 1749 | ch._CmdBuffer.erase(ch._CmdBuffer.Data); // FIXME-OPT: Improve for multiple merges. |
| 1750 | } |
| 1751 | } |
| 1752 | if (ch._CmdBuffer.Size > 0) |
| 1753 | last_cmd = &ch._CmdBuffer.back(); |
| 1754 | new_cmd_buffer_count += ch._CmdBuffer.Size; |
| 1755 | new_idx_buffer_count += ch._IdxBuffer.Size; |
| 1756 | for (int cmd_n = 0; cmd_n < ch._CmdBuffer.Size; cmd_n++) |
| 1757 | { |
| 1758 | ch._CmdBuffer.Data[cmd_n].IdxOffset = idx_offset; |
| 1759 | idx_offset += ch._CmdBuffer.Data[cmd_n].ElemCount; |
| 1760 | } |
| 1761 | } |
| 1762 | draw_list->CmdBuffer.resize(draw_list->CmdBuffer.Size + new_cmd_buffer_count); |
| 1763 | draw_list->IdxBuffer.resize(draw_list->IdxBuffer.Size + new_idx_buffer_count); |
| 1764 | |
| 1765 | // Write commands and indices in order (they are fairly small structures, we don't copy vertices only indices) |
| 1766 | ImDrawCmd* cmd_write = draw_list->CmdBuffer.Data + draw_list->CmdBuffer.Size - new_cmd_buffer_count; |
| 1767 | ImDrawIdx* idx_write = draw_list->IdxBuffer.Data + draw_list->IdxBuffer.Size - new_idx_buffer_count; |
| 1768 | for (int i = 1; i < _Count; i++) |
| 1769 | { |
| 1770 | ImDrawChannel& ch = _Channels[i]; |
| 1771 | if (int sz = ch._CmdBuffer.Size) { memcpy(cmd_write, ch._CmdBuffer.Data, sz * sizeof(ImDrawCmd)); cmd_write += sz; } |
| 1772 | if (int sz = ch._IdxBuffer.Size) { memcpy(idx_write, ch._IdxBuffer.Data, sz * sizeof(ImDrawIdx)); idx_write += sz; } |
| 1773 | } |
| 1774 | draw_list->_IdxWritePtr = idx_write; |
| 1775 | |
| 1776 | // Ensure there's always a non-callback draw command trailing the command-buffer |
no test coverage detected