? Update renderer display when not visible ?

I have tabbed pane in which the first tab is a GLJPanel containing the 3D scene. In my second tab I have something unimportant.

Now, say I have the second tab selected, so this makes the 3D scene of the first tab hidden…but while in the second tab I want to invoke the renderer’s display() method because it has to perform a calculation for me…how do I do this?

I can’t seem to be able to call display() because it requires a GLdrawable, that I don’t have.
I can’t retrieve the GLJPanel.getGL() object because it is null.
I call repaint() on the GLJPanel but nothing happens.
invalidate() does not do anything either.

But the second I click back to the first tab, the repaint occurs and the updates occur as needed…because the window/panel is visible.

How can I force the display() method to be invoked on the Renderer?

BTW, what I have is a Frame Buffer Object (FBO) which I use to process a scene in the background and I want to be able to do this without having to display the 3D GLJPanel and still have updates occur on the back buffer.

If you can’t get the GL from the GLJPanel, I’m pretty sure that means the GLJPanel’s context has been cleaned up (at least that’s what happens when a GLCanvas is removed from a window, which is similar).

Here is an approach that works well with me:
I have a “shadow” context that will always be around. If possible I use a 1x1 Pbuffer, otherwise I use a GLCanvas. The nice thing about the GLCanvas is that it has a GLContext that’s sharable, if not usable, without having a visible window. This means that in most situations it can stay offscreen.

Then everytime I have another window created, I have it share itself with the shadow context, this way everything is only needed once, and I don’t have to worry about losing textures when a user closes the window.

Rendering things like fbos, or doing other gl work that doesn’t actually display anything is tricky, especially to get it to play with the GLEventListener model. My approach was to wrap these “tasks” in Runnables that could be attached to contexts. Then I would display() a context’s drawable and it would process the attached tasks. To render something to that drawable, you’d just need a render task.

This post is getting long, so I’m sorry, but there’s more :slight_smile: -> According to OpenGL 3 (not sure on the extension) fbos are NOT shared across multiple contexts, so you have to do a little more voodoo for fbos to work. I chose to have an fbo wrapper that keeps track of its configuration, and has a map from contexts to fbo ids. When an fbo needs to be bound, it checks if it exists already and proceeds along an obvious course of action.

I’ve implemented most of this into my graphics engine, Ferox, so there is some example code in here: http://code.google.com/p/ferox-gl/source/browse/#svn/trunk/src/com/ferox/renderer/impl/jogl I would recommend looking into JoglSurfaceFactory, JoglRenderSurface, ShadowContext, and AttachableSurfaceImplHelper if you’re interested.

wow, thanks for all of that info.

You just overwhelmed me with topics I know next to nothing about and so I will have a lot of work ahead of me. Thanks again for all of that and I’ll post back here when I have some more understanding and hopefully with a solution.

lhkbob, I’ve read your post several times and it is still out of my league but I’ll attempt to write down my thoughts and I hope your or others can correct me.

First of, let me tell you my current situation and what my intention is. I am using a GLJPanel to currently display a 3D vehicle at a desired orientation. Clearly I know how to do this and it works. Next I needed to be able to retrieve the projection of this 3D vehicle onto a 2D screen, so I used an Orthographic projection to draw my 3D scene. This gave me a true projection of the 3D vehicle of which I only care about the area of the screen that this projection takes up so I used a FBO to be able to retrieve the pixel data and to process/count the visible pixels and subtract those from the background pixels. This too works. Basically I have a display() method in which I draw the normal 3D scene using a Perspective projection, and whenever I hit a certain keyboard key it enables a boolean flag which is read during the display() call and then it calls a “screenshot” method that I have. This “screenshot” method simply enables the FBO, retrieves the pixel data and process it and then disables the FBO. Effectively, during the keyboard key press to activate screenshot the display() loop does the regular 3D display and publishes this to my GLJPanel, and in the background it does the FBO display and processing on the back buffer. I’m hope what I wrote above is correct and the terminology is correct … I know how to hack code together but I can’t explain it well.

So, the above is what I’ve been doing up till now. Right now I need to have a way to perform this “screenshot” functionality without having to have the 3D display active. I realize I’ll still have to create a 3D display so that the rendering can occur but I was searching for a way where the 3D display would either not be actively drawing to a window, or as a last resort, the 3D display would be hidden or minimized, etc. This last thing is got me to the current predicament. As I mentioned before, up till now I have a 3D display of my vehicle, and in the background it process the pixels of the vehicle projection. Well, the pixels are stored in a BufferedImage so I wanted to have a way for a user to view this image, and for the heck of it, have the user view the 3D scene as well…so I decided to create a tabbed pane display. I’ve attached a couple of screenshots to show you my current tool. The ‘3dview’ screenshot shows the 3D view with the vehicle in it, the ‘2dview’ screenshot is the projected view of the same vehicle.

