public class Engine {
	
	private static final String TAG = "Engine";
	
	/**
	 * If the game should stop updating/rendering.
	 */
	public boolean paused = false;

	/**
	 * Cap on the elapsed time (default at 60 FPS). Raise this to allow for lower framerates (eg. 1 / 30).
	 */
	public float maxElapsed = 1/60f;

	/**
	 * The max amount of frames that can be skipped in fixed framerate mode.
	 */
	public int maxFrameSkip = 5;

	/**
	 * The amount of milliseconds between ticks in fixed framerate mode.
	 */
	public int tickRate = 4;
	
	private float mDelta = 0;
	private long mTime;
	private long mLast;
	private long mPrev;
	private Timer mTimer;
	private float mRate;
	private float mSkip;
	

	// Debug timing information.
	private long mUpdateTime;
	private long mRenderTime;
	private long mGameTime;
	private long mJavaTime;
	
	// FrameRate tracking.
	private long mFrameLast = 0;
	private long mFrameListSum = 0;
	private Vector<Long> mFrameList = new Vector<Long>();
	
	public static final Vector<Timer> TIMERS = new Vector<Timer>();
	
	
	public static int mPendingEvents = 0;
	
	public static int mEventListenersCount = 0;
	public static final OnEventListener mEventListeners[] = new OnEventListener[10];
	
	
	public static void checkEvents() {
		synchronized (mEventListeners) {
			if ((mPendingEvents & Event.TIMER) > 0) {
				for (int i = 0; i < mEventListenersCount; i++) {
					if (mEventListeners[i].type == Event.TIMER) {
						mEventListeners[i].event();
					}
				}
				mPendingEvents ^= Event.TIMER;
			} else if ((mPendingEvents & Event.ADDED_TO_STAGE) > 0) {
				for (int i = 0; i < mEventListenersCount; i++) {
					if (mEventListeners[i].type == Event.ADDED_TO_STAGE) {
						mEventListeners[i].event();
					}
				}
				mPendingEvents ^= Event.ADDED_TO_STAGE;
			} else if ((mPendingEvents & Event.ENTER_FRAME) > 0) {
				for (int i = 0; i < mEventListenersCount; i++) {
					if (mEventListeners[i].type == Event.ENTER_FRAME) {
						mEventListeners[i].event();
					}
				}
				mPendingEvents ^= Event.ENTER_FRAME;
			}
		}
	}
	
	public static void fire(int event) {
		mPendingEvents |= event;
	}
	
	private OnEventListener onStage = new OnEventListener(Event.ADDED_TO_STAGE) {
		@Override
		public void event() {
			// remove event listener
			removeEventListener(onStage);

			// switch worlds
			if (FP.mGoto != null) 
				checkWorld();

			// game start
			init();

			// start game loop
			mRate = 1000 / FP.assignedFrameRate;
			if (FP.fixed) {
				// fixed framerate
				mSkip = mRate * maxFrameSkip;
				mLast = mPrev = SystemClock.uptimeMillis();
				mTimer = new Timer(tickRate);
				addEventListener(onTimer);
				mTimer.start();
				TIMERS.add(mTimer);
			} else {
				// nonfixed framerate
				mLast = SystemClock.uptimeMillis();
				addEventListener(onEnterFrame);
			}
			
			FP.screen.resize();
		}
	};
	
	private OnEventListener onTimer = new OnEventListener(Event.TIMER) {
		@Override
		public void event() {
			// update timer
			mTime = SystemClock.uptimeMillis();
			mDelta += (mTime - mLast);
			//Log.d(TAG, String.format("Delta %f millis this frame %d to hit rate %f", mDelta, (mTime - mLast), mRate));
			mLast = mTime;

			// quit if a frame hasn't passed
			if (mDelta < mRate) 
				return;

			// update timer
			mGameTime = mTime;
			FP.javaTime = mTime - mJavaTime;

			// update console
			//if (FP._console) 
			//	FP._console.update();

			// update loop
			if (mDelta > mSkip)
				mDelta = mSkip;
			while (mDelta > mRate) {
				// update timer
				mUpdateTime = mTime;
				mDelta -= mRate;
				FP.elapsed = (mTime - mPrev) / 1000.0f;
				if (FP.elapsed > maxElapsed) 
					FP.elapsed = maxElapsed;
				FP.elapsed *= FP.rate;
				mPrev = mTime;

				// update loop
				if (!paused) 
					update();

				// update input
				Input.update();

				// update timer
				mTime = SystemClock.uptimeMillis();
				FP.updateTime = mTime - mUpdateTime;
			}

			// update timer
			mRenderTime = mTime;

			// render loop
			// Handled in GL Thread
			//if (!paused) 
			//	render();
			
			// update timer
			mTime = mJavaTime = SystemClock.uptimeMillis();
			FP.renderTime = mTime - mRenderTime;
			FP.gameTime =  mTime - mGameTime;
		}
	};
	
	private OnEventListener onEnterFrame = new OnEventListener(Event.ENTER_FRAME) {
		@Override
		public void event() {
			// update timer
			mTime = mGameTime = SystemClock.uptimeMillis();
			FP.javaTime = mTime - mJavaTime;
			mUpdateTime = mTime;
			FP.elapsed = (mTime - mLast) / 1000.0f;
			if (FP.elapsed > maxElapsed) 
				FP.elapsed = maxElapsed;
			FP.elapsed *= FP.rate;
			
			//Log.d(TAG, String.format("Elapsed %f millis delta millis %d to hit rate %f", FP.elapsed, (mTime - mLast), mRate));
			mLast = mTime;

			// update console
			//if (FP.mConsole != null) 
			//	FP.mConsole.update();
			 
			// update loop
			if (!paused) 
				update();

			// update input
			Input.update();

			// update timer
			mTime = mRenderTime = SystemClock.uptimeMillis();
			FP.updateTime = mTime - mUpdateTime;

			// render loop
			// Handled in GL Thread
			//if (!paused) 
			//	render();
			
			// update timer
			mTime = mJavaTime = SystemClock.uptimeMillis();

			FP.gameTime = mTime - mGameTime;
		}
	};

	public Engine(int width, int height) {
		this(width,height, 60, false);
	}
	/**
	 * Constructor. Defines startup information about your game.
	 * @param	width			The width of your game.
	 * @param	height			The height of your game.
	 * @param	frameRate		The game framerate, in frames per second.
	 * @param	fixed			If a fixed-framerate should be used.
	 */
	public Engine(int width, int height, float frameRate, boolean fixed) {
		// global game properties
		FP.width = width;
		FP.height = height;
		
		FP.halfWidth = width/2;
		FP.halfHeight = height/2;
		
		FP.assignedFrameRate = frameRate;
		FP.fixed = fixed;

		// global game objects
		FP.engine = this;
		FP.screen = new Screen();
		FP.bounds = new Rect(0, 0, width, height);
		FP.setWorld(new World());

		// miscellanious startup stuff
		if (FP.getRandomSeed() == 0) 
			FP.randomizeSeed();
		FP.entity = new Entity();
		FP.mTime = SystemClock.uptimeMillis();

		// on-stage event listener
		addEventListener(onStage);
		
		//Initializes the console.
		if (FP.debug) {
			FP.getConsole();
		}
	}
	
	public void addEventListener(OnEventListener listener) {
		if (mEventListenersCount < 10) {
			mEventListeners[mEventListenersCount++] = listener;
		} else {
			Log.e(TAG, "Could not add a new event listener too many listeners");
		}
	}
	
	public void removeEventListener(OnEventListener listener) {
		boolean found = false;
		for (int i = 0; i < mEventListenersCount; i++) {
			if (found) {
				if (i+1 < 9) {
					mEventListeners[i] = mEventListeners[i+1];
				} else {
					mEventListeners[i] = null;
				}
			}
			if (listener == mEventListeners[i]) {
				found = true;
				mEventListeners[i] = mEventListeners[i+1];
			}
		}
		if (found) {
			mEventListenersCount--;
		}
	}
	
	public static void clearEventListeners() {
		mEventListenersCount = 0;
	}
	
	/** @private Switch Worlds if they've changed. */
	private void checkWorld() {
		if (FP.mGoto == null) 
			return;
		World world = FP.getWorld();
		if(world != null) { 
			world.end();
			world.removeAll();
			world.updateLists();
			if (world.autoClear && world.mTween != null)
				world.clearTweens();
		}
		
		FP.mWorld = FP.mGoto;
		if (world != null) {
			world = null;
			System.gc();
			System.gc();
		}
		FP.mGoto = null;
		FP.camera = FP.mWorld.camera;
		FP.mWorld.updateLists();
		FP.mWorld.begin();
		FP.mWorld.updateLists();
		
		FP.mWorld.active = true;
	}
	
	/**
	 * Override this, called after Engine has been added to the stage.
	 */
	public void init() {

	}
	
	/**
	 * Updates the game, updating the World and Entities.
	 */
	public void update() {
		if (FP.getWorld().active) {
			if (FP.getWorld().mTween != null) 
				FP.getWorld().updateTweens();
			FP.getWorld().update();
		}
		FP.getWorld().updateLists();
		if (FP.mGoto != null)
			checkWorld();
	}
	
