Problem Changing Scene on Timer Event

I have an application that needs to change (completely) the scene when a timer event occurs, and I’m not really sure the proper way to do it. Do I create a new Canvas? Or do I create a new Listener (remove the old one from the canvas and add the new one)? Or is there some other method? I’ve tried doing it with both ways described above, and it doesn’t seem to work. If I simply call the method that adds the new listener (for example) directly, it draws fine. However if I call that same method from a timer thread, it doesn’t draw (just a black screen). That would seem to indicate some kind of threading problem. I’m not really sure where to go from here. Any pointers are definitely appreciated…
Thanks,
gb

Could you post the relevant code?

Here is some sample code that uses a timer to send repaint events to a JFrame at a specified interval. It alternates the color of some text on the window with each update.


import java.awt.Color;
import java.awt.Graphics;
import java.lang.reflect.InvocationTargetException;
import java.util.Timer;
import java.util.TimerTask;

import javax.swing.JFrame;
import javax.swing.SwingUtilities;

public class TimerTest implements Runnable
{
	JFrame f 			= new MyFrame();
	int repaintCount 	= 0;	 
	
	public static void main(String[] args) 
	{
		try
		{
			SwingUtilities.invokeAndWait(new TimerTest());
		}
		catch (InvocationTargetException e)
		{
			e.printStackTrace();
		}
		catch (InterruptedException e)
		{
			e.printStackTrace();
		}
	}

	public void run() 
	{
		f.setBounds(0, 0, 500, 500);
		f.getContentPane().setBackground(Color.BLACK);
		f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		f.setVisible(true);
		f.setIgnoreRepaint(true);
		Timer t = new Timer(true);
		t.scheduleAtFixedRate(new MyTimerTask(), 0, 250); // run every 250 millis econds (or 4 times a second)
	}

	private class MyTimerTask extends TimerTask
	{
		public void run() 
		{
			f.repaint();
			repaintCount++;
		}
	}
	
	private class MyFrame extends JFrame
	{
		public void paint(Graphics g)
		{
			super.paint(g);
			Color c = (repaintCount % 2 == 0) ? Color.RED : Color.BLUE;
			g.setColor(c);
			g.drawString("THIS IS A TEST", 200, 240);
			g.dispose();
		}
	}
}

Thanks for your reply,
Actually, what I want to do is essentially replace the entire scene…I don’t want to change objects being drawn; I want to dump the whole thing and go to a different scene. I have tried things along the lines of:

pseudo_NewScene()
{
canvas.removeGLEventListener(oldListener);
canvas.addGLEventListener(newListener);
}

If I call pseudo_NewScene from my main thread it works fine. If I call it from the Timer, the new scene doesn’t draw. The init(gl) and the display(gl) methods still get called, but nothing is rendered. It seems as though there might be some kind of GLContext problem…but I’m unable to muck my way through it.
gb

I’m not sure why you need to change anything in the canvas. Why can’t you just stop drawing the old scene and start drawing the new scene?

Well, after scouring other posts (such as http://www.java-gaming.org/forums/index.php?topic=4988.0) from people that seemed to know a lot more than I (most everyone!), it seemed like the thing to do… Each scene is essentially its own GLEventListener class, with its own init(gl), display(gl), etc. The process of changing scenes means closing down the current listener and adding in the new one.

So when you say “just stop drawing the old scene and start drawing the new one”, I’m assuming you mean keep a single GLEventListener, and then using some kind of state/switch mechanism inside each of the methods (init()/display()/etc) to reference the active scene class? I can give that a try I suppose…or am I missing your point? I’ll certainly do that if that is the ‘proper’ way to do things…but it seems to me (he says stubbornly) that removeGLEventListener and addGLEventListener should work. And essentially they do, as long as I don’t do the remove/add from a Timer thread ( Timer.schedule() ). That’s the part that’s got me confused…

You’re on the right track. There’s no reason for your scene to be a GLEventListener. You could do something like:


public interface Scene
{
   public void render( GLDrawable drawable );
}

Have one GLEventListener that holds a reference to the current scene object, and just calls scene.render( drawable ) in the display() method. Now drawing a different scene is just a matter of changing the reference to point to a different Scene object, no monkeying with the canvas needed.

As to the problem you were seeing: Almost definitely a threading problem. I would guess that jogl is trying to finish rendering a frame before the new listener is added. However, rendering occurs on the same thread as the timer, and so a deadlock occurs.
JOGL is very strict about it’s threading for cross-platform compatibility reasons, and so it’s best to just set up your canvas once and then leave it alone.

If you dead-set on what you’ve got now, try spawning a new thread from the timer and changing the eventlistener in that

Problem solved…pretty much. The real issue was that after I changed the listener (or changed the render class the listener was referencing), I needed to call canvas.reshape()…essentially reset the gluPerspective. The reason it showed up with a timer was not a thread problem, but the fact that the main frame was already established. More of a ‘timing’ problem than a ‘timer’ problem. I’m not exactly sure why I have to reset the gluPerspective, I haven’t changed the listener or the canvas…there’s probably something else going on here I need to figure out. But that’s the essence of it, thanks to all that contributed.
Gary B