What made me notice my current problem was that nothing would change in the 2D projection view when I changed the attitude values of the orientation of the vehicle. The values would be accepted, the calls to enable the screenshot boolean flag was made, the GLJPanel.display() method was called to try to force a redisplay but nothing happened…ie, the ‘screenshot’ method never got called from the renderer’s display() loop which means the display() method never got invoked. When I swtiched to the “Asset View” tab to see the 3D view of the vehicle, then the display() method was called and the resulting screenshot was processed. I’ll be honest, I don’t know what happens when you switch tabs where one tab contains a JOGL window. I don’t know if this causes the GL context of the display to go null but it doesn’t make sense that it would since when I bring up the 3D view tab it doesn’t call init() to recreate anything, so the GL context must still be valid?

Well, figuring that the GL context was still valid when in the 2d view/tab, I thought maybe I can ask the GLJPanel (which I can ‘canvas’) for the GL using canvas.getGL(), but simply making this call results in a NullPointerException. It is not that the result of ‘canvas.getGL()’ is null, but simply trying to make this call results in the exception…not sure if I’m doing something wrong here or not.

Ok, so now back to the lhkbob post…what I could gather from that post was that I need an valid GL context and one possible way is to use a GLCanvas since it has a sharable context and lhkbob seems to imply that you can have this context available without making the window visible…ok, but will I still have the same issue above where I try to getGL() and it gives me a null pointer exception? or will it work because I’d be using a GLCanvas instead of a GLJPanel? If I can get the GL then I can tell the FBO to retrieve the pixels and I can do my “screenshot” function.

As for the other comments…boy, I thought I understood them but I’m still trying to learn this so I’ll end this post right now before I say something really stupid.

Sorry about posting so much, I tend to go overboard :-\

Now that I have a better understanding of your situation, I think my approach could work with yours, but it’s probably not the easiest.
Here is my advice:

  1. Create a GLPBuffer with 1x1 dimensions (or a GLCanvas that isn’t made visible if a computer doesn’t have pbuffer support).
  2. Create two GLJPanels, 1 for each asset. When you create them, use the constructor that takes a GLContext shareWith, and pass in the context from #1
  3. Instead of using fbos for the 2d display, just render it directly to that panel when its up.

This way only works if you only need to display the 2d image,
if you need access to it all of the time, I’d use this:

  1. Create a GLPBuffer with the size of the 2d imag
  2. Create your single GLJPanel as before, sharing it with the pbuffer’s context in #1
  3. Do 2 display calls, one for the pbuffer ortho image, and one for the GLJPanel.
  4. Use glReadPixels to get the image out of the pbuffer to put in your BufferedImage, and display this as normal.

Because a GLPBuffer is an offscreen context (more heavyweight than an fbo), you can call display() on it whenever you need it to be rendered, without having to worry about different scenarios.

HTH

Thanks again for the info, but I got a little confused by your statement between the two options you listed, so let me ask some followup questions.

Is Approach #1 for the case where I have both the 3D and 2D views? The reason is because you say create 2 GLJPanels, but I’m not sure what is the need for the second GLJPanel. In my 2D view I am simply overriding the paintComponent to draw the BufferedImage that I get from my FBO. This brings me to my other question, you say I don’t need to use FBOs for the 2d display, but I’m not sure how I would render the 3D view into the 2D view that I need. I understand my 2D view is Orthographic, but really what is important to me are the pixels of that view which I use to make calculations. The fact that I can display the BufferedImage of those pixels is frosting on the cake, but it is more important that I be able to retrieve the pixel counts.

Before Approach #2 you mention “This way only works if you only need to display the 2d image”…I wasn’t sure if you were still referring to the Approach #1 or to the new approach you were about to describe. I figured it was in reference to Approach #2, but in that approach it seems like I’m not “only” displaying the 2D image but still displaying the 3D view as well…because I still have a GLJPanel being created and I’m still going to be doing 2 display calls.

If I understood everything, and that’s a big if right now, I believe the final answer is that instead of using a FBO I would be using a GLPBuffer in its place. The way I currently use the FBOs is that they are created in the init() of my GLJPanel renderer and created/used/destroyed in the display() method, but you mention that I should call the display() on the GLPBuffer in order to renderer what I need to - in this case the Orthographic image.

