Package ch.sahits.game.rendering

Source Code of ch.sahits.game.rendering.MainFullScreenFrame

package ch.sahits.game.rendering;

import java.awt.Color;
import java.awt.DisplayMode;
import java.awt.EventQueue;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.GraphicsConfiguration;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.Image;
import java.awt.Insets;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Toolkit;
import java.awt.Window;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import java.awt.image.BufferStrategy;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import javax.imageio.ImageIO;
import javax.swing.JFrame;

import org.apache.log4j.Logger;

import ch.sahits.game.event.KeyPressEvent;

public abstract class MainFullScreenFrame extends JFrame implements Runnable, WindowListener {
  private static final long serialVersionUID = 6115721848767388765L;
  private static final Logger logger = Logger.getLogger(MainFullScreenFrame.class);
    private Rectangle rect;
    private List<Renderable> views = new ArrayList<Renderable>();
 
    private static final int NUM_BUFFERS = 2; // used for page flipping

    private static int DEFAULT_FPS = 25;

    public static long ONE_SECOND_IN_NS = 1000000000L;

//    private static long MAX_STATS_INTERVAL = ONE_SECOND_IN_NS;
    // record stats every 1 second (roughly)

    private static final int NO_DELAYS_PER_YIELD = 16;
    /*
     * Number of frames with a delay of 0 ms before the animation thread yields
     * to other running threads.
     */

    private static int MAX_FRAME_SKIPS = 5; // was 2;
    // no. of frames that can be skipped in any one animation loop
    // i.e the games state is updated but not rendered

    private static int NUM_FPS = 10;
    // number of FPS values stored to get an average


    // used for gathering statistics
//    private long statsInterval = 0L; // in ns
//    private long prevStatsTime;
//    private long totalElapsedTime = 0L;
    private long gameStartTime; // TODO remove

//    private long frameCount = 0;
    private double fpsStore[];
//    private long statsCount = 0;
//    private double averageFPS = 0.0;
//
    @SuppressWarnings("unused")
    private long framesSkipped = 0L;
//    private long totalFramesSkipped = 0L;
    private double upsStore[];
//    private double averageUPS = 0.0;

//    private DecimalFormat df = new DecimalFormat("0.##"); // 2 dp
//    private DecimalFormat timedf = new DecimalFormat("0.####"); // 4 dp

    private Thread animator; // the thread that performs the animation
    private volatile boolean running = false; // used to stop the animation
                          // thread
    /** Period between two consecutive draw actions in ns */
    private long period;

    private boolean finishedOff = false;
   
    @SuppressWarnings("unused")
    private KeyListener listener = null;

    // // used by quit 'button'
    // private volatile boolean isOverQuitButton = false;
    // private Rectangle quitArea;

    // used by the pause 'button'
    // private volatile boolean isOverPauseButton = false;
    // private Rectangle pauseArea;
    // private volatile boolean isPaused = false;

    private Font font;
    @SuppressWarnings("unused")
    private FontMetrics metrics;

    // used for full-screen exclusive mode
    private GraphicsDevice gd;
    @SuppressWarnings("unused")
    private Graphics gScr;
    @SuppressWarnings("unused")
    private BufferStrategy bufferStrategy;
      private Graphics dbg;
      private Image dbImage = null;
   
