DisplayConfigurable.java :  » Game » rugl » com » rugl » Java Open Source

Java Open Source » Game » rugl 
rugl » com » rugl » DisplayConfigurable.java
/*
 * Copyright (c) 2007, Ryan McNally All rights reserved.
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met: Redistributions of source code must retain the above
 * copyright notice, this list of conditions and the following
 * disclaimer. Redistributions in binary form must reproduce the above
 * copyright notice, this list of conditions and the following
 * disclaimer in the documentation and/or other materials provided
 * with the distribution. Neither the name of the <ORGANIZATION> nor
 * the names of its contributors may be used to endorse or promote
 * products derived from this software without specific prior written
 * permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
 * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
 * DAMAGE.
 */

package com.rugl;

import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;

import org.lwjgl.LWJGLException;
import org.lwjgl.opengl.Display;
import org.lwjgl.opengl.DisplayMode;
import org.lwjgl.opengl.PixelFormat;
import org.lwjgl.util.Dimension;

import com.rugl.console.Console;
import com.ryanm.config.Configurable;
import com.ryanm.config.Configurator;
import com.ryanm.config.imp.AbstractConfigurator;
import com.ryanm.config.imp.AnnotatedConfigurator;
import com.ryanm.config.imp.ConfigurableType;
import com.ryanm.config.imp.Description;
import com.ryanm.config.imp.NumberRange;
import com.ryanm.config.imp.Variable;

/**
 * @author ryanm
 */
@ConfigurableType( "display" )
@Description( "Controls resolution and so on" )
public class DisplayConfigurable implements Configurable
{
  private DisplayMode[] availableModes;

  private Conf current = new Conf();

  private Conf target = new Conf();

  int frameRate = 60;

  private AbstractConfigurator conf = null;

  private List<Listener> listeners = new LinkedList<Listener>();

  /**
   * @author ryanm
   */
  public static enum Samples
  {
    /***/
    NONE( 0 ),
    /***/
    TWO( 2 ),
    /***/
    FOUR( 4 ),
    /***/
    SIX( 6 ),
    /***/
    EIGHT( 8 ),
    /***/
    SIXTEEN( 16 );

    /**
     * The number of samples
     */
    public final int samples;

    private Samples( int samples )
    {
      this.samples = samples;
    }
  };

  DisplayConfigurable()
  {
    try
    {
      availableModes = Display.getAvailableDisplayModes();

      DisplayMode m = Display.getDisplayMode();
      target.res.setSize( m.getWidth(), m.getHeight() );

      target.fullscreen = Display.isFullscreen();
      Display.setVSyncEnabled( target.vsync );
    }
    catch( LWJGLException e )
    {
      e.printStackTrace();
      System.exit( -1 );
    }
  }

  /**
   * Gets the current target resolution
   * 
   * @return the current resolution
   */
  @Variable( "resolution" )
  public Dimension getResolution()
  {
    return target.res;
  }

  /**
   * Sets the target resolution
   * 
   * @param d
   *           the new resolution
   */
  @Variable( "resolution" )
  public void setResolution( Dimension d )
  {
    target.res.setSize( d );
  }

  /**
   * Determines if the display is in fullscreen mode
   * 
   * @return <code>true</code> if fullscreen, <code>false</code> is
   *         windowed
   */
  @Variable( "fullscreen" )
  public boolean isFullscreen()
  {
    return target.fullscreen;
  }

  /**
   * Sets the display to fullscreen mode
   * 
   * @param b
   *           <code>true</code> for fullscreen, <code>false</code>
   *           for windowed
   */
  @Variable( "fullscreen" )
  public void setFullScreen( boolean b )
  {
    target.fullscreen = b;
  }

  /**
   * Determines if the display is vsynced
   * 
   * @return <code>true</code> if vsynced, <code>false</code>
   *         otherwise
   */
  @Variable( "vsync" )
  public boolean isVSynced()
  {
    return target.vsync;
  }

  /**
   * Sets the display target to be vsynced
   * 
   * @param b
   *           <code>true</code> to vsync, <code>false</code>
   *           otherwise
   */
  @Variable( "vsync" )
  public void setVSyned( boolean b )
  {
    target.vsync = b;
  }

  /**
   * Gets the target frame rate
   * 
   * @return The maximum frames per second
   */
  @Variable( "frame rate" )
  public int getFrameRate()
  {
    return target.framerate;
  }

  /**
   * Sets the target frame rate
   * 
   * @param fr
   *           The desired maximum frames per second
   */
  @Variable( "frame rate" )
  @NumberRange( { 0 } )
  public void setFrameRate( int fr )
  {
    target.framerate = fr;
  }

  /**
   * Gets the target sampling mode
   * 
   * @return The target sampling mode, or null for no samples
   */
  @Variable( "fsaa" )
  @Description( "The full screen anti-aliasing mode" )
  public Samples getSamples()
  {
    return target.samples;
  }

  /**
   * Sets the target sampling mode
   * 
   * @param s
   *           The sampling mode to try for
   */
  @Variable( "fsaa" )
  public void setSamples( Samples s )
  {
    target.samples = s;
  }

