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

framebuffer support #207

Closed
paultech opened this issue May 5, 2015 · 8 comments
Closed

framebuffer support #207

paultech opened this issue May 5, 2015 · 8 comments

Comments

@paultech
Copy link

paultech commented May 5, 2015

Hello,

I'd like to submit a feature request for support of offscreen rendering via framebuffers. This would allow for 3D GUI support. Something along the lines of

Clientside:

  • ImGUI::startFramebuffer();
  • ImGUI::endFramebuffer();

Renderside:

  • ImDrawCmd::framebuffer_id void* - similar to how textures work now. Implementation is sole responsibility of the renderside.
@ocornut
Copy link
Owner

ocornut commented May 5, 2015

What do you mean by 3D GUI support? what are you trying to achieve? Are you aiming to render different part of the gui to different outputs?
You can already render the output twice (e.g. if you have a stereo render for VR)

@paultech
Copy link
Author

paultech commented May 5, 2015

The direct goal is to separate what draw commands should be rendered to what framebuffer. Utilizing the framebuffer allows me to write to texture and display the result as part of my 3D scene.

Example ImGUI being rendered on a in-game LCD screen.

If this is too specific for a single use case (since it will also require special handling for inputs) I understand

@ocornut
Copy link
Owner

ocornut commented May 5, 2015

You can give it a shot since it is a fairly trivial patch, but my intuition is that it'll mess with some assumptions that ImGui can make in term of inputs. It would depends of how much inputs you are trying to use.

Using ImGui::GetInternalStateSize(), ImGui::SetInternalState(), you may be able to have multiple ImGui state running simultaneously and that may be easy to do. I haven't tested it however.

@Pagghiu
Copy link
Contributor

Pagghiu commented May 6, 2015

I've tried having "Multiple IMGUI" contexts using ImGui::GetInternalState()/ImGui::SetInternalState().

screen shot 2015-05-06 at 10 21 24

A quick testing shows it works, paying attention to the following:

  1. You have to call ImGui::SetInternalState every time before touching the state (of course) and call ImGui::Shutdown for each "Context" you're deleting (for example after closing the modal dialog shown in the shot) otherwise you will be leaking memory.
  2. When you call ImGui::Shutdown for one context, all Fonts will be deleted, so you must "regenerate" them for the other contexts that may still be alive.

FYI, the application in this shot is integrating ImGui together with MFC (it's needed for a legacy app) in a Windows Message Loop that also uses Async IO (so not the typical "redraw at 60 hz" realtime loop).
In other words, ImGui gets regenerated/redrawn only when some event happens, either User related (mouse/keyboard interaction etc.) or IO related (network message arrived, etc.).
The IO Loop is based on Libuv, the same used by NodeJS, and the C++ library Api is similar to node as well. Imgui is a perfect fit because you can regenerate the entire UI only when necessary with a fraction of code compared to classic UI frameworks.
It's pretty cool that when user is doing nothing, the software is waiting in a kernel call in Windows (or OSX) message loop and in the IO loop (running in another thread), so that everything is at 0% CPU Usage most of the time!

@ocornut
Copy link
Owner

ocornut commented May 9, 2015

Nice!

When you call ImGui::Shutdown for one context, all Fonts will be deleted, so you must "regenerate" them for the other contexts that may still be alive.

I made Shutdown() now tests if io.Fonts is != NULL before clearing it, so you can temporarily swap this value to avoid this if you want. The reason behind this setup is a little tricky.

  • I cannot call new() before the first Update() - because the user may replace the allocators.
  • I want io.Fonts to be set automatically for the user so they can call io.Fonts->GetTexDataAsRGBA32() on startup.
  • The definition of the ImFontAtlas type is a little bulky and for this reason I don't want it to be defined before ImGuiIO to make imgui.h more easy to read. This is why it is a pointer.

Because of this I made the font atlas global, which also make sense in most (but not all) use of multiple contexts. However as a user you can still manually create other ImFontAtlas if you need them.

// Statically allocated font atlas. This is merely a maneuver to keep ImFontAtlas definition at the bottom of the .h file (otherwise it'd be inside ImGuiIO)
// Also we wouldn't be able to new() one at this point, before users may define IO.MemAllocFn.
static ImFontAtlas GDefaultFontAtlas;

ImGuiIO::ImGuiIO()
{
    Fonts = &GDefaultFontAtlas;

If you have any idea how to make that better? The global font atlas could use a sort of reference counter but it is tricky because the pointer can be replaced by the user any time.
For now you can take a copy of the io.Fonts pointer, swap io.Fonts to NULL before calling Shutdown() and destroy the font atlas yourself when you are done with all instances of ImGui.

This all stem from the lack of an explicit ImGui::Init() function really (I thought it was "nice" to not have one initially).

@Pagghiu
Copy link
Contributor

Pagghiu commented May 9, 2015

Thanks for adding that != NULL test!

All of your three reasons make sense to me and I agree with your decision of making the static font atlas. FYI in most situations when creating multiple contexts you're sharing font textures as well as in OpenGL you set the current context to some hwnd and you reuse textures.

Setting fonts to null is fine as long as is clearly stated in the Shutdown documentation, and I would avoid refcounting as well. User will need to refcount other things anyway to properly shutdown OpenGL Contexts or other API equivalent of ogl contexts (I did it) and the same "condition" will be used to call the proper ImGui::Shutdown.
Another way could be adding a (defaulted true) parameter to ImGui::Shutdown to decide if to release fonts or "shared context data" in general (not sure if there is anything else other than Fonts shared between InternalDatas).
But it's just personal taste in APIs ;)

@hypernewbie
Copy link

Woo!
A reference counter is probably the way to go here.

Maybe have a global state struct, add an ImGui::PushContext(...) and ImGUI::PopContext.(...) stack, the former just does SetInteralState(state++) and the PopContext does everything shutdown except delete the shared data.

@ocornut
Copy link
Owner

ocornut commented Jun 17, 2015

I'll close this for now.
@paultech are multiple imgui contexts ok, if you are still pursing this?

I'm not sure I'll be making a change to the the Fonts pointer for now, it looks like it's manageable and if you are dealing with multiple contexts it's only a minor complication to handle.

@ocornut ocornut closed this as completed Jun 17, 2015
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants