Skip to main content

If you don't have an IBM ID and password, register here.

By clicking Submit, you agree to the developerWorks terms of use.

The first time you sign into developerWorks, a profile is created for you. This profile includes the first name, last name, and display name you identified when you registered with developerWorks. Select information in your developerWorks profile is displayed to the public, but you may edit the information at any time. Your first name, last name (unless you choose to hide them), and display name will accompany the content that you post.

All information submitted is secure.

The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerworks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

By clicking Submit, you agree to the developerWorks terms of use.

All information submitted is secure.

Magic with Merlin: Exercise complete control over your graphics display

Fullscreen Exclusive Mode API lets you change display modes and draw directly to video RAM

John Zukowski (jaz@zukowski.net), President, JZ Ventures, Inc.
Author photo
John Zukowski conducts strategic Java consulting with JZ Ventures, Inc. and serves as the resident guru for a number of jGuru's community-driven Java FAQs. His latest books include Learn Java with JBuilder 6 from Apress and Mastering Java 2: J2SE 1.4 from Sybex. Contact John at jaz@zukowski.net.

Summary:  Game developers and computer speed nuts alike will love Merlin's new Fullscreen Exclusive Mode (FEM) API, with which you can write directly to video memory with complete control over the graphics display. In this latest Magic with Merlin installment, Java programming expert John Zukowski introduces the power of this new Merlin feature.

View more content in this series

Date:  29 Apr 2003
Level:  Introductory

Comments:  

Do you enjoy upsetting people by making your programs do annoying things? If you answered "yes," this month's tip is sure to be a pleaser. With J2SE 1.4, your Java programs can now change video modes and seize absolute control of the screen. You need not let anyone else play nicely; you literally can possess total control. For this god-like power, thank the new Fullscreen Exclusive Mode (FEM) API.

Even if you answered "no" and you don't get your kicks by annoying others, you'll find the FEM API has much to offer. The FEM API delivers complete control of the display by writing directly to video RAM -- perfect for game development, although other uses abound. Some programs, for instance, simply look and work better with a certain size screen. Read on to discover your inner control freak.

Change display modes

Let's begin by examining the FEM API's java.awt.DislayMode class, which wraps the screen dimensions and refresh rate for a particular display mode. The modes supported are specific to a system's hardware support.

To find out a specific system's supported modes, ask the GraphicsEnvironment. From that environment you get the default screen device, a GraphicDevice, from which you get the display modes, as seen in Listing 1:


Listing 1. Look up display modes
    GraphicsEnvironment graphicsEnvironment =
      GraphicsEnvironment.getLocalGraphicsEnvironment();
    GraphicsDevice graphicsDevice =
      graphicsEnvironment.getDefaultScreenDevice();
    DisplayMode displayModes[] =
      graphicsDevice.getDisplayModes();

You can also discover the current display mode with the getDisplayMode() method, as shown in Listing 2:


Listing 2. Get the current display mode
DisplayMode originalDisplayMode =
      graphicsDevice.getDisplayMode();

Changing modes proves relatively easy, but you must first ask if the involved graphics device supports changing with the GraphicsDevice's isDisplayChangeSupported() method.

Once that's known, to change modes use the setDisplayMode() method, passing in the new mode. The display-mode change typically occurs in a try/finally block such that the finally block resets code to the original mode. While that process is not absolutely required, it ensures a safe mode upon the program's completion. Listing 3 shows a typical pattern for changing display modes:


Listing 3. Change modes
    GraphicsDevice graphicsDevice = ...
    DisplayMode originalDisplayMode = graphicsDevice.getDisplayMode();
    DisplayMode newDisplayMode = ...
    try {
      if (graphicsDevice.isDisplayChangeSupported()) {
        graphicsDevice.setDisplayMode(newDisplayMode);
      }
    } finally {
      graphicsDevice.setDisplayMode(originalDisplayMode);
    }


Use fullscreen windows

With the FEM API, entering fullscreen windows is a snap: just pass a window to the GraphicsDevice's setFullScreenWindow() method, as shown in Listing 4. When you want to return to nonfullscreen mode, pass null into the method. Of course, first check whether the GraphicsDevice supports fullscreen mode by employing the isFullScreenSupported() method.


Listing 4. Enter fullscreen mode
    GraphicsDevice graphicsDevice = ...
    Window window = ...
    try {
      if (graphicsDevice.isFullScreenSupported()) {
        graphicsDevice.setFullScreenWindow(window);
      }
    } finally {
      graphicsDevice.setFullScreenWindow(null);
    }

To illustrate everything you've learned so far, Listing 5 contains a complete example. The code in Listing 5 gets the display modes, picks one at random to change to, then displays a fullscreen window with the text "Hello, World!" The new display mode's characteristics display so you can see the specific screen size, refresh rate, and bit depth.


Listing 5. Mode changing example
import java.awt.*;
import javax.swing.*;
import java.util.Random;