	/**
	 * Renders the game, rendering the World and Entities.
	 */
	public void render() {
		if (FP.getWorld() == null) {
			return;
		}
		// timing stuff
		long t = SystemClock.uptimeMillis();
		if (mFrameLast != 0) 
			mFrameLast = t;

		// render loop
		//FP.screen.swap();
		//Draw.resetTarget();
		//FP.screen.refresh();
		World world = FP.getWorld();
		if (world.visible)
			world.render();

		// more timing stuff
		t = SystemClock.uptimeMillis();
		long time = t - mFrameLast;
		mFrameListSum += time;
		mFrameList.add(time);
		if (mFrameList.size() > 10) {
			mFrameListSum -= mFrameList.get(0);
			mFrameList.remove(0);
		}
		if (mFrameListSum > 0 ) 
			FP.frameRate = 1000.0f / (mFrameListSum / mFrameList.size());
		
		mFrameLast = t;
	}
} public class Entity extends Tweener {

	private static final String TAG = "Entity";
	
    /**
     * If the Entity should render.
     */
    public boolean visible = true;

    /**
     * If the Entity should respond to collision checks.
     */
    public boolean collidable = true;

    /**
     * X position of the Entity in the World.
     */
    //public int x = 0;

    /**
     * Y position of the Entity in the World.
     */
    //public int y = 0;

    /**
     * Width of the Entity's hitbox.
     */
    public int width;

    /**
     * Height of the Entity's hitbox.
     */
    public int height;

    /**
     * X origin of the Entity's hitbox.
     */
    public int originX;

    /**
     * Y origin of the Entity's hitbox.
     */
    public int originY;

    /**
     * The BitmapData target to draw the Entity to. Leave as null to render to the current screen buffer (default).
     */
    public Bitmap renderTarget;
    
    // Entity information.
    private World mWorld;
    protected boolean mAdded;
    protected String mType = "";
    private String mName;
    private int mLayer = 0;
    protected Entity mUpdatePrev;
    protected Entity mUpdateNext;
    protected Entity mRenderPrev;
    protected Entity mRenderNext;
    protected Entity mTypePrev;
    protected Entity mTypeNext;
    
    // Collision information.
    private final Mask HITBOX = new Mask();
    private Mask mMask;
    private float mX;
    private float mY;
    private float mMoveX;
    private float mMoveY;
    
    // Rendering information.
    private Graphic mGraphic;
    private Point mPoint = FP.point;
    private Point mCamera = FP.point2;
    
    
    public Entity() {
        this(0,0, null, null);
    }
    public Entity(int x, int y) {
        this(x, y, null, null);
    }
    public Entity(int x, int y, Graphic graphic) {
        this(x, y, graphic, null);
    }
    
    public Entity(int x, int y, Graphic graphic, Mask mask) {
        this.x = x;
        this.y = y;
        if (graphic != null) { 
            mGraphic = graphic;
            mGraphic.mAssign.assigned(this);
        }
        if (mask != null) {
            mMask = mask;
        }
        HITBOX.assignTo(this);
            
    }
    
    public String toString() {
    	return String.format("%s: %s xy<%d, %d> origin<%d, %d> wh<%d, %d>", getClass().getName(), mType, x, y, originX, originY, width, height);
    }
    
    /**
	 * Override this, called when the Entity is added to a World.
	 */
	public void added() {

	}
	
	/**
	 * Override this, called when the Entity is removed from a World.
	 */
	public void removed() {

	}
	
	/**
	 * Updates the Entity.
	 */
	public void update() { 

	}
	
	/**
	 * Renders the Entity. If you override this for special behaviour,
	 * remember to call super.render() to render the Entity's graphic.
	 */
	public void render() { 
		if (mGraphic != null && mGraphic.visible) {
			if (mGraphic.relative) {
				mPoint.x = x;
				mPoint.y = y;
			}
			else 
				mPoint.x = mPoint.y = 0;
			mCamera.x = FP.camera.x;
			mCamera.y = FP.camera.y;
			//TODO replace this with GL10 gl
			mGraphic.render(OpenGLSystem.getGL(), mPoint, mCamera);
			//Log.d(TAG, "Entity rendered to " + FP.buffer.toString());
		}
	}
	
	/**
	 * Checks for a collision against an Entity type.
	 * @param	type		The Entity type to check for.
	 * @param	x			Virtual x position to place this Entity.
	 * @param	y			Virtual y position to place this Entity.
	 * @return	The first Entity collided with, or null if none were collided.
	 */
	public Entity collide(String type, int x, int y) {
		if (mWorld == null) 
			return null;

		Entity e = mWorld.mTypeFirst.get(type);
		if (!collidable || e == null) 
			return null;

		mX = this.x; mY = this.y;
		this.x = x; this.y = y;

		if (mMask == null) {
			while (e != null) {
				if (x - originX + width > e.x - e.originX
				&& y - originY + height > e.y - e.originY
				&& x - originX < e.x - e.originX + e.width
				&& y - originY < e.y - e.originY + e.height
				&& e.collidable && e != this)
				{
					if (e.mMask == null || e.mMask.collide(HITBOX))
					{
						this.x = (int)mX; this.y = (int)mY;
						return e;
					}
				}
				e = e.mTypeNext;
			}
			this.x = (int)mX; this.y = (int)mY;
			return null;
		}

		while (e != null) {
			if (x - originX + width > e.x - e.originX
			&& y - originY + height > e.y - e.originY
			&& x - originX < e.x - e.originX + e.width
			&& y - originY < e.y - e.originY + e.height
			&& e.collidable && e != this) {
				if (mMask.collide(e.mMask != null ? e.mMask : e.HITBOX)) {
					this.x = (int)mX; this.y = (int)mY;
					return e;
				}
			}
			e = e.mTypeNext;
		}
		this.x = (int)mX; this.y = (int)mY;
		return null;
	}
	
	/**
	 * Checks for collision against multiple Entity types.
	 * @param	types		An Array or Vector of Entity types to check for.
	 * @param	x			Virtual x position to place this Entity.
	 * @param	y			Virtual y position to place this Entity.
	 * @return	The first Entity collided with, or null if none were collided.
	 */
	public Entity collideTypes(Vector<String> types, int x, int y) {
		if (mWorld == null)
			return null;
		Entity e;
		for (int i = 0; i < types.size(); i++) {
			if ((e = collide(types.get(i), x, y)) != null) 
				return e;
		}
		return null;
	}
	
	/**
	 * Checks if this Entity collides with a specific Entity.
	 * @param	e		The Entity to collide against.
	 * @param	x		Virtual x position to place this Entity.
	 * @param	y		Virtual y position to place this Entity.
	 * @return	The Entity if they overlap, or null if they don't.
	 */
	public Entity collideWith(Entity e, int x, int y) {
		mX = this.x; mY = this.y;
		this.x = x; this.y = y;

		if (x - originX + width > e.x - e.originX
		&& y - originY + height > e.y - e.originY
		&& x - originX < e.x - e.originX + e.width
		&& y - originY < e.y - e.originY + e.height
		&& collidable && e.collidable)
		{
			if (mMask == null) {
				if (e.mMask == null || e.mMask.collide(HITBOX)) {
					this.x = (int)mX; this.y = (int)mY;
					return e;
				}
				this.x = (int)mX; this.y = (int)mY;
				return null;
			}
			if (mMask.collide(e.mMask != null ? e.mMask : e.HITBOX))
			{
				this.x = (int)mX; this.y = (int)mY;
				return e;
			}
		}
		this.x = (int)mX; this.y = (int)mY;
		return null;
	}
	
	/**
	 * Checks if this Entity overlaps the specified rectangle.
	 * @param	x			Virtual x position to place this Entity.
	 * @param	y			Virtual y position to place this Entity.
	 * @param	rX			X position of the rectangle.
	 * @param	rY			Y position of the rectangle.
	 * @param	rWidth		Width of the rectangle.
	 * @param	rHeight		Height of the rectangle.
	 * @return	If they overlap.
	 */
	public boolean collideRect(int x, int y, int rX, int rY, int rWidth, int rHeight) {
		if (x - originX + width >= rX && y - originY + height >= rY
		&& x - originX <= rX + rWidth && y - originY <= rY + rHeight) {
			if (mMask == null) 
				return true;
			mX = this.x; mY = this.y;
			this.x = x; this.y = y;
			FP.entity.x = rX;
			FP.entity.y = rY;
			FP.entity.width = rWidth;
			FP.entity.height = rHeight;
			if (mMask.collide(FP.entity.HITBOX)) {
				this.x = (int)mX; this.y = (int)mY;
				return true;
			}
			this.x = (int)mX; this.y = (int)mY;
			return false;
		}
		return false;
	}
	
	/**
	 * Checks if this Entity overlaps the specified position.
	 * @param	x			Virtual x position to place this Entity.
	 * @param	y			Virtual y position to place this Entity.
	 * @param	pX			X position.
	 * @param	pY			Y position.
	 * @return	If the Entity intersects with the position.
	 */
	public boolean collidePoint(int x, int y, int pX, int pY) {
		if (pX >= x - originX && pY >= y - originY
		&& pX < x - originX + width && pY < y - originY + height) {
			if (mMask == null) 
				return true;
			mX = this.x; mY = this.y;
			this.x = x; this.y = y;
			FP.entity.x = pX;
			FP.entity.y = pY;
			FP.entity.width = 1;
			FP.entity.height = 1;
			if (mMask.collide(FP.entity.HITBOX)) {
				this.x = (int)mX; this.y = (int)mY;
				return true;
			}
			this.x = (int)mX; this.y = (int)mY;
			return false;
		}
		return false;
	}
	
	/**
	 * Populates an array with all collided Entities of a type.
	 * @param	type		The Entity type to check for.
	 * @param	x			Virtual x position to place this Entity.
	 * @param	y			Virtual y position to place this Entity.
	 * @param	array		The Array or Vector object to populate.
	 * @return	The array, populated with all collided Entities.
	 */
	public void collideInto(String type, int x, int y, Vector<Entity> array) {
		if (mWorld == null) 
			return;

		Entity e = mWorld.mTypeFirst.get(type);
		if (!collidable || e == null) 
			return;

		mX = this.x; mY = this.y;
		this.x = x; this.y = y;

		if (mMask == null){
			while (e != null){
				if (x - originX + width > e.x - e.originX
				&& y - originY + height > e.y - e.originY
				&& x - originX < e.x - e.originX + e.width
				&& y - originY < e.y - e.originY + e.height
				&& e.collidable && e != this)
				{
					if (e.mMask == null || e.mMask.collide(HITBOX))
						array.add(e);
				}
				e = e.mTypeNext;
			}
			this.x = (int)mX; this.y = (int)mY;
			return;
		}

		while (e != null) {
			if (x - originX + width > e.x - e.originX
			&& y - originY + height > e.y - e.originY
			&& x - originX < e.x - e.originX + e.width
			&& y - originY < e.y - e.originY + e.height
			&& e.collidable && e != this)
			{
				if (mMask.collide(e.mMask != null ? e.mMask : e.HITBOX)) 
					array.add(e);
			}
			e = e.mTypeNext;
		}
		this.x = (int)mX; this.y = (int)mY;
		return;
	}
	
	/**
	 * Populates an array with all collided Entities of multiple types.
	 * @param	types		An array of Entity types to check for.
	 * @param	x			Virtual x position to place this Entity.
	 * @param	y			Virtual y position to place this Entity.
	 * @param	array		The Array or Vector object to populate.
	 * @return	The array, populated with all collided Entities.
	 */
	public void collideTypesInto(Vector<String> types, int x, int y, Vector<Entity> array) {
		if (mWorld == null) 
			return;
		for (int i = 0; i < types.size(); i++) {
			collideInto(types.get(i), x, y, array);
		}
	}
	
	/**
	 * If the Entity collides with the camera rectangle.
	 */
	public boolean onCamera() {
		return collideRect(x, y, FP.camera.x, FP.camera.y, FP.width, FP.height);
	}
	
	/**
	 * The World object this Entity has been added to.
	 */
	public World getWorld() {
		return mWorld;
	}
	
	/**
	 * The World object this Entity has been added to.
	 */
	public void setWorld(World w) {
		mWorld = w;
	}
	
	/**
	 * Half the Entity's width.
	 */
	public float getHalfWidth() { return width / 2; }

	/**
	 * Half the Entity's height.
	 */
	public float getHalfHeight() { return height / 2; }
	
	/**
	 * The center x position of the Entity's hitbox.
	 */
	public float getCenterX() { return x - originX + width / 2; }

	/**
	 * The center y position of the Entity's hitbox.
	 */
	public float getCenterY() { return y - originY + height / 2; }
	
	/**
	 * The leftmost position of the Entity's hitbox.
	 */
	public int getLeft() { return x - originX; }

	/**
	 * The rightmost position of the Entity's hitbox.
	 */
	public int getRight() { return x - originX + width; }
	
	/**
	 * The topmost position of the Entity's hitbox.
	 */
	public int getTop() { return y - originY; }

	/**
	 * The bottommost position of the Entity's hitbox.
	 */
	public int getBottom() { return y - originY + height; }
	
	/**
	 * The rendering layer of this Entity. Higher layers are rendered first.
	 */
	public int getLayer() { return mLayer; }
	public void setLayer(int value) {
		if (mLayer == value) 
			return;
		if (!mAdded) {
			mLayer = value;
			return;
		}
		mWorld.removeRender(this);
		mLayer = value;
		mWorld.addRender(this);
	}
	
	/**
	 * The collision type, used for collision checking.
	 */
	public String getType() { return mType; }
	public void setType(String value) {
		if (mType.equals(value))
			return;
		if (!mAdded)
		{
			mType = value;
			return;
		}
		if (!"".equals(mType)) 
			mWorld.removeType(this);
		mType = value;
		if (!"".equals(value)) 
			mWorld.addType(this);
	}
	
	/**
	 * An optional Mask component, used for specialized collision. If this is
	 * not assigned, collision checks will use the Entity's hitbox by default.
	 */
	public Mask getMask() { return mMask; }
	public void setMask(Mask value) {
		if (mMask == value) 
			return;
		if (mMask != null) 
			mMask.assignTo(null);
		mMask = value;
		if (value != null) 
			mMask.assignTo(this);
	}
	
	public Graphic getGraphic() { return mGraphic; }
    public void setGraphic(Graphic g) {
    	if (g != null) { 
            mGraphic = g;
            mGraphic.mAssign.assigned(this);
            mGraphic.active = true;
        }
    }
    
    public Graphic addGraphic(Graphic g) {
    	Graphic graphic = getGraphic();
    	if (graphic instanceof GraphicList) {
    		((GraphicList)graphic).add(g);	
    	} else {
    		GraphicList list = new GraphicList();
    		if (graphic != null) {
    			list.add(graphic);
    		}
    		setGraphic(list);
    	}
    	return g;
    }

    /**
	 * Sets the Entity's hitbox properties.
	 * @param	width		Width of the hitbox.
	 * @param	height		Height of the hitbox.
	 */
    public void setHitbox(int width, int height) {
    	setHitbox(width, height, 0, 0);
    }
    
	/**
	 * Sets the Entity's hitbox properties.
	 * @param	width		Width of the hitbox.
	 * @param	height		Height of the hitbox.
	 * @param	originX		X origin of the hitbox.
	 * @param	originY		Y origin of the hitbox.
	 */
	public void setHitbox(int width, int height, int originX, int originY) {
		this.width = width;
		this.height = height;
		this.originX = originX;
		this.originY = originY;
	}
	
	/**
	 * Sets the Entity's hitbox to match that of the provided object.
	 * @param	o		The object defining the hitbox (eg. an Image or Rectangle).
	 */
	public void setHitboxTo(Rect r) {
		setHitbox(r.width(), r.height(), -r.left, -r.top);
	}
	
	/**
	 * Sets the origin of the Entity.
	 * @param	x		X origin.
	 * @param	y		Y origin.
	 */
	public void setOrigin(int x , int y) {
		originX = x;
		originY = y;
	}
	
	/**
	 * Center's the Entity's origin (half width & height).
	 */
	public void centerOrigin() {
		originX = width / 2;
		originY = height / 2;
	}
	
	public double distanceFrom(Entity e) {
		return distanceFrom(e, false);
	}
	/**
	 * Calculates the distance from another Entity.
	 * @param	e				The other Entity.
	 * @param	useHitboxes		If hitboxes should be used to determine the distance. If not, the Entities' x/y positions are used.
	 * @return	The distance.
	 */
	public double distanceFrom(Entity e, boolean useHitboxes) {
		if (!useHitboxes) 
			return Math.sqrt((x - e.x) * (x - e.x) + (y - e.y) * (y - e.y));
		return FP.distanceRects(x - originX, y - originY, width, height, e.x - e.originX, e.y - e.originY, e.width, e.height);
	}
	
	public double distanceToPoint(int px, int py) {
		return distanceToPoint(px, py, false);
	}
	/**
	 * Calculates the distance from this Entity to the point.
	 * @param	px				X position.
	 * @param	py				Y position.
	 * @param	useHitboxes		If hitboxes should be used to determine the distance. If not, the Entities' x/y positions are used.
	 * @return	The distance.
	 */
	public double distanceToPoint(int px, int py, boolean useHitbox) {
		if (!useHitbox) 
			return Math.sqrt((x - px) * (x - px) + (y - py) * (y - py));
		return FP.distanceRectPoint(px, py, x - originX, y - originY, width, height);
	}
	
	/**
	 * Calculates the distance from this Entity to the rectangle.
	 * @param	rx			X position of the rectangle.
	 * @param	ry			Y position of the rectangle.
	 * @param	rwidth		Width of the rectangle.
	 * @param	rheight		Height of the rectangle.
	 * @return	The distance.
	 */
	public double distanceToRect(int rx, int ry, int rwidth, int rheight) {
		return FP.distanceRects(rx, ry, rwidth, rheight, x - originX, y - originY, width, height);
	}
	
	public void moveBy(int x, int y) {
		moveBy(x,y, null, false);
	}
	/**
	 * Moves the Entity by the amount, retaining integer values for its x and y.
	 * @param	x			Horizontal offset.
	 * @param	y			Vertical offset.
	 * @param	solidType	An optional collision type to stop flush against upon collision.
	 * @param	sweep		If sweeping should be used (prevents fast-moving objects from going through solidType).
	 */
	public void moveBy(int x, int y, String solidType, boolean sweep) {
		mMoveX += x;
		mMoveY += y;
		x = Math.round(mMoveX);
		y = Math.round(mMoveY);
		mMoveX -= x;
		mMoveY -= y;
		if (solidType != null) {
			int sign;
			Entity e;
			if (x != 0) {
				if (collidable && (sweep || collide(solidType, this.x + x, this.y)  != null)) {
					sign = x > 0 ? 1 : -1;
					while (x != 0) {
						if ((e = collide(solidType, this.x + sign, this.y)) != null) {
							moveCollideX(e);
							break;
						} else {
							this.x += sign;
							x -= sign;
						}
					}
				}
				else 
					this.x += x;
			}
			if (y != 0) {
				if (collidable && (sweep || collide(solidType, this.x, this.y + y) != null)) {
					sign = y > 0 ? 1 : -1;
					while (y != 0) {
						if ((e = collide(solidType, this.x, this.y + sign)) != null) {
							moveCollideY(e);
							break;
						} else {
							this.y += sign;
							y -= sign;
						}
					}
				}
				else 
					this.y += y;
			}
		} else {
			this.x += x;
			this.y += y;
		}
	}
	
	public void moveTo(int x, int y) {
		moveTo(x,y,null,false);
	}
	/**
	 * Moves the Entity to the position, retaining integer values for its x and y.
	 * @param	x			X position.
	 * @param	y			Y position.
	 * @param	solidType	An optional collision type to stop flush against upon collision.
	 * @param	sweep		If sweeping should be used (prevents fast-moving objects from going through solidType).
	 */
	public void moveTo(int x, int y, String solidType, boolean sweep) {
		moveBy(x - this.x, y - this.y, solidType, sweep);
	}
	
	public void moveTowards(int x, int y, int amount) {
		moveTowards(x, y, amount, null, false);
	}
	/**
	 * Moves towards the target position, retaining integer values for its x and y.
	 * @param	x			X target.
	 * @param	y			Y target.
	 * @param	amount		Amount to move.
	 * @param	solidType	An optional collision type to stop flush against upon collision.
	 * @param	sweep		If sweeping should be used (prevents fast-moving objects from going through solidType).
	 */
	public void moveTowards(int x, int y, int amount, String solidType, boolean sweep) {
		mPoint.x = x - this.x;
		mPoint.y = y - this.y;
		double len = PointF.length(mPoint.x, mPoint.y);
		mPoint.x /= len;
		mPoint.y /= len;
		moveBy(mPoint.x, mPoint.y, solidType, sweep);
	}
	
	/**
	 * When you collide with an Entity on the x-axis with moveTo() or moveBy().
	 * @param	e		The Entity you collided with.
	 */
	public void moveCollideX(Entity e) {

	}
	
	/**
	 * When you collide with an Entity on the y-axis with moveTo() or moveBy().
	 * @param	e		The Entity you collided with.
	 */
	public void moveCollideY(Entity e) {

	}
	
	public void clampHorizontal(int left, int right) {
		clampHorizontal(left, right, 0);
	}
	/**
	 * Clamps the Entity's hitbox on the x-axis.
	 * @param	left		Left bounds.
	 * @param	right		Right bounds.
	 * @param	padding		Optional padding on the clamp.
	 */
	public void clampHorizontal(int left, int right, int padding) {
		if (x - originX < left + padding)
			x = left + originX + padding;
		if (x - originX + width > right - padding)
			x = right - width + originX - padding;
	}
	
	public void clampVertical(int top, int bottom) {
		clampVertical(top, bottom, 0);
	}
	/**
	 * Clamps the Entity's hitbox on the y axis.
	 * @param	top			Min bounds.
	 * @param	bottom		Max bounds.
	 * @param	padding		Optional padding on the clamp.
	 */
	public void clampVertical(int top, int bottom, int padding) {
		if (y - originY < top + padding)
			y = top + originY + padding;
		if (y - originY + height > bottom - padding)
			y = bottom - height + originY - padding;
	}
} public class FP {

	private static final String TAG = "FP";
	
    /**
     * The FlashPunk major version.
     */
    public static final String VERSION = "1.6";
    
    /**
     * The default Typeface to use.
     */
    public static Typeface typeface = Typeface.DEFAULT;
    
    /**
     * Width of the game.
     */
    public static int width;
    
    /**
     * Height of the game.
     */
    public static int height;
    
    /**
     * Width of the display that is being rendered to.
     */
    public static int displayWidth;
    
    /**
     * Height of the display that is being rendered to.
     */
    public static int displayHeight;
    
    /**
     * Half width of the game.
     */
    public static float halfWidth;
    
    /**
     * Half height of the game.
     */
    public static float halfHeight;
    
    /**
     * Global scale of the game graphics.
     */
    public static float scale = 1.0f;
    
    /**
     * If the game is running at a fixed framerate.
     */
    public static boolean fixed;
    
    /**
     * If times should be given in frames (as opposed to seconds).
     * Default is true in fixed timestep mode and false in variable timestep mode.
     */
    public static boolean timeInFrames;
    
    /**
     * The framerate of the stage.
     */
    public static float frameRate;
    
    /**
     * The framerate assigned to the stage.
     */
    public static float assignedFrameRate = 60;
    
    /**
     * Time elapsed since the last frame (in seconds).
     */
    public static float elapsed;
    
    /**
     * Timescale applied to FP.elapsed.
     */
    public static float rate = 1;
    
    /**
     * The Screen object, use to transform or offset the Screen.
     */
    public static Screen screen;
    
    /**
     * Turn on debug display
     */
    public static boolean debug = false;
    
    /**
     * The current screen buffer, drawn to in the render loop.
     */
    public static Bitmap buffer;
    
    /**
     * The background screen buffer, ready to draw to screen.
     */
    public static Bitmap backBuffer;
    
    /**
     * A rectangle representing the target size of the screen.
     */
    public static Rect bounds;
    
    /**
     * Point used to determine drawing offset in the render loop.
     */
    public static Point camera = new Point();
    
    /**
     * Global Tweener for tweening values across multiple worlds.
     */
    public static Tweener tweener = new Tweener();
    
    /**
     * If the game currently has input focus or not. Note: may not be correct initially.
     */
    public static boolean focused = true;
    
    /**
     *  Used in graphics drawing to see if there is a faster way to blit.
     */
    public static boolean supportsVBOs = false;
    
    /**
     * Callback to be used when the back button is pressed.
     */
    public static OnBackCallback onBack = PunkActivity.DEFAULT_ON_BACK;
    
    /**
     * The PunkActivity that is currently running. Used to finalize from the engine.
     */
    public static PunkActivity activity;
    /**
     *  Used in graphics drawing to see if there is a the fastest way to blit.
     */
    public static boolean supportsDrawTexture = false;
    
    private static final float HSV[] = new float[3];
    
    // World information.
    protected static World mWorld;
    protected static World mGoto;

    // Console information.
    protected static Console mConsole;

    // Time information.
    protected static long mTime;
    public static long updateTime;
    public static long renderTime;
    public static long gameTime;
    public static long javaTime;

    // Pseudo-random number generation (the seed is set in Engine's constructor).
    private static long mSeed;
    private static long mGetSeed;

    // Volume control.
    private static float mVolume = 1.0f;
    private static float mPan = 0.0f;

    // Used for rad-to-deg and deg-to-rad conversion.
    public static final float DEG = (float)(-180.0 / Math.PI);
    public static final float RAD = (float)(Math.PI / -180.0);

    // Global Flash objects.
    public static Engine engine;

    // Global objects used for rendering, collision, etc.
    public static final  Point point = new Point();
    public static final Point point2 = new Point();
    public static final Point zero = new Point();
    public static final Rect rect = new Rect();
    public static final Matrix matrix = new Matrix();
    public static final Paint paint = new Paint();
    public static final Canvas canvas = new Canvas();
    public static Entity entity;
    
    public static Resources resources;
    public static Context context;

	public static boolean debugOpenGL = false;
        
    public static final float MATRIX_VALUES[] = new float[9];
    
    // Hash for caching FP.getBitmap()
    private static final HashMap<Integer, Bitmap> CACHED_BITMAPS = new HashMap<Integer, Bitmap>();
    
    /**
     * Resize the screen.
     * @param width     New width.
     * @param height    New height.
     */
    public static void resize(int width, int height) {
        FP.width = width;
        FP.height = height;
        FP.halfWidth = width/2;
        FP.halfHeight = height/2;
        FP.bounds.right = width;
        FP.bounds.bottom = height;
        FP.screen.resize();
    }
    
    public static float dip(float dip) { 
		return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dip, resources.getDisplayMetrics());
	}
    
    public static World getWorld() {
        return mWorld;
    }
    
    /**
     * The currently active World object. When you set this, the World is flagged
     * to switch, but won't actually do so until the end of the current frame.
     */
    public static void setWorld(World world) {
        if (mWorld != null && mWorld.equals(world))
            return;
        mGoto = world;
    }
    
    /**
     * Sets the camera position.
     * @param   x   X position.
     * @param   y   Y position.
     */
    public static void setCamera(int x, int y) {
        camera.x = x;
        camera.y = y;
    }
    
    /**
     * Resets the camera position.
     */
    public static void resetCamera() {
        camera.x = camera.y = 0;
    }
    
    /**
     * Global volume factor for all sounds, a value from 0 to 1.
     */
    public static float getVolume() {
    	return mVolume;
    }
    
    /**
     * Global volume factor for all sounds, a value from 0 to 1.
     */
    public static void setVolume(float value) {
        if (value < 0) 
            value = 0;
        if (mVolume == value) 
            return;
        
        Sfx.setMasterVolume(mVolume = value);
    }
    
    /**
     * Global panning factor for all sounds, a value from -1 to 1.
     */
    public static float getPan() {
        return mPan; 
    }
    
    /**
     * Global panning factor for all sounds, a value from -1 to 1.
     */
    public static void setPan(float value)
    {
        if (value < -1) 
            value = -1;
        if (value > 1) 
            value = 1;
        if (mPan == value)
            return;
        
        Sfx.setMasterPan(mPan = value);
    }
    
    /**
     * Randomly chooses and returns one of the provided values.
     * @param   objs        The Objects you want to randomly choose from. Can be ints, Numbers, Points, etc.
     * @return  A randomly chosen one of the provided parameters.
     */
    public static Object choose(Object... objs) {
        Random r = new Random();
        
        return objs[r.nextInt(objs.length)];
    }
    
    /**
     * Finds the sign of the provided value.
     * @param   value       The Number to evaluate.
     * @return  1 if value > 0, -1 if value < 0, and 0 when value == 0.
     */
    public static int sign(float value)
    {
        return value < 0 ? -1 : (value > 0 ? 1 : 0);
    }
    
    public static int sign(int value)
    {
        return value < 0 ? -1 : (value > 0 ? 1 : 0);
    }
    
    /**
     * Approaches the value towards the target, by the specified amount, without overshooting the target.
     * @param   value   The starting value.
     * @param   target  The target that you want value to approach.
     * @param   amount  How much you want the value to approach target by.
     * @return  The new value.
     */
    public static float approach(float value, float target, float amount) {
        return value < target ? (target < value + amount ? target : value + amount) : (target > value - amount ? target : value - amount);
    }

    /**
     * Linear interpolation between two values.
     * @param   a       First value.
     * @param   b       Second value.
     * @param   t       Interpolation factor.
     * @return  When t=0, returns a. When t=1, returns b. When t=0.5, will return halfway between a and b. Etc.
     */
    public static float  lerp(float a, float b, float t) {
        return a + (b - a) * t;
    }
    
    /**
     * Linear interpolation between two colors.
     * @param   fromColor       First color.
     * @param   toColor         Second color.
     * @param   t               Interpolation value. Clamped to the range [0, 1].
     * return   RGB component-interpolated color value.
     */
    public static int colorLerp(int fromColor, int toColor, float t) {
        if (t <= 0) { return fromColor; }
        if (t >= 1) { return toColor; }
        int a = Color.alpha(fromColor);
        int r = Color.red(fromColor);
        int g = Color.green(fromColor);
        int b = Color.blue(fromColor);
        
        int dA = Color.alpha(toColor) - a;
        int dR = Color.red(toColor) - r;
        int dG = Color.green(toColor) - g;
        int dB = Color.blue(toColor) -b;

        a += dA * t;
        r += dR * t;
        g += dG * t;
        b += dB * t;
        return Color.argb(a, r, g, b);
    }
    
    /**
     * Steps the object towards a point.
     * @param   object      Object to move (must have an x and y property).
     * @param   x           X position to step towards.
     * @param   y           Y position to step towards.
     * @param   distance    The distance to step (will not overshoot target).
     */
    public static void stepTowards(Positionable object, int x, int y, float distance) {
        point.x = x - object.x;
        point.y = y - object.y;
        double len = PointF.length(point.x, point.y);
        if (len <= distance)
        {
            object.x = x;
            object.y = y;
            return;
        }
        float deltax = (float)(point.x / len) * distance;
        float deltay = (float)(point.y / len) * distance;
        object.x = object.x + FP.sign(deltax) * Math.round(Math.abs(deltax));
        object.y = object.y + FP.sign(deltay) * Math.round(Math.abs(deltay));
    }
    
    /**
     * Anchors the object to a position.
     * @param   object      The object to anchor.
     * @param   anchor      The anchor object.
     * @param   distance    The max distance object can be anchored to the anchor.
     */
    public static void anchorTo(Positionable object, Positionable anchor, float distance)
    {
        point.x = object.x - anchor.x;
        point.y = object.y - anchor.y;
        double len = PointF.length(point.x, point.y);
        if (len > distance) {
            point.x /= len;
            point.y /= len;
        }
        object.x = anchor.x + point.x;
        object.y = anchor.y + point.y;
    }
    
    /**
     * Finds the angle (in degrees) from point 1 to point 2.
     * @param   x1      The first x-position.
     * @param   y1      The first y-position.
     * @param   x2      The second x-position.
     * @param   y2      The second y-position.
     * @return  The angle from (x1, y1) to (x2, y2).
     */
    public static double angle(int x1, int y1, int x2, int y2) {
        return angle((float)x1,(float)y1,(float)x2,(float)y2);
    }
    
    public static double angle(float x1, float y1, float x2, float y2) {
        double a = Math.atan2(y2 - y1, x2 - x1) * DEG;
        return a < 0 ? a + 360 : a;
    }
    
    /**
     * Sets the x/y values of the provided object to a vector of the specified angle and length.
     * @param   object      The object whose x/y properties should be set.
     * @param   angle       The angle of the vector, in degrees.
     * @param   length      The distance to the vector from (0, 0).
     * @param   x           X offset.
     * @param   y           Y offset.
     */
    public static void angleXY(Positionable object, double angle) {
        angleXY(object, angle,1,0,0);
    }
    public static void angleXY(Positionable object, double angle, double length) {
        angleXY(object, angle, length, 0, 0);
    }
    public static void angleXY(Positionable object, double angle, double length, int x) {
        angleXY(object, angle, length, x, 0);
    }
    public static void angleXY(Positionable object, double angle, double length, int x, int y) {
        angle *= RAD;
        object.x = (int)(Math.cos(angle) * length + x);
        object.y = (int)(Math.sin(angle) * length + y);
    }
    
    /**
     * Rotates the object around the anchor by the specified amount.
     * @param   object      Object to rotate around the anchor.
     * @param   anchor      Anchor to rotate around.
     * @param   angle       The amount of degrees to rotate by.
     */
    
    public static void rotateAround(Positionable object, Positionable anchor, double angle) {
        rotateAround(object, anchor, angle, true);
    }
    
    public static void rotateAround(Positionable object, Positionable anchor, double angle, boolean relative) {
        if (relative) 
            angle += FP.angle(anchor.x, anchor.y, object.x, object.y);
        FP.angleXY(object, angle, FP.distance(anchor.x, anchor.y, object.x, object.y), anchor.x, anchor.y);
    }
    
    /**
     * Gets the difference of two angles, wrapped around to the range -180 to 180.
     * @param   a   First angle in degrees.
     * @param   b   Second angle in degrees.
     * @return  Difference in angles, wrapped around to the range -180 to 180.
     */
    public static double angleDiff(double a, double b) {
        double diff = b- a;

        while (diff > 180) { diff -= 360; }
        while (diff <= -180) { diff += 360; }

        return diff;
    }
    
    
    /**
     * Find the distance from (0, 0).
     * @param   x1      The first x-position.
     * @param   y1      The first y-position.
     * @return  The distance.
     */
    public static double distance(int x1, int y1) {
        return distance(x1,y1,0,0);
    }
    
    /**
     * Find the distance between two points.
     * @param   x1      The first x-position.
     * @param   y1      The first y-position.
     * @param   x2      The second x-position.
     * @param   y2      The second y-position.
     * @return  The distance.
     */
    public static double distance(int x1, int y1, int x2, int y2) {
        return Math.sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1));
    }
    
    /**
     * Find the distance between two rectangles. Will return 0 if the rectangles overlap.
     * @param   x1      The x-position of the first rect.
     * @param   y1      The y-position of the first rect.
     * @param   w1      The width of the first rect.
     * @param   h1      The height of the first rect.
     * @param   x2      The x-position of the second rect.
     * @param   y2      The y-position of the second rect.
     * @param   w2      The width of the second rect.
     * @param   h2      The height of the second rect.
     * @return  The distance.
     */
    public static double distanceRects(int x1, int y1, int w1, int h1, int x2, int y2, int w2, int h2) {
        if (x1 < x2 + w2 && x2 < x1 + w1)
        {
            if (y1 < y2 + h2 && y2 < y1 + h1) 
                return 0;
            if (y1 > y2) 
                return y1 - (y2 + h2);
            return y2 - (y1 + h1);
        }
        if (y1 < y2 + h2 && y2 < y1 + h1)
        {
            if (x1 > x2) 
                return x1 - (x2 + w2);
            return x2 - (x1 + w1);
        }
        if (x1 > x2)
        {
            if (y1 > y2) 
                return distance(x1, y1, (x2 + w2), (y2 + h2));
            return distance(x1, y1 + h1, x2 + w2, y2);
        }
        if (y1 > y2) 
            return distance(x1 + w1, y1, x2, y2 + h2);
        return distance(x1 + w1, y1 + h1, x2, y2);
    }
    
    /**
     * Find the distance between a point and a rectangle. Returns 0 if the point is within the rectangle.
     * @param   px      The x-position of the point.
     * @param   py      The y-position of the point.
     * @param   rx      The x-position of the rect.
     * @param   ry      The y-position of the rect.
     * @param   rw      The width of the rect.
     * @param   rh      The height of the rect.
     * @return  The distance.
     */
    public static double distanceRectPoint(int px, int py, int rx, int ry, int rw, int rh) {
        if (px >= rx && px <= rx + rw)
        {
            if (py >= ry && py <= ry + rh) 
                return 0;
            if (py > ry) 
                return py - (ry + rh);
            return ry - py;
        }
        if (py >= ry && py <= ry + rh)
        {
            if (px > rx) 
                return px - (rx + rw);
            return rx - px;
        }
        if (px > rx)
        {
            if (py > ry) 
                return distance(px, py, rx + rw, ry + rh);
            return distance(px, py, rx + rw, ry);
        }
        if (py > ry) 
            return distance(px, py, rx, ry + rh);
        return distance(px, py, rx, ry);
    }
    
    /**
     * Clamps the value within the minimum and maximum values.
     * @param   value       The Number to evaluate.
     * @param   min         The minimum range.
     * @param   max         The maximum range.
     * @return  The clamped value.
     */
    public static int clamp(int value, int min, int max)
    {
        if (max > min)
        {
            value = value < max ? value : max;
            return value > min ? value : min;
        }
        value = value < min ? value : min;
        return value > max ? value : max;
    }
    
    /**
     * Clamps the object inside the rectangle.
     * @param   object      The object to clamp (must have an x and y property).
     * @param   x           Rectangle's x.
     * @param   y           Rectangle's y.
     * @param   width       Rectangle's width.
     * @param   height      Rectangle's height.
     */
    public static void clampInRect(Positionable object, int x, int y, int width, int height) {
        clampInRect(object, x, y, width, height, 0);
    }
    
    /**
     * Clamps the object inside the rectangle.
     * @param   object      The object to clamp (must have an x and y property).
     * @param   x           Rectangle's x.
     * @param   y           Rectangle's y.
     * @param   width       Rectangle's width.
     * @param   height      Rectangle's height.
     * @param   padding     Padding on the Rectangle.
     */
    public static void clampInRect(Positionable object, int x, int y, int width, int height, int padding) {
        object.x = clamp(object.x, x + padding, x + width - padding);
        object.y = clamp(object.y, y + padding, y + height - padding);
    }
    
    /**
     * Transfers a value from one scale to another scale. For example, scale(.5, 0, 1, 10, 20) == 15, and scale(3, 0, 5, 100, 0) == 40.
     * @param   value       The value on the first scale.
     * @param   min         The minimum range of the first scale.
     * @param   max         The maximum range of the first scale.
     * @param   min2        The minimum range of the second scale.
     * @param   max2        The maximum range of the second scale.
     * @return  The scaled value.
     */
    public static double scale(double value, double min, double max, double min2, double max2) {
        return min2 + ((value - min) / (max - min)) * (max2 - min2);
    }
    
    /**
     * Transfers a value from one scale to another scale, but clamps the return value within the second scale.
     * @param   value       The value on the first scale.
     * @param   min         The minimum range of the first scale.
     * @param   max         The maximum range of the first scale.
     * @param   min2        The minimum range of the second scale.
     * @param   max2        The maximum range of the second scale.
     * @return  The scaled and clamped value.
     */
    public static double scaleClamp(double value, double min, double max, double min2, double max2) {
        value = min2 + ((value - min) / (max - min)) * (max2 - min2);
        if (max2 > min2)
        {
            value = value < max2 ? value : max2;
            return value > min2 ? value : min2;
        }
        value = value < min2 ? value : min2;
        return value > max2 ? value : max2;
    }
    
    /**
     * The random seed used by FP's random functions.
     */
    public static long getRandomSeed() {
        return mGetSeed;
    }
    
    public static void setRandomSeed(int value) {
        mSeed = FP.clamp(value,1, Integer.MAX_VALUE);
        mGetSeed = mSeed;
    }
    
    /**
     * Randomizes the random seed using Java's Math.random() function.
     */
    public static void randomizeSeed() {
        setRandomSeed((int)(Integer.MAX_VALUE * Math.random()));
    }
    
    /**
     * A pseudo-random Number produced using FP's random seed, where 0 <= Number < 1.
     */
    public static double random() {
        mSeed = (mSeed * 16807) % Integer.MAX_VALUE;
        return (double)mSeed / Integer.MAX_VALUE;
    }
    
    /**
     * Returns a pseudo-random uint.
     * @param   amount      The returned int will always be 0 <= uint < amount.
     * @return  The uint.
     */
    public static int rand(int amount) {
        mSeed = (mSeed * 16807) % Integer.MAX_VALUE;
        return (int)(((double)mSeed / Integer.MAX_VALUE) * amount);
    }
    
    /**
	 * Returns the next item after current in the list of options.
	 * @param	current		The currently selected item (must be one of the options).
	 * @param	options		An array of all the items to cycle through.
	 * @param	loop		If true, will jump to the first item after the last item is reached.
	 * @return	The next item in the list.
	 */
	public static Object next(Object current, Object[] options, boolean loop) {
		
		for (int i = 0; i < options.length; i++) {
			if (options[i].equals(current)) {
				if (loop) {
					return options[i+1 % options.length];
				} else {
					return options[Math.max(i + 1, options.length - 1)];
				}
			}
		}
		return null;
	}
	
	/**
	 * Returns the item previous to the current in the list of options.
	 * @param	current		The currently selected item (must be one of the options).
	 * @param	options		An array of all the items to cycle through.
	 * @param	loop		If true, will jump to the last item after the first is reached.
	 * @return	The previous item in the list.
	 */
	public static Object prev(Object current, Object[] options, boolean loop) {
		
		for (int i = 0; i < options.length; i++) {
			if (options[i].equals(current)) {
				if (loop) {
					return options[(i-1 + options.length) % options.length];
				} else {
					return options[Math.max(i - 1, 0)];
				}
			}
		}
		return null;
	}
	
	/**
	 * Swaps the current item between a and b. Useful for quick state/string/value swapping.
	 * @param	current		The currently selected item.
	 * @param	a			Item a.
	 * @param	b			Item b.
	 * @return	Returns a if current is b, and b if current is a.
	 */
	public static Object swap(Object current, Object a, Object b) {
		return (current == a) ? b : a;
	}

	
	/**
	 * Creates a color value by combining the chosen RGB values.
	 * @param	R		The red value of the color, from 0 to 255.
	 * @param	G		The green value of the color, from 0 to 255.
	 * @param	B		The blue value of the color, from 0 to 255.
	 * @return	The color uint.
	 */
	public static int getColorRGB(int r, int g, int b) {
		return Color.rgb(r, g, b);
	}
	
	/**
	 * Creates a color value with the chosen HSV values.
	 * @param	h		The hue of the color (from 0 to 1).
	 * @param	s		The saturation of the color (from 0 to 1).
	 * @param	v		The value of the color (from 0 to 1).
	 * @return	The color uint.
	 */
	public static int getColorHSV(float h, float s, float v) {
		
		HSV[0] = h;
		HSV[1] = s;
		HSV[2] = v;
		return Color.HSVToColor(HSV);
	}
	
	/**
	 * Finds the red factor of a color.
	 * @param	color		The color to evaluate.
	 * @return	A uint from 0 to 255.
	 */
	public static int getRed(int color) {
		return Color.red(color);
	}
	
	/**
	 * Finds the green factor of a color.
	 * @param	color		The color to evaluate.
	 * @return	A uint from 0 to 255.
	 */
	public static int getGreen(int color) {
		return Color.green(color);
	}
	
	/**
	 * Finds the blue factor of a color.
	 * @param	color		The color to evaluate.
	 * @return	A uint from 0 to 255.
	 */
	public static int getBlue(int color) {
		return Color.blue(color);
	}
	
	/**
	 * Sets a time flag.
	 * @return	Time elapsed (in milliseconds) since the last time flag was set.
	 */
	public static long timeFlag() {
		long t = System.currentTimeMillis();
		long e = t - mTime;
		mTime = t;
		return e;
	}
	
	/**
	 * The global Console object.
	 */
	public static Console getConsole() {
		if (mConsole == null) 
			mConsole = new Console();
		return mConsole;
	}
	
	/**
	 * Logs data to the console.
	 * @param	...data		The data parameters to log, can be variables, objects, etc. Parameters will be separated by a space (" ").
	 */
	public static void log(Object... data) {
		if (mConsole != null) {
			if (data.length > 1) {
				int i = 0;
				String s = "";
				while (i < data.length)
				{
					if (i > 0)
						s += " ";
					s += data[i++].toString();
				}
				mConsole.log(s);
			} else {
				mConsole.log(data[0].toString());
			}
		}
	}
	
	
	/**
	 * Get a list of a directory of the assets path.
	 * @param path to check for files
	 * @return a string array of the filenames.
	 */
	public static String[] getAssetList(String path) {
		try {
			return FP.context.getAssets().list(path);
		} catch (IOException e) {
			e.printStackTrace();
		}
		return null;
	}
	
	/**
	 * Get the file descriptor of an asset.
	 * @param path to the file.
	 * @return the file descriptor for the asset. 
	 */
	public static InputStream getAsset(String file) {
		try {
			return FP.context.getAssets().open(file);
		} catch (IOException e) {
			e.printStackTrace();
		}
		return null;
	}
	
	/**
	 * Loads the file as an XML object.
	 * @param	file		The embedded file to load.
	 * @return	An XML object representing the file.
	 */
	public static Document getXML(int resId) {
		return createDocument(FP.context.getResources().openRawResource(resId));
		
	}
	
	/**
	 * Loads the file as an XML object.
	 * @param	assetFile		The asset file to load.
	 * @return	An XML object representing the file.
	 */
	public static Document getXML(String assetFile) {
		return createDocument(getAsset(assetFile));
	}
	
	private static Document createDocument(InputStream is) {
		if (is == null) {
			return null;
		}
		DocumentBuilderFactory builderfactory = DocumentBuilderFactory.newInstance();
		Document d;
		try {
			d = builderfactory.newDocumentBuilder().parse(is);
			return d;
		} catch (SAXException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} catch (ParserConfigurationException e) {
			e.printStackTrace();
		}
		return null;
	}
	
	public static Map<String, Number> tweenmap(String k1, Number v1) {
		return tweenmap(k1, v1, null, null, null, null, null, null, null, null);
	}
	
	public static Map<String, Number> tweenmap(String k1, Number v1, String k2, Number v2) {
		return tweenmap(k1,v1,k2,v2, null, null, null, null, null, null);
	}
	
	public static Map<String, Number> tweenmap(String k1, Number v1, String k2, Number v2,  String k3, Number v3) {
		return tweenmap(k1,v1,k2,v2,k3,v3, null, null, null, null);
	}
	
	public static Map<String, Number> tweenmap(String k1, Number v1, String k2, Number v2, String k3, Number v3,  String k4, Number v4) {
		return tweenmap(k1,v1,k2,v2,k3,v3,k4,v4, null, null);
	}
	
	public static Map<String, Number> tweenmap(String k1, Number v1, String k2, Number v2,
											String k3, Number v3, String k4, Number v4,
											String k5, Number v5) {
		Map<String, Number> theMap = new HashMap<String, Number>();
		
		if (k5 != null) 
			theMap.put(k5, v5);
		if (k4 != null) 
			theMap.put(k4, v4);
		if (k3 != null) 
			theMap.put(k3, v3);
		if (k2 != null) 
			theMap.put(k2, v2);
		if (k1 != null) 
			theMap.put(k1, v1);
		
		return theMap;
	}
	
	public static class TweenOptions {
		int type;
		OnCompleteCallback complete;
		OnEaseCallback ease;
		Tweener tweener;
		
		public TweenOptions(int theType, OnCompleteCallback theComplete, OnEaseCallback theEase, Tweener theTweener) {
			type = theType;
			complete = theComplete;
			ease = theEase;
			tweener = theTweener;
		}
	}
	
	public static MultiVarTween tween(Object object, Map<String, Number> values, float duration) {
		return tween(object, values, duration, null);
	}
	/**
	 * Tweens numeric public properties of an Object. Shorthand for creating a MultiVarTween tween, starting it and adding it to a Tweener.
	 * @param	object		The object containing the properties to tween.
	 * @param	values		An object containing key/value pairs of properties and target values.
	 * @param	duration	Duration of the tween.
	 * @param	options		An object containing key/value pairs of the following optional parameters:
	 * 						type		Tween type.
	 * 						complete	Optional completion callback function.
	 * 						ease		Optional easer function.
	 * 						tweener		The Tweener to add this Tween to.
	 * @return	The added MultiVarTween object.
	 * 
	 * Example: FP.tween(object, { x: 500, y: 350 }, 2.0, { ease: easeFunction, complete: onComplete } );
	 */
	
	public static MultiVarTween tween(Object object, Map<String, Number> values, float duration, TweenOptions options) {
		int type = Tween.ONESHOT;
		OnCompleteCallback complete = null;
		OnEaseCallback ease = null;
		Tweener tweener = FP.getWorld();
		
		if (object instanceof Tweener)  
			tweener = (Tweener)object;
		if (options != null){
			type = options.type;
			complete = options.complete;
			ease = options.ease;
			tweener = options.tweener;
		}
		MultiVarTween tween = new MultiVarTween(complete, type);
		tween.tween(object, values, duration, ease);
		tweener.addTween(tween);
		return tween;
	} 
	
	public static int[] frames(int from, int to) {
		return frames(from, to, 0);
	}
	
	/**
	 * Gets an array of frame indices.
	 * @param	from	Starting frame.
	 * @param	to		Ending frame.
	 * @param	skip	Skip amount every frame (eg. use 1 for every 2nd frame).
	 */
	public static int[] frames(int from, int to, int skip) {
		int index = 0;
		skip++;
		int a[] = new int[(int)(Math.abs(to - from) / skip) + 1];
		if (from < to) {
			while (from <= to) {
				a[index++] = from;
				from += skip;
			}
		} else {
			while (from >= to) {
				a[index++] = from;
				from -= skip;
			}
		}
		return a;
	}
	
	/**
	 * Shuffles the elements in the array.
	 * @param	a		The Object to shuffle (an Array or Vector).
	 */
	public static void shuffle(Object[] a) {
		int i = a.length;
		int j;
		Object t;
		
		while (--i > 0) {
			t = a[i];
			a[i] = a[j = FP.rand(i + 1)];
			a[j] = t;
		}
	}
	
	/**
	 * Shuffles the elements in the array.
	 * @param	a		The Object to shuffle (an Array or Vector).
	 */
	public static void shuffle(Vector<Object> a) {
		int i = a.size();
		int j;
		Object t;
		
		while (--i > 0) {
			t = a.get(i);
			a.add(i, a.get(j = FP.rand(i + 1)));
			a.add(j, t);
		}
	}
	
	/**
	 * Get a bitmap from the Android resource package using Resource id. Consider these immutable and cached.
	 * 
	 * Make a copy if you need to edit it.
	 * @param resId the resource id to load.
	 * @return A bitmap of resource id for the current display density.
	 */
	public static Bitmap getBitmap(int resId) {
		Bitmap bm = CACHED_BITMAPS.get(resId);
		if (bm == null) {
			//TODO do something with scale.
			Drawable d = FP.resources.getDrawable(resId);
			bm = ((BitmapDrawable) d).getBitmap();
			CACHED_BITMAPS.put(resId, bm);
		}
		return bm;
	}
	
	public static void clearCachedBitmaps() {
		Iterator<Integer> it = CACHED_BITMAPS.keySet().iterator();
		while (it.hasNext()) {
			int i = it.next();
			it.remove();
		}
	}
} public class Graphic {
	
	public interface OnAssignToEntityCallback {
		public void assigned(Entity e);
	}
    
	private static final OnAssignToEntityCallback NULL_CALLBACK = new OnAssignToEntityCallback() {
		public void assigned(Entity e) { }
	};
	
    /**
     * If the graphic should update.
     */
    public boolean active = false;
    
    /**
     * If the graphic should render.
     */
    public boolean visible = true;
    
    /**
     * X offset.
     */
    public float x = 0;
    
    /**
     * Y offset.
     */
    public float y = 0;
    
    /**
     * X scrollfactor, effects how much the camera offsets the drawn graphic.
     * Can be used for parallax effect, eg. Set to 0 to follow the camera,
     * 0.5 to move at half-speed of the camera, or 1 (default) to stay still.
     */
    public float scrollX = 1;
    
    /**
     * Y scrollfactor, effects how much the camera offsets the drawn graphic.
     * Can be used for parallax effect, eg. Set to 0 to follow the camera,
     * 0.5 to move at half-speed of the camera, or 1 (default) to stay still.
     */
    public float scrollY = 1;
    
    /**
     * If the graphic should render at its position relative to its parent Entity's position.
     */
    public boolean relative = true;
    
    protected final Point mPoint = new Point();
    protected OnAssignToEntityCallback mAssign = NULL_CALLBACK;
    
    /**
     * Constructor.
     */
    public Graphic() {
        
    }
    
    /**
     * Updates the graphic
     */
    public void update() {
    }

    /**
     * Renders the graphic to the screen buffer.
     * @param the GL context we are drawing to.
     * @param point The position to draw the graphic.
     * @param camera The camera offset.
     */
    public void render(GL10 gl, Point point, Point camera) {
    	
    }
    
    protected void setOnAssign(OnAssignToEntityCallback func) { 
        mAssign = func;
    }
    
    protected OnAssignToEntityCallback getOnAssignToEntityCallback() { 
        return mAssign;
    }
    
    /**
     * Releases any native memory, like bitmaps, So that memory is handled better. 
     */
    protected void release() {
    	
    }
    
    public void reload() {
    	
    }
} public class Sfx {
	
	private static final String TAG = "Sfx";
	
	/**
	 * Optional callback function for when the sound finishes playing.
	 */
	public OnCompleteCallback complete;
	
	private static float GLOBAL_VOLUME = 1.0f;
	private static float GLOBAL_PAN = 0.0f;
	
	public static SoundPool SOUND_POOL = new SoundPool(32, AudioManager.STREAM_MUSIC, 0);
	public static final Vector<Sfx> SOUNDS = new Vector<Sfx>();
	
	private int mSoundId;
	private int mStreamId;
	
	// Sound infromation.
	private float mVolume = 1.0f;
	private float mPan = 0.0f;
	private boolean mLooping = false;
	private boolean mPlayed = false;
	
	public static void setMasterVolume(float volume) {
		GLOBAL_VOLUME = volume;
		for(Sfx s : SOUNDS) {
			// reset using the new global volume
			s.setVolume(s.getVolume());
		}
	}
	
	public static void setMasterPan(float pan) {
		GLOBAL_PAN = pan;
		for(Sfx s : SOUNDS) {
			// reset using the new global pan
			s.setPan(s.getPan());
		}
	}
	
	/**
	 * Creates a sound effect from an raw resource. Store a reference to
	 * this object so that you can play the sound using play() or loop().
	 * @param	source		The embedded sound resource to use.
	 */
	public Sfx(int resId) {
		this(resId, null);
	}
	
	/**
	 * Creates a sound effect from an raw resource. Store a reference to
	 * this object so that you can play the sound using play() or loop().
	 * @param	source		The embedded sound resource to use.
	 * @param	complete	Optional callback function for when the sound finishes playing.
	 */
	public Sfx(int resId, OnCompleteCallback completeFunction) {
		complete = completeFunction;
		initSoundPool();
		mSoundId = SOUND_POOL.load(FP.context, resId, 1);
		if (mSoundId > 0) {
			SOUNDS.add(this);
		}
	}
	
	/**
	 * Creates a sound effect from an asset source. Store a reference to
	 * this object so that you can play the sound using play() or loop().
	 * @param	source		The embedded sound class to use.
	 */
	public Sfx(AssetFileDescriptor assetFd) {
		this(assetFd, null);
	}
	
	/**
	 * Creates a sound effect from an asset source. Store a reference to
	 * this object so that you can play the sound using play() or loop().
	 * @param	source		The embedded sound class to use.
	 * @param	complete	Optional callback function for when the sound finishes playing.
	 */
	public Sfx(AssetFileDescriptor assetFd, OnCompleteCallback completeFunction) {
		complete = completeFunction;
		initSoundPool();
		mSoundId = SOUND_POOL.load(assetFd, 1);
		if (mSoundId > 0) {
			SOUNDS.add(this);
		}
	}
	
	/**
	 * Creates a sound effect from an file path. Store a reference to
	 * this object so that you can play the sound using play() or loop().
	 * @param	source		The embedded sound class to use.
	 */
	public Sfx(String path) {
		this(path, null);
	}
	
	/**
	 * Creates a sound effect from an file path. Store a reference to
	 * this object so that you can play the sound using play() or loop().
	 * @param	source		The embedded sound class to use.
	 * @param	complete	Optional callback function for when the sound finishes playing.
	 */
	public Sfx(String path, OnCompleteCallback completeFunction) {
		complete = completeFunction;
		initSoundPool();
		mSoundId = SOUND_POOL.load(path, 1);
		if (mSoundId > 0) {
			SOUNDS.add(this);
		}
	}
	
	private void initSoundPool() {
		if (SOUND_POOL == null) {
			SOUND_POOL = new SoundPool(32, AudioManager.STREAM_MUSIC, 0);
		}
	}
	
	private void play(float vol, float pan, int loop) {
		float left, right;
		
		mVolume = vol;
		mPan = pan;
		
		left = leftPan(vol, pan);
		right = rightPan(vol, pan);
		
		SOUND_POOL.stop(mStreamId);
		mStreamId = SOUND_POOL.play(mSoundId, left, right, 0, loop, 1.0f);
		
		mPlayed = true;
	}
	
	private float leftPan(float vol, float pan) {
		return pan > 0 ? (1.0f - pan) * (vol * GLOBAL_VOLUME) : vol * GLOBAL_VOLUME;
	}
	
	private float rightPan(float vol, float pan) {
		return pan > 0 ? (1.0f - pan) * (vol * GLOBAL_VOLUME) : vol * GLOBAL_VOLUME;
	}
	
	/**
	 * Plays the sound once at max volume
	 */
	public void play() {
		play(1.0f, 0);
	}
	
	/**
	 * Plays the sound once with even panning.
	 * @param	vol		Volume factor, a value from 0 to 1.
	 */
	public void play(float vol) {
		play(vol, 0);
	}
	
	/**
	 * Plays the sound once.
	 * @param	vol		Volume factor, a value from 0 to 1.
	 * @param	pan		Panning factor, a value from -1 to 1.
	 */
	public void play(float vol, float pan) {
		play(vol, pan, 0);
	}
	
	/**
	 * Plays the sound looping at max volume. Will loop continuously until you call stop(), play(), or loop() again.
	 * @param	vol		Volume factor, a value from 0 to 1.
	 */
	public void loop() {
		loop(1.0f, 0);
	}
	
	/**
	 * Plays the sound looping. Will loop continuously until you call stop(), play(), or loop() again.
	 * @param	vol		Volume factor, a value from 0 to 1.
	 */
	public void loop(float vol) {
		loop(vol, 0);
	}
	
	/**
	 * Plays the sound looping. Will loop continuously until you call stop(), play(), or loop() again.
	 * @param	vol		Volume factor, a value from 0 to 1.
	 * @param	pan		Panning factor, a value from -1 to 1.
	 */
	public void loop(float vol, float pan) {
		play(vol, pan, -1);
		mLooping = true;
	}
	
	/**
	 * Will set the sound to stop looping after this last playout.
	 */
	public void stopLooping() {
		SOUND_POOL.setLoop(mStreamId, 0);
		mLooping = false;
	}
	
	/**
	 * Stops the sound if it is currently playing.
	 * @return
	 */
	public boolean stop() {
		SOUND_POOL.pause(mStreamId);
		mLooping = false;
		return true;
	}
	
	/**
	 * Resumes the sound from the position stop() was called on it.
	 */
	public void resume() {
		SOUND_POOL.resume(mStreamId);
	}
	
	/**
	 * Get the volume factor (a value from 0 to 1) of the sound during playback.
	 */
	public float getVolume() { return mVolume; }
	
	/**
	 * Alter the volume factor (a value from 0 to 1) of the sound during playback.
	 */
	public void setVolume(float value) {
		if (value < 0) 
			value = 0;
		if (mVolume == value) 
			return;
		mVolume = value;
		SOUND_POOL.setVolume(mStreamId, leftPan(mVolume, mPan), rightPan(mVolume, mPan));
	}
	
	/**
	 * Get the panning factor (a value from -1 to 1) of the sound during playback.
	 */
	public float getPan() { return mPan; }
	
	/**
	 * Alter the panning factor (a value from -1 to 1) of the sound during playback.
	 */
	public void setPan(float value) {
		if (value < -1) 
			value = -1;
		if (value > 1) 
			value = 1;
		if (mPan == value) 
			return;
		mPan = value;
		SOUND_POOL.setVolume(mStreamId, leftPan(mVolume, mPan), rightPan(mVolume, mPan));
	}
	
	/**
	 * If the sound has been played.
	 */
	public boolean getPlayed() { return mPlayed; }
	
	/**
	 * If the sound is currently playing. Only knows if it is looping.
	 */
	public boolean getPlaying() { return mLooping && mPlayed; }
	
	public void release() {
		SOUND_POOL.unload(mStreamId);
		SOUNDS.remove(this);
	}
	
	public static void releaseAll() {
		if (SOUND_POOL != null) {
			SOUND_POOL.release();
			SOUND_POOL = null;
		}
		SOUNDS.clear();
	}
}
 public class Event {
	public static abstract class OnEventListener {
		public int type;
		public OnEventListener(int eventType) {
			this.type = eventType;
		}
		public abstract void event();
	}
	
	/**
	 * When the surface is ready to draw.
	 */
	public static final int ADDED_TO_STAGE = 1;
	/**
	 * Screen has refreshed.
	 */
	public static final int ENTER_FRAME = 2;
	/**
	 * When a timer fires.
	 */
	public static final int TIMER = 4;
}
 public class Timer {

	private long mElapsed = 0;
	private long mStart;
	private boolean mRunning;
	private long mTickRate;
	
	private static Thread TIMER_THREAD;
	
	public Timer(long tickRate) {
		mTickRate = tickRate;
		Engine.TIMERS.add(this);
	}
	
	public void start() {
		mStart = System.currentTimeMillis();
		mRunning = true;
		if (TIMER_THREAD == null || !TIMER_THREAD.isAlive()) {
			TIMER_THREAD = new Thread(new Runnable() {
				
				public void run() {
					while (mRunning) {
						update();
						try {
							Thread.sleep(4);
						} catch (InterruptedException e) {
							e.printStackTrace();
						}
					}
				}
			});
			TIMER_THREAD.start();
		}
	}
	
	public void stop() {
		mRunning = false;
	}
	
	public void update() {
		mElapsed = System.currentTimeMillis() - mStart;
		if (mElapsed > mTickRate) {
			Engine.fire(Event.TIMER);
			mStart = System.currentTimeMillis();
		}
	}
}
 @Deprecated
