LWJGL Basics 5 (Fullscreen)

From LWJGL
Jump to: navigation, search

Contents

Why use Fullscreen?

There are many reasons for using fullscreen mode which may include the following:

  • Changing the screen resolution to get extra speed from the game or better looking graphics.
  • Enable VSync to allow tear free graphics.
  • Enable a much more immersive experience for users.


Using Fullscreen

Creating a windowed Display was covered in tutorial 1 and is just two lines of code.

Display.setDisplayMode(new DisplayMode(width,height));
Display.create();


To use a fullscreen Display, a DisplayMode that is supported in fullscreen mode must be set and fullscreen must be enabled by calling Display.setFullscreen(true).


Display.setDisplayMode(displayMode);
Display.setFullscreen(true);
Display.create();


What is a DisplayMode?

DisplayMode is a class that encapsulates the various properties that make up the Display. This includes the following properties :

  • getWidth() - The width of the Display in pixels.
  • getHeight() - The height of the Display in pixels.
  • getBitsPerPixel() - Bits per pixel, also sometimes known as the number of colors.
  • getFrequency() - Refresh rate or frequency of frame drawing.


The initial DisplayMode will be the same as the computers desktop resolution. The original desktop resolution can be obtained at any time as a DisplayMode by calling Display.getDesktopDisplayMode().


Obtaining DisplayModes supported in fullscreen

A list of fullscreen resolutions supported by the graphics card can be obtained by calling the Display.getAvailableDisplayModes() method. This list can then be scrolled through to pick the desired DisplayMode.

DisplayMode[] modes = Display.getAvailableDisplayModes();

for (int i=0;i<modes.length;i++) {
    DisplayMode current = modes[i];
    System.out.println(current.getWidth() + "x" + current.getHeight() + "x" +
                        current.getBitsPerPixel() + " " + current.getFrequency() + "Hz");
}

The DisplayMode is set by using Display.setDisplayMode(). If the Display has already been created then the Display will resize immediately to match the new DisplayMode otherwise it will be apply once Display.create() is called.


The current set DisplayMode can be obtained by calling Display.getDisplayMode(), if no DisplayMode is set it will be the same as Display.getDesktopDisplayMode().


The Display.setFullscreen(boolean) method can be used to switch to fullscreen mode or back to windowed mode.


The BitsPerPixel value has pretty much standardised these days to either 32bit color (Windows) or 24bit color (Linux and Mac). It has become rare to find computers that still use the old 16bit, 256 color or even *shock* 16 color modes. Accordingly, it is a good idea to just pick and use the default desktop color value.


The Frequency value is the rate at which frames are drawn. Again its a good idea to just use the default desktop frequency as its more likely to be supported by the monitor (even if the video card supports others). CRT monitors can easily support different frequencies and refresh rates but with TFT monitors now becoming more common it is best to just stick with the default frequncy.


Convenience method to Switch Resolution

Using the above information the following method is an example that will allow finding and switching to a requested DisplayMode.

/**
 * Set the display mode to be used 
 * 
 * @param width The width of the display required
 * @param height The height of the display required
 * @param fullscreen True if we want fullscreen mode
 */
public void setDisplayMode(int width, int height, boolean fullscreen) {

    // return if requested DisplayMode is already set
    if ((Display.getDisplayMode().getWidth() == width) && 
        (Display.getDisplayMode().getHeight() == height) && 
	(Display.isFullscreen() == fullscreen)) {
	    return;
    }

    try {
        DisplayMode targetDisplayMode = null;
		
	if (fullscreen) {
	    DisplayMode[] modes = Display.getAvailableDisplayModes();
	    int freq = 0;
				
	    for (int i=0;i<modes.length;i++) {
	        DisplayMode current = modes[i];
					
		if ((current.getWidth() == width) && (current.getHeight() == height)) {
		    if ((targetDisplayMode == null) || (current.getFrequency() >= freq)) {
		        if ((targetDisplayMode == null) || (current.getBitsPerPixel() > targetDisplayMode.getBitsPerPixel())) {
			    targetDisplayMode = current;
			    freq = targetDisplayMode.getFrequency();
                        }
                    }

		    // if we've found a match for bpp and frequence against the 
		    // original display mode then it's probably best to go for this one
		    // since it's most likely compatible with the monitor
		    if ((current.getBitsPerPixel() == Display.getDesktopDisplayMode().getBitsPerPixel()) &&
                        (current.getFrequency() == Display.getDesktopDisplayMode().getFrequency())) {
                            targetDisplayMode = current;
                            break;
                    }
                }
            }
        } else {
            targetDisplayMode = new DisplayMode(width,height);
        }

        if (targetDisplayMode == null) {
            System.out.println("Failed to find value mode: "+width+"x"+height+" fs="+fullscreen);
            return;
        }

        Display.setDisplayMode(targetDisplayMode);
        Display.setFullscreen(fullscreen);
			
    } catch (LWJGLException e) {
        System.out.println("Unable to setup mode "+width+"x"+height+" fullscreen="+fullscreen + e);
    }
}


