|
|
@ -448,26 +448,46 @@ |
|
|
|
It could be an identifier to your OpenGL texture (cast GLuint to void*), a pointer to your custom engine material (cast MyMaterial* to void*), etc. |
|
|
|
At the end of the chain, your renderer takes this void* to cast it back into whatever it needs to select a current texture to render. |
|
|
|
Refer to examples applications, where each renderer (in a imgui_impl_xxxx.cpp file) is treating ImTextureID as a different thing. |
|
|
|
(C++ tip: OpenGL uses integers to identify textures. You can safely store an integer into a void*, just cast it to void*, don't take it's address!) |
|
|
|
|
|
|
|
// The example OpenGL back-end uses integers to identify textures.
|
|
|
|
// You can safely store an integer into a void* by casting it. e.g. (void*)(intptr_t)MY_GL_UINT to cast to void*.
|
|
|
|
GLuint my_opengl_texture; |
|
|
|
glGenTextures(1, &my_opengl_texture); |
|
|
|
// [...] load image, render to texture, etc.
|
|
|
|
ImGui::Image((void*)(intptr_t)my_opengl_texture, ImVec2(512,512)); |
|
|
|
|
|
|
|
// The example DirectX11 back-end uses ID3D11ShaderResourceView* to identify textures.
|
|
|
|
ID3D11ShaderResourceView* my_texture_view; |
|
|
|
device->CreateShaderResourceView(my_texture, &my_shader_resource_view_desc, &my_texture_view); |
|
|
|
ImGui::Image((void*)my_texture_view, ImVec2(512,512)); |
|
|
|
|
|
|
|
To display a custom image/texture within an ImGui window, you may use ImGui::Image(), ImGui::ImageButton(), ImDrawList::AddImage() functions. |
|
|
|
Dear ImGui will generate the geometry and draw calls using the ImTextureID that you passed and which your renderer can use. |
|
|
|
You may call ImGui::ShowMetricsWindow() to explore active draw lists and visualize/understand how the draw data is generated. |
|
|
|
It is your responsibility to get textures uploaded to your GPU. |
|
|
|
|
|
|
|
Q: How can I have multiple widgets with the same label or without a label? |
|
|
|
Q: I have multiple widgets with the same label, and only the first one works. Why is that? |
|
|
|
A: A primer on labels and the ID Stack... |
|
|
|
|
|
|
|
- Elements that are typically not clickable, such as Text() items don't need an ID. |
|
|
|
Dear ImGui internally need to uniquely identify UI elements. |
|
|
|
Elements that are typically not clickable (such as calls to the Text functions) don't need an ID. |
|
|
|
Interactive widgets (such as calls to Button buttons) need a unique ID. |
|
|
|
Unique ID are used internally to track active widgets and occasionally associate state to widgets. |
|
|
|
Unique ID are implicitly built from the hash of multiple elements that identify the "path" to the UI element. |
|
|
|
|
|
|
|
- Interactive widgets require state to be carried over multiple frames (most typically Dear ImGui |
|
|
|
often needs to remember what is the "active" widget). To do so they need a unique ID. Unique ID |
|
|
|
are typically derived from a string label, an integer index or a pointer. |
|
|
|
- Unique ID are often derived from a string label: |
|
|
|
|
|
|
|
Button("OK"); // Label = "OK", ID = top of id stack + hash of "OK"
|
|
|
|
Button("Cancel"); // Label = "Cancel", ID = top of id stack + hash of "Cancel"
|
|
|
|
Button("OK"); // Label = "OK", ID = hash of (..., "OK")
|
|
|
|
Button("Cancel"); // Label = "Cancel", ID = hash of (..., "Cancel")
|
|
|
|
|
|
|
|
- ID are uniquely scoped within windows, tree nodes, etc. which all pushes to the ID stack. Having |
|
|
|
two buttons labeled "OK" in different windows or different tree locations is fine. |
|
|
|
We used "..." above to signify whatever was already pushed to the ID stack previously: |
|
|
|
|
|
|
|
Begin("MyWindow"); |
|
|
|
Button("OK"); // Label = "OK", ID = hash of ("MyWindow", "OK")
|
|
|
|
End(); |
|
|
|
|
|
|
|
- If you have a same ID twice in the same location, you'll have a conflict: |
|
|
|
|
|
|
@ -482,20 +502,22 @@ |
|
|
|
This helps solving the simple collision cases when you know e.g. at compilation time which items |
|
|
|
are going to be created: |
|
|
|
|
|
|
|
Button("Play"); // Label = "Play", ID = top of id stack + hash of "Play"
|
|
|
|
Button("Play##foo1"); // Label = "Play", ID = top of id stack + hash of "Play##foo1" (different from above)
|
|
|
|
Button("Play##foo2"); // Label = "Play", ID = top of id stack + hash of "Play##foo2" (different from above)
|
|
|
|
Begin("MyWindow"); |
|
|
|
Button("Play"); // Label = "Play", ID = hash of ("MyWindow", "Play")
|
|
|
|
Button("Play##foo1"); // Label = "Play", ID = hash of ("MyWindow", "Play##foo1") // Different from above
|
|
|
|
Button("Play##foo2"); // Label = "Play", ID = hash of ("MyWindow", "Play##foo2") // Different from above
|
|
|
|
End(); |
|
|
|
|
|
|
|
- If you want to completely hide the label, but still need an ID: |
|
|
|
|
|
|
|
Checkbox("##On", &b); // Label = "", ID = top of id stack + hash of "##On" (no label!)
|
|
|
|
Checkbox("##On", &b); // Label = "", ID = hash of (..., "##On") // No visible label!
|
|
|
|
|
|
|
|
- Occasionally/rarely you might want change a label while preserving a constant ID. This allows |
|
|
|
you to animate labels. For example you may want to include varying information in a window title bar, |
|
|
|
but windows are uniquely identified by their ID. Use "###" to pass a label that isn't part of ID: |
|
|
|
|
|
|
|
Button("Hello###ID"; // Label = "Hello", ID = top of id stack + hash of "ID"
|
|
|
|
Button("World###ID"; // Label = "World", ID = top of id stack + hash of "ID" (same as above)
|
|
|
|
Button("Hello###ID"; // Label = "Hello", ID = hash of (..., "ID")
|
|
|
|
Button("World###ID"; // Label = "World", ID = hash of (..., "ID") // Same as above, even though the label looks different
|
|
|
|
|
|
|
|
sprintf(buf, "My game (%f FPS)###MyGame", fps); |
|
|
|
Begin(buf); // Variable label, ID = hash of "MyGame"
|
|
|
@ -507,45 +529,45 @@ |
|
|
|
You can push a pointer, a string or an integer value into the ID stack. |
|
|
|
Remember that ID are formed from the concatenation of _everything_ in the ID stack! |
|
|
|
|
|
|
|
Begin("Window"); |
|
|
|
for (int i = 0; i < 100; i++) |
|
|
|
{ |
|
|
|
PushID(i); |
|
|
|
Button("Click"); // Label = "Click", ID = top of id stack + hash of integer + hash of "Click"
|
|
|
|
PushID(i); // Push i to the id tack
|
|
|
|
Button("Click"); // Label = "Click", ID = Hash of ("Window", i, "Click")
|
|
|
|
PopID(); |
|
|
|
} |
|
|
|
|
|
|
|
for (int i = 0; i < 100; i++) |
|
|
|
{ |
|
|
|
MyObject* obj = Objects[i]; |
|
|
|
PushID(obj); |
|
|
|
Button("Click"); // Label = "Click", ID = top of id stack + hash of pointer + hash of "Click"
|
|
|
|
Button("Click"); // Label = "Click", ID = Hash of ("Window", obj pointer, "Click")
|
|
|
|
PopID(); |
|
|
|
} |
|
|
|
|
|
|
|
for (int i = 0; i < 100; i++) |
|
|
|
{ |
|
|
|
MyObject* obj = Objects[i]; |
|
|
|
PushID(obj->Name); |
|
|
|
Button("Click"); // Label = "Click", ID = top of id stack + hash of string + hash of "Click"
|
|
|
|
Button("Click"); // Label = "Click", ID = Hash of ("Window", obj->Name, "Click")
|
|
|
|
PopID(); |
|
|
|
} |
|
|
|
End(); |
|
|
|
|
|
|
|
- More example showing that you can stack multiple prefixes into the ID stack: |
|
|
|
|
|
|
|
Button("Click"); // Label = "Click", ID = top of id stack + hash of "Click"
|
|
|
|
Button("Click"); // Label = "Click", ID = hash of (..., "Click")
|
|
|
|
PushID("node"); |
|
|
|
Button("Click"); // Label = "Click", ID = top of id stack + hash of "node" + hash of "Click"
|
|
|
|
Button("Click"); // Label = "Click", ID = hash of (..., "node", "Click")
|
|
|
|
PushID(my_ptr); |
|
|
|
Button("Click"); // Label = "Click", ID = top of id stack + hash of "node" + hash of ptr + hash of "Click"
|
|
|
|
Button("Click"); // Label = "Click", ID = hash of (..., "node", my_ptr, "Click")
|
|
|
|
PopID(); |
|
|
|
PopID(); |
|
|
|
|
|
|
|
- Tree nodes implicitly creates a scope for you by calling PushID(). |
|
|
|
|
|
|
|
Button("Click"); // Label = "Click", ID = top of id stack + hash of "Click"
|
|
|
|
Button("Click"); // Label = "Click", ID = hash of (..., "Click")
|
|
|
|
if (TreeNode("node")) |
|
|
|
{ |
|
|
|
Button("Click"); // Label = "Click", ID = top of id stack + hash of "node" + hash of "Click"
|
|
|
|
Button("Click"); // Label = "Click", ID = hash of (..., "node", "Click")
|
|
|
|
TreePop(); |
|
|
|
} |
|
|
|
|
|
|
|