public class DisplayModes {

  public static void main(String args[]) {
    GraphicsEnvironment graphicsEnvironment =
      GraphicsEnvironment.getLocalGraphicsEnvironment();
    GraphicsDevice graphicsDevice =
      graphicsEnvironment.getDefaultScreenDevice();
    DisplayMode displayModes[] = graphicsDevice.getDisplayModes();
    DisplayMode originalDisplayMode = graphicsDevice.getDisplayMode();
    JWindow window = new JWindow() {
      public void paint(Graphics g) {
        g.setColor(Color.blue);
        g.drawString("Hello, World!", 50, 50);
      }
    };
    try {
      if (graphicsDevice.isFullScreenSupported()) {
        graphicsDevice.setFullScreenWindow(window);
      }
      Random random = new Random();
      int mode = random.nextInt(displayModes.length);
      DisplayMode displayMode = displayModes[mode];
      System.out.println(displayMode.getWidth() + "x" + 
        displayMode.getHeight() + " \t" + displayMode.getRefreshRate() + 
        " / " + displayMode.getBitDepth());
      if (graphicsDevice.isDisplayChangeSupported()) {
        graphicsDevice.setDisplayMode(displayMode);
      }
      Thread.sleep(1000);
    } catch (InterruptedException e) {
    } finally {
      graphicsDevice.setDisplayMode(originalDisplayMode);
      graphicsDevice.setFullScreenWindow(null);
    }
    System.exit(0);
  }
}


Fullscreen rendering

Notice in Listing 5 that the window used for the fullscreen includes a perfectly functional paint() method. However, because the window is in fullscreen mode, the overhead required for the paint() method, how the method deals with clipping, and other associated display-handling behaviors are unnecessary. Indeed, the standard passive rendering proves overkill, slowing fullscreen application down. You needn't deal with such tasks as overlapping or resizing a window, for instance. Instead, take a more active approach and create a tight loop that handles the rendering itself.

If you're familiar with double buffering, you know it manages two Image objects in memory and swaps between them based upon which possesses the current display information. While one Image displays, you draw to the other and swap Image objects between each scene.

Graphics cards employ a similar concept, but instead of working with actual Java Image objects, they swap memory pages. The display changes when you swap memory pages so you need not copy an Image object from program memory to video memory; you merely change video pointers and the display changes. While the double-buffering concept still exists, instead of writing to an Image in program space, you draw directly to video memory space.

The BufferStrategy class masks which of the two aforementioned double-buffering methodologies is used and lets you take advantage of any hardware-based buffering the system offers. To create a BufferStrategy, tell the system the number of buffers you desire with the createBufferStrategy() method and swap between buffers with the getDrawGraphics() method, which returns the next buffer to work with. Conceptually that's all there is to it, but, as Listing 6 shows, the working code requires a bit more effort:


Listing 6. Use a BufferStrategy
  JFrame frame = ...
  frame.createBufferStrategy(2); // Number of buffers to have
  BufferStrategy bufferStrategy = frame.getBufferStrategy();
  while (!done()) {  // Some condition to end
    Graphics g = null;
    try {
      g = bufferStrategy.getDrawGraphics();
      drawNextScene(g); // Method to draw to 
    } finally {
      // Free resources
      if (g != null) {
        g.dispose();
      }
    }
    bufferStrategy.show();
  }

When using a BufferStrategy, you can't assume the last item you drew to the buffer remains valid; you must ask with the contentsLost() method. If lost, you must redraw the entire buffer. Otherwise, you need draw only what's changed since its last usage.

In addition to buffer support with BufferStrategy, the BufferCapabilities class lets you discover what capabilities -- such as full screen mode -- a strategy supports with the getCapabilities() method.


A working example

Putting all the pieces together produces the example program in Listing 7. Because of my limited artistic skills, don't look for a sophisticated game. You will, however, find a complete working example employing a BufferStrategy and fullscreen drawing modes. The example program purposely does not synchronize buffers by remembering what wasn't drawn to the current buffer -- letting you see multiple buffers at work more clearly. The program does randomly draw 100 rectangles to the screen, with a 1/10th-of-a-second delay between draws.


Listing 7. A working example
import java.awt.*;
import java.awt.image.*;
import javax.swing.*;
import java.util.Random;

public class MultipleBuffers {