Vsync

For tear free graphics vertical synchronization needs to be enabled. This is enabled/disabled using the Display.setVSyncEnabled(boolean) method. Vsync only works in fullscreen mode as windowed application do not have direct access to or control over the screen and any buffer flipping is handled by the OS. However Vsync can still act as a framerate limiter in windowed mode.


A full working example is found below. Use the 'F' key to switch to and from fullscreen and use the 'V' key to enable or disable VSync.

import org.lwjgl.LWJGLException;
import org.lwjgl.Sys;
import org.lwjgl.input.Keyboard;
import org.lwjgl.opengl.Display;
import org.lwjgl.opengl.DisplayMode;
import org.lwjgl.opengl.GL11;
 
public class FullscreenExample {
 
	/** position of quad */
	float x = 400, y = 300;
	/** angle of quad rotation */
	float rotation = 0;
 
	/** time at last frame */
	long lastFrame;
 
	/** frames per second */
	int fps;
	/** last fps time */
	long lastFPS;
	
	/** is VSync Enabled */
	boolean vsync;
 
	public void start() {
		try {
			Display.setDisplayMode(new DisplayMode(800, 600));
			Display.create();
		} catch (LWJGLException e) {
			e.printStackTrace();
			System.exit(0);
		}
 
		initGL(); // init OpenGL
		getDelta(); // call once before loop to initialise lastFrame
		lastFPS = getTime(); // call before loop to initialise fps timer
 
		while (!Display.isCloseRequested()) {
			int delta = getDelta();
 
			update(delta);
			renderGL();
 
			Display.update();
			Display.sync(60); // cap fps to 60fps
		}
 
		Display.destroy();
	}
 
	public void update(int delta) {
		// rotate quad
		rotation += 0.15f * delta;
 
		if (Keyboard.isKeyDown(Keyboard.KEY_LEFT)) x -= 0.35f * delta;
		if (Keyboard.isKeyDown(Keyboard.KEY_RIGHT)) x += 0.35f * delta;
 
		if (Keyboard.isKeyDown(Keyboard.KEY_UP)) y -= 0.35f * delta;
		if (Keyboard.isKeyDown(Keyboard.KEY_DOWN)) y += 0.35f * delta;
 
		while (Keyboard.next()) {
		    if (Keyboard.getEventKeyState()) {
		        if (Keyboard.getEventKey() == Keyboard.KEY_F) {
		        	setDisplayMode(800, 600, !Display.isFullscreen());
		        }
		        else if (Keyboard.getEventKey() == Keyboard.KEY_V) {
		        	vsync = !vsync;
		        	Display.setVSyncEnabled(vsync);
		        }
		    }
		}
		
		// keep quad on the screen
		if (x < 0) x = 0;
		if (x > 800) x = 800;
		if (y < 0) y = 0;
		if (y > 600) y = 600;
 
		updateFPS(); // update FPS Counter
	}
 
