DrawList: AddCallback() added an optional size parameter allowing to copy and store any amount of user data for usage by callbacks: (#6969, #4770, #7665)

This commit is contained in:
ocornut 2024-10-11 13:29:13 +02:00
parent f29e505d94
commit 98d52b7b26
4 changed files with 56 additions and 10 deletions

View file

@ -60,6 +60,14 @@ Other changes:
- IO: added 'void* platform_io.Renderer_RenderState' which is set during the - IO: added 'void* platform_io.Renderer_RenderState' which is set during the
ImGui_ImplXXXX_RenderDrawData() of standard backend to expose selected render ImGui_ImplXXXX_RenderDrawData() of standard backend to expose selected render
state to draw callbacks. (#6969, #5834, #7468, #3590) state to draw callbacks. (#6969, #5834, #7468, #3590)
- DrawList: AddCallback() added an optional size parameter allowing to copy and
store any amount of user data for usage by callbacks: (#6969, #4770, #7665)
- If userdata_size == 0: we copy/store the 'userdata' argument as-is (existing behavior).
It will be available unmodified in ImDrawCmd::UserCallbackData during render.
- If userdata_size > 0, we copy/store 'userdata_size' bytes pointed to by 'userdata' (new behavior).
We store them in a buffer stored inside the drawlist. ImDrawCmd::UserCallbackData
will point inside that buffer so you have to retrieve data from there. Your callback
may need to use ImDrawCmd::UserCallbackDataSize if you expect dynamically-sized data.
- Tables: fixed initial auto-sizing issue with synched-instances. (#8045, #7218) - Tables: fixed initial auto-sizing issue with synched-instances. (#8045, #7218)
- InputText: fixed an issue with not declaring ownership of Delete/Backspace/Arrow keys, - InputText: fixed an issue with not declaring ownership of Delete/Backspace/Arrow keys,
preventing use of external shortcuts not guarded by an ActiveId check. (#8048) [@geertbleyen] preventing use of external shortcuts not guarded by an ActiveId check. (#8048) [@geertbleyen]

View file

@ -9,8 +9,7 @@ It's mostly a bunch of personal notes, probably incomplete. Feel free to query i
- doc: add a proper documentation system (maybe relying on automation? #435) - doc: add a proper documentation system (maybe relying on automation? #435)
- doc: checklist app to verify backends/integration of imgui (test inputs, rendering, callback, etc.). - doc: checklist app to verify backends/integration of imgui (test inputs, rendering, callback, etc.).
- doc/tips: tips of the day: website? applet in imgui_club? - doc/tips: tips of the day: website? applet in imgui_club?
- doc/wiki: work on the wiki https://github.com/ocornut/imgui/wiki
- window: preserve/restore relative focus ordering (persistent or not), and e.g. of multiple reappearing windows (#2304) -> also see docking reference to same #. - window: preserve/restore relative focus ordering (persistent or not), and e.g. of multiple reappearing windows (#2304) -> also see docking reference to same #.
- window: calling SetNextWindowSize() every frame with <= 0 doesn't do anything, may be useful to allow (particularly when used for a single axis). (#690) - window: calling SetNextWindowSize() every frame with <= 0 doesn't do anything, may be useful to allow (particularly when used for a single axis). (#690)
- window: add a way for very transient windows (non-saved, temporary overlay over hundreds of objects) to "clean" up from the global window list. perhaps a lightweight explicit cleanup pass. - window: add a way for very transient windows (non-saved, temporary overlay over hundreds of objects) to "clean" up from the global window list. perhaps a lightweight explicit cleanup pass.
@ -44,7 +43,7 @@ It's mostly a bunch of personal notes, probably incomplete. Feel free to query i
- drawlist: maintaining bounding box per command would allow to merge draw command when clipping isn't relied on (typical non-scrolling window or non-overflowing column would merge with previous command). (WIP branch) - drawlist: maintaining bounding box per command would allow to merge draw command when clipping isn't relied on (typical non-scrolling window or non-overflowing column would merge with previous command). (WIP branch)
- drawlist: make it easier to toggle AA per primitive, so we can use e.g. non-AA fill + AA borders more naturally - drawlist: make it easier to toggle AA per primitive, so we can use e.g. non-AA fill + AA borders more naturally
- drawlist: non-AA strokes have gaps between points (#593, #288), glitch especially on RenderCheckmark() and ColorPicker4(). - drawlist: non-AA strokes have gaps between points (#593, #288), glitch especially on RenderCheckmark() and ColorPicker4().
- drawlist: callback: add an extra void* in ImDrawCallback to allow passing render-local data to the callback (would break API). - drawlist: callback: add an extra void* in ImDrawCallback to expose render state instead of pulling from Renderer_RenderState (would break API).
- drawlist: AddRect vs AddLine position confusing (#2441) - drawlist: AddRect vs AddLine position confusing (#2441)
- drawlist/opt: store rounded corners in texture to use 1 quad per corner (filled and wireframe) to lower the cost of rounding. (#1962) - drawlist/opt: store rounded corners in texture to use 1 quad per corner (filled and wireframe) to lower the cost of rounding. (#1962)
- drawlist/opt: AddRect() axis aligned pixel aligned (no-aa) could use 8 triangles instead of 16 and no normal calculation. - drawlist/opt: AddRect() axis aligned pixel aligned (no-aa) could use 8 triangles instead of 16 and no normal calculation.

23
imgui.h
View file

@ -29,7 +29,7 @@
// Library Version // Library Version
// (Integer encoded as XYYZZ for use in #if preprocessor conditionals, e.g. '#if IMGUI_VERSION_NUM >= 12345') // (Integer encoded as XYYZZ for use in #if preprocessor conditionals, e.g. '#if IMGUI_VERSION_NUM >= 12345')
#define IMGUI_VERSION "1.91.4 WIP" #define IMGUI_VERSION "1.91.4 WIP"
#define IMGUI_VERSION_NUM 19132 #define IMGUI_VERSION_NUM 19133
#define IMGUI_HAS_TABLE #define IMGUI_HAS_TABLE
/* /*
@ -2953,9 +2953,11 @@ struct ImDrawCmd
unsigned int IdxOffset; // 4 // Start offset in index buffer. unsigned int IdxOffset; // 4 // Start offset in index buffer.
unsigned int ElemCount; // 4 // Number of indices (multiple of 3) to be rendered as triangles. Vertices are stored in the callee ImDrawList's vtx_buffer[] array, indices in idx_buffer[]. unsigned int ElemCount; // 4 // Number of indices (multiple of 3) to be rendered as triangles. Vertices are stored in the callee ImDrawList's vtx_buffer[] array, indices in idx_buffer[].
ImDrawCallback UserCallback; // 4-8 // If != NULL, call the function instead of rendering the vertices. clip_rect and texture_id will be set normally. ImDrawCallback UserCallback; // 4-8 // If != NULL, call the function instead of rendering the vertices. clip_rect and texture_id will be set normally.
void* UserCallbackData; // 4-8 // The draw callback code can access this. void* UserCallbackData; // 4-8 // Callback user data (when UserCallback != NULL). If called AddCallback() with size == 0, this is a copy of the AddCallback() argument. If called AddCallback() with size > 0, this is pointing to a buffer where data is stored.
int UserCallbackDataSize; // 4 // Size of callback user data when using storage, otherwise 0.
int UserCallbackDataOffset;// 4 // [Internal] Offset of callback user data when using storage, otherwise -1.
ImDrawCmd() { memset(this, 0, sizeof(*this)); } // Also ensure our padding fields are zeroed ImDrawCmd() { memset(this, 0, sizeof(*this)); } // Also ensure our padding fields are zeroed
// Since 1.83: returns ImTextureID associated with this draw call. Warning: DO NOT assume this is always same as 'TextureId' (we will change this function for an upcoming feature) // Since 1.83: returns ImTextureID associated with this draw call. Warning: DO NOT assume this is always same as 'TextureId' (we will change this function for an upcoming feature)
inline ImTextureID GetTexID() const { return TextureId; } inline ImTextureID GetTexID() const { return TextureId; }
@ -3068,6 +3070,7 @@ struct ImDrawList
ImDrawListSplitter _Splitter; // [Internal] for channels api (note: prefer using your own persistent instance of ImDrawListSplitter!) ImDrawListSplitter _Splitter; // [Internal] for channels api (note: prefer using your own persistent instance of ImDrawListSplitter!)
ImVector<ImVec4> _ClipRectStack; // [Internal] ImVector<ImVec4> _ClipRectStack; // [Internal]
ImVector<ImTextureID> _TextureIdStack; // [Internal] ImVector<ImTextureID> _TextureIdStack; // [Internal]
ImVector<ImU8> _CallbacksDataBuf; // [Internal]
float _FringeScale; // [Internal] anti-alias fringe is scaled by this value, this helps to keep things sharp while zooming at vertex buffer content float _FringeScale; // [Internal] anti-alias fringe is scaled by this value, this helps to keep things sharp while zooming at vertex buffer content
const char* _OwnerName; // Pointer to owner window's name for debugging const char* _OwnerName; // Pointer to owner window's name for debugging
@ -3140,8 +3143,18 @@ struct ImDrawList
IMGUI_API void PathBezierQuadraticCurveTo(const ImVec2& p2, const ImVec2& p3, int num_segments = 0); // Quadratic Bezier (3 control points) IMGUI_API void PathBezierQuadraticCurveTo(const ImVec2& p2, const ImVec2& p3, int num_segments = 0); // Quadratic Bezier (3 control points)
IMGUI_API void PathRect(const ImVec2& rect_min, const ImVec2& rect_max, float rounding = 0.0f, ImDrawFlags flags = 0); IMGUI_API void PathRect(const ImVec2& rect_min, const ImVec2& rect_max, float rounding = 0.0f, ImDrawFlags flags = 0);
// Advanced // Advanced: Draw Callbacks
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. // - May be used to alter render state (change sampler, blending, current shader). May be used to emit custom rendering commands (difficult to do correctly, but possible).
// - Use special ImDrawCallback_ResetRenderState callback to instruct backend to reset its render state to the default.
// - Your rendering loop must check for 'UserCallback' in ImDrawCmd and call the function instead of rendering triangles. All standard backends are honoring this.
// - For some backends, the callback may access selected render-states exposed by the backend in a ImGui_ImplXXXX_RenderState structure pointed to by platform_io.Renderer_RenderState.
// - IMPORTANT: please be mindful of the different level of indirection between using size==0 (copying argument) and using size>0 (copying pointed data into a buffer).
// - If userdata_size == 0: we copy/store the 'userdata' argument as-is. It will be available unmodified in ImDrawCmd::UserCallbackData during render.
// - If userdata_size > 0, we copy/store 'userdata_size' bytes pointed to by 'userdata'. We store them in a buffer stored inside the drawlist. ImDrawCmd::UserCallbackData will point inside that buffer so you have to retrieve data from there. Your callback may need to use ImDrawCmd::UserCallbackDataSize if you expect dynamically-sized data.
// - Support for userdata_size > 0 was added in v1.91.4, October 2024. So earlier code always only allowed to copy/store a simple void*.
IMGUI_API void AddCallback(ImDrawCallback callback, void* userdata, size_t userdata_size = 0);
// Advanced: Miscellaneous
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 ImDrawList* CloneOutput() const; // Create a clone of the CmdBuffer/IdxBuffer/VtxBuffer. IMGUI_API ImDrawList* CloneOutput() const; // Create a clone of the CmdBuffer/IdxBuffer/VtxBuffer.

View file

@ -414,6 +414,7 @@ void ImDrawList::_ResetForNewFrame()
_IdxWritePtr = NULL; _IdxWritePtr = NULL;
_ClipRectStack.resize(0); _ClipRectStack.resize(0);
_TextureIdStack.resize(0); _TextureIdStack.resize(0);
_CallbacksDataBuf.resize(0);
_Path.resize(0); _Path.resize(0);
_Splitter.Clear(); _Splitter.Clear();
CmdBuffer.push_back(ImDrawCmd()); CmdBuffer.push_back(ImDrawCmd());
@ -431,6 +432,7 @@ void ImDrawList::_ClearFreeMemory()
_IdxWritePtr = NULL; _IdxWritePtr = NULL;
_ClipRectStack.clear(); _ClipRectStack.clear();
_TextureIdStack.clear(); _TextureIdStack.clear();
_CallbacksDataBuf.clear();
_Path.clear(); _Path.clear();
_Splitter.ClearFreeMemory(); _Splitter.ClearFreeMemory();
} }
@ -470,7 +472,7 @@ void ImDrawList::_PopUnusedDrawCmd()
} }
} }
void ImDrawList::AddCallback(ImDrawCallback callback, void* callback_data) void ImDrawList::AddCallback(ImDrawCallback callback, void* userdata, size_t userdata_size)
{ {
IM_ASSERT_PARANOID(CmdBuffer.Size > 0); IM_ASSERT_PARANOID(CmdBuffer.Size > 0);
ImDrawCmd* curr_cmd = &CmdBuffer.Data[CmdBuffer.Size - 1]; ImDrawCmd* curr_cmd = &CmdBuffer.Data[CmdBuffer.Size - 1];
@ -480,8 +482,26 @@ void ImDrawList::AddCallback(ImDrawCallback callback, void* callback_data)
AddDrawCmd(); AddDrawCmd();
curr_cmd = &CmdBuffer.Data[CmdBuffer.Size - 1]; curr_cmd = &CmdBuffer.Data[CmdBuffer.Size - 1];
} }
curr_cmd->UserCallback = callback; curr_cmd->UserCallback = callback;
curr_cmd->UserCallbackData = callback_data; if (userdata_size == 0)
{
// Store user data directly in command (no indirection)
curr_cmd->UserCallbackData = userdata;
curr_cmd->UserCallbackDataSize = 0;
curr_cmd->UserCallbackDataOffset = -1;
}
else
{
// Copy and store user data in a buffer
IM_ASSERT(userdata != NULL);
IM_ASSERT(userdata_size < (1u << 31));
curr_cmd->UserCallbackData = NULL; // Will be resolved during Render()
curr_cmd->UserCallbackDataSize = (int)userdata_size;
curr_cmd->UserCallbackDataOffset = _CallbacksDataBuf.Size;
_CallbacksDataBuf.resize(_CallbacksDataBuf.Size + (int)userdata_size);
memcpy(_CallbacksDataBuf.Data + (size_t)curr_cmd->UserCallbackDataOffset, userdata, userdata_size);
}
AddDrawCmd(); // Force a new command after us (see comment below) AddDrawCmd(); // Force a new command after us (see comment below)
} }
@ -2222,6 +2242,12 @@ void ImGui::AddDrawListToDrawDataEx(ImDrawData* draw_data, ImVector<ImDrawList*>
if (sizeof(ImDrawIdx) == 2) if (sizeof(ImDrawIdx) == 2)
IM_ASSERT(draw_list->_VtxCurrentIdx < (1 << 16) && "Too many vertices in ImDrawList using 16-bit indices. Read comment above"); IM_ASSERT(draw_list->_VtxCurrentIdx < (1 << 16) && "Too many vertices in ImDrawList using 16-bit indices. Read comment above");
// Resolve callback data pointers
if (draw_list->_CallbacksDataBuf.Size > 0)
for (ImDrawCmd& cmd : draw_list->CmdBuffer)
if (cmd.UserCallback != NULL && cmd.UserCallbackDataOffset != -1 && cmd.UserCallbackDataSize > 0)
cmd.UserCallbackData = draw_list->_CallbacksDataBuf.Data + cmd.UserCallbackDataOffset;
// Add to output list + records state in ImDrawData // Add to output list + records state in ImDrawData
out_list->push_back(draw_list); out_list->push_back(draw_list);
draw_data->CmdListsCount++; draw_data->CmdListsCount++;