public class Text extends Graphic {

	private static final String TAG = "Text";
	
	/**
	 * Rotation of the image, in degrees.
	 */
	public float angle = 0;

	/**
	 * Scale of the image, effects both x and y scale.
	 */
	public float scale = 1;

	/**
	 * X scale of the image.
	 */
	public float scaleX = 1;

	/**
	 * Y scale of the image.
	 */
	public float scaleY = 1;

	/**
	 * X origin of the image, determines transformation point.
	 */
	public int originX;

	/**
	 * Y origin of the image, determines transformation point.
	 */
	public int originY;
	
	private int mTextSize;
	private String mText;
	private Typeface mTypeface;
	private Texture mTexture = new Texture();
	
	private final Rect mRect = new Rect();
	
	private int mColor = 0xffffffff;
	
	private static final Canvas mCanvas = new Canvas();
	private final Paint mPaint = new Paint();
	
	private FloatBuffer mVertexBuffer = AtlasGraphic.getDirectFloatBuffer(8);
	private FloatBuffer mTextureBuffer = AtlasGraphic.getDirectFloatBuffer(8);
	
	public Text(String text) {
		this(text, 20, null);
	}
	
	public Text(String text, int textSize) {
		this(text, textSize, null);
	}
	public Text(String text, int textSize, Typeface tf) {
		super();
		mText = text;
		mTextSize = textSize;
		mTypeface = tf;
		
		updateTexture();
	}
	
