Toggle fullscreen - Lists and textures lost

Hi all

I’m trying to add the toggle fullscreen functionality to my jogl app.
I just want to make a key listener that make my frame switch between fullscreen and windowed mode.

With awt or swing apps i call a method like this from my listener:

public void setFullScreen(boolean fullScreen) {

	frame.dispose();

	size = Toolkit.getDefaultToolkit().getScreenSize();

	if (fullScreen) {
		frame.setUndecorated(true);
		location = new Point(0,0);
	} else {
		frame.setUndecorated(false);
		location = new Point((size.width - 300) / 2, (size.height - 400) / 2);
		size = new Dimension(300, 400);
	}

	frame.setSize(size);
	frame.setLocation(location);

	frame.setVisible(true);

}

But if i have a GLCanvas on my frame i have the problem that all the lists and textures i loaded get lost.
Can you tell me what’s the right way to preserve previously loaded data during the dispose of the frame?
Are there examples to see?

Thanks

The problem is, that the GL context is reconstructed. You may have to code your init() implementation in a way that reconstructs lost resources.

I don’t think switching windowing mode at runtime is a good idea. Maybe you should ask the user to relaunch the game to take such modifications of parameter into account. Maybe you should load your textures once the windowing mode cannot be changed.

I load too many textures that it takes too much time to reload all :’(

And maybe that’s not a good idea to do this feature, but is a good idea to learn how to do :slight_smile:
Many apps has it (try f11 if you are using firefox)
And many games has a menu where select the screen mode, and when you press apply, they change on the fly without reloading.

I think the way is to make a context that is not disposed and to make it accessible from my glcanvas, but i dont know how to do this.
I’m trying to share context with pbuffers, but dunno if they are widely supported.

???

With pbuffers i made it work. This is the code.
Let me know if there is a better way.

Thx

package util.studio;

import java.awt.Dimension;
import java.awt.Frame;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.Point;
import java.awt.Toolkit;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.File;

import javax.media.opengl.GL;
import javax.media.opengl.GLAutoDrawable;
import javax.media.opengl.GLCanvas;
import javax.media.opengl.GLCapabilities;
import javax.media.opengl.GLDrawableFactory;
import javax.media.opengl.GLEventListener;
import javax.media.opengl.GLPbuffer;

import com.sun.opengl.util.texture.Texture;
import com.sun.opengl.util.texture.TextureCoords;
import com.sun.opengl.util.texture.TextureIO;

public class ProvaPBuffer {
GLPbuffer pbuffer;
GLCanvas glCanvas;
Frame frame;
boolean fullscreen;
Dimension size;
Point location;
Texture texture;
TextureCoords coords;

public ProvaPBuffer() {
	pbuffer = GLDrawableFactory.getFactory().createGLPbuffer(new GLCapabilities(), null, 512, 512, null);
	pbuffer.addGLEventListener(new GLEventListener() {
		public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) {
		}

		public void init(GLAutoDrawable drawable) {
			try {
				texture = TextureIO.newTexture(new File("gfx/fungo.png"), true);
				coords = texture.getImageTexCoords();
			} catch (Exception e) {
				e.printStackTrace();
			}
		}

		public void displayChanged(GLAutoDrawable drawable, boolean modeChanged, boolean deviceChanged) {
		}

		public void display(GLAutoDrawable drawable) {
		}
	});
	pbuffer.display();
	GraphicsEnvironment env = GraphicsEnvironment.getLocalGraphicsEnvironment();
	GraphicsDevice[] gd = env.getScreenDevices();
	GLCapabilities glc = new GLCapabilities();
	glCanvas = new GLCanvas(glc, null, pbuffer.getContext(), gd[0]);
	glCanvas.addGLEventListener(new GLEventListener() {
		public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) {
		}

		public void init(GLAutoDrawable drawable) {
		}

		public void displayChanged(GLAutoDrawable drawable, boolean modeChanged, boolean deviceChanged) {
		}

		public void display(GLAutoDrawable drawable) {
			GL gl = drawable.getGL();
			gl.glLoadIdentity();
			gl.glEnable(GL.GL_BLEND);
			gl.glBlendFunc(GL.GL_SRC_ALPHA, GL.GL_ONE_MINUS_SRC_ALPHA);
			texture.enable();
			texture.bind();
			gl.glBegin(GL.GL_QUADS);
			gl.glTexCoord2f(coords.left(), coords.bottom());
			gl.glVertex2f(-1, -1);
			gl.glTexCoord2f(coords.left(), coords.top());
			gl.glVertex2f(-1, 1);
			gl.glTexCoord2f(coords.right(), coords.top());
			gl.glVertex2f(1, 1);
			gl.glTexCoord2f(coords.right(), coords.bottom());
			gl.glVertex2f(1, -1);
			gl.glEnd();
		}
	});
}