  public MainFullScreenFrame() {
    period = ONE_SECOND_IN_NS / DEFAULT_FPS;

    initFullScreen();

    readyForTermination();
    font = new Font("SansSerif", Font.BOLD, 24);
    metrics = this.getFontMetrics(font);

  
    addMouseListener(new MouseAdapter() {
      public void mousePressed(MouseEvent e) {
        testPress(e.getX(), e.getY());
      }
    });

    addMouseMotionListener(new MouseMotionAdapter(){
      public void mouseMoved(MouseEvent e) {
        testMove(e.getX(), e.getY());
      }
    });
    addKeyListener(new KeyAdapter() {
      public void keyPressed(KeyEvent e) {
        testKey(e);
      }
    });

    // initialise timing elements
    fpsStore = new double[NUM_FPS];
    upsStore = new double[NUM_FPS];
    for (int i = 0; i < NUM_FPS; i++) {
      fpsStore[i] = 0.0;
      upsStore[i] = 0.0;
   
    pack();
    calcSizes();

  }
 
  private void initFullScreen() {
    GraphicsEnvironment ge = GraphicsEnvironment
        .getLocalGraphicsEnvironment();
    gd = ge.getDefaultScreenDevice();

    setUndecorated(true); // no menu bar, borders, etc. or Swing components
    setIgnoreRepaint(true); // turn off all paint events since doing active
                // rendering
    // setResizable(false); // This causes Linux to draw taskbars over the
    // java window (Gnome)

    if (!gd.isFullScreenSupported()) {
      logger.fatal("Full-screen exclusive mode not supported");
      System.exit(0);
    }
    gd.setFullScreenWindow(this); // switch on full-screen exclusive mode

    // we can now adjust the display modes, if we wish
    showCurrentMode();

    // setDisplayMode(800, 600, 8); // or try 8 bits
    // setDisplayMode(1280, 1024, 32);

    // reportCapabilities();

//    pWidth = getBounds().width;
//    pHeight = getBounds().height;

    setBufferStrategy();
  } // end of initFullScreen()
 
  /**
   * Switch on page flipping: NUM_BUFFERS == 2 so there will be a 'primary
   * surface' and one 'back buffer'.
   *
   * The use of invokeAndWait() is to avoid a possible deadlock with the event
   * dispatcher thread. Should be fixed in J2SE 1.5
   *
   * createBufferStrategy) is an asynchronous operation, so sleep a bit so
   * that the getBufferStrategy() call will get the correct details.
   */
  private void setBufferStrategy()
  {
    try {
      EventQueue.invokeAndWait(new Runnable() {
        public void run() {
          createBufferStrategy(NUM_BUFFERS);
        }
      });
    } catch (Exception e) {
      logger.fatal("Error while creating buffer strategy", e);
      System.exit(0);
    }

    try { // sleep to give time for the buffer strategy to be carried out
      Thread.sleep(500); // 0.5 sec
    } catch (InterruptedException ex) {
    }

    bufferStrategy = getBufferStrategy(); // store for later
  } // end of setBufferStrategy()

  private void readyForTermination() {
    // for shutdown tasks
    // a shutdown may not only come from the program
    Runtime.getRuntime().addShutdownHook(new Thread() {
      public void run() {
        updateRunning(false);
        finishOff();
      }
    });
  } // end of readyForTermination()
  /**
   * This method sets up the thread driving the game animation. For special needs
   * this method can be overridden, however the super method should always be called.
   */
  protected void gameStart()
  // initialise and start the thread
  {
    if (animator == null || !running) {
      animator = new Thread(this);
      animator.start();
    }
  } // end of gameStart()
  /**
   * Use active rendering to replace the off screen image on the screen
   */
  private void paintScreen()
    // use active rendering to put the buffered image on-screen
    {
      Graphics g;
      try {
        g = this.getGraphics();
        BufferedImage img = new BufferedImage(dbImage.getWidth(this), dbImage.getHeight(this), BufferedImage.TYPE_INT_RGB);
        Graphics gr = img.getGraphics();
        gr.drawImage(dbImage, 0, 0, this);
        ImageIO.write(img, "png", new File("renderedImage.png"));
       
        if ((g != null) && (dbImage != null)){
//          counter++;
          g.drawImage(dbImage, 0, 0, null);
        }
        // Sync the display on some systems.
        // (on Linux, this fixes event queue problems)
        Toolkit.getDefaultToolkit().sync();
        g.dispose();
      }
      catch (Exception e)   // quite commonly seen at applet destruction
      { logger.warn("Graphics error", e); }
    }
 
 
  /**
   * Check the mouse clicks.
   *
   * @param x
   * @param y
   */
  public abstract void testPress(int x, int y);

  /**
   * Handle the mouse movement (e.g. for hovering effects or tooltips )
   *
   * @param x
   * @param y
   */
  protected abstract void testMove(int x, int y);
  /**
   * Handle key presses.
   * A typical implementation would generate a {@link KeyPressEvent}
   * @param key
   */
  protected abstract void testKey(KeyEvent key);
  /**
   * Main method for running the game animation
   */
  public void run()
  /* The frames of the animation are drawn inside the while loop. */
  {
    long beforeTime, afterTime, timeDiff, sleepTime;
    long overSleepTime = 0L;
    int noDelays = 0;
    long excess = 0L;

    gameStartTime = System.nanoTime();
    beforeTime = gameStartTime;

    running = true;

    while (running) {
      gameUpdate();
      gameRender();
      paintScreen();

      afterTime = System.nanoTime();
      timeDiff = afterTime - beforeTime;
      sleepTime = (period - timeDiff) - overSleepTime;

      if (sleepTime > 0) { // some time left in this cycle
        try {
          Thread.sleep(sleepTime / 1000000L); // nano -> ms
        } catch (InterruptedException ex) {
        }
        overSleepTime = (System.nanoTime() - afterTime) - sleepTime;
      } else { // sleepTime <= 0; the frame took longer than the period
        excess -= sleepTime; // store excess time value
        overSleepTime = 0L;

        if (++noDelays >= NO_DELAYS_PER_YIELD) {
          Thread.yield(); // give another thread a chance to run
          noDelays = 0;
        }
      }

      beforeTime = System.nanoTime();

      /*
       * If frame animation is taking too long, update the game state
       * without rendering it, to get the updates/sec nearer to the
       * required FPS.
       */
      int skips = 0;
      while ((excess > period) && (skips < MAX_FRAME_SKIPS)) {
        excess -= period;
        gameUpdate(); // update state but don't render
        skips++;
      }
      framesSkipped += skips;
    }
    finishOff();
  } // end of run()
  /**
   * Timed events belong in this method
   */
  protected abstract void gameUpdate();


  /**
   * Rendering the off screen image that is then replaced
   */
  private void gameRender() {
      if (dbImage == null){
          dbImage = createImage(rect.width, rect.height);
          if (dbImage == null) {
            logger.error("dbImage is null");
            return;
          }
          else
            dbg = dbImage.getGraphics();
        }
     
      // clear the background
      dbg.setColor(Color.BLACK);
      dbg.fillRect(rect.x, rect.y, rect.width, rect.height);

      dbg.setFont(font);

      // report frame count & average FPS and UPS at top left
    // dbg.drawString("Frame Count " + frameCount, 10, 25);

    for (Renderable panel : views) {
      if (panel.isEnabled()){
        panel.gameRender(dbg);
      }
    }
        BufferedImage img = new BufferedImage(dbImage.getWidth(this), dbImage.getHeight(this), BufferedImage.TYPE_INT_RGB);
        Graphics gr = img.getGraphics();
        gr.drawImage(dbImage, 0, 0, this);
        try {
      ImageIO.write(img, "png", new File("renderedImage_1.png"));
    } catch (IOException e) {
      e.printStackTrace();
    }

  } // end of gameRender()
//  /**
//   * The statistics: - the summed periods for all the iterations in this
//   * interval (period is the amount of time a single frame iteration should
//   * take), the actual elapsed time in this interval, the error between these
//   * two numbers;
//   *
//   * - the total frame count, which is the total number of calls to run();
//   *
//   * - the frames skipped in this interval, the total number of frames
//   * skipped. A frame skip is a game update without a corresponding render;
//   *
//   * - the FPS (frames/sec) and UPS (updates/sec) for this interval, the
//   * average FPS & UPS over the last NUM_FPSs intervals.
//   *
//   * The data is collected every MAX_STATS_INTERVAL (1 sec).
//   */
//  private void storeStats()
//  {
//    frameCount++;
//    statsInterval += period;
//
//    if (statsInterval >= MAX_STATS_INTERVAL) { // record stats every
//                          // MAX_STATS_INTERVAL
//      long timeNow = System.nanoTime();
//
//      long realElapsedTime = timeNow - prevStatsTime; // time since last
//                              // stats collection
//      totalElapsedTime += realElapsedTime;
//
//      double timingError = ((double) (realElapsedTime - statsInterval) / statsInterval) * 100.0;
//
//      totalFramesSkipped += framesSkipped;
//
//      double actualFPS = 0; // calculate the latest FPS and UPS
//      double actualUPS = 0;
//      if (totalElapsedTime > 0) {
//        actualFPS = (((double) frameCount / totalElapsedTime) * 1000000000L);
//        actualUPS = (((double) (frameCount + totalFramesSkipped) / totalElapsedTime) * 1000000000L);
//      }
//
//      // store the latest FPS and UPS
//      fpsStore[(int) statsCount % NUM_FPS] = actualFPS;
//      upsStore[(int) statsCount % NUM_FPS] = actualUPS;
//      statsCount = statsCount + 1;
//
//      double totalFPS = 0.0; // total the stored FPSs and UPSs
//      double totalUPS = 0.0;
//      for (int i = 0; i < NUM_FPS; i++) {
//        totalFPS += fpsStore[i];
//        totalUPS += upsStore[i];
//      }
//
//      if (statsCount < NUM_FPS) { // obtain the average FPS and UPS
//        averageFPS = totalFPS / statsCount;
//        averageUPS = totalUPS / statsCount;
//      } else {
//        averageFPS = totalFPS / NUM_FPS;
//        averageUPS = totalUPS / NUM_FPS;
//      }
//      /*
//       * System.out.println(timedf.format( (double)
//       * statsInterval/1000000000L) + " " + timedf.format((double)
//       * realElapsedTime/1000000000L) + "s " + df.format(timingError) +
//       * "% " + frameCount + "c " + framesSkipped + "/" +
//       * totalFramesSkipped + " skip; " + df.format(actualFPS) + " " +
//       * df.format(averageFPS) + " afps; " + df.format(actualUPS) + " " +
//       * df.format(averageUPS) + " aups" );
//       */
//      framesSkipped = 0;
//      prevStatsTime = timeNow;
//      statsInterval = 0L; // reset
//    }
//  } // end of storeStats()

  private void finishOff()
  /*
   * Tasks to do before terminating. Called at end of run() and via the
   * shutdown hook in readyForTermination().
   *
   * The call at the end of run() is not really necessary, but included for
   * safety. The flag stops the code being called twice.
   */
  { // System.out.println("finishOff");
    if (!finishedOff) {
      finishedOff = true;
      // printStats();
      restoreScreen();
      System.exit(0);
    }
  } // end of finishedOff()


  /**
   * Switch off full screen mode. This also resets the display mode if it's
   * been changed.
   */
  private void restoreScreen()
  {
    Window w = gd.getFullScreenWindow();
    if (w != null)
      w.dispose();
    gd.setFullScreenWindow(null);
  } // end of restoreScreen()

  // ------------------ display mode methods -------------------


  private void showCurrentMode()
  // print the display mode details for the graphics device
  {
    DisplayMode dm = gd.getDisplayMode();
    logger.info("Current Display Mode: (" + dm.getWidth() + ","
        + dm.getHeight() + "," + dm.getBitDepth() + ","
        + dm.getRefreshRate() + ")  ");
  }

    /**
     *  Calculate the size of the drawing panel to fill the screen, but
     * leaving room for the JFrame's title bar and insets, the OS's insets
     * (e.g. taskbar) and the textfields under the JPanel.
     */
  private void calcSizes()
    {
      GraphicsConfiguration gc = getGraphicsConfiguration();
    Rectangle screenRect = gc.getBounds();
//System.out.println("Screen bounds: "+screenRect);
    // System.out.println("Screen size: " + screenRect);
      Toolkit tk = Toolkit.getDefaultToolkit();
      Insets desktopInsets = tk.getScreenInsets(gc);
//System.out.println("Desktop insets: "+desktopInsets);
     
//System.out.println("Frame insets "+frameInsets);
     
      rect = new Rectangle(new Point(desktopInsets.left,desktopInsets.top));

      rect.width = screenRect.width - (desktopInsets.left + desktopInsets.right);
//                                - (frameInsets.left + frameInsets.right);

      rect.height = screenRect.height - (desktopInsets.top + desktopInsets.bottom);
//                                  - (frameInsets.top + frameInsets.bottom);
//System.out.println("Frame bounds: "+rect);     
      // System.out.println("pWidth: " + pWidth + "; pHeight: " + pHeight);
    }

  /**
   * Add a new view to the renderable pipeline.
   * @param view to be added
   * @return true if the adding was successful
   */
  public boolean addView(Renderable view) {
    return views.add(view);
  }



  /**
   * Remove a view from the render pipeline
   * @param view to be removed
   * @return true if removal was succesful
   */
  public boolean removeView(Renderable view) {
    return views.remove(view);
  }


  public final Rectangle getRactangle(){
    return rect;
  }
  /**
   * This method my be overriden by subclasses to handle specific tasks when closing the window
   */
  public void windowClosing(WindowEvent e) {
  }
  /**
   * This method my be overriden by subclasses to handle specific tasks when closing the window
   */
  public void windowClosed(WindowEvent e) {
  }

  public void windowIconified(WindowEvent e) {
    updateRunning(false);
    // Send pause to the server
  }

  public void windowDeiconified(WindowEvent e) {
    updateRunning(true);
    // Send pause to the server
  }
  /**
   * Update the running flag
   * @param running
   */
  protected void updateRunning(boolean running) {
    this.running=running;
  }

  public void windowActivated(WindowEvent e) {
    updateRunning(true);
    // Send pause to the server
  }

  public void windowDeactivated(WindowEvent e) {
    updateRunning(false);
    // Send pause to the server
   
  }
  @Override
  public void windowOpened(WindowEvent e) {
  }

}
TOP

Related Classes of ch.sahits.game.rendering.MainFullScreenFrame

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.