AWTGLCanvas problems

Started by CodeBunny, January 28, 2011, 16:52:28

Previous topic - Next topic

CodeBunny

So, for work I'm designing a user interface, and I'm using AWTGLCanvas to render satellite-view maps. The UI has multiple different "views", each showing different data, and this is accomplished by changing the contentPane of a JFrame. Two of these views each need to have an AWTGLCanvas, but right now I'm testing it with only one.

I've figured out how to render continuously to a canvas, but when I switch views and come back, nothing is rendering and I have a black screen. I try using makeCurrent, and I haven't made any GL calls since before I switched views, so I'm not sure what to do next.

What's the best way to accomplish this? Am I doing something wrong? ???

Kai

Hi,

from what I understand, you are detaching the canvas from one window and attaching it to another window? Is that correct? If so, what happens is that the OpenGL context is being reset. That means that all GL states are being set to their respective default values.

I hit into that just a couple of weeks ago when using a docking framework that lets you dock and undock a window. While undocking, the canvas is detached from the original panel it was inside and attached to a new JFrame.

To resolve this, do another "init()" of your OpenGL states that you would do otherwise only once.

broumbroum

Could you list what methods you overrid plz ?
from InitGL() you can do the following :
super.initGL();
makeCurrent();
GLContext.useContext();
youInit();
releaseContext();

and from paintGL() :
super.paintGL();
makeCurrent();
GLContext.useContext();
youRender();
swapBuffers();
releaseContext();

useContext() and releasecontext() should prevent AWTGLCanvas to crash when you switch "views".


As an advice, an alternative to switching the content pane, would be to create "view-layers" defined as follows :
abstract class ViewLayer implements Runnable() {
}
. Whenever you want to switch the "view" you will switch "view-layers" as follows :
ViewLayer getViewLayer(int whatLayer) {
 switch(whatLayer) {
 case "1" :
  return new ViewLayer() { void renderLayer() {
 //render Layer with GL
     }};
  case ....
  }
}
public int CURRENTVIEW = 1;

public void youRender() {
 getViewLayer(CURRENTVIEW).run();   
}
You would leave the canvas active with the above structure instead of "moving" it (which makes it destroy and recreate the context every switch you make and lose all loaded texture. lists etc.).
:)

CodeBunny

Kai: Actually, not quite. I've got two separate canvases, each on a separate JPanel (along with a bunch of other components). To switch views, we  pop the JPanels off and on a single JFrame as needed.

It still sounds like what you're saying could apply, though.

How does initGL work?



broumbroum: I tried to use
getContext().useContext();

but I got an error saying the type Context wasn't visible. What is the method supposed to do?

CodeBunny

I figure it might be simplest if I put up a slimmed down copy of my code.

Right now, since I'm just figuring out how the API needs to work, I have the AWTGLCanvas implementation in an internal class.

private class Map extends AWTGLCanvas
	{
		private static final long serialVersionUID = -5709057525640825162L;

		public Map() throws LWJGLException
		{
			super();
			setIgnoreRepaint(true);
		}
		
		public void initGL()
		{
			super.initGL();
			try
			{
				makeCurrent();
				GLContext.useContext(getContext());
				
				GL11.glDisable(GL11.GL_DEPTH_TEST);
				GL11.glMatrixMode(GL11.GL_PROJECTION);
				GL11.glEnable(GL11.GL_TEXTURE_2D);
				GL11.glEnable(GL11.GL_BLEND);
				GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
				GL11.glDisable(GL11.GL_LIGHTING);
				GL11.glOrtho(0, getWidth(), getHeight(), 0, 1, -1);
				GL11.glMatrixMode(GL11.GL_MODELVIEW);
				GL11.glPushMatrix();
				GL11.glLoadIdentity();
				
				releaseContext();
			}
			catch (LWJGLException e)
			{
				e.printStackTrace();
			}
			
		}
		
		public void paintGL()
		{
			try
			{
				makeCurrent();
				GLContext.useContext(getContext());
				
				draw();
				
				swapBuffers();
				releaseContext();
			}
			catch (LWJGLException e)
			{
				e.printStackTrace();
			}
		}
		
		public void draw()
		{
			// Custom drawing stuff, I know this is working.
		}
	}


Again, I couldn't put getContext().useContext() into the code, but I tried broumbroum's advice as closely as possible.

This renders just as I want it to the first time I use the canvas, but it's black thereafter.

broumbroum


CodeBunny

Hmm. Nothing changed.

This is my code now:

public Map() throws LWJGLException
		{
			super();
			setIgnoreRepaint(true);
		}
		
		public void initGL()
		{
			super.initGL();
			try
			{
				makeCurrent();
				GLContext.useContext(getContext());

				/* Enables 2D rendering. It's a top-down view, and there's no need for any 3D stuff. */
				GL11.glDisable(GL11.GL_DEPTH_TEST);
				GL11.glMatrixMode(GL11.GL_PROJECTION);
				GL11.glEnable(GL11.GL_TEXTURE_2D);
				GL11.glEnable(GL11.GL_BLEND);
				GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
				GL11.glDisable(GL11.GL_LIGHTING);
				GL11.glOrtho(0, getWidth(), getHeight(), 0, 1, -1);
				GL11.glMatrixMode(GL11.GL_MODELVIEW);
				GL11.glPushMatrix();
				GL11.glLoadIdentity();

				ImageLibrary.initialize(); // This is a separate cache for all images used. If this hasn't been called before, it loads new textures.
				
				releaseContext();
			}
			catch (LWJGLException e)
			{
				e.printStackTrace();
			}
		}
		
		public void paintGL()
		{
			try
			{
				makeCurrent();
				GLContext.useContext(getContext());
				
				draw(); // At the moment, this tests performance by rendering thousands of textured quads onscreen at 60 fps.
				
				swapBuffers();
				releaseContext();
			}
			catch (LWJGLException e)
			{
				e.printStackTrace();
			}
		}
	}