void showGui() {
	glCanvas.addKeyListener(new KeyAdapter() {
		@Override
		public void keyPressed(KeyEvent e) {
			if (e.getKeyCode() == KeyEvent.VK_ESCAPE) {
				System.exit(0);
			}
			setFullScreen(!fullscreen);
		}
	});
	frame = new Frame("PorcaProva");
	frame.add(glCanvas);
	frame.setBounds(100, 100, 300, 400);
	frame.setVisible(true);
	glCanvas.requestFocus();
	frame.addWindowListener(new WindowAdapter() {
		@Override
		public void windowClosing(WindowEvent e) {
			System.exit(0);
		}
	});
}

public void setFullScreen(boolean fullScreen) {

	this.fullscreen = fullScreen;

	frame.dispose();

	size = Toolkit.getDefaultToolkit().getScreenSize();

	if (fullScreen) {
		frame.setUndecorated(true);
		location = new Point(0, 0);
	} else {
		frame.setUndecorated(false);
		location = new Point((size.width - 300) / 2, (size.height - 400) / 2);
		size = new Dimension(300, 400);
	}

	frame.setSize(size);
	frame.setLocation(location);

	frame.setVisible(true);
	glCanvas.requestFocus();
}

public static void main(String[] args) {
	ProvaPBuffer p = new ProvaPBuffer();
	p.showGui();
}

}

Another way could be to open a new Frame with a new GLCanvas and provide the old windowed context as the shared in case the PBuffer support causes problems. Then just stop rendering to the windowed canvas and do the fullscreened instead. (I haven’t tried this though)

The solution with pbuffer works well in 1 pc and not in the other 2…
But i cant make the second work!!!
Sharing context between 2 GLCanvas seems to be harder than expected :o

This is the code i wrote:
public synchronized void setFullScreen(boolean fullScreen) {
try {
this.fullscreen = fullScreen;

		animator.stop();
		glCanvas.removeGLEventListener(this);
		glCanvas.removeKeyListener(this);

		GraphicsEnvironment env = GraphicsEnvironment.getLocalGraphicsEnvironment();
		GraphicsDevice[] gd = env.getScreenDevices();
		DisplayMode originalDisplayMode0 = gd[0].getDisplayMode();
		GLCapabilities glc = new GLCapabilities();

		Frame tmpFrame = new Frame("Millennium Pac-Man");
		tmpFrame.setUndecorated(fullscreen);

		GLCanvas tmpCanvas = new GLCanvas(glc, null, glCanvas.getContext(), gd[0]);
		tmpFrame.add(tmpCanvas);

		size = new Dimension(originalDisplayMode0.getWidth(), originalDisplayMode0.getHeight());
		location = new Point();
		if (!fullScreen) {
			location = new Point((size.width - 300) / 2, (size.height - 400) / 2);
			size = new Dimension(300, 400);
		}

		tmpFrame.setSize(size);
		tmpFrame.setLocation(location);
		tmpCanvas.addGLEventListener(this);
		tmpCanvas.addKeyListener(this);
		tmpFrame.setVisible(true);
		tmpCanvas.requestFocus();

		frame.dispose();

		frame = tmpFrame;
		glCanvas = tmpCanvas;
		animator = new Animator(glCanvas);
		animator.start();

	} catch (Exception e) {
		e.printStackTrace();
		System.exit(-1);
	}
}

What’s wrong?

Finaly i have solved it. :persecutioncomplex:
The problem is that the display of the new canvas must be forced before disposing the old one.
Just call tmpCanvas.display() after tmpCanvas.requestFocus() and before frame.dispose()

This works on all computers where i tested it.

Thx. Hope this will help.