  /**
   * Applies the fullscreen, resolution and FSAA targets
   * 
   * @throws LWJGLException
   */
  @Variable( "apply" )
  public void apply() throws LWJGLException
  {
    boolean resDirty = !target.res.equals( current.res );
    boolean fsDirty = target.fullscreen != current.fullscreen;
    boolean vsyncDirty = target.vsync != current.vsync;
    boolean frDirty = target.framerate != current.framerate;
    boolean samplesDirty = target.samples != current.samples;

    if( samplesDirty )
    {
      Display.destroy();
    }

    if( resDirty || samplesDirty )
    {
      DisplayMode dm = null;
      int minDiff = Integer.MAX_VALUE;

      for( DisplayMode displaymode : availableModes )
      {
        int diff =
            Math.abs( displaymode.getWidth() - target.res.getWidth() )
                + Math.abs( displaymode.getHeight() - target.res.getHeight() );

        if( diff < minDiff )
        {
          minDiff = diff;
          dm = displaymode;
        }
      }

      if( dm != null )
      {
        target.res.setSize( dm.getWidth(), dm.getHeight() );
        Display.setDisplayMode( dm );
      }
      else
      {
        System.err.println( "Could not find displaymode" );
      }
    }

    if( frDirty || samplesDirty )
    {
      frameRate = target.framerate;
    }

    if( vsyncDirty || samplesDirty )
    {
      Display.setVSyncEnabled( target.vsync );
    }

    if( fsDirty || samplesDirty )
    {
      Display.setFullscreen( target.fullscreen );
    }

    if( samplesDirty )
    {
      boolean created = false;

      while( !created )
      {
        try
        {
          PixelFormat pf = new PixelFormat( 0, 8, 0, target.samples.samples );
          Display.create( pf );
          created = true;
        }
        catch( LWJGLException e )
        {
          if( target.samples.ordinal() == 0 )
          {
            // we're out of luck, and the pixelformat with 0
            // samples has also failed, oddly
            if( Display.isCreated() )
            {
              Display.destroy();
            }

            Display.create();
            target.samples = Samples.NONE;
            created = true;
          }
          else
          {
            target.samples = Samples.values()[ target.samples.ordinal() - 1 ];
          }
        }
      }
    }

    current.set( target );

    Console.log( "Set display mode " + current.res.getWidth() + "x"
        + current.res.getHeight() + " fullscreen = " + current.fullscreen
        + " vSync = " + current.vsync + " framerate = " + current.framerate
        + " FSAA = " + current.samples );

    for( Listener l : listeners )
    {
      l.displayChanged( resDirty, fsDirty, vsyncDirty, frDirty, samplesDirty );
    }
  }

  /**
   * Sets the target display mode from the currently set one
   */
  @Variable( "reset" )
  public void reset()
  {
    target.set( current );
  }

  /**
   * Registers an object's interest in changes to the display
   * 
   * @param l
   */
  public void addListener( Listener l )
  {
    listeners.add( l );
  }

  /**
   * Registers and object's lack of interest in changes to the
   * display
   * 
   * @param l
   */
  public void removeListener( Listener l )
  {
    listeners.remove( l );
  }

  @Override
  public Configurator getConfigurator()
  {
    if( conf == null )
    {
      conf = AnnotatedConfigurator.buildConfigurator( this );

      Set<String> resRange = new TreeSet<String>();
      for( int i = 0; i < availableModes.length; i++ )
      {
        resRange.add( availableModes[ i ].getWidth() + "x"
            + availableModes[ i ].getHeight() );
      }

      conf.setRange( "resolution", resRange.toArray( new String[ resRange.size() ] ) );
    }

    return conf;
  }

  /**
   * Encapsulates a display configuration
   * 
   * @author ryanm
   */
  private class Conf
  {
    private Dimension res = new Dimension();

    private boolean fullscreen = false;

    private boolean vsync = true;

    private int framerate = 60;

    private Samples samples = Samples.NONE;

    private void set( Conf conf )
    {
      res.setSize( conf.res );
      fullscreen = conf.fullscreen;
      vsync = conf.vsync;
      framerate = conf.framerate;
      samples = conf.samples;
    }
  }

  /**
   * Interface for objects that want to be notified when the screen
   * configuration changes
   * 
   * @author ryanm
   */
  public static interface Listener
  {
    /**
     * Called when some aspect of the screen configuration is
     * changed
     * 
     * @param res
     *           <code>true</code> if the resolution has been
     *           changed
     * @param fs
     *           <code>true</code> if we've changed from fullscreen
     *           to windowed or vice versa
     * @param vsync
     *           <code>true</code> if we used to be vsynced and now
     *           are not, or vice versa
     * @param fr
     *           <code>true</code> if the traget frame rate has
     *           changed
     * @param fsaa
     *           <code>true</code> if the fullscreen anti-aliasing
     *           samples value has changed. NB: if this is true, we
     *           have lost opengl state, so textures will need to be
     *           init()ed again, texcoords recalculated, etc
     */
    public void displayChanged( boolean res, boolean fs, boolean vsync, boolean fr,
        boolean fsaa );
  }
}
java2s.com  | Contact Us | Privacy Policy
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.