-
Notifications
You must be signed in to change notification settings - Fork 34
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
Imgui integration #91
Conversation
Implement Magnum's ImGui integration, and also include ImPlot (a handy plotting library for ImGui). ImPlot is not part of the ImGui integration, so its context must be managed manually. Add a simple FPS counter in OSPMagnum for now; need a better GUI system
Have you tested if ImPlot works? I tested it, and it doesn't work on my computer. |
Good point, I'll test it tonight. I tested ImGui and it worked, and the ImPlot stuff was just copied from my other branch where it also works. I'll let you know. |
@EhWhoAmI I tested it and it works fine, by default the plot scales are weird so double click on the plot area and it should auto-fit the data. I added a graph to the fps counter window, if you can't see it then expand the window until it's visible. |
Alright, great! |
@@ -0,0 +1,309 @@ | |||
#.rst: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No way to avoid copying these two files into our repo? We can't use the ones in the magnum repo directly somehow?
@@ -93,6 +98,9 @@ endif() | |||
# Include ENTT (header only lib) | |||
target_include_directories(osp-magnum PRIVATE ../3rdparty/entt/src) | |||
|
|||
# Include ImPlot (simple library that depends on magnum-integration's imgui) | |||
target_include_directories(osp-magnum PRIVATE ../3rdparty/implot) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Doesn't this automatically get picked up when you add the magnum-imgui library to the list of libraries to link to?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe that implot is separate from ImGui, so you'll have to include it separately
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's true, but it's not what I was asking about.
Normally in CMake, when you have a library, even if it's header-only, you create a "library" in cmake that has all the include directories for the library tied to it.
Then, instead of having your own project use "target_include_directories", you simply do "target_link_libraries" and that automatically populates any shared libraries, static libraries, dependencies, and include directories for you.
So my confusion was "Why aren't we using the cmake "library" for imgui/implot, instead of directly adding their include directories?" If we're doing it this way because imgui/implot don't have cmake "libraries", then that's terrible and we should probably send them patches to fix their broken.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can't remember why I did it this way, but generally implot/imgui are meant to be included directly since they're small libraries with no dependencies. Feel free to explain in more detail how I should go about trying what you're suggesting.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You should make an "interface" library (or use the one that imgui and implot define, in their own cmake file), and then use "target_link_library(MyImPlotInterfaceLib)" to add that library.
The interface library doesn't have any cpp files or shared librarys / static libraries. It just exists to provide an ergnomic way to refer to a header-only-library and all of it's dependencies.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great start!
src/test_application/flight.cpp
Outdated
{ | ||
using namespace Magnum; | ||
|
||
ImGui::Begin("Debug"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Change the window name to Application Status
so that it's clearer what it is?
src/test_application/OSPMagnum.cpp
Outdated
// temporary: draw using first camera component found | ||
scene.draw(scene.get_registry().view<osp::active::ACompCamera>().front()); | ||
} | ||
|
||
|
||
// TODO: GUI and stuff |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can take out this comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm a bit skeptical of how well this will work out further on; it doesn't seem to fit in the ECS that well. I think the main issue is how the state of the gui stored in OSPMagnum, but are all processed from ActiveScene. It looks like a similar case to how SysNewton was originally designed, where it previously stored the physics world in the system which led to spaghetti. Also consider how GUIs should be renderable onto textures and stuff.
Some other possible scheme I thought about:
- Entity 1:
- ACompImguiContext: component that stores the Imgui context
- ACompGuiToScreen: tag component to tell a system to render this context to the screen
- Entity 2:
- ACompGui: refers to an entity that contains a ACompImguiContext (entity 1)
- ACompGuiDebug: tag struct to render the "Debug" window here
- ACompGuiShipStatus: tag struct to render "Ship Status" window here
src/osp/Active/SysGUI.h
Outdated
|
||
struct ACompGUIWindow | ||
{ | ||
std::function<void(ActiveScene&)> m_function; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Components should be state, and this is storing behaviors. Why not just put these directly into the render order?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So get rid of the GUI system, and just insert the lambdas directly? I guess that could work.
src/osp/Active/SysGUI.cpp
Outdated
for (auto [ent, describeElement] | ||
: rScene.get_registry().view<ACompGUIWindow>().each()) | ||
{ | ||
describeElement.m_function(rScene); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So FunctionOrder is a list of function that happens to call this function, which calls another list of functions.
src/test_application/OSPMagnum.h
Outdated
@@ -75,6 +77,10 @@ class OSPMagnum : public Magnum::Platform::Application | |||
constexpr MapActiveScene_t& get_scenes() { return m_scenes; } | |||
|
|||
private: | |||
Magnum::ImGuiIntegration::Context m_imgui{Magnum::NoCreate}; | |||
ImPlotContext* m_implot; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there any problem with storing these contexts in the scene instead?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, OSPMagnum is where the key events are polled (see OSPMagnum.cpp), and need to be passed directly to the m_imgui
member. The ImGui context is more akin to the OpenGL context (similarly stored internal to Magnum::Platform::Application
) and doesn't belong to any particular scene.
@Capital-Asterisk part of the weirdness comes from the way ImGui works in general. It's completely stateless and has a global context, so the weird Drawing to textures has nothing to do with ImGui as it will just draw to whatever framebuffer is actively bound, does our existing renderer have support for that yet in general? We might need to do that first before we can worry about it for the GUIs. |
Imgui is very not stateless; its current context and window is stored as global variables. There can be multiple contexts that can be switched between using SetCurrentContext.
The state of the windows (window size, position, and stuff) is stored in the context. The windows are identified by their title. I don't see any lambda captures in the std::functions, and I really doubt they store anything.
This barebones GUI doesn't need all the features yet, but should at least be structured in a way that supports them. Your current implementation doesn't specify where the GUIs are going to be drawn, and rendering onto virtual instrument screens is one of the intended features. This is why I suggested storing contexts in components, and having a |
The way Magnum Integration encapsulates the Imgui contexts might make the changes I suggested a bit more difficult. Magnum::ImGuiIntegration::Context can be thrown around as a component, but it also bundles a full-on application with it, with OpenGL dependent resources. It looks possible to handle and switch between multiple instances of Context. The on-screen gui component would have to store a reference to OSPMagnum. Like the physics world, contexts can be temporary states that can be deleted and just get regenerated if they're not present. Window states can be saved some other way that Imgui probably has a solution for. |
@Capital-Asterisk Is window position and size the only thing that the ImGui context stores? Values within the windows (collapse state, tickmark states, slider values, etc) are all stored by the user, which is what I have in my functions (the If what you're saying is true, then I'm sort of tempted to either ditch Magnum's ImGui integration, or just start writing our own GUI. For the MVP we literally need like 5 numbers as far as GUI goes, so we aren't really in immediate (lol) need of much. Ditching Magnum's ImGui integration might be the best option as it would allow us to keep using ImGui but retain full control of the contexts. I've already done it this way for ImPlot, so it wouldn't be much different. Thoughts? |
Just pushed a commit (most recent one) with a sort of intermediate experiment in decoupling the GUI from OSPMagnum a bit. I left the event handling inside OSPMagnum, but moved the GUI contexts to components which live in the ActiveScene. The GUI system activates the relevant contexts at the beginning of its update, and then calls the lambdas in the components I had before. It's pretty rough still; in particular, I'm not quite sure where OSPMagnum should decide which scene's GUI contexts to act on (ultimately this would be determined by whichever scene the mouse is currently captured by). I made a function in ActiveScene to fetch the GUI context, but for now I just manually assign it to OSPMagnum's member pointer in flight.cpp. I have some cleanup to do and I just realized I can move more of the GUI rendering code from OSPMagnum to SysGUI (the frame clearing and drawing stuff), but maybe the overall scheme will stimulate some ideas. I suspect @Capital-Asterisk won't like OSPMagnum extracting the GUI information from ActiveScene this way but it's pretty convenient and I haven't figured out a clean way to freeze the control inputs which should be handled by ImGui from within the ActiveScene. I'm open to suggestions though. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Considering rendering GUIs to textures and instrument screens, there should be components to determine which context the ACompGUIWindows are being rendered to. Either a vector stored along side the context that lists entities containing windows, or components in the window entities that point to a context. I'm not quite sure if it's that important to decided that right now though.
void drawEvent() override; | ||
|
||
osp::UserInputHandler m_userInput; | ||
|
||
Magnum::ImGuiIntegration::Context* m_activeImgui{nullptr}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This doesn't seem to point to stable memory
@z-adams I know you're not really actively working on this, but if you have time, could you rebase this PR on the latest code so that the compile errors are taken care of? |
@jonesmz This was last updated before the current rendering system was made so it'll take a little while to bring up to date. I may have time to do it this weekend, I just can't do it at the moment |
@z-adams Closing, because it's been open for several months without action. Feel free to re-open if you decide to work on the imgui stuff again, but I know your FPS game is taking most of your time. |
Add ImGui, ImPlot, and a simple SysGui to test them