So GLPBuffers are basically a GLCanvas or GLJPanel and so I first create my GLJPanel as before, load my 3D model, loads all of the data I need into the GLJPanels context and then I take that context and share it with the GLPBuffer and then tell the GLPBuffer to display the orthographic view (which is my 2D view) and once that happens I can read back the pixels from it as if it had been an FBO, is that correct?

btw, sorry for long posts, but I tend to write up my thoughts as I’m going and they may not be helpful to all but it helps me remember later. As for you your long posts…I think they are awesome. The longer the better (yeah, that’s what she said) because that just means there is more detail and it helps everyone…thanks.

To followup…I found this article on Pbuffers which looked interesting and related a little to my situation

http://today.java.net/pub/a/today/2008/10/30/integrating-glpbuffer-and-graphics2d.html

And in this article they have source code available for a test they did of drawing to a GLCanvas, GLJPanel and a pbuffer and I have a question about this. If I didn’t want to display my 3D scene at all but I did want to draw my 2D view and did want to process the 2D image for its pixels, could I simply draw everything to the PBuffer and bypass the GLJPanel or even GLCanvas? I wouldn’t have to share any contexts then and I could avoid the 3D view all together? I’m asking because in the example code ‘ThePbuffer.java’ they are essentially doing this, as far as I can read it.

Here is the link to the source code if anyone is interested:
http://today.java.net/today/2008/10/30/resources.zip

Sharing the context would be useful when I wanted both the 3D view (using GLJPanel or GLCanvas) and the 2D view (using the GLPBuffer BufferedImage). Correct me if my understanding is wrong…thanks.

followup #2, how do I test to see if pBuffers will be supported by the machine? What check do I do?

For #1, I was suggesting that assuming you only needed to draw the 2d image, in which case why not just render it directly instead of copying it out into a BufferedImage. It seems that you actually need the image so #1 won’t work with you. (so the statement before #2 applied to #1, sorry).

So, I would say go with #2, but I have a few clarifications and advice:
If you’re going to have multiple contexts, create the pbuffer first and share its context with the onscreen panels later. This might not matter, but I feel as if its safer. The pbuffer will have a context right away, but with GLJPanels I’m fuzzier on the details of when things get set up.

Because you’re already copying the 2d image into a BufferedImage, doing it again may not hurt performance that much. If you’re using a GLJPanel, it uses a pbuffer internally and copies out the 3d view, so you’re just moving that work somewhere else.

On the otherhand, if you mix GLCanvas and GLPBuffer, the GLCanvas should get faster screen renders (no copy needed), but for your application, this likely doesn’t matter.

Using the code for ‘ThePbuffer.java’ from the website I mentioned above…
http://today.java.net/pub/a/today/2008/10/30/integrating-glpbuffer-and-graphics2d.html

I wanted to know if using pBuffer is as simple as the replacing the GLJPanel creation with a GLPbuffer creation?

I mean, I used to have the following code:


   canvas = new GLJPanel( capabilities );
   canvas.addGLEventListener( renderer );

and I replaced it with this:


   GLDrawableFactory fac = GLDrawableFactory.getFactory();
   buffer = fac.createGLPbuffer(capabilities , null, width, height, null);
   buffer.addGLEventListener(renderer);

And my Renderer has not changed in the least…nothing different about it. And when I want to cause my display() method to be called and have my rendering occur I simply call


   buffer.display();

In my case, I have an FBO to store the data in a buffered image and then I process this image. But it seems to me that I no longer need the FBO to get me the buffered image, I could basically retrieve the buffered image from the pBuffer itself, correct? Yeah, of course…what am I saying. This is exactly what they do in the ‘ThePbuffer.java’ code itself:


                       ...
			buffer.display();
			GLContext context =  buffer.createContext(null);
			context.makeCurrent();
			BufferedImage image = Screenshot.readToBufferedImage(400, 500);
			context.release();
			context.destroy();
			g.drawImage(image,0,0,null);
                       ...

Does all of that sound correct?

Yep, that all looks correct, except that this scares me:

buffer.display();
GLContext context =  buffer.createContext(null);
context.makeCurrent();
BufferedImage image = Screenshot.readToBufferedImage(400, 500);
context.release();
context.destroy();

It seems they’re creating a new context each time they want to read a buffered image. I’d suggest just call Screenshot.readToBufferedImage() from within your event listener’s display() method.

cool, thanks for the confirmation lhkbob.