	public void setTypeFace(Typeface tf) {
		mTypeface = tf;
		
		updateTexture();
	}
	
	public void setText(String text) {
		if (text.equals(mText)) {
			return;
		}
		mText = text;
		
		updateTexture();
	}

	private void updateTexture() {
		if (mTexture.isLoaded()) {
			// Will allow us to load on this texture again.
			mTexture.release();
		}
		mPaint.reset();
		if (mTypeface != null) {
			mPaint.setTypeface(mTypeface);
		}
		mPaint.setTextSize(mTextSize);
		
		mPaint.setColor(0xffffffff);
		mPaint.setStyle(Style.FILL);
		
		int width = (int)mPaint.measureText(mText);
		int height = (int)(-mPaint.ascent() + mPaint.descent());
		Bitmap newBuffer = Bitmap.createBitmap(Texture.nextHigher2(width), Texture.nextHigher2(height), Config.ARGB_8888);
		mCanvas.setBitmap(newBuffer);
		mCanvas.drawText(mText, 0, -mPaint.ascent(), mPaint);
		
		mRect.set(0, 0, width, height);
		
		mTexture.setTextureBitmap(newBuffer);
		
		AtlasGraphic.setGeometryBuffer(mVertexBuffer, mRect);
		AtlasGraphic.setTextureBuffer(mTextureBuffer, mTexture, mRect);
	}
	
