| 2147 | } |
| 2148 | |
| 2149 | void ImDrawListSplitter::Merge(ImDrawList* draw_list) |
| 2150 | { |
| 2151 | // 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. |
| 2152 | if (_Count <= 1) |
| 2153 | return; |
| 2154 | |
| 2155 | SetCurrentChannel(draw_list, 0); |
| 2156 | draw_list->_PopUnusedDrawCmd(); |
| 2157 | |
| 2158 | // Calculate our final buffer sizes. Also fix the incorrect IdxOffset values in each command. |
| 2159 | int new_cmd_buffer_count = 0; |
| 2160 | int new_idx_buffer_count = 0; |
| 2161 | ImDrawCmd* last_cmd = (_Count > 0 && draw_list->CmdBuffer.Size > 0) ? &draw_list->CmdBuffer.back() : NULL; |
| 2162 | int idx_offset = last_cmd ? last_cmd->IdxOffset + last_cmd->ElemCount : 0; |
| 2163 | for (int i = 1; i < _Count; i++) |
| 2164 | { |
| 2165 | ImDrawChannel& ch = _Channels[i]; |
| 2166 | if (ch._CmdBuffer.Size > 0 && ch._CmdBuffer.back().ElemCount == 0 && ch._CmdBuffer.back().UserCallback == NULL) // Equivalent of PopUnusedDrawCmd() |
| 2167 | ch._CmdBuffer.pop_back(); |
| 2168 | |
| 2169 | if (ch._CmdBuffer.Size > 0 && last_cmd != NULL) |
| 2170 | { |
| 2171 | // Do not include ImDrawCmd_AreSequentialIdxOffset() in the compare as we rebuild IdxOffset values ourselves. |
| 2172 | // Manipulating IdxOffset (e.g. by reordering draw commands like done by RenderDimmedBackgroundBehindWindow()) is not supported within a splitter. |
| 2173 | ImDrawCmd* next_cmd = &ch._CmdBuffer[0]; |
| 2174 | if (ImDrawCmd_HeaderCompare(last_cmd, next_cmd) == 0 && last_cmd->UserCallback == NULL && next_cmd->UserCallback == NULL) |
| 2175 | { |
| 2176 | // Merge previous channel last draw command with current channel first draw command if matching. |
| 2177 | last_cmd->ElemCount += next_cmd->ElemCount; |
| 2178 | idx_offset += next_cmd->ElemCount; |
| 2179 | ch._CmdBuffer.erase(ch._CmdBuffer.Data); // FIXME-OPT: Improve for multiple merges. |
| 2180 | } |
| 2181 | } |
| 2182 | if (ch._CmdBuffer.Size > 0) |
| 2183 | last_cmd = &ch._CmdBuffer.back(); |
| 2184 | new_cmd_buffer_count += ch._CmdBuffer.Size; |
| 2185 | new_idx_buffer_count += ch._IdxBuffer.Size; |
| 2186 | for (int cmd_n = 0; cmd_n < ch._CmdBuffer.Size; cmd_n++) |
| 2187 | { |
| 2188 | ch._CmdBuffer.Data[cmd_n].IdxOffset = idx_offset; |
| 2189 | idx_offset += ch._CmdBuffer.Data[cmd_n].ElemCount; |
| 2190 | } |
| 2191 | } |
| 2192 | draw_list->CmdBuffer.resize(draw_list->CmdBuffer.Size + new_cmd_buffer_count); |
| 2193 | draw_list->IdxBuffer.resize(draw_list->IdxBuffer.Size + new_idx_buffer_count); |
| 2194 | |
| 2195 | // Write commands and indices in order (they are fairly small structures, we don't copy vertices only indices) |
| 2196 | ImDrawCmd* cmd_write = draw_list->CmdBuffer.Data + draw_list->CmdBuffer.Size - new_cmd_buffer_count; |
| 2197 | ImDrawIdx* idx_write = draw_list->IdxBuffer.Data + draw_list->IdxBuffer.Size - new_idx_buffer_count; |
| 2198 | for (int i = 1; i < _Count; i++) |
| 2199 | { |
| 2200 | ImDrawChannel& ch = _Channels[i]; |
| 2201 | if (int sz = ch._CmdBuffer.Size) { memcpy(cmd_write, ch._CmdBuffer.Data, sz * sizeof(ImDrawCmd)); cmd_write += sz; } |
| 2202 | if (int sz = ch._IdxBuffer.Size) { memcpy(idx_write, ch._IdxBuffer.Data, sz * sizeof(ImDrawIdx)); idx_write += sz; } |
| 2203 | } |
| 2204 | draw_list->_IdxWritePtr = idx_write; |
| 2205 | |
| 2206 | // Ensure there's always a non-callback draw command trailing the command-buffer |
no test coverage detected