JMU
Full-Screen Exclusive Graphics
An Introduction with Examples in Java


Prof. David Bernstein
James Madison University

Computer Science Department
bernstdh@jmu.edu


Motivation
Concepts
Issues
Issues (cont.)
Capabilities
javaexamples/fullscreen/ShowCapabilities.java
        import java.awt.*;
import javax.swing.*;

/**
 * A utility that displays  full-screen exclusive 
 * mode graphics capabilities
 *
 * @author  Prof. David Bernstein, James Madison University
 * @version 1.0
 */
public class ShowCapabilities
{

    public static void main(String[] args)
    {
        BufferCapabilities       bcaps;
        DisplayMode[]            modes;
        GraphicsConfiguration[]  configs;
        GraphicsDevice[]         devices;
        GraphicsEnvironment      env;
        ImageCapabilities        icaps;
        int                      aram, i, j, k;


        env     = GraphicsEnvironment.getLocalGraphicsEnvironment();
        devices = env.getScreenDevices();

        System.out.println("Screen Devices: ");
        for (i=0; i < devices.length; i++) {

            System.out.println(i+"\t"+devices[i]);

            if (devices[i].isDisplayChangeSupported())
                System.out.println("\tDisplay Changes Supported");

            if (devices[i].isFullScreenSupported())
                System.out.println("\tFull-Screen Supported");

            aram = devices[i].getAvailableAcceleratedMemory();
            System.out.println("\tAccelerated RAM: "+aram/1024+" Kb");

            configs = devices[i].getConfigurations();
            for (j=0; j < configs.length; j++) {

                System.out.println("\t\tGraphicsConfiguraion "+j);
                icaps = configs[i].getImageCapabilities();
                if (icaps.isAccelerated()) 
                    System.out.println("\t\t\tAccelerated");
                if (icaps.isTrueVolatile()) 
                    System.out.println("\t\t\tTrue Volatile");
                bcaps = configs[i].getBufferCapabilities();
                if (bcaps.isMultiBufferAvailable())
                    System.out.println("\t\t\tMulti Buffer");
                if (bcaps.isPageFlipping())
                    System.out.println("\t\t\tPage Flipping");
            }


            modes = devices[i].getDisplayModes();
            for (j=0; j < modes.length; j++) {

                System.out.println("\t\t"+modes[j].getWidth()+"x"+
                                          modes[j].getHeight()+"x"+
                                          modes[j].getBitDepth());
            }


        }
    }
}
        
Animation
Animation (cont.)

Without a Buffer Strategy

  Graphics g = getPaintGraphics();

  while (!done) 
  {

    // Rendering using g

  }

  g.dispose();
Animation (cont.)

With a Buffer Strategy

    BufferStrategy       strategy;
    Window               window;
    
    // Construct the Window

    // Create the BufferStrategy
    window.createBufferStrategy(2);
    strategy = window.getBufferStrategy();

    Graphics g = strategy.getDrawGraphics();

    while (!done)
    {
        // Rendering using g
        strategy.show();
    }

    g.dispose();
An Example

The Stage Revisited

javaexamples/fullscreen/FullScreenStage.java
        import java.applet.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import java.awt.geom.*;
import java.net.*;
import javax.swing.*;
import java.util.Enumeration;
import java.util.Hashtable;

import visual.dynamic.described.Sprite;
import visual.statik.sampled.ImageFactory;

/**
 * A Stage that uses full-screen exclusive mode
 *
 * @version 1.0
 * @author  Prof. David Bernstein, James Madison University
 *
 */
public class FullScreenStage implements ActionListener, KeyListener
{
    private boolean          shouldRestart;
    private BufferStrategy   bufferStrategy;
    private Graphics         g;
    private Hashtable        sprites;
    private int              frameTime, height, restartTime, time, width;
    private JFrame           frame;
    private Rectangle        bounds;
    private TexturePaint     texture;
    private Timer            timer;