	@Override 
	public void reload() {
		updateTexture();
	}
	
	@Override
	public void render(GL10 gl, Point point, Point camera) {
		super.render(gl, point, camera);
		if (!mTexture.isLoaded()) {
			return;
		}
		
		mTexture.mColorFilter.setColor(mColor);
		mTexture.mColorFilter.applyColorFilter(gl);
		OpenGLSystem.setTexture(gl, mTexture);
		
		mPoint.x = (int)(point.x + x - camera.x * scrollX);
		mPoint.y = (int)(point.y + y - camera.y * scrollY);
		
		gl.glEnable(GL10.GL_TEXTURE_2D);
		gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
		
		gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, mTextureBuffer);
    	gl.glVertexPointer(2, GL10.GL_FLOAT, 0, mVertexBuffer);
    	
    	gl.glPushMatrix();
    	{
    		setMatrix(gl);
			gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, 4);
    	}
    	gl.glPopMatrix();
	}
	
	protected void setMatrix(GL10 gl) {
		
		float sX = scaleX * scale;
		float sY = scaleY * scale;
		
		
		gl.glTranslatef(originX + mPoint.x, originY + mPoint.y, 0f);
		
		if (angle != 0) {
			gl.glRotatef(angle, 0, 0, 1.0f);
		}
		gl.glScalef(sX, sY, 1.0f);
		gl.glTranslatef(-originX, -originY, 0.0f);
	}
	
	/**
	 * The tinted color of the Image. Use 0xFFFFFFFF to draw the Image normally.
	 */
	public int getColor() { 
		return mColor; 
	}
	
	/**
	 * The tinted color of the Image. Use 0xFFFFFFFF to draw the Image normally.
	 */
	public void setColor(int value) {
		mColor = value;
	}
	
	public int getWidth() {
		return mRect.width();
	}

	public int getHeight() {
		return mRect.height();
	}
	
	public static final Typeface getFontFromRes(int resource)
	{ 
	    Typeface tf = null;
	    InputStream is = null;
	    try {
	        is = FP.context.getResources().openRawResource(resource);
	    }
	    catch(NotFoundException e) {
	        Log.e(TAG, "Could not find font in resources!");
	    }

	    String outPath = FP.context.getCacheDir() + "/tmp.raw";

	    try
	    {
	        byte[] buffer = new byte[is.available()];
	        BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(outPath));

	        int l = 0;
	        while((l = is.read(buffer)) > 0)
	            bos.write(buffer, 0, l);

	        bos.close();

	        tf = Typeface.createFromFile(outPath);

	        // clean up
	        new File(outPath).delete();
	    }
	    catch (IOException e)
	    {
	        Log.e(TAG, "Error reading in font!");
	        return null;
	    }

	    Log.d(TAG, "Successfully loaded font.");

	    return tf;      
	}
}
 public class AtlasText extends AtlasGraphic {
	
	private static final String TAG  = "AtlasText";
	
	private String mText = "sff2afs2";
	
	private static final Map<Typeface, Map<Integer, TextAtlas>> mTextAtlasCollection = new HashMap<Typeface, Map<Integer, TextAtlas>>();
	
	private TextAtlas mTextAtlas;
	private Texture mTexture;
	
	private FloatBuffer mGeometryBuffer, mTextureBuffer;
	private ShortBuffer mIndexBuffer;
	private int mIndexCount;
	
	private int mFontSize;
	
	
	public AtlasText(String s, int fontSize) {
		this(s, fontSize, FP.typeface);
	}
	
	public AtlasText(String s, int fontSize, Typeface typeface) {
		super(findOrCreateAtlas(fontSize, typeface));

		mFontSize = fontSize;
		mTextAtlas = mTextAtlasCollection.get(typeface).get(fontSize);
		mTexture = mTextAtlas.getAtlas();
		
		setText(s);
	}
	
	public AtlasText(String s, TextAtlas atlas) {
		super(atlas.getAtlas());
		
		mFontSize = atlas.getFontSize();
		mTextAtlas = atlas;
		mTexture = mTextAtlas.getAtlas();
		setText(s);
		
	}
	
	private static Atlas findOrCreateAtlas(int fontSize, Typeface typeface) {
		Atlas builtAtlas;
		
		if (typeface == null) {
			typeface = Typeface.DEFAULT;
		}
		
		// Check if we have used this Typeface before
		Map<Integer, TextAtlas> typefaceMap = mTextAtlasCollection.get(typeface);
		if (typefaceMap != null) {
			
			// Old Typeface
			TextAtlas existingAtlas = typefaceMap.get(fontSize);
			if (existingAtlas == null) {
				
				// New fontsize
				Log.d(TAG, "New fontsize " + fontSize);
				TextAtlas newAtlas = new TextAtlas(fontSize, typeface);
				typefaceMap.put(fontSize, newAtlas);
				builtAtlas = newAtlas.getAtlas();
			} else {
				
				// Existing TextAtlas
				Log.d(TAG, "Existing Atlas" + fontSize);
				builtAtlas = existingAtlas.getAtlas();
			}
		} else {
			
			//New Typeface
			Log.d(TAG, "New Typeface" + fontSize);
			Map<Integer, TextAtlas> sizeMap = new HashMap<Integer, TextAtlas>();
			TextAtlas newAtlas = new TextAtlas(fontSize, typeface);
			sizeMap.put(fontSize, newAtlas);
			mTextAtlasCollection.put(typeface, sizeMap);
			builtAtlas = newAtlas.getAtlas();
		}
		return builtAtlas;
	}

	public int getSize() {
		return mFontSize;
	}
	
	public void setSize(int fontSize) {
		if (fontSize == mFontSize) {
			return;
		}
		
		Typeface tf = mTextAtlas.getTypeface();
		
		Atlas a = findOrCreateAtlas(fontSize, tf);
		setAtlas(a);
		
		mTextAtlas = mTextAtlasCollection.get(tf).get(fontSize);
		mTexture = mTextAtlas.getAtlas();
		
		String oldText = mText;
		mText = "";
		mFontSize = fontSize;
		setText(oldText);
	}
	
	public void setText(String s) {
		if (mText.equals(s)) {
			return;
		}
		
		mText = s;
		
		mGeometryBuffer = mTextAtlas.getStringGeometryBuffer(mText);
		mTextureBuffer = mTextAtlas.getStringTextureBuffer(mText);
		
		mIndexBuffer = mTextAtlas.setBuffers(mText, mGeometryBuffer, mTextureBuffer);
		mIndexCount = mText.length() * 6;
	}
	
	public String getText() {
		return mText;
	}
	
	@Override
	public void render(GL10 gl, Point point, Point camera) {
		super.render(gl, point, camera);
		if (!mTexture.isLoaded()) {
			return;
		}
		
		mTexture.mColorFilter.setColor(mColor);
		mTexture.mColorFilter.applyColorFilter(gl);
		OpenGLSystem.setTexture(gl, mTexture);
		
		mPoint.x = (int)(point.x + x - camera.x * scrollX);
		mPoint.y = (int)(point.y + y - camera.y * scrollY);
		
		gl.glEnable(GL10.GL_TEXTURE_2D);
		gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
		
		
		gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, mTextureBuffer);
    	gl.glVertexPointer(2, GL10.GL_FLOAT, 0, mGeometryBuffer);
    	
    	gl.glPushMatrix();
    	{
    		setMatrix(gl);
    		gl.glDrawElements(GL10.GL_TRIANGLES, mIndexCount, GL10.GL_UNSIGNED_SHORT, mIndexBuffer);
    	}
    	gl.glPopMatrix();
	}
	
	public int getWidth() {
		return mTextAtlas.getWidth(mText);
	}
	
	public int getHeight() {
		return mTextAtlas.getHeight(mText);
	}

	
}
 public class GraphicList extends Graphic {

	// List information.
	private Vector<Graphic> mGraphics = new Vector<Graphic>();
	private Vector<Graphic> mTemp = new Vector<Graphic>();
	private int mCount;
	private Point mCamera = new Point();
	
	/**
	 * Constructor.
	 * @param	...graphic		Graphic objects to add to the list.
	 */
	public GraphicList(Graphic... graphics) {
		for (int i = 0; i < graphics.length; i++) {
			add(graphics[i]);
		}
	}
	
	/** @private Updates the graphics in the list. */
	@Override
	public void update() {
		int size = mGraphics.size();
		for (int i = 0; i < size; i++) {
			Graphic g = mGraphics.get(i);
			if (g.active)
				g.update();
		}
	}
	
	/** @private Renders the Graphics in the list. */
	@Override
	public void render(GL10 gl, Point point, Point camera) {
		point.x += x;
		point.y += y;
		camera.x *= scrollX;
		camera.y *= scrollY;
		int size = mGraphics.size();
		for (int i = 0; i < size; i++) {
			Graphic g = mGraphics.get(i);
			if (g.visible) {
				if (g.relative) {
					mPoint.x = point.x;
					mPoint.y = point.y;
				}
				else 
					mPoint.x = mPoint.y = 0;
				mCamera.x = camera.x;
				mCamera.y = camera.y;
				
				g.render(gl, mPoint, mCamera);
			}
		}
	}
	
	/**
	 * Adds the Graphic to the list.
	 * @param	graphic		The Graphic to add.
	 * @return	The added Graphic.
	 */
	public Graphic add(Graphic graphic) {
		mGraphics.add(graphic);
		if (!active)
			active = graphic.active;
		return graphic;
	}
	
	/**
	 * Removes the Graphic from the list.
	 * @param	graphic		The Graphic to remove.
	 * @return	The removed Graphic.
	 */
	public Graphic remove(Graphic graphic) {
		if(mGraphics.indexOf(graphic)< 0)
			return graphic;
		mTemp.clear();
		int size = mGraphics.size();
		for (int i = 0; i < size; i++) {
			Graphic g = mGraphics.get(i);
			if (g == graphic) 
				mCount--;
			else
				mTemp.add(g);
		}
		Vector<Graphic> temp = mGraphics; 
		mGraphics = mTemp;
		mTemp = temp;
		updateCheck();
		return graphic;
	}
	
	public void removeAt() {
		removeAt(0);
	}
	/**
	 * Removes the Graphic from the position in the list.
	 * @param	index		Index to remove.
	 */
	public void removeAt(int index) {
		if (mGraphics.size() == 0) 
			return;
		index %= mGraphics.size();
		remove(mGraphics.get(index));
		updateCheck();
	}
	
	/**
	 * Removes all Graphics from the list.
	 */
	public void removeAll() {
		mGraphics.clear();
		mTemp.clear();
		mCount = 0;
		active = false;
	}
	
	/**
	 * All Graphics in this list.
	 */
	public Vector<Graphic> getChildren() { return mGraphics; }
	
	/**
	 * Amount of Graphics in this list.
	 */
	public int getCount() { return mCount; }
	
	/**
	 * Check if the Graphiclist should update.
	 */
	private void updateCheck() {
		active = false;
		int size = mGraphics.size();
		for (int i = 0; i < size; i++) {
			Graphic g = mGraphics.get(i);
			if (g.active) {
				active = true;
				return;
			}
		}
	}
}
 public class Atlas extends Texture {

	private static final String TAG = "Atlas";
	
	public static final Vector<Atlas> ATLAS = new Vector<Atlas>();
	
	private final Map<String, SubTexture> mSubTextures = new HashMap<String, SubTexture>();
	
	public Atlas() {
		ATLAS.add(this);
	}
	
	public Atlas(Bitmap texture) {
		setTextureBitmap(texture);
		ATLAS.add(this);
	}
	
	/**
	 * Loads a texture atlas in the Sparrow format.
	 * 
	 * Use TexturePacker with no texture cropping and power of two dimensions.
	 * 
	 * @param xmlPath The absolute path to the xml file in the assets directory.
	 */
	public Atlas(String xmlPath) {
		File xml = new File(xmlPath);
		String assetPath = xml.getParent();
		xml = null;
		
		Document doc = FP.getXML(xmlPath);
		
		NodeList tal = doc.getElementsByTagName("TextureAtlas");
		Node ta = tal.item(0);
		
		String texturePath = assetPath + File.separator + ta.getAttributes().getNamedItem("imagePath").getNodeValue();
		Log.d(TAG, "Loading " + texturePath);
		
		// This can start loading the texture in the OpenGL thread.
		setTextureBitmap(texturePath);
		
		NodeList stl = ta.getChildNodes();
		int subTextureCount = stl.getLength();
		for (int i = 0; i < subTextureCount; i++) {
			Node st = stl.item(i);
			if (st.getNodeType() == Node.TEXT_NODE) {
				continue;
			}
			NamedNodeMap atts = st.getAttributes();
			
			String name;
			int x, y, width, height;
			name = atts.getNamedItem("name").getNodeValue();
			
			x = Integer.parseInt(atts.getNamedItem("x").getNodeValue());
			y = Integer.parseInt(atts.getNamedItem("y").getNodeValue());
			width = Integer.parseInt(atts.getNamedItem("width").getNodeValue());
			height = Integer.parseInt(atts.getNamedItem("height").getNodeValue());
			
			mSubTextures.put(name, new SubTexture(this, x, y, width, height));
		}
		
		if (!ATLAS.contains(this)) {
			ATLAS.add(this);
		}
	}
	
	public void addSubTexture(String name, Rect clip) {
		mSubTextures.put(name, new SubTexture(this, clip.left, clip.top, clip.width(), clip.height()));
	}
	
	public SubTexture getSubTexture(String name) {
		SubTexture st = mSubTextures.get(name);
		if (st == null) {
			Log.e(TAG, "Subtexture '" + name + "' does not exist.");
		}
		return st;
	}
	
}
 public class TextAtlas {

	private static final String TAG = "TextAtlas";
	
	private static final int SPACER = 1;
	
	private final Paint mPaint = new Paint();
	
	private Atlas mAtlas;
	private Bitmap mBitmap;
	
	private Typeface mTypeface;
	private int mFontSize;
	
	private final String CHARACTERS = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ !@#$%^&*()-+_=,./;'[]\\<>?:\"{}|`~";
	
	public TextAtlas(int fontSize) {
		this(fontSize, null);
	}
	
	public TextAtlas(int fontSize, Typeface tf) {
		mTypeface = tf;
		mFontSize = fontSize;
		
		mPaint.setColor(Color.WHITE);
		mPaint.setTextSize(fontSize);
		if (mTypeface != null) {
			mPaint.setTypeface(mTypeface);
		}
		
		float totalWidth = mPaint.measureText(CHARACTERS);
		float rows = totalWidth / 2048;
		int characterHeight = (int)(-mPaint.ascent() + mPaint.descent());
		float totalHeight = characterHeight * (rows+1);
		if (totalHeight > 2048) {
			Log.e(TAG, "TOO BIG FOR TEXTURE. FAILED TO CREATE");
			return;
		}
		
		mBitmap = Bitmap.createBitmap(1024, Texture.nextHigher2((int)totalHeight), Config.ARGB_8888);
		Canvas c = new Canvas(mBitmap);
		Log.d(TAG, String.format("Font bitmap of size %d is %dx%d", mFontSize, 1024, mBitmap.getHeight()));
		mAtlas = new Atlas();
		
		int x = 0;
		int y = 0;
		Rect r = new Rect();
		for (int i = 0; i < CHARACTERS.length(); i++) {
			String character = CHARACTERS.substring(i, i+1);
			int characterWidth = (int)mPaint.measureText(character);
			
			if (x + characterWidth > mBitmap.getWidth()) {
				x = 0;
				y += characterHeight + SPACER;
			}
			
			c.drawText(character, x, y - mPaint.ascent(), mPaint);
			
			
			r.set(x, y, x + characterWidth, y + characterHeight);
			mAtlas.addSubTexture(character, r);
			
			x += characterWidth + SPACER;
		}
		
		mAtlas.setTextureBitmap(mBitmap);
		
		/*
		try {
			mBitmap.compress(CompressFormat.PNG, 85, FP.context.openFileOutput("font.png", Context.MODE_WORLD_READABLE));
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		}
		*/
	}
	
	public int getFontSize() {
		return mFontSize;
	}
	
	public Typeface getTypeface() {
		return mTypeface;
	}
	
	public FloatBuffer getStringGeometryBuffer(String s) {
		FloatBuffer mVertexBuffer = AtlasGraphic.getDirectFloatBuffer(s.length() * 8);
		return mVertexBuffer;
	}
	public FloatBuffer getStringTextureBuffer(String s) {
		FloatBuffer mTextureBuffer = AtlasGraphic.getDirectFloatBuffer(s.length() * 8);
		return mTextureBuffer;
	}
	
	public ShortBuffer setBuffers(String s, FloatBuffer vertex, FloatBuffer texture) {
		
		ShortBuffer indexBuffer = AtlasGraphic.getDirectShortBuffer(s.length() * 6);
		
		indexBuffer.position(0);
		vertex.position(0);
		texture.position(0);
		
		int x = 0;
		int y = 0;
		
		int textureWidth = mAtlas.getWidth();
		int textureHeight = mAtlas.getHeight();
		
		for (int i = 0; i < s.length(); i++) {
			String character = s.substring(i, i+1);
			
			if ("\n".equals(character)) {
				character = " ";
				y += -mPaint.ascent() + mPaint.descent();
				x = (int) -mPaint.measureText(character);
				
			} else if ("\t".equals(character)) {
				character = " ";
				x += mPaint.measureText("\t") - mPaint.measureText(character);
			}
			SubTexture subTexture = mAtlas.getSubTexture(character);
			Rect r = subTexture.getBounds();
			
			//Log.d(TAG, String.format("drawing '%s' at %d,%d to %d,%d", character, x, y, x + r.width(), y + r.height()));
			
			vertex.put(x).put(y);
			vertex.put(x+r.width()).put(y);
			vertex.put(x).put(y+r.height());
			vertex.put(x+r.width()).put(y+r.height());
			
			//Log.d(TAG, "Character texture at " + r.toShortString());
			
			texture.put((float)r.left/textureWidth).put((float)r.top/textureHeight);
			texture.put((float)(r.left + r.width())/textureWidth).put((float)r.top/textureHeight);
			texture.put((float)r.left/textureWidth).put((float)(r.top + r.height())/textureHeight);
			texture.put((float)(r.left + r.width())/textureWidth).put((float)(r.top + r.height())/textureHeight);
			
			indexBuffer.put((short)(i*4));
			indexBuffer.put((short)((i*4)+1));
			indexBuffer.put((short)((i*4)+2));
			
			indexBuffer.put((short)((i*4)+1));
			indexBuffer.put((short)((i*4)+3));
			indexBuffer.put((short)((i*4)+2));
			
			x += r.width();
		}
		indexBuffer.position(0);
		vertex.position(0);
		texture.position(0);
		return indexBuffer;
	}
	
	public Atlas getAtlas() {
		return mAtlas;
	}
	
	public int getWidth(String s) {
		return (int)mPaint.measureText(s);
	}
	
	public int getHeight(String s) {
		String[] split = s.split("\n");
		return (int)(-mPaint.ascent() + mPaint.descent()) * split.length;
	}
	
	public static final Typeface getFontFromAssets(String path) {
		Typeface tf = Typeface.createFromAsset(FP.context.getAssets(), path);	
		return tf;
	}
	
	public static final Typeface getFontFromRes(int resource) {
	    Typeface tf = null;
	    InputStream is = null;
	    try {
	        is = FP.context.getResources().openRawResource(resource);
	    }
	    catch(NotFoundException e) {
	        Log.e(TAG, "Could not find font in resources!");
	    }

	    String outPath = FP.context.getCacheDir() + "/tmp.raw";

	    try
	    {
	        byte[] buffer = new byte[is.available()];
	        BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(outPath));

	        int l = 0;
	        while((l = is.read(buffer)) > 0)
	            bos.write(buffer, 0, l);

	        bos.close();

	        tf = Typeface.createFromFile(outPath);

	        // clean up
	        new File(outPath).delete();
	    }
	    catch (IOException e)
	    {
	        Log.e(TAG, "Error reading in font!");
	        return null;
	    }

	    Log.d(TAG, "Successfully loaded font.");

	    return tf;      
	}
}
 public class Input {

	/**
	 * Map from KeyCode to Action (ACTION_DOWN, ACTION_UP)
	 */
	public static final Map<Integer, Integer> KEY_STATE = new HashMap<Integer, Integer>();
	
	/**
	 * If the mouse button is down.
	 */
	public static boolean mouseDown = false;

	/**
	 * If the mouse button is up.
	 */
	public static boolean mouseUp = true;

	/**
	 * If the mouse button was pressed this frame.
	 */
	public static boolean mousePressed = false;

	/**
	 * If the mouse button was released this frame.
	 */
	public static boolean mouseReleased = false;
	
	/**
	 * X positions of up to two fingers on the screen.
	 */
	public static int[] getMouseX() {
		return FP.screen.getTouchX();
	}

	/**
	 * Y position of up to two fingers on the screen.
	 */
	public static int[] getMouseY() {
		return FP.screen.getTouchY();
	}
	
	/**
	 * Gets the number of pointers on the screen.
	 * @return The number of points
	 */
	public static int getTouchesCount() {
		return FP.screen.getTouchesCount();
	}
	
	/**
	 * Gets the points of contact with the screen.
	 * @return An array of points use getTouchesCount() to find the size;
	 */
	public static Point[] getTouches() {
		return FP.screen.getTouches();
	}
	
	/**
	 * Store the state of the inputs.
	 * @param keyCode
	 * @param event
	 */
	public static void onKeyChange(int keyCode, KeyEvent event) {
		switch(event.getAction()) {
		case KeyEvent.ACTION_DOWN:
			KEY_STATE.put(keyCode, 1);
			break;
		case KeyEvent.ACTION_UP:
			KEY_STATE.put(keyCode, 0);
			break;
		case KeyEvent.ACTION_MULTIPLE:
			String keys = event.getCharacters();
			for (int i = 0; i < keys.length(); i++) {
				KEY_STATE.put((int)keys.charAt(i), 1);
			}
			break;
		}
	}
	
	public static boolean checkKey(int keyCode) {
		return KEY_STATE.containsKey(keyCode) && KEY_STATE.get(keyCode) == 1;
	}
	
	/** @private Called by Engine to update the input. */
	public static void update() {
		if (mousePressed) 
			mousePressed = false;
		if (mouseReleased) 
			mouseReleased = false;
	}
}

