views:

519

answers:

3

I have an MDI app written in Qt. Some of the subwindows include QGLWidgets, i.e., OpenGL contexts. The most salient of these use OpenGL vertex and fragment shaders to visualize their data.

I need to programmatically capture a screenshot of the application's main window, including of course all the subwindows that happen to be visible. Sounds easy at first ("definitely been asked many times, so let's just google it!"), but after a closer look it seems to be getting a bit tricky...

Now here's what I've tried so far:

  1. QPixmap::grabWidget doesn't work for the subwindows that use shader programs, apparently because the redirection context does not seem to support the necessary OpenGL extensions. (The rendering code checks that the associated context supports the required extensions, and refuses to continue if not.)
  2. QPixmap::grabWindow silently leaves all OpenGL contexts empty -- even those that use basic primitives only.
  3. QGLWidget::grabFrameBuffer works, but captures only the OpenGL context of the specific subwindow, whereas I'd like to grab the whole application (essentially what Alt+PrtScr does in Windows).

I also tried doing first #2 and then iterating #3 for all subwindows, just copying the result of #3 into the right location of the image from #2. This worked very well, until I made some subwindows overlap -- in which case the images from #3 overwrite the subwindow frames, etc. So this approach would probably require much more code in order to handle all the nasty corner cases...

Some additional background: Once I get the screenshot, I'm going to put several of them in a seqence in order to create a video -- probably using ffmpeg. That makes this question a kind of continuation to (the first part of) my previous question; it's just that the app has evolved from a single-context standalone OpenGL program to something that uses Qt for the overall windowing and UI widget stuff, and embeds the graphics in subwindows.

While I would of course prefer a nice, Qt-ish cross-platform solution, I'm willing to consider resorting to a Windows-specific hack, too. (Which ought to be possible, as I can see Alt+PrtScr doing very much the right thing.)

So, any suggestions?

+1  A: 

Very hackish, but does capturing the desktop (without hiding your window) like in this tutorial and cropping everything but your window work?

More generally, I'm not even sure that the OpenGL spec demands that output has to be placed in the front buffer: an implementation could just use video overlays (or Voodoo2-esque VGA pass-through shenanigans) for output.

genpfault
It *does* work! Now why couldn't I think of this myself? ... The only drawback I see is that this is basically somewhat slower when compared to grabbing just the window of interest. This might turn out to be relevant, because I'm actually trying to grab a video. But I'm accepting the answer anyway, because it does exactly what I asked for -- thank you very much!
Pukku
A: 

Is this any use??
The Grabber examples shows how to retrieve the contents of an OpenGL framebuffer

Martin Beckett
It uses grabFrameBuffer(), therefore captures the OpenGL viewport only. See item #3 in the question.
Pukku
+1  A: 

The only thing I can think of off-hand is to do the following psuedocode:

 for each window
     grab the window into its own pixmap
     grab the GL portions and paste into the windows
 order the window pixmaps by depth of the window (deepest first)
 initialize a common pixmap
 for each window pixmap
     paint the window pixmap into the common pixmap at the appropriate location.
Caleb Huitt - cjhuitt
I agree that this should work, therefore +1. But at least for now, I'm going to take the lazy path :)
Pukku