Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unable to pass two objects to ImDrawList::AddCallback() #4770

Closed
h4k1m0u opened this issue Nov 27, 2021 · 5 comments
Closed

Unable to pass two objects to ImDrawList::AddCallback() #4770

h4k1m0u opened this issue Nov 27, 2021 · 5 comments

Comments

@h4k1m0u
Copy link

h4k1m0u commented Nov 27, 2021

As a follow-up to #4748, I've managed to use a custom shader to set a rectangle to a different color as explained in the example shown in #4174. While doing this I've sent my shader class instance as a 2nd argument to ImDrawList::AddCallback() and it worked fine.

Now I also want to send the texture to the same method in order to modify it. However, when I combine the shader program instance and the texture either in the same struct or in an std::pair and set AddCallback's 2nd argument to a pointer to this structure, I get a segmentation fault. I verified inside the lambda function that neither the program nor the texture were set (their ids were random), which wasn't the case when only the program shader instance was sent to the lambda function (via AddCallback).

Anyone familiar with ImDrawList has an explanation for why only a single variable could be sent as AddCallback's first argument? or maybe I should proceed differently?

  auto callback_data = std::make_pair(&m_program, &m_texture);

  ImDrawList* draw_list = ImGui::GetWindowDrawList();
  draw_list->AddCallback([](const ImDrawList* parent_list, const ImDrawCmd* cmd) {
    // function pointer based on lambda fct cannot capture variables (passed as arg below)
    auto* callback_data = static_cast<std::pair<Program*, Texture2D*> *>(cmd->UserCallbackData);
    Program* program = callback_data->first;
    Texture2D* texture = callback_data->second;
    std::cout << "texture: " << callback_data->second->id << '\n';

    // projection matrix from viewport size (`GetDrawData()`: what to render)
    ImDrawData* draw_data = ImGui::GetDrawData();
    ImVec2 position = draw_data->DisplayPos;
    ImVec2 size = draw_data->DisplaySize;
    glm::mat4 projection2d = glm::ortho(0.0f, size.x, 0.0f, size.y);
    std::cout << "position: " << position.x << " " << position.y << '\n';
    std::cout << "size: " << size.x << " " << size.y << '\n';

    // pass shaders uniforms
    Uniforms uniforms = {
      {"ProjMtx", projection2d},
      {"texture", *texture}
    };
    program->use();
    program->set_uniforms(uniforms);
  }, &callback_data);
  // }, &m_program);
@PathogenDavid
Copy link
Contributor

Your std::pair is allocated on the stack, so by the time the callback is executed it has been deallocated and replaced with garbage. You need to store the pair somewhere that's longer lived.

@h4k1m0u
Copy link
Author

h4k1m0u commented Nov 28, 2021

I think you were right, I've only had to put the callback in a static class method and the AddCallback() call (with the callback_data) in the same block and before ImGui::Render() for it to work.

@h4k1m0u h4k1m0u closed this as completed Nov 28, 2021
@ocornut
Copy link
Owner

ocornut commented Nov 28, 2021 via email

@h4k1m0u
Copy link
Author

h4k1m0u commented Nov 28, 2021

Now that I think about it, I could've sent directly the id of the shader and that of the texture (not sure if it would've made a difference). I'm just too lazy to memorize opengl functions, that's why I prefer to use my own wrapper classes.

ocornut added a commit that referenced this issue Oct 11, 2024
…copy and store any amount of user data for usage by callbacks: (#6969, #4770, #7665)
@ocornut
Copy link
Owner

ocornut commented Oct 11, 2024

FYI this has been simplified with 98d52b7, AddCallback() now supports passing any amount of data that will be copied internally inside a buffer inside DrawList. This should make it easier to use callback for variety of usages.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants