TestbedMain.java :  » UnTagged » lineflyer » org » jbox2d » testbed » Android Open Source

Android Open Source » UnTagged » lineflyer 
lineflyer » org » jbox2d » testbed » TestbedMain.java
/*
 * JBox2D - A Java Port of Erin Catto's Box2D
 * 
 * JBox2D homepage: http://jbox2d.sourceforge.net/ 
 * Box2D homepage: http://www.box2d.org
 * 
 * This software is provided 'as-is', without any express or implied
 * warranty.  In no event will the authors be held liable for any damages
 * arising from the use of this software.
 * 
 * Permission is granted to anyone to use this software for any purpose,
 * including commercial applications, and to alter it and redistribute it
 * freely, subject to the following restrictions:
 * 
 * 1. The origin of this software must not be misrepresented; you must not
 * claim that you wrote the original software. If you use this software
 * in a product, an acknowledgment in the product documentation would be
 * appreciated but is not required.
 * 2. Altered source versions must be plainly marked as such, and must not be
 * misrepresented as being the original software.
 * 3. This notice may not be removed or altered from any source distribution.
 */

package org.jbox2d.testbed;

import java.awt.event.MouseWheelEvent;
import java.awt.event.MouseWheelListener;
import java.util.ArrayList;

import org.jbox2d.common.Vec2;
import org.jbox2d.dynamics.DebugDraw;
import org.jbox2d.testbed.tests.*;

import processing.core.PApplet;

/**
 * TestbedMain is the holder PApplet for the entire testbed.
 * It has first stab at input events, and delegates them out
 * to the appropriate handlers if necessary.  It handles the
 * list of tests to run, and starts them as needed.
 * <BR><BR>For applet safety, no variables are static, because
 * in the browser a page reload does <em>not</em> reset static
 * variables (even though the applet may get restarted otherwise).
 * From a design perspective this is not ideal, but hey - this
 * is just a demo, anyways, let's not get too bent out of
 * shape over it.
 * <BR><BR>In the future, other classes should be checked to
 * make sure this odd static variable behavior is not causing
 * memory leaks in the browser.
 * 
 * @author ewjordan
 *
 */
public class TestbedMain extends PApplet {
  /** I let Eclipse generate this to shut it up about its warnings. */
  private static final long serialVersionUID = 1712524774634907635L;
  /** The list of registered examples */
  protected ArrayList<AbstractExample> tests = new ArrayList<AbstractExample>(0);
  /** Currently running example */
  protected AbstractExample currentTest = null;
  /** 
   * Index of current example in tests array.
   * Assumes that the array structure does not change,
   * though it's safe to add things on to the end. 
   */
  protected int currentTestIndex = 0;
  /** Is the options window open? */
  protected boolean handleOptions = false;
  
  // Little bit of input stuff
  // TODO ewjordan: refactor into an input handler class
  /** Is the shift key held? */
  public boolean shiftKey = false;
    
  /** Was the mouse down last frame? */
    boolean pmousePressed = false;
    
    /** Our options handler - displays GUI and sets TestSettings for currentTest. */
    public TestbedOptions options;
    
    // Processing handles fps pinning, but we
    // report fps on our own just to be sure.
    
    /** FPS that we want to achieve */
    final static float targetFPS = 60.0f;
    /** Number of frames to average over when computing real FPS */
    final int fpsAverageCount = 100; 
    /** Array of timings */
    long[] nanos;
    /** When we started the nanotimer */
    long nanoStart; //
    
    /** Number of frames since we started this example. */
    long frameCount = 0;
    
    /** Drawing handler to use. */
    public DebugDraw g;

    /** Constructor - real initialization happens in setup() function */
    public TestbedMain() {
      super();
    }
    