    /**
     * Explicit Value Constructor
     *
     * @param frameTime    Milliseconds between exitFrame events
     */
    public FullScreenStage(int frameTime)
    {
       BufferedImage         image;
       GraphicsConfiguration graphicsConfiguration;
       GraphicsDevice        graphicsDevice;
       GraphicsEnvironment   graphicsEnvironment;
       Rectangle2D.Float     r;
       
       
       
       sprites        = new Hashtable();
       
       this.frameTime = frameTime;
       time           = -frameTime;
       shouldRestart  = false;
       restartTime    = -1;
       
       
       
       // Configure graphics-related objects
       graphicsEnvironment =
          GraphicsEnvironment.getLocalGraphicsEnvironment();
       graphicsDevice =
          graphicsEnvironment.getDefaultScreenDevice();
       graphicsConfiguration = graphicsDevice.getDefaultConfiguration();
       
       // Configure the JFrame
       frame = new JFrame(graphicsConfiguration);
       frame.setUndecorated(true);
       frame.setIgnoreRepaint(true);
       frame.setResizable(false);
       frame.addKeyListener(this);
       
       // Set full-screen exclusive mode (if supported)
       if (graphicsDevice.isFullScreenSupported())
          graphicsDevice.setFullScreenWindow(frame);
       
       
       // Configure the BufferStrategy
       frame.createBufferStrategy(2);
       bufferStrategy = frame.getBufferStrategy();
       
       
       // Get the rendering engine
       g = bufferStrategy.getDrawGraphics();
       
       // Get the bounds 
       bounds = frame.getBounds();
       
       image = ImageFactory.createBufferedImage("sky.jpeg");
       r = new Rectangle2D.Float(0.0f,0.0f,        
                                 (float)(image.getWidth()), 
                                 (float)(image.getHeight()));
       texture = new TexturePaint(image, r);
       
       // Create a Timer in a separate Thread
       timer = new Timer(frameTime, this);
    }




    /**
     * Part of being an ActionListener (for the Timer)
     *
     * @param ae   The ActionEvent to handle
     */
    public void actionPerformed(ActionEvent ae)
    {        
       if (ae.getSource() == timer)
       {
          time += frameTime;
          if ((shouldRestart) && (time >= restartTime)) time = 0;
          fireExitFrame();
          render();  // Instead of repaint()
       }
    }



    /**
     * Add a MouseMotionListener
     */
    public void addMouseMotionListener(MouseMotionListener mml)
    {
       frame.addMouseMotionListener(mml);
    }
    



    /**
     * Add a Sprite to the Stage
     *
     * @param s   The Sprite to add
     */
    public void addSprite(Sprite s)
    {
        sprites.put(s, s);
    }



    /**
     * Draw (i.e., render) the Stage
     *
     * @param g  The Graphics context to paint on
     */
    public void draw(Graphics g)
    {
        Enumeration e;
        Graphics2D  g2;
        Sprite      s;

        g2 = (Graphics2D)g;

        // Paint the background
        g2.setPaint(texture);
        g2.fillRect(0,0,bounds.width,bounds.height);

        // Have each Sprite render itself
        //
        e = sprites.elements();

        while (e.hasMoreElements()) {

            s = (Sprite)e.nextElement();
            s.render(g2);
        }
    }




    /**
     * Fire an exitFrame event to every Sprite
     */
    public void fireExitFrame()
    {
        Enumeration       e;
        Sprite s;


        e = sprites.elements();

        while (e.hasMoreElements()) {

            s = (Sprite)e.nextElement();
            s.exitFrame(time);
        }
    }



    /**
     * Handle key Pressedevents (required by KeyListener)
     *
     * @param evt   The KeyEvent
     */
    public void keyPressed(KeyEvent evt)
    {
        if (evt.getKeyCode() == KeyEvent.VK_Q) stop(); 
    }


    /**
     * Handle keyReleased events (required by KeyListener)
     *
     * @param evt   The KeyEvent
     */
    public void keyReleased(KeyEvent evt)
    {
    }


    /**
     * Handle keyTyped events (required by KeyListener)
     *
     * @param evt   The KeyEvent
     */
    public void keyTyped(KeyEvent evt)
    {
    }



    /**
     * Render the stage (in lieu of repaint)
     */
    public void render()
    {
        draw(g);
        bufferStrategy.show();
    }



    /**
     * Remove a Sprite from the Stage
     *
     * @param s   The Sprite to add
     */
    public void removeSprite(Sprite s)
    {
        sprites.remove(s);
    }



    /**
     * Start the Stage
     */
    public void start()
    {
        timer.start();
    }
    
    

    /**
     * Stop the Stage
     */
    public void stop()
    {
        timer.stop();
        g.dispose();
        System.exit(0);
    }
}