import java.lang.reflect.InvocationTargetException;
import java.util.Vector;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
import net.androidpunk.Engine;
import net.androidpunk.Entity;
import net.androidpunk.FP;
import net.androidpunk.Graphic;
import net.androidpunk.R;
import net.androidpunk.Sfx;
import net.androidpunk.flashcompat.Event;
import net.androidpunk.flashcompat.Timer;
import net.androidpunk.graphics.Text;
import net.androidpunk.graphics.atlas.AtlasText;
import net.androidpunk.graphics.atlas.GraphicList;
import net.androidpunk.graphics.opengl.Atlas;
import net.androidpunk.graphics.opengl.TextAtlas;
import net.androidpunk.utils.Input;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
import android.content.res.Configuration;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Rect;
import android.media.AudioManager;
import android.media.AudioManager.OnAudioFocusChangeListener;
import android.opengl.GLSurfaceView;
import android.os.Bundle;
import android.os.SystemClock;
import android.util.Log;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
import android.view.WindowManager;

	        	}
	        	 
	        } else if (focusChange == AudioManager.AUDIOFOCUS_LOSS) {
	        	// We are out.
	        	mAudioManager.abandonAudioFocus(afChangeListener);
	        }
	    }
	};
	
	protected class EngineRunner extends Thread {
		@Override
		public void run() {
			while(mRunning) {
				step();
			}
			Log.d(TAG, "Exiting Engine");
		}
		
		private void step() {
			if (mStarted) {
				long now = SystemClock.uptimeMillis();
				Engine.fire(Event.ENTER_FRAME);
				synchronized (mUpdateLock) {
					Engine.checkEvents();
				}
				mSurfaceView.requestRender();
				long delta = SystemClock.uptimeMillis() - now;
				
				if (delta < 16) {
					try {
						Thread.sleep(16-delta);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
			}
		}
	}

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		
		FP.activity = this;
		FP.resources = getResources();
		FP.context = this;
		setContentView(R.layout.main);
		
		mSurfaceView = (GLSurfaceView) findViewById(R.id.surface_view);
		mSurfaceView.setOnTouchListener(this);
		mRenderer = new APRenderer();
		mSurfaceView.setRenderer(mRenderer);
		mSurfaceView.setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);
		if (FP.debugOpenGL) {
			mSurfaceView.setDebugFlags(GLSurfaceView.DEBUG_CHECK_GL_ERROR);
		}
		
		getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
		
		setVolumeControlStream(AudioManager.STREAM_MUSIC);
		
		mAudioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
		
		FP.typeface = TextAtlas.getFontFromRes(R.raw.novamono);
	}
	
	@Override
	protected void onPause() {
		super.onPause();
		mSurfaceView.onPause();
		
		mRunning = false;
		for (Timer t : Engine.TIMERS) {
			t.stop();
		}
		mAudioManager.abandonAudioFocus(afChangeListener);

	}

	@Override
	protected void onResume() {
		super.onResume();
		mRunning = true;
		if (mGameThread == null || !mGameThread.isAlive()) {
			mGameThread = new EngineRunner();
			mGameThread.start();
		}
		/*
		if (mRenderThread == null || !mRenderThread.isAlive()) {
			mRenderThread = new RenderRunner();
			mRenderThread.start();
		}
		*/
		mSurfaceView.onResume();
		
		for (Timer t : Engine.TIMERS) {
			t.start();
		}
		// Request audio focus for playback
		int result = mAudioManager.requestAudioFocus(afChangeListener,
                // Use the music stream.
                AudioManager.STREAM_MUSIC,
                // Request permanent focus.
                AudioManager.AUDIOFOCUS_GAIN);
		if (result != AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
			Log.e(TAG, "Failed to request focus. No sound.");
		}
		// A real resume to game state.
		if (mEngine != null) {
			// Reload the atlas
			int count = Atlas.ATLAS.size();
			for (int i = 0; i < count; i++) {
				Atlas.ATLAS.get(i).reload();
			}
			// TODO make bitmap font so I can load that atlas instead of scowring the entities for the Text to reload.
			Vector<Entity> v = new Vector<Entity>();
			FP.getWorld().getAll(v);
			count = v.size();
			for (int i = 0; i < count; i++) {
				Entity e = v.get(i);

				Graphic g = e.getGraphic();