    /**
     * Called once upon program initialization (by Processing).
     * Here we set up graphics, set the framerate, register
     * all the testbed examples, set up a mousewheel listener,
     * and set up the frame rate timer.
     */
    public void setup() {
      /* On newer machines especially, the default JAVA2D renderer
       * is slow as hell and tends to drop frames.  I have no idea
       * why, but for now let's use P3D and live without the smoothing...
       */
      size(640,480,P3D);
      frameRate(targetFPS);
      g = new ProcessingDebugDraw(this);
      //smooth();
      for (int i=0; i<100; ++i) {
        this.requestFocus();
      }
      /* Register the examples */
      // Simple functionality examples
      registerExample(new SensorTest(this));
      registerExample(new BlobTest(this));
      //registerExample(new SpringRestitutionTest(this));
      registerExample(new RestitutionCannon(this));
      registerExample(new BipedTest(this));
      registerExample(new SpriteBinding(this));
      registerExample(new Pulleys(this));
      registerExample(new Overhang(this));
      registerExample(new VaryingRestitution(this));
      registerExample(new VaryingFriction(this));
      registerExample(new MotorsAndLimits(this));
      registerExample(new VerticalStack(this));
      registerExample(new Domino(this));
      registerExample(new CompoundShapes(this));
      registerExample(new Chain(this));
      registerExample(new Bridge(this));
      registerExample(new Gears(this));
      
      // Shape drawing demo
      registerExample(new ShapeDrawing(this));
      
      // Stress tests
      registerExample(new Pyramid(this));
      registerExample(new DominoTower(this));
      registerExample(new Circles(this));
      
      // Bug tests
      registerExample(new CCDTest(this));
      registerExample(new DistanceTest(this));
      //registerExample(new BugTest(this));

      //Set up the mouse wheel listener to control zooming
      addMouseWheelListener(new MouseWheelListener() {
            public void mouseWheelMoved(MouseWheelEvent e) {
              if (currentTest != null) {
                ProcessingDebugDraw d = (ProcessingDebugDraw)(currentTest.m_debugDraw);
                int notches = e.getWheelRotation();
                  Vec2 oldCenter = d.screenToWorld(width / 2.0f, height / 2.0f);
                  //Change the zoom and clamp it to reasonable values 
                  if (notches < 0) {
                    d.scaleFactor = min(300f, d.scaleFactor * 1.05f);
                  }
                  else if (notches > 0) {
                    d.scaleFactor = max(.02f, d.scaleFactor / 1.05f);
                  }
                  Vec2 newCenter = d.screenToWorld(width / 2.0f, height / 2.0f);
                  d.transX -= (oldCenter.x - newCenter.x) * d.scaleFactor;
                  d.transY -= (oldCenter.y - newCenter.y) * d.scaleFactor;
                  currentTest.cachedCamScale = d.scaleFactor;
              }
            }
        });
      
      
      /* Set up the timers for FPS reporting */
      nanos = new long[fpsAverageCount];
      long nanosPerFrameGuess = (long)(1000000000.0 / targetFPS);
      nanos[fpsAverageCount-1] = System.nanoTime();
      for (int i=fpsAverageCount-2; i>=0; --i) {
        nanos[i] = nanos[i+1] - nanosPerFrameGuess;
      }
      nanoStart = System.nanoTime();
      
      options = new TestbedOptions(this);
    }
    
    /**
     * This is the main looping function, and is called targetFPS times per second.
     * In the testbed, Processing takes care of the timing of these calls for us,
     * but in your own game you will likely need to handle that yourself.  This function
     * also keeps detailed track of the current FPS and Vec2 creations for optimization
     * purposes.
     */
    public void draw() {

      if (handleOptions) {
        options.handleOptions();
      } else{
        background(0);
        Vec2.creationCount = 0;

        /* Make sure we've got a valid test to run and reset it if needed */
        if (currentTest == null) {
          currentTestIndex = 0;
          currentTest = tests.get(currentTestIndex);
          nanoStart = System.nanoTime();
          frameCount = 0;
        }
        if (currentTest.needsReset) {
          //System.out.println("Resetting "+currentTest.getName());
          TestSettings s = currentTest.settings; //copy settings
          currentTest.initialize();
          if (s != null) currentTest.settings = s;
          nanoStart = System.nanoTime();
          frameCount = 0;
        }
        currentTest.m_textLine = AbstractExample.textLineHeight;
        g.drawString(5, currentTest.m_textLine, currentTest.getName(),AbstractExample.white);
        currentTest.m_textLine += 2*AbstractExample.textLineHeight;

        /* Take our time step (drawing is done here, too) */
        currentTest.step();

        /* If the user wants to move the canvas, do it */
        handleCanvasDrag();


        /* ==== Vec2 creation and FPS reporting ==== */
        if (currentTest.settings.drawStats) {
          g.drawString(5, currentTest.m_textLine, "Vec2 creations/frame: "+Vec2.creationCount, AbstractExample.white);
          currentTest.m_textLine += AbstractExample.textLineHeight;
        }

        for (int i=0; i<fpsAverageCount-1; ++i) {
          nanos[i] = nanos[i+1];
        }
        nanos[fpsAverageCount-1] = System.nanoTime();
        float averagedFPS = (float) ( (fpsAverageCount-1) * 1000000000.0 / (nanos[fpsAverageCount-1]-nanos[0]));
        ++frameCount;
        float totalFPS = (float) (frameCount * 1000000000 / (1.0*(System.nanoTime()-nanoStart)));        
        if (currentTest.settings.drawStats) {
          g.drawString(5, currentTest.m_textLine, "Average FPS ("+fpsAverageCount+" frames): "+averagedFPS, AbstractExample.white);
          currentTest.m_textLine += AbstractExample.textLineHeight;
          g.drawString(5, currentTest.m_textLine, "Average FPS (entire test): "+totalFPS, AbstractExample.white);
          currentTest.m_textLine += AbstractExample.textLineHeight;
        }
      }

    /* Store whether the mouse was pressed this step */
    pmousePressed = mousePressed;
    }
    
    /**
     * Allows the world to be dragged with a right-click.
     */
    public void handleCanvasDrag() {
      //Handle mouse dragging stuff
        //Left mouse attaches mouse joint to object.
        //Right mouse drags canvas.
      ProcessingDebugDraw d = (ProcessingDebugDraw)(currentTest.m_debugDraw);
    
        //Vec2 mouseWorld = d.screenToWorld(mouseX, mouseY);
        if (mouseButton == RIGHT) {
            if (mousePressed) {
                d.transX += mouseX - pmouseX;
                d.transY -= mouseY - pmouseY;
                Vec2 v = d.screenToWorld(width*.5f,height*.5f);
                currentTest.cachedCamX = v.x;
                currentTest.cachedCamY = v.y;
            }
        }
    
    }
    
    /** Dispatch mousePressed events to the current test. */
    public void mousePressed() {
      if (currentTest == null || handleOptions) return;
      currentTest.mouseDown(new Vec2(mouseX,mouseY));
    }
    
    /** Dispatch mouseReleased events to the current test. */
    public void mouseReleased() {
      if (currentTest == null || handleOptions) return;
      currentTest.mouseUp();
    }
    
    /** Dispatch mouseMoved events to the current test. */
    public void mouseMoved() {
      if (currentTest == null || handleOptions) return;
      currentTest.mouseMove(new Vec2(mouseX,mouseY));
    }
    
    /** Just report a mouseMoved event if mouseDragged. */
    public void mouseDragged() {
      mouseMoved();
    }
    
    /**
     * Apply keyboard shortcuts, do keypress handling, and then
     * send the key event to the current test if appropriate.
     */
    public void keyPressed() {
      if (key=='o') {
        handleOptions = !handleOptions;
        if (handleOptions) options.initialize(currentTest);
      }
      
      if (keyCode == PApplet.SHIFT) {
            shiftKey = true;
        }
      if (handleOptions) return;
      if (keyCode == PApplet.RIGHT) {
        ++currentTestIndex;
        if (currentTestIndex >= tests.size()) currentTestIndex = 0;
        //System.out.println(currentTestIndex);
        currentTest = tests.get(currentTestIndex);
        currentTest.needsReset = true;
        return;
      } else if (keyCode == PApplet.LEFT) {
        --currentTestIndex;
        if (currentTestIndex < 0) currentTestIndex = tests.size()-1;
        //System.out.println(currentTestIndex);
        currentTest = tests.get(currentTestIndex);
        currentTest.needsReset = true;
        return;
      }
      if (currentTest == null) return;
      if (key == 'r') currentTest.needsReset = true;
      if (key == ' ') currentTest.launchBomb();
      if (key == 'p') {
        currentTest.settings.pause = !currentTest.settings.pause;
      }
      if (key == '+' && currentTest.settings.pause) {
          currentTest.settings.singleStep = true;
        }
      if (key == 's') currentTest.settings.drawStats = !currentTest.settings.drawStats;
      if (key == 'c') currentTest.settings.drawContactPoints = !currentTest.settings.drawContactPoints;
      if (key == 'b') currentTest.settings.drawAABBs = !currentTest.settings.drawAABBs;
        
      currentTest.keyPressed(key);
    }
    
    /** Handle keyReleased events and pass them on to currentTest. */
    public void keyReleased() {
      if (keyCode == PApplet.SHIFT) {
            shiftKey = false;
        }
      if (currentTest == null) return;
      currentTest.keyReleased(key);
    }
    
    /** Register an AbstractExample to the current list of examples. */
    public void registerExample(AbstractExample test) {
      tests.add(test);
    }

    /** Start PApplet as a Java program (can also be run as an applet). */
    static public void main(String args[]) {
        PApplet.main(new String[] { "org.jbox2d.testbed.TestbedMain" });
    }

}
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.