  public static void main(String args[]) {
    GraphicsEnvironment graphicsEnvironment =
      GraphicsEnvironment.getLocalGraphicsEnvironment();
    GraphicsDevice graphicsDevice =
      graphicsEnvironment.getDefaultScreenDevice();
    DisplayMode displayModes[] = graphicsDevice.getDisplayModes();
    DisplayMode originalDisplayMode = graphicsDevice.getDisplayMode();
    JFrame frame = new JFrame();
    frame.setUndecorated(true);
    frame.setIgnoreRepaint(true);
    try {
      if (graphicsDevice.isFullScreenSupported()) {
        graphicsDevice.setFullScreenWindow(frame);
      }
      Random random = new Random();
      int mode = random.nextInt(displayModes.length);
      DisplayMode displayMode = displayModes[mode];
      System.out.println(displayMode.getWidth() + "x" + 
        displayMode.getHeight() + " \t" + displayMode.getRefreshRate() + 
        " / " + displayMode.getBitDepth());
      if (graphicsDevice.isDisplayChangeSupported()) {
        graphicsDevice.setDisplayMode(displayMode);
      }
      frame.createBufferStrategy(2);
      BufferStrategy bufferStrategy = frame.getBufferStrategy();
      int width = frame.getWidth();
      int height = frame.getHeight();
      for (int i=0; i<100; i++) {
        Graphics g = bufferStrategy.getDrawGraphics();
        g.setColor(new Color(random.nextInt()));
	g.fillRect(random.nextInt(width), 
	    random.nextInt(height), 100, 100);
        bufferStrategy.show();
        g.dispose();
        Thread.sleep(100);
      }
    } catch (InterruptedException e) {
    } finally {
      graphicsDevice.setDisplayMode(originalDisplayMode);
      graphicsDevice.setFullScreenWindow(null);
    }
    System.exit(0);
  }
}

The example program would benefit from such enhancements as keeping the buffers synchronized or checking if the complete buffer must be redrawn when contents are lost. The former task requires remembering only the last rectangle drawn (and the color), while the latter requires remembering them all.


First the screen, then the known universe!

With the new Fullscreen Exclusive Mode API, Java development becomes a mainstream option for game development. The API replaces the need to work with platform-specific APIs like DirectX or OpenGL, instead relying on a standard API across all Java-enabled platforms. It's more than an aspiring programming despot could imagine.


Resources

About the author

Author photo

John Zukowski conducts strategic Java consulting with JZ Ventures, Inc. and serves as the resident guru for a number of jGuru's community-driven Java FAQs. His latest books include Learn Java with JBuilder 6 from Apress and Mastering Java 2: J2SE 1.4 from Sybex. Contact John at jaz@zukowski.net.

Report abuse help

Report abuse

Thank you. This entry has been flagged for moderator attention.


Report abuse help

Report abuse

Report abuse submission failed. Please try again later.


developerWorks: Sign in

If you don't have an IBM ID and password, register here.


Forgot your IBM ID?


Forgot your password?
Change your password


By clicking Submit, you agree to the developerWorks terms of use.

 


The first time you sign into developerWorks, a profile is created for you. This profile includes the first name, last name, and display name you identified when you registered with developerWorks. Select information in your developerWorks profile is displayed to the public, but you may edit the information at any time. Your first name, last name (unless you choose to hide them), and display name will accompany the content that you post.

Choose your display name

The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerWorks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

(Must be between 3 – 31 characters.)


By clicking Submit, you agree to the developerWorks terms of use.

 


Rate this article

Comments

Help: Update or add to My dW interests

What's this?

This little timesaver lets you update your My developerWorks profile with just one click! The general subject of this content (AIX and UNIX, Information Management, Lotus, Rational, Tivoli, WebSphere, Java, Linux, Open source, SOA and Web services, Web development, or XML) will be added to the interests section of your profile, if it's not there already. You only need to be logged in to My developerWorks.

And what's the point of adding your interests to your profile? That's how you find other users with the same interests as yours, and see what they're reading and contributing to the community. Your interests also help us recommend relevant developerWorks content to you.

View your My developerWorks profile

Return from help

Help: Remove from My dW interests

What's this?

Removing this interest does not alter your profile, but rather removes this piece of content from a list of all content for which you've indicated interest. In a future enhancement to My developerWorks, you'll be able to see a record of that content.

View your My developerWorks profile

Return from help

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=Java technology
ArticleID=10803
ArticleTitle=Magic with Merlin: Exercise complete control over your graphics display
publish-date=04292003
author1-email=jaz@zukowski.net
author1-email-cc=jaloi@us.ibm.com

Tags

Help
Use the search field to find all types of content in My developerWorks with that tag.

Use the slider bar to see more or fewer tags.

For articles in technology zones (such as Java technology, Linux, Open source, XML), Popular tags shows the top tags for all technology zones. For articles in product zones (such as Info Mgmt, Rational, WebSphere), Popular tags shows the top tags for just that product zone.

For articles in technology zones (such as Java technology, Linux, Open source, XML), My tags shows your tags for all technology zones. For articles in product zones (such as Info Mgmt, Rational, WebSphere), My tags shows your tags for just that product zone.

Use the search field to find all types of content in My developerWorks with that tag. Popular tags shows the top tags for this particular content zone (for example, Java technology, Linux, WebSphere). My tags shows your tags for this particular content zone (for example, Java technology, Linux, WebSphere).