I'm sorry if I seem dense about this, but I don't really understand what's going on behind the scenes, or why removing a Canvas from a JFrame and putting it back on would cause it to go black. Initially I thought that it was because multiple calls of glOrtho() multiplied the viewport so it couldn't be seen, but from what I understand these calls don't have that problem.

Fool Running

AWTGLCanvas makes the context current so you shouldn't need to do it manually.
Also, there is no need for a try/catch block around your code, there is a method called exceptionOccurred that you can override that gets called when an exception occurs.

As for your problem, make sure that ImageLibrary.initialize() is loading the images again (after initGL is called a second time). I think, as Kai suggested, the context is getting destroyed which is deleting all your textures. You can also try disable texturing and see if you get anything on screen (to see if it is, indeed, caused by missing textures). My guess is that when the context is destroyed and re-created (calling initGL again), something is not getting loaded.
Programmers will, one day, rule the world... and the world won't notice until its too late.Just testing the marquee option ;D

CodeBunny

Reloading the textures did it. :D Thank you very much.

Is there any way to keep the textures around/keep the context alive? It seems a bit expensive to flush them in and out whenever a view is changed, especially because I'll be reusing most of them.

CodeBunny

Also, now I'm running into a new problem: the canvas size is behaving kind of weird.

First off, when I set the size of the canvas, I need to set the size to twice of that of its parent JPanel. This value seems to be exact.

The GUI has the capability of popping off individual sections and placing them on JDialogues in front of the parent JFrame. When I do this with the Canvas, it's size in the JDialogue is skewed for some reason (it's shrunk to ~half size across and horizontal), and this shrunken view stays when it's put back on the main Jframe.

Here are some screenshots:

The Initial View (Set to 2x regular scale):


The Map Popped onto a JDialog:


The Map Put back into the JFrame:

Fool Running

Quote from: CodeBunny on February 02, 2011, 18:23:38
Is there any way to keep the textures around/keep the context alive?
I think you'll need to do something with a shared OpenGL context. Basically, you'll need to create a common context that won't be destroyed (maybe by using a PBuffer) that you can then use as the context for the AWTGLCanvas. Because the common context won't get destroyed, you shouldn't have to re-create the textures, etc. Unfortunately, I don't remember if it's possible to do in LWJGL with an AWTGLCanvas.
Quote from: CodeBunny on February 02, 2011, 21:26:44
Also, now I'm running into a new problem: the canvas size is behaving kind of weird.

First off, when I set the size of the canvas, I need to set the size to twice of that of its parent JPanel. This value seems to be exact.

The GUI has the capability of popping off individual sections and placing them on JDialogues in front of the parent JFrame. When I do this with the Canvas, it's size in the JDialogue is skewed for some reason (it's shrunk to ~half size across and horizontal), and this shrunken view stays when it's put back on the main Jframe.
If you don't make the initial size twice the JPanel, what happens to the GUI when moved to the JDialog and back (i.e. is it still half-size, or is it 1/4 size)? Can you set a layout manager on the JPanel to make it stretch to its size instead of setting it manually (and on the JDialog as well)? Is the JPanel you're adding the GUI to the size you think it should be or is it half size as well (might need to add a layout manager for stretching the JPanel as well)?
Programmers will, one day, rule the world... and the world won't notice until its too late.Just testing the marquee option ;D

CodeBunny

Quote from: Fool Running on February 03, 2011, 14:00:46
If you don't make the initial size twice the JPanel, what happens to the GUI when moved to the JDialog and back (i.e. is it still half-size, or is it 1/4 size)? Can you set a layout manager on the JPanel to make it stretch to its size instead of setting it manually (and on the JDialog as well)? Is the JPanel you're adding the GUI to the size you think it should be or is it half size as well (might need to add a layout manager for stretching the JPanel as well)?

It's weird, if I set it to what should be normal size, it's half size, but when popped onto the JDialog it's shrunk again, but not nearly as much. Basically, it just warps it a little bit.

For the parent JPanel, I set the min, max, and preferred size to be the same dimension. That's the same dimension I use for the AWTGLCanvas.

The LayoutManager is GridBag. It should be stretching the canvas to fill the JPanel, if possible.

Fool Running

Quote from: CodeBunny on February 03, 2011, 15:02:29
The LayoutManager is GridBag. It should be stretching the canvas to fill the JPanel, if possible.
Only thing I can think of is to check the settings on your GridBag cells (i.e. the one you are adding your GUI to) to make sure it is using 100% of the available width/height. You might also try changing, temporarily, to a BorderLayout with the GUI in the center to see if the problem is caused by your GridBag settings or something else.
Other then that, I'm out of ideas. :-\
Programmers will, one day, rule the world... and the world won't notice until its too late.Just testing the marquee option ;D

CodeBunny

Alright, I'll give it a check when I can.

Unfortunately, my laptop was broken, and I'm painstakingly rebuilding most of the project from an old backup.

CodeBunny

You're right, using BorderLayout.CENTER worked well. :D

However, the canvas apparently does not scale very well. When I change the dimensions of the JPanel it is on (by resizing the JFrame) I get some weird results - sometimes it goes blank until I resize it again, sometimes it continues without a hitch, and when I scale it to a much larger size, the render results look displaced on the screen.

What exactly happens when I resize an AWTGLCanvas?