	/**
	 * Set the display mode to be used 
	 * 
	 * @param width The width of the display required
	 * @param height The height of the display required
	 * @param fullscreen True if we want fullscreen mode
	 */
	public void setDisplayMode(int width, int height, boolean fullscreen) {

		// return if requested DisplayMode is already set
                if ((Display.getDisplayMode().getWidth() == width) && 
			(Display.getDisplayMode().getHeight() == height) && 
			(Display.isFullscreen() == fullscreen)) {
			return;
		}
		
		try {
			DisplayMode targetDisplayMode = null;
			
			if (fullscreen) {
				DisplayMode[] modes = Display.getAvailableDisplayModes();
				int freq = 0;
				
				for (int i=0;i<modes.length;i++) {
					DisplayMode current = modes[i];
					
					if ((current.getWidth() == width) && (current.getHeight() == height)) {
						if ((targetDisplayMode == null) || (current.getFrequency() >= freq)) {
							if ((targetDisplayMode == null) || (current.getBitsPerPixel() > targetDisplayMode.getBitsPerPixel())) {
								targetDisplayMode = current;
								freq = targetDisplayMode.getFrequency();
							}
						}

						// if we've found a match for bpp and frequence against the 
						// original display mode then it's probably best to go for this one
						// since it's most likely compatible with the monitor
						if ((current.getBitsPerPixel() == Display.getDesktopDisplayMode().getBitsPerPixel()) &&
						    (current.getFrequency() == Display.getDesktopDisplayMode().getFrequency())) {
							targetDisplayMode = current;
							break;
						}
					}
				}
			} else {
				targetDisplayMode = new DisplayMode(width,height);
			}
			
			if (targetDisplayMode == null) {
				System.out.println("Failed to find value mode: "+width+"x"+height+" fs="+fullscreen);
				return;
			}

			Display.setDisplayMode(targetDisplayMode);
			Display.setFullscreen(fullscreen);
			
		} catch (LWJGLException e) {
			System.out.println("Unable to setup mode "+width+"x"+height+" fullscreen="+fullscreen + e);
		}
	}
	
	/** 
	 * Calculate how many milliseconds have passed 
	 * since last frame.
	 * 
	 * @return milliseconds passed since last frame 
	 */
	public int getDelta() {
	    long time = getTime();
	    int delta = (int) (time - lastFrame);
	    lastFrame = time;
 
	    return delta;
	}
 
	/**
	 * Get the accurate system time
	 * 
	 * @return The system time in milliseconds
	 */
	public long getTime() {
	    return (Sys.getTime() * 1000) / Sys.getTimerResolution();
	}
 
	/**
	 * Calculate the FPS and set it in the title bar
	 */
	public void updateFPS() {
		if (getTime() - lastFPS > 1000) {
			Display.setTitle("FPS: " + fps);
			fps = 0;
			lastFPS += 1000;
		}
		fps++;
	}
 
	public void initGL() {
		GL11.glMatrixMode(GL11.GL_PROJECTION);
		GL11.glLoadIdentity();
		GL11.glOrtho(0, 800, 0, 600, 1, -1);
		GL11.glMatrixMode(GL11.GL_MODELVIEW);
	}
 
	public void renderGL() {
		// Clear The Screen And The Depth Buffer
		GL11.glClear(GL11.GL_COLOR_BUFFER_BIT | GL11.GL_DEPTH_BUFFER_BIT);
 
		// R,G,B,A Set The Color To Blue One Time Only
		GL11.glColor3f(0.5f, 0.5f, 1.0f);
 
		// draw quad
		GL11.glPushMatrix();
			GL11.glTranslatef(x, y, 0);
			GL11.glRotatef(rotation, 0f, 0f, 1f);
			GL11.glTranslatef(-x, -y, 0);
 
			GL11.glBegin(GL11.GL_QUADS);
				GL11.glVertex2f(x - 50, y - 50);
				GL11.glVertex2f(x + 50, y - 50);
				GL11.glVertex2f(x + 50, y + 50);
				GL11.glVertex2f(x - 50, y + 50);
			GL11.glEnd();
		GL11.glPopMatrix();
	}
 
	public static void main(String[] argv) {
		FullscreenExample fullscreenExample = new FullscreenExample();
		fullscreenExample.start();
	}
}


Credit

Tutorial Credit - Ninja Cave

Personal tools
Namespaces

Variants
Actions
Navigation
Tools