/' or have .length() == 0.
+ */
+ public static void setAssetBasePath(final String pAssetBasePath) {
+ if(pAssetBasePath.endsWith("/") || pAssetBasePath.length() == 0) {
+ MusicFactory.sAssetBasePath = pAssetBasePath;
+ } else {
+ throw new IllegalStateException("pAssetBasePath must end with '/' or be lenght zero.");
+ }
+ }
+
+ // ===========================================================
+ // Methods for/from SuperClass/Interfaces
+ // ===========================================================
+
+ // ===========================================================
+ // Methods
+ // ===========================================================
+
+ public static Music createMusicFromFile(final MusicManager pMusicManager, final Context pContext, final File pFile) throws IOException {
+ final MediaPlayer mediaPlayer = new MediaPlayer();
+
+ mediaPlayer.setDataSource(new FileInputStream(pFile).getFD());
+ mediaPlayer.prepare();
+
+ final Music music = new Music(pMusicManager, mediaPlayer);
+ pMusicManager.add(music);
+
+ return music;
+ }
+
+ public static Music createMusicFromAsset(final MusicManager pMusicManager, final Context pContext, final String pAssetPath) throws IOException {
+ final MediaPlayer mediaPlayer = new MediaPlayer();
+
+ final AssetFileDescriptor assetFileDescritor = pContext.getAssets().openFd(MusicFactory.sAssetBasePath + pAssetPath);
+ mediaPlayer.setDataSource(assetFileDescritor.getFileDescriptor(), assetFileDescritor.getStartOffset(), assetFileDescritor.getLength());
+ mediaPlayer.prepare();
+
+ final Music music = new Music(pMusicManager, mediaPlayer);
+ pMusicManager.add(music);
+
+ return music;
+ }
+
+ public static Music createMusicFromResource(final MusicManager pMusicManager, final Context pContext, final int pMusicResID) throws IOException {
+ final MediaPlayer mediaPlayer = MediaPlayer.create(pContext, pMusicResID);
+ mediaPlayer.prepare();
+
+ final Music music = new Music(pMusicManager, mediaPlayer);
+ pMusicManager.add(music);
+
+ return music;
+ }
+
+ // ===========================================================
+ // Inner and Anonymous Classes
+ // ===========================================================
+}
diff --git a/AndEngine/src/org/anddev/andengine/audio/music/MusicManager.java b/AndEngine/src/org/anddev/andengine/audio/music/MusicManager.java
new file mode 100644
index 0000000..4465777
--- /dev/null
+++ b/AndEngine/src/org/anddev/andengine/audio/music/MusicManager.java
@@ -0,0 +1,41 @@
+package org.anddev.andengine.audio.music;
+
+import org.anddev.andengine.audio.BaseAudioManager;
+
+/**
+ * @author Nicolas Gramlich
+ * @since 15:01:23 - 13.06.2010
+ */
+public class MusicManager extends BaseAudioManager/' or have .length() == 0.
+ */
+ public static void setAssetBasePath(final String pAssetBasePath) {
+ if(pAssetBasePath.endsWith("/") || pAssetBasePath.length() == 0) {
+ SoundFactory.sAssetBasePath = pAssetBasePath;
+ } else {
+ throw new IllegalStateException("pAssetBasePath must end with '/' or be lenght zero.");
+ }
+ }
+
+ // ===========================================================
+ // Methods for/from SuperClass/Interfaces
+ // ===========================================================
+
+ // ===========================================================
+ // Methods
+ // ===========================================================
+
+ public static Sound createSoundFromPath(final SoundManager pSoundManager, final Context pContext, final String pPath) throws IOException {
+ final int soundID = pSoundManager.getSoundPool().load(pPath, 1);
+ final Sound sound = new Sound(pSoundManager, soundID);
+ pSoundManager.add(sound);
+ return sound;
+ }
+
+ public static Sound createSoundFromAsset(final SoundManager pSoundManager, final Context pContext, final String pAssetPath) throws IOException {
+ final int soundID = pSoundManager.getSoundPool().load(pContext.getAssets().openFd(SoundFactory.sAssetBasePath + pAssetPath), 1);
+ final Sound sound = new Sound(pSoundManager, soundID);
+ pSoundManager.add(sound);
+ return sound;
+ }
+
+ public static Sound createSoundFromResource(final SoundManager pSoundManager, final Context pContext, final int pSoundResID) {
+ final int soundID = pSoundManager.getSoundPool().load(pContext, pSoundResID, 1);
+ final Sound sound = new Sound(pSoundManager, soundID);
+ pSoundManager.add(sound);
+ return sound;
+ }
+
+ public static Sound createSoundFromFileDescriptor(final SoundManager pSoundManager, final FileDescriptor pFileDescriptor, final long pOffset, final long pLength) throws IOException {
+ final int soundID = pSoundManager.getSoundPool().load(pFileDescriptor, pOffset, pLength, 1);
+ final Sound sound = new Sound(pSoundManager, soundID);
+ pSoundManager.add(sound);
+ return sound;
+ }
+
+ // ===========================================================
+ // Inner and Anonymous Classes
+ // ===========================================================
+}
diff --git a/AndEngine/src/org/anddev/andengine/audio/sound/SoundLibrary.java b/AndEngine/src/org/anddev/andengine/audio/sound/SoundLibrary.java
new file mode 100644
index 0000000..b830172
--- /dev/null
+++ b/AndEngine/src/org/anddev/andengine/audio/sound/SoundLibrary.java
@@ -0,0 +1,37 @@
+package org.anddev.andengine.audio.sound;
+
+import org.anddev.andengine.util.Library;
+
+/**
+ * @author Nicolas Gramlich
+ * @since 20:41:56 - 20.08.2010
+ */
+public class SoundLibrary extends Library+ * A return value of 1 indicates that the line segment must turn in the + * direction that takes the positive X axis towards the negative Y axis. In + * the default coordinate system used by Java 2D, this direction is + * counterclockwise. + *
+ * A return value of -1 indicates that the line segment must turn in the + * direction that takes the positive X axis towards the positive Y axis. In + * the default coordinate system, this direction is clockwise. + *
+ * A return value of 0 indicates that the point lies exactly on the line + * segment. Note that an indicator value of 0 is rare and not useful for + * determining colinearity because of floating point rounding issues. + *
+ * If the point is colinear with the line segment, but not between the
+ * endpoints, then the value will be -1 if the point lies
+ * "beyond (X1, Y1)" or 1 if the point lies "beyond (X2, Y2)".
+ *
+ * @param pX1
+ * , Y1 the coordinates of the beginning of the specified
+ * line segment
+ * @param pX2
+ * , Y2 the coordinates of the end of the specified line
+ * segment
+ * @param pPX
+ * , PY the coordinates of the specified point to be
+ * compared with the specified line segment
+ * @return an integer that indicates the position of the third specified
+ * coordinates with respect to the line segment formed by the first
+ * two specified coordinates.
+ */
+ public static int relativeCCW(final float pX1, final float pY1, float pX2, float pY2, float pPX, float pPY) {
+ pX2 -= pX1;
+ pY2 -= pY1;
+ pPX -= pX1;
+ pPY -= pY1;
+ float ccw = pPX * pY2 - pPY * pX2;
+ if (ccw == 0.0f) {
+ // The point is colinear, classify based on which side of
+ // the segment the point falls on. We can calculate a
+ // relative value using the projection of PX,PY onto the
+ // segment - a negative value indicates the point projects
+ // outside of the segment in the direction of the particular
+ // endpoint used as the origin for the projection.
+ ccw = pPX * pX2 + pPY * pY2;
+ if (ccw > 0.0f) {
+ // Reverse the projection to be relative to the original X2,Y2
+ // X2 and Y2 are simply negated.
+ // PX and PY need to have (X2 - X1) or (Y2 - Y1) subtracted
+ // from them (based on the original values)
+ // Since we really want to get a positive answer when the
+ // point is "beyond (X2,Y2)", then we want to calculate
+ // the inverse anyway - thus we leave X2 & Y2 negated.
+ pPX -= pX2;
+ pPY -= pY2;
+ ccw = pPX * pX2 + pPY * pY2;
+ if (ccw < 0.0f) {
+ ccw = 0.0f;
+ }
+ }
+ }
+ return (ccw < 0.0f) ? -1 : ((ccw > 0.0f) ? 1 : 0);
+ }
+
+ // ===========================================================
+ // Inner and Anonymous Classes
+ // ===========================================================
+}
diff --git a/AndEngine/src/org/anddev/andengine/collision/LineCollisionChecker.java b/AndEngine/src/org/anddev/andengine/collision/LineCollisionChecker.java
new file mode 100644
index 0000000..2170e1d
--- /dev/null
+++ b/AndEngine/src/org/anddev/andengine/collision/LineCollisionChecker.java
@@ -0,0 +1,40 @@
+package org.anddev.andengine.collision;
+
+/**
+ * @author Nicolas Gramlich
+ * @since 19:27:22 - 17.07.2010
+ */
+public class LineCollisionChecker extends ShapeCollisionChecker {
+ // ===========================================================
+ // Constants
+ // ===========================================================
+
+ // ===========================================================
+ // Fields
+ // ===========================================================
+
+ // ===========================================================
+ // Constructors
+ // ===========================================================
+
+ // ===========================================================
+ // Getter & Setter
+ // ===========================================================
+
+ // ===========================================================
+ // Methods for/from SuperClass/Interfaces
+ // ===========================================================
+
+ // ===========================================================
+ // Methods
+ // ===========================================================
+
+ public static boolean checkLineCollision(final float pX1, final float pY1, final float pX2, final float pY2, final float pX3, final float pY3, final float pX4, final float pY4) {
+ return ((BaseCollisionChecker.relativeCCW(pX1, pY1, pX2, pY2, pX3, pY3) * BaseCollisionChecker.relativeCCW(pX1, pY1, pX2, pY2, pX4, pY4) <= 0)
+ && (BaseCollisionChecker.relativeCCW(pX3, pY3, pX4, pY4, pX1, pY1) * BaseCollisionChecker.relativeCCW(pX3, pY3, pX4, pY4, pX2, pY2) <= 0));
+ }
+
+ // ===========================================================
+ // Inner and Anonymous Classes
+ // ===========================================================
+}
diff --git a/AndEngine/src/org/anddev/andengine/collision/RectangularShapeCollisionChecker.java b/AndEngine/src/org/anddev/andengine/collision/RectangularShapeCollisionChecker.java
new file mode 100644
index 0000000..9ff4b74
--- /dev/null
+++ b/AndEngine/src/org/anddev/andengine/collision/RectangularShapeCollisionChecker.java
@@ -0,0 +1,79 @@
+package org.anddev.andengine.collision;
+
+import static org.anddev.andengine.util.constants.Constants.VERTEX_INDEX_X;
+import static org.anddev.andengine.util.constants.Constants.VERTEX_INDEX_Y;
+
+import org.anddev.andengine.entity.shape.RectangularShape;
+
+/**
+ * @author Nicolas Gramlich
+ * @since 11:50:19 - 11.03.2010
+ */
+public class RectangularShapeCollisionChecker extends ShapeCollisionChecker {
+ // ===========================================================
+ // Constants
+ // ===========================================================
+
+ private static final int RECTANGULARSHAPE_VERTEX_COUNT = 4;
+
+ private static final float[] VERTICES_CONTAINS_TMP = new float[2 * RECTANGULARSHAPE_VERTEX_COUNT];
+ private static final float[] VERTICES_COLLISION_TMP_A = new float[2 * RECTANGULARSHAPE_VERTEX_COUNT];
+ private static final float[] VERTICES_COLLISION_TMP_B = new float[2 * RECTANGULARSHAPE_VERTEX_COUNT];
+
+ // ===========================================================
+ // Fields
+ // ===========================================================
+
+ // ===========================================================
+ // Constructors
+ // ===========================================================
+
+ // ===========================================================
+ // Getter & Setter
+ // ===========================================================
+
+ // ===========================================================
+ // Methods for/from SuperClass/Interfaces
+ // ===========================================================
+
+ // ===========================================================
+ // Methods
+ // ===========================================================
+
+ public static boolean checkContains(final RectangularShape pRectangularShape, final float pX, final float pY) {
+ RectangularShapeCollisionChecker.fillVertices(pRectangularShape, VERTICES_CONTAINS_TMP);
+ return ShapeCollisionChecker.checkContains(VERTICES_CONTAINS_TMP, 2 * RECTANGULARSHAPE_VERTEX_COUNT, pX, pY);
+ }
+
+ public static boolean checkCollision(final RectangularShape pRectangularShapeA, final RectangularShape pRectangularShapeB) {
+ RectangularShapeCollisionChecker.fillVertices(pRectangularShapeA, VERTICES_COLLISION_TMP_A);
+ RectangularShapeCollisionChecker.fillVertices(pRectangularShapeB, VERTICES_COLLISION_TMP_B);
+
+ return ShapeCollisionChecker.checkCollision(2 * RECTANGULARSHAPE_VERTEX_COUNT, 2 * RECTANGULARSHAPE_VERTEX_COUNT, VERTICES_COLLISION_TMP_A, VERTICES_COLLISION_TMP_B);
+ }
+
+ public static void fillVertices(final RectangularShape pRectangularShape, final float[] pVertices) {
+ final float left = 0;
+ final float top = 0;
+ final float right = pRectangularShape.getWidth();
+ final float bottom = pRectangularShape.getHeight();
+
+ pVertices[0 + VERTEX_INDEX_X] = left;
+ pVertices[0 + VERTEX_INDEX_Y] = top;
+
+ pVertices[2 + VERTEX_INDEX_X] = right;
+ pVertices[2 + VERTEX_INDEX_Y] = top;
+
+ pVertices[4 + VERTEX_INDEX_X] = right;
+ pVertices[4 + VERTEX_INDEX_Y] = bottom;
+
+ pVertices[6 + VERTEX_INDEX_X] = left;
+ pVertices[6 + VERTEX_INDEX_Y] = bottom;
+
+ pRectangularShape.getLocalToSceneTransformation().transform(pVertices);
+ }
+
+ // ===========================================================
+ // Inner and Anonymous Classes
+ // ===========================================================
+}
diff --git a/AndEngine/src/org/anddev/andengine/collision/ShapeCollisionChecker.java b/AndEngine/src/org/anddev/andengine/collision/ShapeCollisionChecker.java
new file mode 100644
index 0000000..e111f1d
--- /dev/null
+++ b/AndEngine/src/org/anddev/andengine/collision/ShapeCollisionChecker.java
@@ -0,0 +1,108 @@
+package org.anddev.andengine.collision;
+
+import org.anddev.andengine.util.constants.Constants;
+
+
+/**
+ * @author Nicolas Gramlich
+ * @since 11:50:19 - 11.03.2010
+ */
+public class ShapeCollisionChecker extends BaseCollisionChecker {
+ // ===========================================================
+ // Constants
+ // ===========================================================
+
+ // ===========================================================
+ // Fields
+ // ===========================================================
+
+ // ===========================================================
+ // Constructors
+ // ===========================================================
+
+ // ===========================================================
+ // Getter & Setter
+ // ===========================================================
+
+ // ===========================================================
+ // Methods for/from SuperClass/Interfaces
+ // ===========================================================
+
+ // ===========================================================
+ // Methods
+ // ===========================================================
+
+ public static boolean checkCollision(final int pVerticesALength, final int pVerticesBLength, final float[] pVerticesA, final float[] pVerticesB) {
+ /* Check all the lines of A ... */
+ for(int a = pVerticesALength - 4; a >= 0; a -= 2) {
+ /* ... against all lines in B. */
+ if(ShapeCollisionChecker.checkCollisionSub(a, a + 2, pVerticesA, pVerticesB, pVerticesBLength)){
+ return true;
+ }
+ }
+ /* Also check the 'around the corner of the array' line of A against all lines in B. */
+ if(ShapeCollisionChecker.checkCollisionSub(pVerticesALength - 2, 0, pVerticesA, pVerticesB, pVerticesBLength)){
+ return true;
+ } else {
+ /* At last check if one polygon 'contains' the other one by checking
+ * if one vertex of the one vertices is contained by all of the other vertices. */
+ if(ShapeCollisionChecker.checkContains(pVerticesA, pVerticesALength, pVerticesB[Constants.VERTEX_INDEX_X], pVerticesB[Constants.VERTEX_INDEX_Y])) {
+ return true;
+ } else if(ShapeCollisionChecker.checkContains(pVerticesB, pVerticesBLength, pVerticesA[Constants.VERTEX_INDEX_X], pVerticesA[Constants.VERTEX_INDEX_Y])) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+ }
+
+ /**
+ * Checks line specified by pVerticesA[pVertexIndexA1] and pVerticesA[pVertexIndexA2] against all lines in pVerticesB.
+ */
+ private static boolean checkCollisionSub(final int pVertexIndexA1, final int pVertexIndexA2, final float[] pVerticesA, final float[] pVerticesB, final int pVerticesBLength) {
+ /* Check against all the lines of B. */
+ final float vertexA1X = pVerticesA[pVertexIndexA1 + Constants.VERTEX_INDEX_X];
+ final float vertexA1Y = pVerticesA[pVertexIndexA1 + Constants.VERTEX_INDEX_Y];
+ final float vertexA2X = pVerticesA[pVertexIndexA2 + Constants.VERTEX_INDEX_X];
+ final float vertexA2Y = pVerticesA[pVertexIndexA2 + Constants.VERTEX_INDEX_Y];
+
+ for(int b = pVerticesBLength - 4; b >= 0; b -= 2) {
+ if(LineCollisionChecker.checkLineCollision(vertexA1X, vertexA1Y, vertexA2X, vertexA2Y, pVerticesB[b + Constants.VERTEX_INDEX_X], pVerticesB[b + Constants.VERTEX_INDEX_Y], pVerticesB[b + 2 + Constants.VERTEX_INDEX_X], pVerticesB[b + 2 + Constants.VERTEX_INDEX_Y])){
+ return true;
+ }
+ }
+ /* Also check the 'around the corner of the array' line of B. */
+ if(LineCollisionChecker.checkLineCollision(vertexA1X, vertexA1Y, vertexA2X, vertexA2Y, pVerticesB[pVerticesBLength - 2], pVerticesB[pVerticesBLength - 1], pVerticesB[Constants.VERTEX_INDEX_X], pVerticesB[Constants.VERTEX_INDEX_Y])){
+ return true;
+ }
+ return false;
+ }
+
+ public static boolean checkContains(final float[] pVertices, final int pVerticesLength, final float pX, final float pY) {
+ int edgeResultSum = 0;
+
+ for(int i = pVerticesLength - 4; i >= 0; i -= 2) {
+ final int edgeResult = BaseCollisionChecker.relativeCCW(pVertices[i], pVertices[i + 1], pVertices[i + 2], pVertices[i + 3], pX, pY);
+ if(edgeResult == 0) {
+ return true;
+ } else {
+ edgeResultSum += edgeResult;
+ }
+ }
+ /* Also check the 'around the corner of the array' line. */
+ final int edgeResult = BaseCollisionChecker.relativeCCW(pVertices[pVerticesLength - 2], pVertices[pVerticesLength - 1], pVertices[Constants.VERTEX_INDEX_X], pVertices[Constants.VERTEX_INDEX_Y], pX, pY);
+ if(edgeResult == 0){
+ return true;
+ } else {
+ edgeResultSum += edgeResult;
+ }
+
+ final int vertexCount = pVerticesLength / 2;
+ /* Point is not on the edge, so check if the edge is on the same side(left or right) of all edges. */
+ return edgeResultSum == vertexCount || edgeResultSum == -vertexCount ;
+ }
+
+ // ===========================================================
+ // Inner and Anonymous Classes
+ // ===========================================================
+}
diff --git a/AndEngine/src/org/anddev/andengine/engine/DoubleSceneSplitScreenEngine.java b/AndEngine/src/org/anddev/andengine/engine/DoubleSceneSplitScreenEngine.java
new file mode 100644
index 0000000..dfb5345
--- /dev/null
+++ b/AndEngine/src/org/anddev/andengine/engine/DoubleSceneSplitScreenEngine.java
@@ -0,0 +1,170 @@
+package org.anddev.andengine.engine;
+
+import javax.microedition.khronos.opengles.GL10;
+
+import org.anddev.andengine.engine.camera.Camera;
+import org.anddev.andengine.engine.options.EngineOptions;
+import org.anddev.andengine.entity.scene.Scene;
+import org.anddev.andengine.input.touch.TouchEvent;
+import org.anddev.andengine.opengl.util.GLHelper;
+
+/**
+ * @author Nicolas Gramlich
+ * @since 22:28:34 - 27.03.2010
+ */
+public class DoubleSceneSplitScreenEngine extends Engine {
+ // ===========================================================
+ // Constants
+ // ===========================================================
+
+ // ===========================================================
+ // Fields
+ // ===========================================================
+
+ private Scene mSecondScene;
+ private final Camera mSecondCamera;
+
+ // ===========================================================
+ // Constructors
+ // ===========================================================
+
+ public DoubleSceneSplitScreenEngine(final EngineOptions pEngineOptions, final Camera pSecondCamera) {
+ super(pEngineOptions);
+ this.mSecondCamera = pSecondCamera;
+ }
+
+ // ===========================================================
+ // Getter & Setter
+ // ===========================================================
+
+ @Deprecated
+ @Override
+ public Camera getCamera() {
+ return super.mCamera;
+ }
+
+ public Camera getFirstCamera() {
+ return super.mCamera;
+ }
+
+ public Camera getSecondCamera() {
+ return this.mSecondCamera;
+ }
+
+ @Deprecated
+ @Override
+ public Scene getScene() {
+ return super.getScene();
+ }
+
+ public Scene getFirstScene() {
+ return super.getScene();
+ }
+
+ public Scene getSecondScene() {
+ return this.mSecondScene;
+ }
+
+ @Deprecated
+ @Override
+ public void setScene(final Scene pScene) {
+ super.setScene(pScene);
+ }
+
+ public void setFirstScene(final Scene pScene) {
+ super.setScene(pScene);
+ }
+
+ public void setSecondScene(final Scene pScene) {
+ this.mSecondScene = pScene;
+ }
+
+ // ===========================================================
+ // Methods for/from SuperClass/Interfaces
+ // ===========================================================
+
+ @Override
+ protected void onDrawScene(final GL10 pGL) {
+ final Camera firstCamera = this.getFirstCamera();
+ final Camera secondCamera = this.getSecondCamera();
+
+ final int surfaceWidth = this.mSurfaceWidth;
+ final int surfaceWidthHalf = surfaceWidth >> 1;
+
+ final int surfaceHeight = this.mSurfaceHeight;
+
+ GLHelper.enableScissorTest(pGL);
+
+ /* First Screen. With first camera, on the left half of the screens width. */
+ {
+ pGL.glScissor(0, 0, surfaceWidthHalf, surfaceHeight);
+ pGL.glViewport(0, 0, surfaceWidthHalf, surfaceHeight);
+
+ super.mScene.onDraw(pGL, firstCamera);
+ firstCamera.onDrawHUD(pGL);
+ }
+
+ /* Second Screen. With second camera, on the right half of the screens width. */
+ {
+ pGL.glScissor(surfaceWidthHalf, 0, surfaceWidthHalf, surfaceHeight);
+ pGL.glViewport(surfaceWidthHalf, 0, surfaceWidthHalf, surfaceHeight);
+
+ this.mSecondScene.onDraw(pGL, secondCamera);
+ secondCamera.onDrawHUD(pGL);
+ }
+
+ GLHelper.disableScissorTest(pGL);
+ }
+
+ @Override
+ protected Camera getCameraFromSurfaceTouchEvent(final TouchEvent pTouchEvent) {
+ if(pTouchEvent.getX() <= this.mSurfaceWidth >> 1) {
+ return this.getFirstCamera();
+ } else {
+ return this.getSecondCamera();
+ }
+ }
+
+ @Override
+ protected Scene getSceneFromSurfaceTouchEvent(final TouchEvent pTouchEvent) {
+ if(pTouchEvent.getX() <= this.mSurfaceWidth >> 1) {
+ return this.getFirstScene();
+ } else {
+ return this.getSecondScene();
+ }
+ }
+
+ @Override
+ protected void onUpdateScene(final float pSecondsElapsed) {
+ super.onUpdateScene(pSecondsElapsed);
+ if(this.mSecondScene != null) {
+ this.mSecondScene.onUpdate(pSecondsElapsed);
+ }
+ }
+
+ @Override
+ protected void convertSurfaceToSceneTouchEvent(final Camera pCamera, final TouchEvent pSurfaceTouchEvent) {
+ final int surfaceWidthHalf = this.mSurfaceWidth >> 1;
+
+ if(pCamera == this.getFirstCamera()) {
+ pCamera.convertSurfaceToSceneTouchEvent(pSurfaceTouchEvent, surfaceWidthHalf, this.mSurfaceHeight);
+ } else {
+ pSurfaceTouchEvent.offset(-surfaceWidthHalf, 0);
+ pCamera.convertSurfaceToSceneTouchEvent(pSurfaceTouchEvent, surfaceWidthHalf, this.mSurfaceHeight);
+ }
+ }
+
+ @Override
+ protected void updateUpdateHandlers(final float pSecondsElapsed) {
+ super.updateUpdateHandlers(pSecondsElapsed);
+ this.getSecondCamera().onUpdate(pSecondsElapsed);
+ }
+
+ // ===========================================================
+ // Methods
+ // ===========================================================
+
+ // ===========================================================
+ // Inner and Anonymous Classes
+ // ===========================================================
+}
diff --git a/AndEngine/src/org/anddev/andengine/engine/Engine.java b/AndEngine/src/org/anddev/andengine/engine/Engine.java
new file mode 100644
index 0000000..eec8b20
--- /dev/null
+++ b/AndEngine/src/org/anddev/andengine/engine/Engine.java
@@ -0,0 +1,715 @@
+package org.anddev.andengine.engine;
+
+import javax.microedition.khronos.opengles.GL10;
+import javax.microedition.khronos.opengles.GL11;
+
+import org.anddev.andengine.audio.music.MusicFactory;
+import org.anddev.andengine.audio.music.MusicManager;
+import org.anddev.andengine.audio.sound.SoundFactory;
+import org.anddev.andengine.audio.sound.SoundManager;
+import org.anddev.andengine.engine.camera.Camera;
+import org.anddev.andengine.engine.handler.IUpdateHandler;
+import org.anddev.andengine.engine.handler.UpdateHandlerList;
+import org.anddev.andengine.engine.handler.runnable.RunnableHandler;
+import org.anddev.andengine.engine.options.EngineOptions;
+import org.anddev.andengine.entity.scene.Scene;
+import org.anddev.andengine.input.touch.TouchEvent;
+import org.anddev.andengine.input.touch.controller.ITouchController;
+import org.anddev.andengine.input.touch.controller.ITouchController.ITouchEventCallback;
+import org.anddev.andengine.input.touch.controller.SingleTouchControler;
+import org.anddev.andengine.opengl.buffer.BufferObjectManager;
+import org.anddev.andengine.opengl.font.FontFactory;
+import org.anddev.andengine.opengl.font.FontManager;
+import org.anddev.andengine.opengl.texture.TextureManager;
+import org.anddev.andengine.opengl.texture.region.TextureRegionFactory;
+import org.anddev.andengine.opengl.util.GLHelper;
+import org.anddev.andengine.sensor.SensorDelay;
+import org.anddev.andengine.sensor.accelerometer.AccelerometerData;
+import org.anddev.andengine.sensor.accelerometer.AccelerometerSensorOptions;
+import org.anddev.andengine.sensor.accelerometer.IAccelerometerListener;
+import org.anddev.andengine.sensor.location.ILocationListener;
+import org.anddev.andengine.sensor.location.LocationProviderStatus;
+import org.anddev.andengine.sensor.location.LocationSensorOptions;
+import org.anddev.andengine.sensor.orientation.IOrientationListener;
+import org.anddev.andengine.sensor.orientation.OrientationData;
+import org.anddev.andengine.sensor.orientation.OrientationSensorOptions;
+import org.anddev.andengine.util.Debug;
+import org.anddev.andengine.util.constants.TimeConstants;
+
+import android.content.Context;
+import android.hardware.Sensor;
+import android.hardware.SensorEvent;
+import android.hardware.SensorEventListener;
+import android.hardware.SensorManager;
+import android.location.Location;
+import android.location.LocationListener;
+import android.location.LocationManager;
+import android.location.LocationProvider;
+import android.os.Bundle;
+import android.os.Vibrator;
+import android.view.Display;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.View.OnTouchListener;
+import android.view.WindowManager;
+
+/**
+ * @author Nicolas Gramlich
+ * @since 12:21:31 - 08.03.2010
+ */
+public class Engine implements SensorEventListener, OnTouchListener, ITouchEventCallback, TimeConstants, LocationListener {
+ // ===========================================================
+ // Constants
+ // ===========================================================
+
+ private static final SensorDelay SENSORDELAY_DEFAULT = SensorDelay.GAME;
+
+ // ===========================================================
+ // Fields
+ // ===========================================================
+
+ private boolean mRunning = false;
+
+ private long mLastTick = -1;
+ private float mSecondsElapsedTotal = 0;
+
+ private final State mThreadLocker = new State();
+
+ private final UpdateThread mUpdateThread = new UpdateThread();
+
+ private final RunnableHandler mUpdateThreadRunnableHandler = new RunnableHandler();
+
+ private final EngineOptions mEngineOptions;
+ protected final Camera mCamera;
+
+ private ITouchController mTouchController;
+
+ private SoundManager mSoundManager;
+ private MusicManager mMusicManager;
+ private final TextureManager mTextureManager = new TextureManager();
+ private final BufferObjectManager mBufferObjectManager = new BufferObjectManager();
+ private final FontManager mFontManager = new FontManager();
+
+ protected Scene mScene;
+
+ private Vibrator mVibrator;
+
+ private ILocationListener mLocationListener;
+ private Location mLocation;
+
+ private IAccelerometerListener mAccelerometerListener;
+ private AccelerometerData mAccelerometerData;
+
+ private IOrientationListener mOrientationListener;
+ private OrientationData mOrientationData;
+
+ private final UpdateHandlerList mUpdateHandlers = new UpdateHandlerList();
+
+ protected int mSurfaceWidth = 1; // 1 to prevent accidental DIV/0
+ protected int mSurfaceHeight = 1; // 1 to prevent accidental DIV/0
+
+ private boolean mIsMethodTracing;
+
+ // ===========================================================
+ // Constructors
+ // ===========================================================
+
+ public Engine(final EngineOptions pEngineOptions) {
+ TextureRegionFactory.setAssetBasePath("");
+ SoundFactory.setAssetBasePath("");
+ MusicFactory.setAssetBasePath("");
+ FontFactory.setAssetBasePath("");
+
+ BufferObjectManager.setActiveInstance(this.mBufferObjectManager);
+
+ this.mEngineOptions = pEngineOptions;
+ this.setTouchController(new SingleTouchControler());
+ this.mCamera = pEngineOptions.getCamera();
+
+ if(this.mEngineOptions.needsSound()) {
+ this.mSoundManager = new SoundManager();
+ }
+
+ if(this.mEngineOptions.needsMusic()) {
+ this.mMusicManager = new MusicManager();
+ }
+
+ this.mUpdateThread.start();
+ }
+
+ // ===========================================================
+ // Getter & Setter
+ // ===========================================================
+
+ public boolean isRunning() {
+ return this.mRunning;
+ }
+
+ public synchronized void start() {
+ if(!this.mRunning) {
+ this.mLastTick = System.nanoTime();
+ this.mRunning = true;
+ }
+ }
+
+ public synchronized void stop() {
+ if(this.mRunning) {
+ this.mRunning = false;
+ }
+ }
+
+ public Scene getScene() {
+ return this.mScene;
+ }
+
+ public void setScene(final Scene pScene) {
+ this.mScene = pScene;
+ }
+
+ public EngineOptions getEngineOptions() {
+ return this.mEngineOptions;
+ }
+
+ public Camera getCamera() {
+ return this.mCamera;
+ }
+
+ public float getSecondsElapsedTotal() {
+ return this.mSecondsElapsedTotal;
+ }
+
+ public void setSurfaceSize(final int pSurfaceWidth, final int pSurfaceHeight) {
+ // Debug.w("SurfaceView size changed to (width x height): " + pSurfaceWidth + " x " + pSurfaceHeight, new Exception());
+ this.mSurfaceWidth = pSurfaceWidth;
+ this.mSurfaceHeight = pSurfaceHeight;
+ }
+
+ public int getSurfaceWidth() {
+ return this.mSurfaceWidth;
+ }
+
+ public int getSurfaceHeight() {
+ return this.mSurfaceHeight;
+ }
+
+ public ITouchController getTouchController() {
+ return this.mTouchController;
+ }
+
+ public void setTouchController(final ITouchController pTouchController) {
+ this.mTouchController = pTouchController;
+ this.mTouchController.applyTouchOptions(this.mEngineOptions.getTouchOptions());
+ this.mTouchController.setTouchEventCallback(this);
+ }
+
+ public AccelerometerData getAccelerometerData() {
+ return this.mAccelerometerData;
+ }
+
+ public OrientationData getOrientationData() {
+ return this.mOrientationData;
+ }
+
+ public SoundManager getSoundManager() throws IllegalStateException {
+ if(this.mSoundManager != null) {
+ return this.mSoundManager;
+ } else {
+ throw new IllegalStateException("To enable the SoundManager, check the EngineOptions!");
+ }
+ }
+
+ public MusicManager getMusicManager() throws IllegalStateException {
+ if(this.mMusicManager != null) {
+ return this.mMusicManager;
+ } else {
+ throw new IllegalStateException("To enable the MusicManager, check the EngineOptions!");
+ }
+ }
+
+ public TextureManager getTextureManager() {
+ return this.mTextureManager;
+ }
+
+ public FontManager getFontManager() {
+ return this.mFontManager;
+ }
+
+ public void clearUpdateHandlers() {
+ this.mUpdateHandlers.clear();
+ }
+
+ public void registerUpdateHandler(final IUpdateHandler pUpdateHandler) {
+ this.mUpdateHandlers.add(pUpdateHandler);
+ }
+
+ public void unregisterUpdateHandler(final IUpdateHandler pUpdateHandler) {
+ this.mUpdateHandlers.remove(pUpdateHandler);
+ }
+
+ public boolean isMethodTracing() {
+ return this.mIsMethodTracing;
+ }
+
+ public void startMethodTracing(final String pTraceFileName) {
+ if(!this.mIsMethodTracing) {
+ this.mIsMethodTracing = true;
+ android.os.Debug.startMethodTracing(pTraceFileName);
+ }
+ }
+
+ public void stopMethodTracing() {
+ if(this.mIsMethodTracing) {
+ android.os.Debug.stopMethodTracing();
+ this.mIsMethodTracing = false;
+ }
+ }
+
+ // ===========================================================
+ // Methods for/from SuperClass/Interfaces
+ // ===========================================================
+
+ @Override
+ public void onAccuracyChanged(final Sensor pSensor, final int pAccuracy) {
+ if(this.mRunning) {
+ switch(pSensor.getType()) {
+ case Sensor.TYPE_ACCELEROMETER:
+ if(this.mAccelerometerData != null) {
+ this.mAccelerometerData.setAccuracy(pAccuracy);
+ this.mAccelerometerListener.onAccelerometerChanged(this.mAccelerometerData);
+ } else if(this.mOrientationData != null) {
+ this.mOrientationData.setAccelerometerAccuracy(pAccuracy);
+ this.mOrientationListener.onOrientationChanged(this.mOrientationData);
+ }
+ break;
+ case Sensor.TYPE_MAGNETIC_FIELD:
+ this.mOrientationData.setMagneticFieldAccuracy(pAccuracy);
+ this.mOrientationListener.onOrientationChanged(this.mOrientationData);
+ break;
+ }
+ }
+ }
+
+ @Override
+ public void onSensorChanged(final SensorEvent pEvent) {
+ if(this.mRunning) {
+ switch(pEvent.sensor.getType()) {
+ case Sensor.TYPE_ACCELEROMETER:
+ if(this.mAccelerometerData != null) {
+ this.mAccelerometerData.setValues(pEvent.values);
+ this.mAccelerometerListener.onAccelerometerChanged(this.mAccelerometerData);
+ } else if(this.mOrientationData != null) {
+ this.mOrientationData.setAccelerometerValues(pEvent.values);
+ this.mOrientationListener.onOrientationChanged(this.mOrientationData);
+ }
+ break;
+ case Sensor.TYPE_MAGNETIC_FIELD:
+ this.mOrientationData.setMagneticFieldValues(pEvent.values);
+ this.mOrientationListener.onOrientationChanged(this.mOrientationData);
+ break;
+ }
+ }
+ }
+
+ @Override
+ public void onLocationChanged(final Location pLocation) {
+ if(this.mLocation == null) {
+ this.mLocation = pLocation;
+ } else {
+ if(pLocation == null) {
+ this.mLocationListener.onLocationLost();
+ } else {
+ this.mLocation = pLocation;
+ this.mLocationListener.onLocationChanged(pLocation);
+ }
+ }
+ }
+
+ @Override
+ public void onProviderDisabled(final String pProvider) {
+ this.mLocationListener.onLocationProviderDisabled();
+ }
+
+ @Override
+ public void onProviderEnabled(final String pProvider) {
+ this.mLocationListener.onLocationProviderEnabled();
+ }
+
+ @Override
+ public void onStatusChanged(final String pProvider, final int pStatus, final Bundle pExtras) {
+ switch(pStatus) {
+ case LocationProvider.AVAILABLE:
+ this.mLocationListener.onLocationProviderStatusChanged(LocationProviderStatus.AVAILABLE, pExtras);
+ break;
+ case LocationProvider.OUT_OF_SERVICE:
+ this.mLocationListener.onLocationProviderStatusChanged(LocationProviderStatus.OUT_OF_SERVICE, pExtras);
+ break;
+ case LocationProvider.TEMPORARILY_UNAVAILABLE:
+ this.mLocationListener.onLocationProviderStatusChanged(LocationProviderStatus.TEMPORARILY_UNAVAILABLE, pExtras);
+ break;
+ }
+ }
+
+ @Override
+ public boolean onTouch(final View pView, final MotionEvent pSurfaceMotionEvent) {
+ if(this.mRunning) {
+ final boolean handled = this.mTouchController.onHandleMotionEvent(pSurfaceMotionEvent);
+ try {
+ /*
+ * As a human cannot interact 1000x per second, we pause the
+ * UI-Thread for a little.
+ */
+ Thread.sleep(20); // TODO Maybe this can be removed, when TouchEvents are handled on the UpdateThread!
+ } catch (final InterruptedException e) {
+ Debug.e(e);
+ }
+ return handled;
+ } else {
+ return false;
+ }
+ }
+
+ @Override
+ public boolean onTouchEvent(final TouchEvent pSurfaceTouchEvent) {
+ /*
+ * Let the engine determine which scene and camera this event should be
+ * handled by.
+ */
+ final Scene scene = this.getSceneFromSurfaceTouchEvent(pSurfaceTouchEvent);
+ final Camera camera = this.getCameraFromSurfaceTouchEvent(pSurfaceTouchEvent);
+
+ this.convertSurfaceToSceneTouchEvent(camera, pSurfaceTouchEvent);
+
+ if(this.onTouchHUD(camera, pSurfaceTouchEvent)) {
+ return true;
+ } else {
+ /* If HUD didn't handle it, Scene may handle it. */
+ return this.onTouchScene(scene, pSurfaceTouchEvent);
+ }
+ }
+
+ protected boolean onTouchHUD(final Camera pCamera, final TouchEvent pSceneTouchEvent) {
+ if(pCamera.hasHUD()) {
+ return pCamera.getHUD().onSceneTouchEvent(pSceneTouchEvent);
+ } else {
+ return false;
+ }
+ }
+
+ protected boolean onTouchScene(final Scene pScene, final TouchEvent pSceneTouchEvent) {
+ if(pScene != null) {
+ return pScene.onSceneTouchEvent(pSceneTouchEvent);
+ } else {
+ return false;
+ }
+ }
+
+ // ===========================================================
+ // Methods
+ // ===========================================================
+
+ public void runOnUpdateThread(final Runnable pRunnable) {
+ this.mUpdateThreadRunnableHandler.postRunnable(pRunnable);
+ }
+
+ public void interruptUpdateThread(){
+ this.mUpdateThread.interrupt();
+ }
+
+ public void onResume() {
+ this.mTextureManager.reloadTextures();
+ this.mFontManager.reloadFonts();
+ BufferObjectManager.setActiveInstance(this.mBufferObjectManager);
+ this.mBufferObjectManager.reloadBufferObjects();
+ }
+
+ public void onPause() {
+
+ }
+
+ protected Camera getCameraFromSurfaceTouchEvent(final TouchEvent pTouchEvent) {
+ return this.getCamera();
+ }
+
+ protected Scene getSceneFromSurfaceTouchEvent(final TouchEvent pTouchEvent) {
+ return this.mScene;
+ }
+
+ protected void convertSurfaceToSceneTouchEvent(final Camera pCamera, final TouchEvent pSurfaceTouchEvent) {
+ pCamera.convertSurfaceToSceneTouchEvent(pSurfaceTouchEvent, this.mSurfaceWidth, this.mSurfaceHeight);
+ }
+
+ public void onLoadComplete(final Scene pScene) {
+ this.setScene(pScene);
+ }
+
+ void onTickUpdate() throws InterruptedException {
+ if(this.mRunning) {
+ final long secondsElapsed = this.getNanosecondsElapsed();
+
+ this.onUpdate(secondsElapsed);
+
+ this.yieldDraw();
+ } else {
+ this.yieldDraw();
+
+ Thread.sleep(16);
+ }
+ }
+
+ private void yieldDraw() throws InterruptedException {
+ final State threadLocker = this.mThreadLocker;
+ threadLocker.notifyCanDraw();
+ threadLocker.waitUntilCanUpdate();
+ }
+
+ protected void onUpdate(final long pNanosecondsElapsed) throws InterruptedException {
+ final float pSecondsElapsed = (float)pNanosecondsElapsed / TimeConstants.NANOSECONDSPERSECOND;
+
+ this.mSecondsElapsedTotal += pSecondsElapsed;
+ this.mLastTick += pNanosecondsElapsed;
+
+ this.mTouchController.onUpdate(pSecondsElapsed);
+ this.updateUpdateHandlers(pSecondsElapsed);
+ this.onUpdateScene(pSecondsElapsed);
+ }
+
+ protected void onUpdateScene(final float pSecondsElapsed) {
+ if(this.mScene != null) {
+ this.mScene.onUpdate(pSecondsElapsed);
+ }
+ }
+
+ protected void updateUpdateHandlers(final float pSecondsElapsed) {
+ this.mUpdateThreadRunnableHandler.onUpdate(pSecondsElapsed);
+ this.mUpdateHandlers.onUpdate(pSecondsElapsed);
+ this.getCamera().onUpdate(pSecondsElapsed);
+ }
+
+ public void onDrawFrame(final GL10 pGL) throws InterruptedException {
+ final State threadLocker = this.mThreadLocker;
+
+ threadLocker.waitUntilCanDraw();
+
+ this.mTextureManager.updateTextures(pGL);
+ this.mFontManager.updateFonts(pGL);
+ if(GLHelper.EXTENSIONS_VERTEXBUFFEROBJECTS) {
+ this.mBufferObjectManager.updateBufferObjects((GL11) pGL);
+ }
+
+ this.onDrawScene(pGL);
+
+ threadLocker.notifyCanUpdate();
+ }
+
+ protected void onDrawScene(final GL10 pGL) {
+ final Camera camera = this.getCamera();
+
+ this.mScene.onDraw(pGL, camera);
+
+ camera.onDrawHUD(pGL);
+ }
+
+ private long getNanosecondsElapsed() {
+ final long now = System.nanoTime();
+
+ return this.calculateNanosecondsElapsed(now, this.mLastTick);
+ }
+
+ protected long calculateNanosecondsElapsed(final long pNow, final long pLastTick) {
+ return pNow - pLastTick;
+ }
+
+ public boolean enableVibrator(final Context pContext) {
+ this.mVibrator = (Vibrator) pContext.getSystemService(Context.VIBRATOR_SERVICE);
+ return this.mVibrator != null;
+ }
+
+ public void vibrate(final long pMilliseconds) throws IllegalStateException {
+ if(this.mVibrator != null) {
+ this.mVibrator.vibrate(pMilliseconds);
+ } else {
+ throw new IllegalStateException("You need to enable the Vibrator before you can use it!");
+ }
+ }
+
+ public void vibrate(final long[] pPattern, final int pRepeat) throws IllegalStateException {
+ if(this.mVibrator != null) {
+ this.mVibrator.vibrate(pPattern, pRepeat);
+ } else {
+ throw new IllegalStateException("You need to enable the Vibrator before you can use it!");
+ }
+ }
+
+ public void enableLocationSensor(final Context pContext, final ILocationListener pLocationListener, final LocationSensorOptions pLocationSensorOptions) {
+ this.mLocationListener = pLocationListener;
+
+ final LocationManager locationManager = (LocationManager) pContext.getSystemService(Context.LOCATION_SERVICE);
+ final String locationProvider = locationManager.getBestProvider(pLocationSensorOptions, pLocationSensorOptions.isEnabledOnly());
+ // TODO locationProvider can be null, in that case return false. Successful case should return true.
+ locationManager.requestLocationUpdates(locationProvider, pLocationSensorOptions.getMinimumTriggerTime(), pLocationSensorOptions.getMinimumTriggerDistance(), this);
+
+ this.onLocationChanged(locationManager.getLastKnownLocation(locationProvider));
+ }
+
+ public void disableLocationSensor(final Context pContext) {
+ final LocationManager locationManager = (LocationManager) pContext.getSystemService(Context.LOCATION_SERVICE);
+ locationManager.removeUpdates(this);
+ }
+
+ /**
+ * @see {@link Engine#enableAccelerometerSensor(Context, IAccelerometerListener, AccelerometerSensorOptions)}
+ */
+ public boolean enableAccelerometerSensor(final Context pContext, final IAccelerometerListener pAccelerometerListener) {
+ return this.enableAccelerometerSensor(pContext, pAccelerometerListener, new AccelerometerSensorOptions(SENSORDELAY_DEFAULT));
+ }
+
+ /**
+ * @return true when the sensor was successfully enabled, false otherwise.
+ */
+ public boolean enableAccelerometerSensor(final Context pContext, final IAccelerometerListener pAccelerometerListener, final AccelerometerSensorOptions pAccelerometerSensorOptions) {
+ final SensorManager sensorManager = (SensorManager) pContext.getSystemService(Context.SENSOR_SERVICE);
+ if(this.isSensorSupported(sensorManager, Sensor.TYPE_ACCELEROMETER)) {
+ this.mAccelerometerListener = pAccelerometerListener;
+
+ if(this.mAccelerometerData == null) {
+ this.mAccelerometerData = new AccelerometerData();
+ }
+
+ this.registerSelfAsSensorListener(sensorManager, Sensor.TYPE_ACCELEROMETER, pAccelerometerSensorOptions.getSensorDelay());
+
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+
+ /**
+ * @return true when the sensor was successfully disabled, false otherwise.
+ */
+ public boolean disableAccelerometerSensor(final Context pContext) {
+ final SensorManager sensorManager = (SensorManager) pContext.getSystemService(Context.SENSOR_SERVICE);
+ if(this.isSensorSupported(sensorManager, Sensor.TYPE_ACCELEROMETER)) {
+ this.unregisterSelfAsSensorListener(sensorManager, Sensor.TYPE_ACCELEROMETER);
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * @see {@link Engine#enableOrientationSensor(Context, IOrientationListener, OrientationSensorOptions)}
+ */
+ public boolean enableOrientationSensor(final Context pContext, final IOrientationListener pOrientationListener) {
+ return this.enableOrientationSensor(pContext, pOrientationListener, new OrientationSensorOptions(SENSORDELAY_DEFAULT));
+ }
+
+ /**
+ * @return true when the sensor was successfully enabled, false otherwise.
+ */
+ public boolean enableOrientationSensor(final Context pContext, final IOrientationListener pOrientationListener, final OrientationSensorOptions pOrientationSensorOptions) {
+ final SensorManager sensorManager = (SensorManager) pContext.getSystemService(Context.SENSOR_SERVICE);
+ if(this.isSensorSupported(sensorManager, Sensor.TYPE_ACCELEROMETER) && this.isSensorSupported(sensorManager, Sensor.TYPE_MAGNETIC_FIELD)) {
+ this.mOrientationListener = pOrientationListener;
+
+ if(this.mOrientationData == null) {
+ final Display display = ((WindowManager) pContext.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
+ final int displayRotation = display.getOrientation();
+ this.mOrientationData = new OrientationData(displayRotation);
+ }
+
+ this.registerSelfAsSensorListener(sensorManager, Sensor.TYPE_ACCELEROMETER, pOrientationSensorOptions.getSensorDelay());
+ this.registerSelfAsSensorListener(sensorManager, Sensor.TYPE_MAGNETIC_FIELD, pOrientationSensorOptions.getSensorDelay());
+
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+
+ /**
+ * @return true when the sensor was successfully disabled, false otherwise.
+ */
+ public boolean disableOrientationSensor(final Context pContext) {
+ final SensorManager sensorManager = (SensorManager) pContext.getSystemService(Context.SENSOR_SERVICE);
+ if(this.isSensorSupported(sensorManager, Sensor.TYPE_ACCELEROMETER) && this.isSensorSupported(sensorManager, Sensor.TYPE_MAGNETIC_FIELD)) {
+ this.unregisterSelfAsSensorListener(sensorManager, Sensor.TYPE_ACCELEROMETER);
+ this.unregisterSelfAsSensorListener(sensorManager, Sensor.TYPE_MAGNETIC_FIELD);
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ private boolean isSensorSupported(final SensorManager pSensorManager, final int pType) {
+ return pSensorManager.getSensorList(pType).size() > 0;
+ }
+
+ private void registerSelfAsSensorListener(final SensorManager pSensorManager, final int pType, final SensorDelay pSensorDelay) {
+ final Sensor sensor = pSensorManager.getSensorList(pType).get(0);
+ pSensorManager.registerListener(this, sensor, pSensorDelay.getDelay());
+ }
+
+ private void unregisterSelfAsSensorListener(final SensorManager pSensorManager, final int pType) {
+ final Sensor sensor = pSensorManager.getSensorList(pType).get(0);
+ pSensorManager.unregisterListener(this, sensor);
+ }
+
+ // ===========================================================
+ // Inner and Anonymous Classes
+ // ===========================================================
+
+ private class UpdateThread extends Thread {
+ public UpdateThread() {
+ super("UpdateThread");
+ }
+
+ @Override
+ public void run() {
+ android.os.Process.setThreadPriority(Engine.this.mEngineOptions.getUpdateThreadPriority());
+ try {
+ while(true) {
+ Engine.this.onTickUpdate();
+ }
+ } catch (final InterruptedException e) {
+ Debug.d("UpdateThread interrupted. Don't worry - this Exception is most likely expected!", e);
+ this.interrupt();
+ }
+ }
+ }
+
+ private static class State {
+ boolean mDrawing = false;
+
+ public synchronized void notifyCanDraw() {
+ // Debug.d(">>> notifyCanDraw");
+ this.mDrawing = true;
+ this.notifyAll();
+ // Debug.d("<<< notifyCanDraw");
+ }
+
+ public synchronized void notifyCanUpdate() {
+ // Debug.d(">>> notifyCanUpdate");
+ this.mDrawing = false;
+ this.notifyAll();
+ // Debug.d("<<< notifyCanUpdate");
+ }
+
+ public synchronized void waitUntilCanDraw() throws InterruptedException {
+ // Debug.d(">>> waitUntilCanDraw");
+ while(this.mDrawing == false) {
+ this.wait();
+ }
+ // Debug.d("<<< waitUntilCanDraw");
+ }
+
+ public synchronized void waitUntilCanUpdate() throws InterruptedException {
+ // Debug.d(">>> waitUntilCanUpdate");
+ while(this.mDrawing == true) {
+ this.wait();
+ }
+ // Debug.d("<<< waitUntilCanUpdate");
+ }
+ }
+}
diff --git a/AndEngine/src/org/anddev/andengine/engine/FixedStepEngine.java b/AndEngine/src/org/anddev/andengine/engine/FixedStepEngine.java
new file mode 100644
index 0000000..3dce1d9
--- /dev/null
+++ b/AndEngine/src/org/anddev/andengine/engine/FixedStepEngine.java
@@ -0,0 +1,60 @@
+package org.anddev.andengine.engine;
+
+import org.anddev.andengine.engine.options.EngineOptions;
+
+
+/**
+ * A subclass of {@link Engine} that tries to achieve a specific amount of updates per second.
+ * When the time since the last update is bigger long the steplength, additional updates are executed.
+ *
+ * @author Nicolas Gramlich
+ * @since 10:17:47 - 02.08.2010
+ */
+public class FixedStepEngine extends Engine {
+ // ===========================================================
+ // Constants
+ // ===========================================================
+
+ // ===========================================================
+ // Fields
+ // ===========================================================
+
+ private final long mStepLength;
+ private long mSecondsElapsedAccumulator;
+
+ // ===========================================================
+ // Constructors
+ // ===========================================================
+
+ public FixedStepEngine(final EngineOptions pEngineOptions, final int pStepsPerSecond) {
+ super(pEngineOptions);
+ this.mStepLength = NANOSECONDSPERSECOND / pStepsPerSecond;
+ }
+
+ // ===========================================================
+ // Getter & Setter
+ // ===========================================================
+
+ // ===========================================================
+ // Methods for/from SuperClass/Interfaces
+ // ===========================================================
+
+ @Override
+ public void onUpdate(final long pNanosecondsElapsed) throws InterruptedException {
+ this.mSecondsElapsedAccumulator += pNanosecondsElapsed;
+
+ final long stepLength = this.mStepLength;
+ while(this.mSecondsElapsedAccumulator >= stepLength) {
+ super.onUpdate(stepLength);
+ this.mSecondsElapsedAccumulator -= stepLength;
+ }
+ }
+
+ // ===========================================================
+ // Methods
+ // ===========================================================
+
+ // ===========================================================
+ // Inner and Anonymous Classes
+ // ===========================================================
+}
diff --git a/AndEngine/src/org/anddev/andengine/engine/LimitedFPSEngine.java b/AndEngine/src/org/anddev/andengine/engine/LimitedFPSEngine.java
new file mode 100644
index 0000000..7062c9f
--- /dev/null
+++ b/AndEngine/src/org/anddev/andengine/engine/LimitedFPSEngine.java
@@ -0,0 +1,63 @@
+package org.anddev.andengine.engine;
+
+import org.anddev.andengine.engine.options.EngineOptions;
+
+/**
+ * A subclass of {@link Engine} that tries to achieve a specific amount of
+ * updates per second. When the time since the last update is bigger long the
+ * steplength, additional updates are executed.
+ *
+ * @author Nicolas Gramlich
+ * @since 10:17:47 - 02.08.2010
+ */
+public class LimitedFPSEngine extends Engine {
+ // ===========================================================
+ // Constants
+ // ===========================================================
+
+ // ===========================================================
+ // Fields
+ // ===========================================================
+
+ private final long mPreferredFrameLengthNanoseconds;
+
+ // ===========================================================
+ // Constructors
+ // ===========================================================
+
+ public LimitedFPSEngine(final EngineOptions pEngineOptions, final int pFramesPerSecond) {
+ super(pEngineOptions);
+ this.mPreferredFrameLengthNanoseconds = NANOSECONDSPERSECOND / pFramesPerSecond;
+ }
+
+ // ===========================================================
+ // Getter & Setter
+ // ===========================================================
+
+ // ===========================================================
+ // Methods for/from SuperClass/Interfaces
+ // ===========================================================
+
+ @Override
+ public void onUpdate(final long pNanosecondsElapsed) throws InterruptedException {
+ final long preferredFrameLengthNanoseconds = this.mPreferredFrameLengthNanoseconds;
+ final long deltaFrameLengthNanoseconds = preferredFrameLengthNanoseconds - pNanosecondsElapsed;
+
+ if(deltaFrameLengthNanoseconds <= 0) {
+ super.onUpdate(pNanosecondsElapsed);
+ } else {
+ final int sleepTimeMilliseconds = (int) (deltaFrameLengthNanoseconds / NANOSECONDSPERMILLISECOND);
+
+ Thread.sleep(sleepTimeMilliseconds);
+ super.onUpdate(pNanosecondsElapsed + deltaFrameLengthNanoseconds);
+ }
+ }
+
+ // ===========================================================
+ // Methods
+ // ===========================================================
+
+ // ===========================================================
+ // Inner and Anonymous Classes
+ // ===========================================================
+}
diff --git a/AndEngine/src/org/anddev/andengine/engine/SingleSceneSplitScreenEngine.java b/AndEngine/src/org/anddev/andengine/engine/SingleSceneSplitScreenEngine.java
new file mode 100644
index 0000000..6429c7f
--- /dev/null
+++ b/AndEngine/src/org/anddev/andengine/engine/SingleSceneSplitScreenEngine.java
@@ -0,0 +1,123 @@
+package org.anddev.andengine.engine;
+
+import javax.microedition.khronos.opengles.GL10;
+
+import org.anddev.andengine.engine.camera.Camera;
+import org.anddev.andengine.engine.options.EngineOptions;
+import org.anddev.andengine.input.touch.TouchEvent;
+import org.anddev.andengine.opengl.util.GLHelper;
+
+/**
+ * @author Nicolas Gramlich
+ * @since 22:28:34 - 27.03.2010
+ */
+public class SingleSceneSplitScreenEngine extends Engine {
+ // ===========================================================
+ // Constants
+ // ===========================================================
+
+ // ===========================================================
+ // Fields
+ // ===========================================================
+
+ private final Camera mSecondCamera;
+
+ // ===========================================================
+ // Constructors
+ // ===========================================================
+
+ public SingleSceneSplitScreenEngine(final EngineOptions pEngineOptions, final Camera pSecondCamera) {
+ super(pEngineOptions);
+ this.mSecondCamera = pSecondCamera;
+ }
+
+ // ===========================================================
+ // Getter & Setter
+ // ===========================================================
+
+ @Deprecated
+ @Override
+ public Camera getCamera() {
+ return super.mCamera;
+ }
+
+ public Camera getFirstCamera() {
+ return super.mCamera;
+ }
+
+ public Camera getSecondCamera() {
+ return this.mSecondCamera;
+ }
+
+ // ===========================================================
+ // Methods for/from SuperClass/Interfaces
+ // ===========================================================
+
+ @Override
+ protected void onDrawScene(final GL10 pGL) {
+ final Camera firstCamera = this.getFirstCamera();
+ final Camera secondCamera = this.getSecondCamera();
+
+ final int surfaceWidth = this.mSurfaceWidth;
+ final int surfaceWidthHalf = surfaceWidth >> 1;
+
+ final int surfaceHeight = this.mSurfaceHeight;
+
+ GLHelper.enableScissorTest(pGL);
+
+ /* First Screen. With first camera, on the left half of the screens width. */
+ {
+ pGL.glScissor(0, 0, surfaceWidthHalf, surfaceHeight);
+ pGL.glViewport(0, 0, surfaceWidthHalf, surfaceHeight);
+
+ super.mScene.onDraw(pGL, firstCamera);
+ firstCamera.onDrawHUD(pGL);
+ }
+
+ /* Second Screen. With second camera, on the right half of the screens width. */
+ {
+ pGL.glScissor(surfaceWidthHalf, 0, surfaceWidthHalf, surfaceHeight);
+ pGL.glViewport(surfaceWidthHalf, 0, surfaceWidthHalf, surfaceHeight);
+
+ super.mScene.onDraw(pGL, secondCamera);
+ secondCamera.onDrawHUD(pGL);
+ }
+
+ GLHelper.disableScissorTest(pGL);
+ }
+
+ @Override
+ protected Camera getCameraFromSurfaceTouchEvent(final TouchEvent pTouchEvent) {
+ if(pTouchEvent.getX() <= this.mSurfaceWidth >> 1) {
+ return this.getFirstCamera();
+ } else {
+ return this.getSecondCamera();
+ }
+ }
+
+ @Override
+ protected void convertSurfaceToSceneTouchEvent(final Camera pCamera, final TouchEvent pSurfaceTouchEvent) {
+ final int surfaceWidthHalf = this.mSurfaceWidth >> 1;
+
+ if(pCamera == this.getFirstCamera()) {
+ pCamera.convertSurfaceToSceneTouchEvent(pSurfaceTouchEvent, surfaceWidthHalf, this.mSurfaceHeight);
+ } else {
+ pSurfaceTouchEvent.offset(-surfaceWidthHalf, 0);
+ pCamera.convertSurfaceToSceneTouchEvent(pSurfaceTouchEvent, surfaceWidthHalf, this.mSurfaceHeight);
+ }
+ }
+
+ @Override
+ protected void updateUpdateHandlers(final float pSecondsElapsed) {
+ super.updateUpdateHandlers(pSecondsElapsed);
+ this.getSecondCamera().onUpdate(pSecondsElapsed);
+ }
+
+ // ===========================================================
+ // Methods
+ // ===========================================================
+
+ // ===========================================================
+ // Inner and Anonymous Classes
+ // ===========================================================
+}
diff --git a/AndEngine/src/org/anddev/andengine/engine/camera/BoundCamera.java b/AndEngine/src/org/anddev/andengine/engine/camera/BoundCamera.java
new file mode 100644
index 0000000..789bc8e
--- /dev/null
+++ b/AndEngine/src/org/anddev/andengine/engine/camera/BoundCamera.java
@@ -0,0 +1,164 @@
+package org.anddev.andengine.engine.camera;
+
+/**
+ * @author Nicolas Gramlich
+ * @since 15:55:54 - 27.07.2010
+ */
+public class BoundCamera extends Camera {
+ // ===========================================================
+ // Constants
+ // ===========================================================
+
+ // ===========================================================
+ // Fields
+ // ===========================================================
+
+ protected boolean mBoundsEnabled;
+
+ private float mBoundsMinX;
+ private float mBoundsMaxX;
+ private float mBoundsMinY;
+ private float mBoundsMaxY;
+
+ private float mBoundsCenterX;
+ private float mBoundsCenterY;
+
+ private float mBoundsWidth;
+ private float mBoundsHeight;
+
+ // ===========================================================
+ // Constructors
+ // ===========================================================
+
+ public BoundCamera(final float pX, final float pY, final float pWidth, final float pHeight) {
+ super(pX, pY, pWidth, pHeight);
+ }
+
+ public BoundCamera(final float pX, final float pY, final float pWidth, final float pHeight, final float pBoundMinX, final float pBoundMaxX, final float pBoundMinY, final float pBoundMaxY) {
+ super(pX, pY, pWidth, pHeight);
+ this.setBounds(pBoundMinX, pBoundMaxX, pBoundMinY, pBoundMaxY);
+ this.mBoundsEnabled = true;
+ }
+
+ // ===========================================================
+ // Getter & Setter
+ // ===========================================================
+
+ public boolean isBoundsEnabled() {
+ return this.mBoundsEnabled;
+ }
+
+ public void setBoundsEnabled(final boolean pBoundsEnabled) {
+ this.mBoundsEnabled = pBoundsEnabled;
+ }
+
+ public void setBounds(final float pBoundMinX, final float pBoundMaxX, final float pBoundMinY, final float pBoundMaxY) {
+ this.mBoundsMinX = pBoundMinX;
+ this.mBoundsMaxX = pBoundMaxX;
+ this.mBoundsMinY = pBoundMinY;
+ this.mBoundsMaxY = pBoundMaxY;
+
+ this.mBoundsWidth = this.mBoundsMaxX - this.mBoundsMinX;
+ this.mBoundsHeight = this.mBoundsMaxY - this.mBoundsMinY;
+
+ this.mBoundsCenterX = this.mBoundsMinX + this.mBoundsWidth * 0.5f;
+ this.mBoundsCenterY = this.mBoundsMinY + this.mBoundsHeight * 0.5f;
+ }
+
+ public float getBoundsWidth() {
+ return this.mBoundsWidth;
+ }
+
+ public float getBoundsHeight() {
+ return this.mBoundsHeight;
+ }
+
+ @Override
+ public void setCenter(final float pCenterX, final float pCenterY) {
+ super.setCenter(pCenterX, pCenterY);
+
+ if(this.mBoundsEnabled) {
+ this.ensureInBounds();
+ }
+ }
+
+ // ===========================================================
+ // Methods for/from SuperClass/Interfaces
+ // ===========================================================
+
+ // ===========================================================
+ // Methods
+ // ===========================================================
+
+ protected void ensureInBounds() {
+ super.setCenter(this.determineBoundedX(), this.determineBoundedY());
+ }
+
+ private float determineBoundedX() {
+ if(this.mBoundsWidth < this.getWidth()) {
+ return this.mBoundsCenterX;
+ } else {
+ final float currentCenterX = this.getCenterX();
+
+ final float minXBoundExceededAmount = this.mBoundsMinX - this.getMinX();
+ final boolean minXBoundExceeded = minXBoundExceededAmount > 0;
+
+ final float maxXBoundExceededAmount = this.getMaxX() - this.mBoundsMaxX;
+ final boolean maxXBoundExceeded = maxXBoundExceededAmount > 0;
+
+ if(minXBoundExceeded) {
+ if(maxXBoundExceeded) {
+ /* Min and max X exceeded. */
+ return currentCenterX - maxXBoundExceededAmount + minXBoundExceededAmount;
+ } else {
+ /* Only min X exceeded. */
+ return currentCenterX + minXBoundExceededAmount;
+ }
+ } else {
+ if(maxXBoundExceeded) {
+ /* Only max X exceeded. */
+ return currentCenterX - maxXBoundExceededAmount;
+ } else {
+ /* Nothing exceeded. */
+ return currentCenterX;
+ }
+ }
+ }
+ }
+
+ private float determineBoundedY() {
+ if(this.mBoundsHeight < this.getHeight()) {
+ return this.mBoundsCenterY;
+ } else {
+ final float currentCenterY = this.getCenterY();
+
+ final float minYBoundExceededAmount = this.mBoundsMinY - this.getMinY();
+ final boolean minYBoundExceeded = minYBoundExceededAmount > 0;
+
+ final float maxYBoundExceededAmount = this.getMaxY() - this.mBoundsMaxY;
+ final boolean maxYBoundExceeded = maxYBoundExceededAmount > 0;
+
+ if(minYBoundExceeded) {
+ if(maxYBoundExceeded) {
+ /* Min and max Y exceeded. */
+ return currentCenterY - maxYBoundExceededAmount + minYBoundExceededAmount;
+ } else {
+ /* Only min Y exceeded. */
+ return currentCenterY + minYBoundExceededAmount;
+ }
+ } else {
+ if(maxYBoundExceeded) {
+ /* Only max Y exceeded. */
+ return currentCenterY - maxYBoundExceededAmount;
+ } else {
+ /* Nothing exceeded. */
+ return currentCenterY;
+ }
+ }
+ }
+ }
+
+ // ===========================================================
+ // Inner and Anonymous Classes
+ // ===========================================================
+}
diff --git a/AndEngine/src/org/anddev/andengine/engine/camera/Camera.java b/AndEngine/src/org/anddev/andengine/engine/camera/Camera.java
new file mode 100644
index 0000000..d733a98
--- /dev/null
+++ b/AndEngine/src/org/anddev/andengine/engine/camera/Camera.java
@@ -0,0 +1,364 @@
+package org.anddev.andengine.engine.camera;
+
+import static org.anddev.andengine.util.constants.Constants.VERTEX_INDEX_X;
+import static org.anddev.andengine.util.constants.Constants.VERTEX_INDEX_Y;
+
+import javax.microedition.khronos.opengles.GL10;
+
+import org.anddev.andengine.collision.BaseCollisionChecker;
+import org.anddev.andengine.engine.camera.hud.HUD;
+import org.anddev.andengine.engine.handler.IUpdateHandler;
+import org.anddev.andengine.entity.IEntity;
+import org.anddev.andengine.entity.shape.RectangularShape;
+import org.anddev.andengine.input.touch.TouchEvent;
+import org.anddev.andengine.opengl.util.GLHelper;
+import org.anddev.andengine.util.MathUtils;
+
+/**
+ * @author Nicolas Gramlich
+ * @since 10:24:18 - 25.03.2010
+ */
+public class Camera implements IUpdateHandler {
+ // ===========================================================
+ // Constants
+ // ===========================================================
+
+ protected static final float[] VERTICES_TOUCH_TMP = new float[2];
+
+ // ===========================================================
+ // Fields
+ // ===========================================================
+
+ private float mMinX;
+ private float mMaxX;
+ private float mMinY;
+ private float mMaxY;
+
+ private float mNearZ = -1.0f;
+ private float mFarZ = 1.0f;
+
+ private HUD mHUD;
+
+ private IEntity mChaseEntity;
+
+ protected float mRotation = 0;
+ protected float mCameraSceneRotation = 0;
+
+ // ===========================================================
+ // Constructors
+ // ===========================================================
+
+ public Camera(final float pX, final float pY, final float pWidth, final float pHeight) {
+ this.mMinX = pX;
+ this.mMaxX = pX + pWidth;
+ this.mMinY = pY;
+ this.mMaxY = pY + pHeight;
+ }
+
+ // ===========================================================
+ // Getter & Setter
+ // ===========================================================
+
+ public float getMinX() {
+ return this.mMinX;
+ }
+
+ public float getMaxX() {
+ return this.mMaxX;
+ }
+
+ public float getMinY() {
+ return this.mMinY;
+ }
+
+ public float getMaxY() {
+ return this.mMaxY;
+ }
+
+ public float getNearZClippingPlane() {
+ return this.mNearZ;
+ }
+
+ public float getFarZClippingPlane() {
+ return this.mFarZ;
+ }
+
+ public void setNearZClippingPlane(final float pNearZClippingPlane) {
+ this.mNearZ = pNearZClippingPlane;
+ }
+
+ public void setFarZClippingPlane(final float pFarZClippingPlane) {
+ this.mFarZ = pFarZClippingPlane;
+ }
+
+ public void setZClippingPlanes(final float pNearZClippingPlane, final float pFarZClippingPlane) {
+ this.mNearZ = pNearZClippingPlane;
+ this.mFarZ = pFarZClippingPlane;
+ }
+
+ public float getWidth() {
+ return this.mMaxX - this.mMinX;
+ }
+
+ public float getHeight() {
+ return this.mMaxY - this.mMinY;
+ }
+
+ public float getCenterX() {
+ final float minX = this.mMinX;
+ return minX + (this.mMaxX - minX) * 0.5f;
+ }
+
+ public float getCenterY() {
+ final float minY = this.mMinY;
+ return minY + (this.mMaxY - minY) * 0.5f;
+ }
+
+ public void setCenter(final float pCenterX, final float pCenterY) {
+ final float dX = pCenterX - this.getCenterX();
+ final float dY = pCenterY - this.getCenterY();
+
+ this.mMinX += dX;
+ this.mMaxX += dX;
+ this.mMinY += dY;
+ this.mMaxY += dY;
+ }
+
+ public void offsetCenter(final float pX, final float pY) {
+ this.setCenter(this.getCenterX() + pX, this.getCenterY() + pY);
+ }
+
+ public HUD getHUD() {
+ return this.mHUD;
+ }
+
+ public void setHUD(final HUD pHUD) {
+ this.mHUD = pHUD;
+ pHUD.setCamera(this);
+ }
+
+ public boolean hasHUD() {
+ return this.mHUD != null;
+ }
+
+ public void setChaseEntity(final IEntity pChaseEntity) {
+ this.mChaseEntity = pChaseEntity;
+ }
+
+ public float getRotation() {
+ return this.mRotation;
+ }
+
+ public void setRotation(final float pRotation) {
+ this.mRotation = pRotation;
+ }
+
+ public float getCameraSceneRotation() {
+ return this.mCameraSceneRotation;
+ }
+
+ public void setCameraSceneRotation(final float pCameraSceneRotation) {
+ this.mCameraSceneRotation = pCameraSceneRotation;
+ }
+
+ // ===========================================================
+ // Methods for/from SuperClass/Interfaces
+ // ===========================================================
+
+ @Override
+ public void onUpdate(final float pSecondsElapsed) {
+ if(this.mHUD != null) {
+ this.mHUD.onUpdate(pSecondsElapsed);
+ }
+
+ if(this.mChaseEntity != null) {
+ final float[] centerCoordinates = this.mChaseEntity.getSceneCenterCoordinates();
+ this.setCenter(centerCoordinates[VERTEX_INDEX_X], centerCoordinates[VERTEX_INDEX_Y]);
+ }
+ }
+
+ @Override
+ public void reset() {
+
+ }
+
+ // ===========================================================
+ // Methods
+ // ===========================================================
+
+ public void onDrawHUD(final GL10 pGL) {
+ if(this.mHUD != null) {
+ this.mHUD.onDraw(pGL, this);
+ }
+ }
+
+ public boolean isRectangularShapeVisible(final RectangularShape pRectangularShape) {
+ final float otherLeft = pRectangularShape.getX();
+ final float otherTop = pRectangularShape.getY();
+ final float otherRight = pRectangularShape.getWidthScaled() + otherLeft;
+ final float otherBottom = pRectangularShape.getHeightScaled() + otherTop;
+
+ // TODO Should also use RectangularShapeCollisionChecker
+ return BaseCollisionChecker.checkAxisAlignedRectangleCollision(this.getMinX(), this.getMinY(), this.getMaxX(), this.getMaxY(), otherLeft, otherTop, otherRight, otherBottom);
+ }
+
+ public void onApplyMatrix(final GL10 pGL) {
+ GLHelper.setProjectionIdentityMatrix(pGL);
+
+ pGL.glOrthof(this.getMinX(), this.getMaxX(), this.getMaxY(), this.getMinY(), this.mNearZ, this.mFarZ);
+
+ final float rotation = this.mRotation;
+ if(rotation != 0) {
+ this.applyRotation(pGL, this.getCenterX(), this.getCenterY(), rotation);
+ }
+ }
+
+ public void onApplyPositionIndependentMatrix(final GL10 pGL) {
+ GLHelper.setProjectionIdentityMatrix(pGL);
+
+ final float width = this.mMaxX - this.mMinX;
+ final float height = this.mMaxY - this.mMinY;
+
+ pGL.glOrthof(0, width, height, 0, this.mNearZ, this.mFarZ);
+
+ final float rotation = this.mRotation;
+ if(rotation != 0) {
+ this.applyRotation(pGL, width * 0.5f, height * 0.5f, rotation);
+ }
+ }
+
+ public void onApplyCameraSceneMatrix(final GL10 pGL) {
+ GLHelper.setProjectionIdentityMatrix(pGL);
+
+ final float width = this.mMaxX - this.mMinX;
+ final float height = this.mMaxY - this.mMinY;
+
+ pGL.glOrthof(0, width, height, 0, this.mNearZ, this.mFarZ);
+
+ final float cameraSceneRotation = this.mCameraSceneRotation;
+ if(cameraSceneRotation != 0) {
+ this.applyRotation(pGL, width * 0.5f, height * 0.5f, cameraSceneRotation);
+ }
+ }
+
+ private void applyRotation(final GL10 pGL, final float pRotationCenterX, final float pRotationCenterY, final float pAngle) {
+ pGL.glTranslatef(pRotationCenterX, pRotationCenterY, 0);
+ pGL.glRotatef(pAngle, 0, 0, 1);
+ pGL.glTranslatef(-pRotationCenterX, -pRotationCenterY, 0);
+ }
+
+ public void convertSceneToCameraSceneTouchEvent(final TouchEvent pSceneTouchEvent) {
+ this.unapplySceneRotation(pSceneTouchEvent);
+
+ this.applySceneToCameraSceneOffset(pSceneTouchEvent);
+
+ this.applyCameraSceneRotation(pSceneTouchEvent);
+ }
+
+ public void convertCameraSceneToSceneTouchEvent(final TouchEvent pCameraSceneTouchEvent) {
+ this.unapplyCameraSceneRotation(pCameraSceneTouchEvent);
+
+ this.unapplySceneToCameraSceneOffset(pCameraSceneTouchEvent);
+
+ this.applySceneRotation(pCameraSceneTouchEvent);
+ }
+
+ protected void applySceneToCameraSceneOffset(final TouchEvent pSceneTouchEvent) {
+ pSceneTouchEvent.offset(-this.mMinX, -this.mMinY);
+ }
+
+ protected void unapplySceneToCameraSceneOffset(final TouchEvent pCameraSceneTouchEvent) {
+ pCameraSceneTouchEvent.offset(this.mMinX, this.mMinY);
+ }
+
+ private void applySceneRotation(final TouchEvent pCameraSceneTouchEvent) {
+ final float rotation = -this.mRotation;
+ if(rotation != 0) {
+ VERTICES_TOUCH_TMP[VERTEX_INDEX_X] = pCameraSceneTouchEvent.getX();
+ VERTICES_TOUCH_TMP[VERTEX_INDEX_Y] = pCameraSceneTouchEvent.getY();
+
+ MathUtils.rotateAroundCenter(VERTICES_TOUCH_TMP, rotation, this.getCenterX(), this.getCenterY());
+
+ pCameraSceneTouchEvent.set(VERTICES_TOUCH_TMP[VERTEX_INDEX_X], VERTICES_TOUCH_TMP[VERTEX_INDEX_Y]);
+ }
+ }
+
+ private void unapplySceneRotation(final TouchEvent pSceneTouchEvent) {
+ final float rotation = this.mRotation;
+
+ if(rotation != 0) {
+ VERTICES_TOUCH_TMP[VERTEX_INDEX_X] = pSceneTouchEvent.getX();
+ VERTICES_TOUCH_TMP[VERTEX_INDEX_Y] = pSceneTouchEvent.getY();
+
+ MathUtils.revertRotateAroundCenter(VERTICES_TOUCH_TMP, rotation, this.getCenterX(), this.getCenterY());
+
+ pSceneTouchEvent.set(VERTICES_TOUCH_TMP[VERTEX_INDEX_X], VERTICES_TOUCH_TMP[VERTEX_INDEX_Y]);
+ }
+ }
+
+ private void applyCameraSceneRotation(final TouchEvent pSceneTouchEvent) {
+ final float cameraSceneRotation = -this.mCameraSceneRotation;
+
+ if(cameraSceneRotation != 0) {
+ VERTICES_TOUCH_TMP[VERTEX_INDEX_X] = pSceneTouchEvent.getX();
+ VERTICES_TOUCH_TMP[VERTEX_INDEX_Y] = pSceneTouchEvent.getY();
+
+ MathUtils.rotateAroundCenter(VERTICES_TOUCH_TMP, cameraSceneRotation, (this.mMaxX - this.mMinX) * 0.5f, (this.mMaxY - this.mMinY) * 0.5f);
+
+ pSceneTouchEvent.set(VERTICES_TOUCH_TMP[VERTEX_INDEX_X], VERTICES_TOUCH_TMP[VERTEX_INDEX_Y]);
+ }
+ }
+
+ private void unapplyCameraSceneRotation(final TouchEvent pCameraSceneTouchEvent) {
+ final float cameraSceneRotation = -this.mCameraSceneRotation;
+
+ if(cameraSceneRotation != 0) {
+ VERTICES_TOUCH_TMP[VERTEX_INDEX_X] = pCameraSceneTouchEvent.getX();
+ VERTICES_TOUCH_TMP[VERTEX_INDEX_Y] = pCameraSceneTouchEvent.getY();
+
+ MathUtils.revertRotateAroundCenter(VERTICES_TOUCH_TMP, cameraSceneRotation, (this.mMaxX - this.mMinX) * 0.5f, (this.mMaxY - this.mMinY) * 0.5f);
+
+ pCameraSceneTouchEvent.set(VERTICES_TOUCH_TMP[VERTEX_INDEX_X], VERTICES_TOUCH_TMP[VERTEX_INDEX_Y]);
+ }
+ }
+
+ public void convertSurfaceToSceneTouchEvent(final TouchEvent pSurfaceTouchEvent, final int pSurfaceWidth, final int pSurfaceHeight) {
+ final float relativeX;
+ final float relativeY;
+
+ final float rotation = this.mRotation;
+ if(rotation == 0) {
+ relativeX = pSurfaceTouchEvent.getX() / pSurfaceWidth;
+ relativeY = pSurfaceTouchEvent.getY() / pSurfaceHeight;
+ } else if(rotation == 180) {
+ relativeX = 1 - (pSurfaceTouchEvent.getX() / pSurfaceWidth);
+ relativeY = 1 - (pSurfaceTouchEvent.getY() / pSurfaceHeight);
+ } else {
+ VERTICES_TOUCH_TMP[VERTEX_INDEX_X] = pSurfaceTouchEvent.getX();
+ VERTICES_TOUCH_TMP[VERTEX_INDEX_Y] = pSurfaceTouchEvent.getY();
+
+ MathUtils.rotateAroundCenter(VERTICES_TOUCH_TMP, rotation, pSurfaceWidth / 2, pSurfaceHeight / 2);
+
+ relativeX = VERTICES_TOUCH_TMP[VERTEX_INDEX_X] / pSurfaceWidth;
+ relativeY = VERTICES_TOUCH_TMP[VERTEX_INDEX_Y] / pSurfaceHeight;
+ }
+
+ this.convertAxisAlignedSurfaceToSceneTouchEvent(pSurfaceTouchEvent, relativeX, relativeY);
+ }
+
+ private void convertAxisAlignedSurfaceToSceneTouchEvent(final TouchEvent pSurfaceTouchEvent, final float pRelativeX, final float pRelativeY) {
+ final float minX = this.getMinX();
+ final float maxX = this.getMaxX();
+ final float minY = this.getMinY();
+ final float maxY = this.getMaxY();
+
+ final float x = minX + pRelativeX * (maxX - minX);
+ final float y = minY + pRelativeY * (maxY - minY);
+
+ pSurfaceTouchEvent.set(x, y);
+ }
+
+ // ===========================================================
+ // Inner and Anonymous Classes
+ // ===========================================================
+}
diff --git a/AndEngine/src/org/anddev/andengine/engine/camera/CameraFactory.java b/AndEngine/src/org/anddev/andengine/engine/camera/CameraFactory.java
new file mode 100644
index 0000000..5989e8c
--- /dev/null
+++ b/AndEngine/src/org/anddev/andengine/engine/camera/CameraFactory.java
@@ -0,0 +1,52 @@
+package org.anddev.andengine.engine.camera;
+
+import android.app.Activity;
+import android.util.DisplayMetrics;
+
+/**
+ * @author Nicolas Gramlich
+ * @since 13:50:42 - 03.07.2010
+ */
+public class CameraFactory {
+ // ===========================================================
+ // Constants
+ // ===========================================================
+
+ // ===========================================================
+ // Fields
+ // ===========================================================
+
+ // ===========================================================
+ // Constructors
+ // ===========================================================
+
+ // ===========================================================
+ // Getter & Setter
+ // ===========================================================
+
+ // ===========================================================
+ // Methods for/from SuperClass/Interfaces
+ // ===========================================================
+
+ // ===========================================================
+ // Methods
+ // ===========================================================
+
+ public static Camera createPixelPerfectCamera(final Activity pActivity, final float pCenterX, final float pCenterY) {
+ final DisplayMetrics displayMetrics = CameraFactory.getDisplayMetrics(pActivity);
+
+ final float width = displayMetrics.widthPixels;
+ final float height = displayMetrics.heightPixels;
+ return new Camera(pCenterX - width * 0.5f, pCenterY - height * 0.5f, width, height);
+ }
+
+ private static DisplayMetrics getDisplayMetrics(final Activity pActivity) {
+ final DisplayMetrics displayMetrics = new DisplayMetrics();
+ pActivity.getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
+ return displayMetrics;
+ }
+
+ // ===========================================================
+ // Inner and Anonymous Classes
+ // ===========================================================
+}
diff --git a/AndEngine/src/org/anddev/andengine/engine/camera/SmoothCamera.java b/AndEngine/src/org/anddev/andengine/engine/camera/SmoothCamera.java
new file mode 100644
index 0000000..f264c59
--- /dev/null
+++ b/AndEngine/src/org/anddev/andengine/engine/camera/SmoothCamera.java
@@ -0,0 +1,147 @@
+package org.anddev.andengine.engine.camera;
+
+
+/**
+ * @author Nicolas Gramlich
+ * @since 22:11:17 - 25.03.2010
+ */
+public class SmoothCamera extends ZoomCamera {
+ // ===========================================================
+ // Constants
+ // ===========================================================
+
+ // ===========================================================
+ // Fields
+ // ===========================================================
+
+ private float mMaxVelocityX;
+ private float mMaxVelocityY;
+ private float mMaxZoomFactorChange;
+
+ private float mTargetCenterX;
+ private float mTargetCenterY;
+
+ private float mTargetZoomFactor;
+
+ // ===========================================================
+ // Constructors
+ // ===========================================================
+
+ public SmoothCamera(final float pX, final float pY, final float pWidth, final float pHeight, final float pMaxVelocityX, final float pMaxVelocityY, final float pMaxZoomFactorChange) {
+ super(pX, pY, pWidth, pHeight);
+ this.mMaxVelocityX = pMaxVelocityX;
+ this.mMaxVelocityY = pMaxVelocityY;
+ this.mMaxZoomFactorChange = pMaxZoomFactorChange;
+
+ this.mTargetCenterX = this.getCenterX();
+ this.mTargetCenterY = this.getCenterY();
+
+ this.mTargetZoomFactor = 1.0f;
+ }
+
+ // ===========================================================
+ // Getter & Setter
+ // ===========================================================
+
+ @Override
+ public void setCenter(final float pCenterX, final float pCenterY) {
+ this.mTargetCenterX = pCenterX;
+ this.mTargetCenterY = pCenterY;
+ }
+
+ public void setCenterDirect(final float pCenterX, final float pCenterY) {
+ super.setCenter(pCenterX, pCenterY);
+ this.mTargetCenterX = pCenterX;
+ this.mTargetCenterY = pCenterY;
+ }
+
+ @Override
+ public void setZoomFactor(final float pZoomFactor) {
+ this.mTargetZoomFactor = pZoomFactor;
+ }
+
+ public void setMaxVelocityX(final float pMaxVelocityX) {
+ this.mMaxVelocityX = pMaxVelocityX;
+ }
+
+ public void setMaxVelocityY(final float pMaxVelocityY) {
+ this.mMaxVelocityY = pMaxVelocityY;
+ }
+
+ public void setMaxVelocityX(final float pMaxVelocityX, final float pMaxVelocityY) {
+ this.mMaxVelocityX = pMaxVelocityX;
+ this.mMaxVelocityY = pMaxVelocityY;
+ }
+
+ public void setMaxZoomFactorChange(final float pMaxZoomFactorChange) {
+ this.mMaxZoomFactorChange = pMaxZoomFactorChange;
+ }
+
+ // ===========================================================
+ // Methods for/from SuperClass/Interfaces
+ // ===========================================================
+
+ @Override
+ public void onUpdate(final float pSecondsElapsed) {
+ super.onUpdate(pSecondsElapsed);
+ /* Update center. */
+ final float currentCenterX = this.getCenterX();
+ final float currentCenterY = this.getCenterY();
+
+ final float targetCenterX = this.mTargetCenterX;
+ final float targetCenterY = this.mTargetCenterY;
+
+ if(currentCenterX != targetCenterX || currentCenterY != targetCenterY) {
+ final float diffX = targetCenterX - currentCenterX;
+ final float dX = this.cutToMaxVelocityX(diffX, pSecondsElapsed);
+
+ final float diffY = targetCenterY - currentCenterY;
+ final float dY = this.cutToMaxVelocityY(diffY, pSecondsElapsed);
+
+ super.setCenter(currentCenterX + dX, currentCenterY + dY);
+ }
+
+ /* Update zoom. */
+ final float currentZoom = this.getZoomFactor();
+
+ final float targetZoomFactor = this.mTargetZoomFactor;
+
+ if(currentZoom != targetZoomFactor) {
+ final float diffZoom = targetZoomFactor - currentZoom;
+ final float dZoom = this.cutToMaxZoomFactorChange(diffZoom, pSecondsElapsed);
+ super.setZoomFactor(currentZoom + dZoom);
+ }
+ }
+
+ private float cutToMaxVelocityX(final float pValue, final float pSecondsElapsed) {
+ if(pValue > 0) {
+ return Math.min(pValue, this.mMaxVelocityX * pSecondsElapsed);
+ } else {
+ return Math.max(pValue, -this.mMaxVelocityX * pSecondsElapsed);
+ }
+ }
+
+ private float cutToMaxVelocityY(final float pValue, final float pSecondsElapsed) {
+ if(pValue > 0) {
+ return Math.min(pValue, this.mMaxVelocityY * pSecondsElapsed);
+ } else {
+ return Math.max(pValue, -this.mMaxVelocityY * pSecondsElapsed);
+ }
+ }
+
+ private float cutToMaxZoomFactorChange(final float pValue, final float pSecondsElapsed) {
+ if(pValue > 0) {
+ return Math.min(pValue, this.mMaxZoomFactorChange * pSecondsElapsed);
+ } else {
+ return Math.max(pValue, -this.mMaxZoomFactorChange * pSecondsElapsed);
+ }
+ }
+
+ // ===========================================================
+ // Methods
+ // ===========================================================
+
+ // ===========================================================
+ // Inner and Anonymous Classes
+ // ===========================================================
+}
diff --git a/AndEngine/src/org/anddev/andengine/engine/camera/ZoomCamera.java b/AndEngine/src/org/anddev/andengine/engine/camera/ZoomCamera.java
new file mode 100644
index 0000000..98a59a4
--- /dev/null
+++ b/AndEngine/src/org/anddev/andengine/engine/camera/ZoomCamera.java
@@ -0,0 +1,147 @@
+package org.anddev.andengine.engine.camera;
+
+import static org.anddev.andengine.util.constants.Constants.VERTEX_INDEX_X;
+import static org.anddev.andengine.util.constants.Constants.VERTEX_INDEX_Y;
+
+import org.anddev.andengine.input.touch.TouchEvent;
+import org.anddev.andengine.util.MathUtils;
+
+
+
+/**
+ * @author Nicolas Gramlich
+ * @since 15:48:11 - 24.06.2010
+ * TODO min/max(X/Y) values could be cached and only updated once the zoomfactor/center changed.
+ */
+public class ZoomCamera extends BoundCamera {
+ // ===========================================================
+ // Constants
+ // ===========================================================
+
+ // ===========================================================
+ // Fields
+ // ===========================================================
+
+ private float mZoomFactor = 1.0f;
+
+ // ===========================================================
+ // Constructors
+ // ===========================================================
+
+ public ZoomCamera(final float pX, final float pY, final float pWidth, final float pHeight) {
+ super(pX, pY, pWidth, pHeight);
+ }
+
+ // ===========================================================
+ // Getter & Setter
+ // ===========================================================
+
+ public float getZoomFactor() {
+ return this.mZoomFactor;
+ }
+
+ public void setZoomFactor(final float pZoomFactor) {
+ this.mZoomFactor = pZoomFactor;
+
+ if(this.mBoundsEnabled) {
+ this.ensureInBounds();
+ }
+ }
+
+ // ===========================================================
+ // Methods for/from SuperClass/Interfaces
+ // ===========================================================
+
+ @Override
+ public float getMinX() {
+ if(this.mZoomFactor == 1.0f) {
+ return super.getMinX();
+ } else {
+ final float centerX = this.getCenterX();
+ return centerX - (centerX - super.getMinX()) / this.mZoomFactor;
+ }
+ }
+
+ @Override
+ public float getMaxX() {
+ if(this.mZoomFactor == 1.0f) {
+ return super.getMaxX();
+ } else {
+ final float centerX = this.getCenterX();
+ return centerX + (super.getMaxX() - centerX) / this.mZoomFactor;
+ }
+ }
+
+ @Override
+ public float getMinY() {
+ if(this.mZoomFactor == 1.0f) {
+ return super.getMinY();
+ } else {
+ final float centerY = this.getCenterY();
+ return centerY - (centerY - super.getMinY()) / this.mZoomFactor;
+ }
+ }
+
+ @Override
+ public float getMaxY() {
+ if(this.mZoomFactor == 1.0f) {
+ return super.getMaxY();
+ } else {
+ final float centerY = this.getCenterY();
+ return centerY + (super.getMaxY() - centerY) / this.mZoomFactor;
+ }
+ }
+
+ @Override
+ public float getWidth() {
+ return super.getWidth() / this.mZoomFactor;
+ }
+
+ @Override
+ public float getHeight() {
+ return super.getHeight() / this.mZoomFactor;
+ }
+
+ @Override
+ protected void applySceneToCameraSceneOffset(final TouchEvent pSceneTouchEvent) {
+ final float zoomFactor = this.mZoomFactor;
+ if(zoomFactor != 1) {
+ final float scaleCenterX = this.getCenterX();
+ final float scaleCenterY = this.getCenterY();
+
+ VERTICES_TOUCH_TMP[VERTEX_INDEX_X] = pSceneTouchEvent.getX();
+ VERTICES_TOUCH_TMP[VERTEX_INDEX_Y] = pSceneTouchEvent.getY();
+
+ MathUtils.scaleAroundCenter(VERTICES_TOUCH_TMP, zoomFactor, zoomFactor, scaleCenterX, scaleCenterY);
+
+ pSceneTouchEvent.set(VERTICES_TOUCH_TMP[VERTEX_INDEX_X], VERTICES_TOUCH_TMP[VERTEX_INDEX_Y]);
+ }
+ super.applySceneToCameraSceneOffset(pSceneTouchEvent);
+ }
+
+ @Override
+ protected void unapplySceneToCameraSceneOffset(final TouchEvent pCameraSceneTouchEvent) {
+ super.unapplySceneToCameraSceneOffset(pCameraSceneTouchEvent);
+
+ final float zoomFactor = this.mZoomFactor;
+ if(zoomFactor != 1) {
+ final float scaleCenterX = this.getCenterX();
+ final float scaleCenterY = this.getCenterY();
+
+ VERTICES_TOUCH_TMP[VERTEX_INDEX_X] = pCameraSceneTouchEvent.getX();
+ VERTICES_TOUCH_TMP[VERTEX_INDEX_Y] = pCameraSceneTouchEvent.getY();
+
+ MathUtils.revertScaleAroundCenter(VERTICES_TOUCH_TMP, zoomFactor, zoomFactor, scaleCenterX, scaleCenterY);
+
+ pCameraSceneTouchEvent.set(VERTICES_TOUCH_TMP[VERTEX_INDEX_X], VERTICES_TOUCH_TMP[VERTEX_INDEX_Y]);
+ }
+ }
+
+ // ===========================================================
+ // Methods
+ // ===========================================================
+
+ // ===========================================================
+ // Inner and Anonymous Classes
+ // ===========================================================
+}
diff --git a/AndEngine/src/org/anddev/andengine/engine/camera/hud/HUD.java b/AndEngine/src/org/anddev/andengine/engine/camera/hud/HUD.java
new file mode 100644
index 0000000..e230779
--- /dev/null
+++ b/AndEngine/src/org/anddev/andengine/engine/camera/hud/HUD.java
@@ -0,0 +1,54 @@
+package org.anddev.andengine.engine.camera.hud;
+
+import org.anddev.andengine.engine.camera.Camera;
+import org.anddev.andengine.entity.scene.CameraScene;
+import org.anddev.andengine.entity.scene.Scene;
+
+/**
+ * While you can add a {@link HUD} to {@link Scene}, you should not do so.
+ * {@link HUD}s are meant to be added to {@link Camera}s via {@link Camera#setHUD(HUD)}.
+ *
+ * @author Nicolas Gramlich
+ * @since 14:13:13 - 01.04.2010
+ */
+public class HUD extends CameraScene {
+ // ===========================================================
+ // Constants
+ // ===========================================================
+
+ // ===========================================================
+ // Fields
+ // ===========================================================
+
+ // ===========================================================
+ // Constructors
+ // ===========================================================
+
+ public HUD() {
+ this(1);
+
+ this.setBackgroundEnabled(false);
+ }
+
+ public HUD(final int pLayerCount) {
+ super(pLayerCount);
+
+ this.setBackgroundEnabled(false);
+ }
+
+ // ===========================================================
+ // Getter & Setter
+ // ===========================================================
+
+ // ===========================================================
+ // Methods for/from SuperClass/Interfaces
+ // ===========================================================
+
+ // ===========================================================
+ // Methods
+ // ===========================================================
+
+ // ===========================================================
+ // Inner and Anonymous Classes
+ // ===========================================================
+}
diff --git a/AndEngine/src/org/anddev/andengine/engine/camera/hud/controls/AnalogOnScreenControl.java b/AndEngine/src/org/anddev/andengine/engine/camera/hud/controls/AnalogOnScreenControl.java
new file mode 100644
index 0000000..e972d21
--- /dev/null
+++ b/AndEngine/src/org/anddev/andengine/engine/camera/hud/controls/AnalogOnScreenControl.java
@@ -0,0 +1,103 @@
+package org.anddev.andengine.engine.camera.hud.controls;
+
+import org.anddev.andengine.engine.camera.Camera;
+import org.anddev.andengine.input.touch.TouchEvent;
+import org.anddev.andengine.input.touch.detector.ClickDetector;
+import org.anddev.andengine.input.touch.detector.ClickDetector.IClickDetectorListener;
+import org.anddev.andengine.opengl.texture.region.TextureRegion;
+import org.anddev.andengine.util.MathUtils;
+import org.anddev.andengine.util.constants.TimeConstants;
+
+import android.util.FloatMath;
+
+/**
+ * @author Nicolas Gramlich
+ * @since 00:21:55 - 11.07.2010
+ */
+public class AnalogOnScreenControl extends BaseOnScreenControl implements TimeConstants, IClickDetectorListener {
+ // ===========================================================
+ // Constants
+ // ===========================================================
+
+ // ===========================================================
+ // Fields
+ // ===========================================================
+
+ private final ClickDetector mClickDetector = new ClickDetector(this);
+
+ // ===========================================================
+ // Constructors
+ // ===========================================================
+
+ public AnalogOnScreenControl(final float pX, final float pY, final Camera pCamera, final TextureRegion pControlBaseTextureRegion, final TextureRegion pControlKnobTextureRegion, final float pTimeBetweenUpdates, final IAnalogOnScreenControlListener pAnalogOnScreenControlListener) {
+ super(pX, pY, pCamera, pControlBaseTextureRegion, pControlKnobTextureRegion, pTimeBetweenUpdates, pAnalogOnScreenControlListener);
+ this.mClickDetector.setEnabled(false);
+ }
+
+ public AnalogOnScreenControl(final float pX, final float pY, final Camera pCamera, final TextureRegion pControlBaseTextureRegion, final TextureRegion pControlKnobTextureRegion, final float pTimeBetweenUpdates, final long pOnControlClickMaximumMilliseconds, final IAnalogOnScreenControlListener pAnalogOnScreenControlListener) {
+ super(pX, pY, pCamera, pControlBaseTextureRegion, pControlKnobTextureRegion, pTimeBetweenUpdates, pAnalogOnScreenControlListener);
+ this.mClickDetector.setTriggerClickMaximumMilliseconds(pOnControlClickMaximumMilliseconds);
+ }
+
+ // ===========================================================
+ // Getter & Setter
+ // ===========================================================
+
+ @Override
+ public IAnalogOnScreenControlListener getOnScreenControlListener() {
+ return (IAnalogOnScreenControlListener)super.getOnScreenControlListener();
+ }
+
+ public void setOnControlClickEnabled(final boolean pOnControlClickEnabled) {
+ this.mClickDetector.setEnabled(pOnControlClickEnabled);
+ }
+
+ public void setOnControlClickMaximumMilliseconds(final long pOnControlClickMaximumMilliseconds) {
+ this.mClickDetector.setTriggerClickMaximumMilliseconds(pOnControlClickMaximumMilliseconds);
+ }
+
+ // ===========================================================
+ // Methods for/from SuperClass/Interfaces
+ // ===========================================================
+
+ @Override
+ public void onClick(final ClickDetector pClickDetector, final TouchEvent pTouchEvent) {
+ this.getOnScreenControlListener().onControlClick(this);
+ }
+
+ @Override
+ protected boolean onHandleControlBaseTouched(final TouchEvent pSceneTouchEvent, final float pTouchAreaLocalX, final float pTouchAreaLocalY) {
+ this.mClickDetector.onSceneTouchEvent(null, pSceneTouchEvent);
+ return super.onHandleControlBaseTouched(pSceneTouchEvent, pTouchAreaLocalX, pTouchAreaLocalY);
+ }
+
+ @Override
+ protected void onUpdateControlKnob(final float pRelativeX, final float pRelativeY) {
+ if(pRelativeX * pRelativeX + pRelativeY * pRelativeY <= 0.25f) {
+ super.onUpdateControlKnob(pRelativeX, pRelativeY);
+ } else {
+ final float angleRad = MathUtils.atan2(pRelativeY, pRelativeX);
+ super.onUpdateControlKnob(FloatMath.cos(angleRad) * 0.5f, FloatMath.sin(angleRad) * 0.5f);
+ }
+ }
+
+ // ===========================================================
+ // Methods
+ // ===========================================================
+
+ // ===========================================================
+ // Inner and Anonymous Classes
+ // ===========================================================
+
+ public interface IAnalogOnScreenControlListener extends IOnScreenControlListener {
+ // ===========================================================
+ // Final Fields
+ // ===========================================================
+
+ // ===========================================================
+ // Methods
+ // ===========================================================
+
+ public void onControlClick(final AnalogOnScreenControl pAnalogOnScreenControl);
+ }
+}
diff --git a/AndEngine/src/org/anddev/andengine/engine/camera/hud/controls/BaseOnScreenControl.java b/AndEngine/src/org/anddev/andengine/engine/camera/hud/controls/BaseOnScreenControl.java
new file mode 100644
index 0000000..1c264a4
--- /dev/null
+++ b/AndEngine/src/org/anddev/andengine/engine/camera/hud/controls/BaseOnScreenControl.java
@@ -0,0 +1,215 @@
+package org.anddev.andengine.engine.camera.hud.controls;
+
+import static org.anddev.andengine.util.constants.Constants.VERTEX_INDEX_X;
+import static org.anddev.andengine.util.constants.Constants.VERTEX_INDEX_Y;
+
+import org.anddev.andengine.engine.camera.Camera;
+import org.anddev.andengine.engine.camera.hud.HUD;
+import org.anddev.andengine.engine.handler.timer.ITimerCallback;
+import org.anddev.andengine.engine.handler.timer.TimerHandler;
+import org.anddev.andengine.entity.IEntity;
+import org.anddev.andengine.entity.scene.Scene;
+import org.anddev.andengine.entity.scene.Scene.IOnSceneTouchListener;
+import org.anddev.andengine.entity.sprite.Sprite;
+import org.anddev.andengine.input.touch.TouchEvent;
+import org.anddev.andengine.opengl.texture.region.TextureRegion;
+import org.anddev.andengine.util.MathUtils;
+
+import android.view.MotionEvent;
+
+/**
+ * @author Nicolas Gramlich
+ * @since 10:43:09 - 11.07.2010
+ */
+public abstract class BaseOnScreenControl extends HUD implements IOnSceneTouchListener {
+ // ===========================================================
+ // Constants
+ // ===========================================================
+
+ private static final int INVALID_POINTER_ID = -1;
+
+ // ===========================================================
+ // Fields
+ // ===========================================================
+
+ private final Sprite mControlBase;
+ private final Sprite mControlKnob;
+
+ private float mControlValueX;
+ private float mControlValueY;
+
+ private final IOnScreenControlListener mOnScreenControlListener;
+
+ private int mActivePointerID = INVALID_POINTER_ID;
+
+ // ===========================================================
+ // Constructors
+ // ===========================================================
+
+ public BaseOnScreenControl(final float pX, final float pY, final Camera pCamera, final TextureRegion pControlBaseTextureRegion, final TextureRegion pControlKnobTextureRegion, final float pTimeBetweenUpdates, final IOnScreenControlListener pOnScreenControlListener) {
+ this.setCamera(pCamera);
+
+ this.mOnScreenControlListener = pOnScreenControlListener;
+ /* Create the control base. */
+ this.mControlBase = new Sprite(pX, pY, pControlBaseTextureRegion) {
+ @Override
+ public boolean onAreaTouched(final TouchEvent pSceneTouchEvent, final float pTouchAreaLocalX, final float pTouchAreaLocalY) {
+ return BaseOnScreenControl.this.onHandleControlBaseTouched(pSceneTouchEvent, pTouchAreaLocalX, pTouchAreaLocalY);
+ }
+ };
+
+ /* Create the control knob. */
+ this.mControlKnob = new Sprite(0, 0, pControlKnobTextureRegion);
+ this.onHandleControlKnobReleased();
+
+ /* Register listeners and add objects to this HUD. */
+ this.setOnSceneTouchListener(this);
+ this.registerTouchArea(this.mControlBase);
+ this.registerUpdateHandler(new TimerHandler(pTimeBetweenUpdates, true, new ITimerCallback() {
+ @Override
+ public void onTimePassed(final TimerHandler pTimerHandler) {
+ BaseOnScreenControl.this.mOnScreenControlListener.onControlChange(BaseOnScreenControl.this, BaseOnScreenControl.this.mControlValueX, BaseOnScreenControl.this.mControlValueY);
+ }
+ }));
+
+ final IEntity firstChild = this.getFirstChild();
+ firstChild.attachChild(this.mControlBase);
+ firstChild.attachChild(this.mControlKnob);
+
+ this.setTouchAreaBindingEnabled(true);
+ }
+
+ // ===========================================================
+ // Getter & Setter
+ // ===========================================================
+
+ public Sprite getControlBase() {
+ return this.mControlBase;
+ }
+
+ public Sprite getControlKnob() {
+ return this.mControlKnob;
+ }
+
+ public IOnScreenControlListener getOnScreenControlListener() {
+ return this.mOnScreenControlListener;
+ }
+
+ // ===========================================================
+ // Methods for/from SuperClass/Interfaces
+ // ===========================================================
+
+ @Override
+ public boolean onSceneTouchEvent(final Scene pScene, final TouchEvent pSceneTouchEvent) {
+ final int pointerID = pSceneTouchEvent.getPointerID();
+ if(pointerID == this.mActivePointerID) {
+ this.onHandleControlBaseLeft();
+
+ switch(pSceneTouchEvent.getAction()) {
+ case MotionEvent.ACTION_UP:
+ case MotionEvent.ACTION_CANCEL:
+ this.mActivePointerID = INVALID_POINTER_ID;
+ }
+ }
+ return false;
+ }
+
+ // ===========================================================
+ // Methods
+ // ===========================================================
+
+ public void refreshControlKnobPosition() {
+ this.onUpdateControlKnob(this.mControlValueX * 0.5f, this.mControlValueY * 0.5f);
+ }
+
+ /**
+ * When the touch happened outside of the bounds of this OnScreenControl.
+ * */
+ protected void onHandleControlBaseLeft() {
+ this.onUpdateControlKnob(0, 0);
+ }
+
+ /**
+ * When the OnScreenControl was released.
+ */
+ protected void onHandleControlKnobReleased() {
+ this.onUpdateControlKnob(0, 0);
+ }
+
+ protected boolean onHandleControlBaseTouched(final TouchEvent pSceneTouchEvent, final float pTouchAreaLocalX, final float pTouchAreaLocalY) {
+ final int pointerID = pSceneTouchEvent.getPointerID();
+
+ switch(pSceneTouchEvent.getAction()) {
+ case MotionEvent.ACTION_DOWN:
+ if(this.mActivePointerID == INVALID_POINTER_ID) {
+ this.mActivePointerID = pointerID;
+ this.updateControlKnob(pSceneTouchEvent, pTouchAreaLocalX, pTouchAreaLocalY);
+ return true;
+ }
+ break;
+ case MotionEvent.ACTION_UP:
+ case MotionEvent.ACTION_CANCEL:
+ if(this.mActivePointerID == pointerID) {
+ this.mActivePointerID = INVALID_POINTER_ID;
+ this.onHandleControlKnobReleased();
+ return true;
+ }
+ break;
+ default:
+ if(this.mActivePointerID == pointerID) {
+ this.updateControlKnob(pSceneTouchEvent, pTouchAreaLocalX, pTouchAreaLocalY);
+ return true;
+ }
+ break;
+ }
+ return true;
+ }
+
+ private void updateControlKnob(final TouchEvent pSceneTouchEvent, final float pTouchAreaLocalX, final float pTouchAreaLocalY) {
+ final Sprite controlBase = this.mControlBase;
+
+ final float relativeX = MathUtils.bringToBounds(0, controlBase.getWidth(), pTouchAreaLocalX) / controlBase.getWidth() - 0.5f;
+ final float relativeY = MathUtils.bringToBounds(0, controlBase.getHeight(), pTouchAreaLocalY) / controlBase.getHeight() - 0.5f;
+
+ this.onUpdateControlKnob(relativeX, relativeY);
+ }
+
+ /**
+ * @param pRelativeX from -0.5 (left) to 0.5 (right).
+ * @param pRelativeY from -0.5 (top) to 0.5 (bottom).
+ */
+ protected void onUpdateControlKnob(final float pRelativeX, final float pRelativeY) {
+ final Sprite controlBase = this.mControlBase;
+ final Sprite controlKnob = this.mControlKnob;
+
+ this.mControlValueX = 2 * pRelativeX;
+ this.mControlValueY = 2 * pRelativeY;
+
+ final float[] controlBaseSceneCenterCoordinates = controlBase.getSceneCenterCoordinates();
+ final float x = controlBaseSceneCenterCoordinates[VERTEX_INDEX_X] - controlKnob.getWidth() * 0.5f + pRelativeX * controlBase.getWidthScaled();
+ final float y = controlBaseSceneCenterCoordinates[VERTEX_INDEX_Y] - controlKnob.getHeight() * 0.5f + pRelativeY * controlBase.getHeightScaled();
+
+ controlKnob.setPosition(x, y);
+ }
+
+ // ===========================================================
+ // Inner and Anonymous Classes
+ // ===========================================================
+
+ public static interface IOnScreenControlListener {
+ // ===========================================================
+ // Constants
+ // ===========================================================
+
+ // ===========================================================
+ // Methods
+ // ===========================================================
+
+ /**
+ * @param pBaseOnScreenControl
+ * @param pValueX between -1 (left) to 1 (right).
+ * @param pValueY between -1 (up) to 1 (down).
+ */
+ public void onControlChange(final BaseOnScreenControl pBaseOnScreenControl, final float pValueX, final float pValueY);
+ }
+}
diff --git a/AndEngine/src/org/anddev/andengine/engine/camera/hud/controls/DigitalOnScreenControl.java b/AndEngine/src/org/anddev/andengine/engine/camera/hud/controls/DigitalOnScreenControl.java
new file mode 100644
index 0000000..103297c
--- /dev/null
+++ b/AndEngine/src/org/anddev/andengine/engine/camera/hud/controls/DigitalOnScreenControl.java
@@ -0,0 +1,67 @@
+package org.anddev.andengine.engine.camera.hud.controls;
+
+import org.anddev.andengine.engine.camera.Camera;
+import org.anddev.andengine.opengl.texture.region.TextureRegion;
+
+/**
+ * @author Nicolas Gramlich
+ * @since 00:21:55 - 11.07.2010
+ */
+public class DigitalOnScreenControl extends BaseOnScreenControl {
+ // ===========================================================
+ // Constants
+ // ===========================================================
+
+ // ===========================================================
+ // Fields
+ // ===========================================================
+
+ // ===========================================================
+ // Constructors
+ // ===========================================================
+
+ public DigitalOnScreenControl(final float pX, final float pY, final Camera pCamera, final TextureRegion pControlBaseTextureRegion, final TextureRegion pControlKnobTextureRegion, final float pTimeBetweenUpdates, final IOnScreenControlListener pOnScreenControlListener) {
+ super(pX, pY, pCamera, pControlBaseTextureRegion, pControlKnobTextureRegion, pTimeBetweenUpdates, pOnScreenControlListener);
+ }
+
+ // ===========================================================
+ // Getter & Setter
+ // ===========================================================
+
+ // ===========================================================
+ // Methods for/from SuperClass/Interfaces
+ // ===========================================================
+
+ @Override
+ protected void onUpdateControlKnob(final float pRelativeX, final float pRelativeY) {
+ if(pRelativeX == 0 && pRelativeY == 0) {
+ super.onUpdateControlKnob(0, 0);
+ }
+
+ if(Math.abs(pRelativeX) > Math.abs(pRelativeY)) {
+ if(pRelativeX > 0) {
+ super.onUpdateControlKnob(0.5f, 0);
+ } else if(pRelativeX < 0) {
+ super.onUpdateControlKnob(-0.5f, 0);
+ } else if(pRelativeX == 0) {
+ super.onUpdateControlKnob(0, 0);
+ }
+ } else {
+ if(pRelativeY > 0) {
+ super.onUpdateControlKnob(0, 0.5f);
+ } else if(pRelativeY < 0) {
+ super.onUpdateControlKnob(0, -0.5f);
+ } else if(pRelativeY == 0) {
+ super.onUpdateControlKnob(0, 0);
+ }
+ }
+ }
+
+ // ===========================================================
+ // Methods
+ // ===========================================================
+
+ // ===========================================================
+ // Inner and Anonymous Classes
+ // ===========================================================
+}
diff --git a/AndEngine/src/org/anddev/andengine/engine/handler/BaseEntityUpdateHandler.java b/AndEngine/src/org/anddev/andengine/engine/handler/BaseEntityUpdateHandler.java
new file mode 100644
index 0000000..40c3d05
--- /dev/null
+++ b/AndEngine/src/org/anddev/andengine/engine/handler/BaseEntityUpdateHandler.java
@@ -0,0 +1,55 @@
+package org.anddev.andengine.engine.handler;
+
+import org.anddev.andengine.entity.IEntity;
+
+/**
+ * @author Nicolas Gramlich
+ * @since 14:00:25 - 24.12.2010
+ */
+public abstract class BaseEntityUpdateHandler implements IUpdateHandler {
+ // ===========================================================
+ // Constants
+ // ===========================================================
+
+ // ===========================================================
+ // Fields
+ // ===========================================================
+
+ private final IEntity mEntity;
+
+ // ===========================================================
+ // Constructors
+ // ===========================================================
+
+ public BaseEntityUpdateHandler(final IEntity pEntity) {
+ this.mEntity = pEntity;
+ }
+
+ // ===========================================================
+ // Getter & Setter
+ // ===========================================================
+
+ // ===========================================================
+ // Methods for/from SuperClass/Interfaces
+ // ===========================================================
+
+ protected abstract void onUpdate(final float pSecondsElapsed, final IEntity pEntity);
+
+ @Override
+ public final void onUpdate(final float pSecondsElapsed) {
+ this.onUpdate(pSecondsElapsed, this.mEntity);
+ }
+
+ @Override
+ public void reset() {
+
+ }
+
+ // ===========================================================
+ // Methods
+ // ===========================================================
+
+ // ===========================================================
+ // Inner and Anonymous Classes
+ // ===========================================================
+}
diff --git a/AndEngine/src/org/anddev/andengine/engine/handler/IUpdateHandler.java b/AndEngine/src/org/anddev/andengine/engine/handler/IUpdateHandler.java
new file mode 100644
index 0000000..add606a
--- /dev/null
+++ b/AndEngine/src/org/anddev/andengine/engine/handler/IUpdateHandler.java
@@ -0,0 +1,36 @@
+package org.anddev.andengine.engine.handler;
+
+import org.anddev.andengine.util.IMatcher;
+
+/**
+ * @author Nicolas Gramlich
+ * @since 12:24:09 - 11.03.2010
+ */
+public interface IUpdateHandler {
+ // ===========================================================
+ // Final Fields
+ // ===========================================================
+
+ // ===========================================================
+ // Methods
+ // ===========================================================
+
+ public void onUpdate(final float pSecondsElapsed);
+ public void reset();
+
+ // TODO Maybe add onRegister and onUnregister. (Maybe add SimpleUpdateHandler that implements all methods, but onUpdate)
+
+ // ===========================================================
+ // Inner and Anonymous Classes
+ // ===========================================================
+
+ public interface IUpdateHandlerMatcher extends IMatchertrue to proceed, false to stop further collosion-checks.
+ */
+ public boolean onCollision(final IShape pCheckShape, final IShape pTargetShape);
+}
diff --git a/AndEngine/src/org/anddev/andengine/engine/handler/physics/PhysicsHandler.java b/AndEngine/src/org/anddev/andengine/engine/handler/physics/PhysicsHandler.java
new file mode 100644
index 0000000..7abbd3e
--- /dev/null
+++ b/AndEngine/src/org/anddev/andengine/engine/handler/physics/PhysicsHandler.java
@@ -0,0 +1,160 @@
+package org.anddev.andengine.engine.handler.physics;
+
+import org.anddev.andengine.engine.handler.BaseEntityUpdateHandler;
+import org.anddev.andengine.entity.IEntity;
+
+/**
+ * @author Nicolas Gramlich
+ * @since 13:53:07 - 24.12.2010
+ */
+public class PhysicsHandler extends BaseEntityUpdateHandler {
+ // ===========================================================
+ // Constants
+ // ===========================================================
+
+ // ===========================================================
+ // Fields
+ // ===========================================================
+
+ private boolean mEnabled = true;
+
+ protected float mAccelerationX = 0;
+ protected float mAccelerationY = 0;
+
+ protected float mVelocityX = 0;
+ protected float mVelocityY = 0;
+
+ protected float mAngularVelocity = 0;
+
+ // ===========================================================
+ // Constructors
+ // ===========================================================
+
+ public PhysicsHandler(final IEntity pEntity) {
+ super(pEntity);
+ }
+
+ // ===========================================================
+ // Getter & Setter
+ // ===========================================================
+
+ public boolean isEnabled() {
+ return this.mEnabled;
+ }
+
+ public void setEnabled(final boolean pEnabled) {
+ this.mEnabled = pEnabled;
+ }
+
+ public float getVelocityX() {
+ return this.mVelocityX;
+ }
+
+ public float getVelocityY() {
+ return this.mVelocityY;
+ }
+
+ public void setVelocityX(final float pVelocityX) {
+ this.mVelocityX = pVelocityX;
+ }
+
+ public void setVelocityY(final float pVelocityY) {
+ this.mVelocityY = pVelocityY;
+ }
+
+ public void setVelocity(final float pVelocity) {
+ this.mVelocityX = pVelocity;
+ this.mVelocityY = pVelocity;
+ }
+
+ public void setVelocity(final float pVelocityX, final float pVelocityY) {
+ this.mVelocityX = pVelocityX;
+ this.mVelocityY = pVelocityY;
+ }
+
+ public float getAccelerationX() {
+ return this.mAccelerationX;
+ }
+
+ public float getAccelerationY() {
+ return this.mAccelerationY;
+ }
+
+ public void setAccelerationX(final float pAccelerationX) {
+ this.mAccelerationX = pAccelerationX;
+ }
+
+ public void setAccelerationY(final float pAccelerationY) {
+ this.mAccelerationY = pAccelerationY;
+ }
+
+ public void setAcceleration(final float pAccelerationX, final float pAccelerationY) {
+ this.mAccelerationX = pAccelerationX;
+ this.mAccelerationY = pAccelerationY;
+ }
+
+ public void setAcceleration(final float pAcceleration) {
+ this.mAccelerationX = pAcceleration;
+ this.mAccelerationY = pAcceleration;
+ }
+
+ public void accelerate(final float pAccelerationX, final float pAccelerationY) {
+ this.mAccelerationX += pAccelerationX;
+ this.mAccelerationY += pAccelerationY;
+ }
+
+ public float getAngularVelocity() {
+ return this.mAngularVelocity;
+ }
+
+ public void setAngularVelocity(final float pAngularVelocity) {
+ this.mAngularVelocity = pAngularVelocity;
+ }
+
+ // ===========================================================
+ // Methods for/from SuperClass/Interfaces
+ // ===========================================================
+
+ @Override
+ protected void onUpdate(final float pSecondsElapsed, final IEntity pEntity) {
+ if(this.mEnabled) {
+ /* Apply linear acceleration. */
+ final float accelerationX = this.mAccelerationX;
+ final float accelerationY = this.mAccelerationY;
+ if(accelerationX != 0 || accelerationY != 0) {
+ this.mVelocityX += accelerationX * pSecondsElapsed;
+ this.mVelocityY += accelerationY * pSecondsElapsed;
+ }
+
+ /* Apply angular velocity. */
+ final float angularVelocity = this.mAngularVelocity;
+ if(angularVelocity != 0) {
+ pEntity.setRotation(pEntity.getRotation() + angularVelocity * pSecondsElapsed);
+ }
+
+ /* Apply linear velocity. */
+ final float velocityX = this.mVelocityX;
+ final float velocityY = this.mVelocityY;
+ if(velocityX != 0 || velocityY != 0) {
+ pEntity.setPosition(pEntity.getX() + velocityX * pSecondsElapsed, pEntity.getY() + velocityY * pSecondsElapsed);
+ }
+ }
+ }
+
+ @Override
+ public void reset() {
+ this.mAccelerationX = 0;
+ this.mAccelerationY = 0;
+ this.mVelocityX = 0;
+ this.mVelocityY = 0;
+ this.mAngularVelocity = 0;
+ }
+
+ // ===========================================================
+ // Methods
+ // ===========================================================
+
+ // ===========================================================
+ // Inner and Anonymous Classes
+ // ===========================================================
+}
diff --git a/AndEngine/src/org/anddev/andengine/engine/handler/runnable/RunnableHandler.java b/AndEngine/src/org/anddev/andengine/engine/handler/runnable/RunnableHandler.java
new file mode 100644
index 0000000..f13b0c0
--- /dev/null
+++ b/AndEngine/src/org/anddev/andengine/engine/handler/runnable/RunnableHandler.java
@@ -0,0 +1,60 @@
+package org.anddev.andengine.engine.handler.runnable;
+
+import java.util.ArrayList;
+
+import org.anddev.andengine.engine.handler.IUpdateHandler;
+
+/**
+ * @author Nicolas Gramlich
+ * @since 10:24:39 - 18.06.2010
+ */
+public class RunnableHandler implements IUpdateHandler {
+ // ===========================================================
+ // Constants
+ // ===========================================================
+
+ // ===========================================================
+ // Fields
+ // ===========================================================
+
+ private final ArrayListfalse
+ */
+ public boolean isDisableExtensionVertexBufferObjects() {
+ return this.mDisableExtensionVertexBufferObjects;
+ }
+
+ // ===========================================================
+ // Methods for/from SuperClass/Interfaces
+ // ===========================================================
+
+ // ===========================================================
+ // Methods
+ // ===========================================================
+
+ // ===========================================================
+ // Inner and Anonymous Classes
+ // ===========================================================
+}
diff --git a/AndEngine/src/org/anddev/andengine/engine/options/TouchOptions.java b/AndEngine/src/org/anddev/andengine/engine/options/TouchOptions.java
new file mode 100644
index 0000000..76f9be1
--- /dev/null
+++ b/AndEngine/src/org/anddev/andengine/engine/options/TouchOptions.java
@@ -0,0 +1,57 @@
+package org.anddev.andengine.engine.options;
+
+/**
+ * @author Nicolas Gramlich
+ * @since 16:03:09 - 08.09.2010
+ */
+public class TouchOptions {
+ // ===========================================================
+ // Constants
+ // ===========================================================
+
+ // ===========================================================
+ // Fields
+ // ===========================================================
+
+ private boolean mRunOnUpdateThread;
+
+ // ===========================================================
+ // Constructors
+ // ===========================================================
+
+ // ===========================================================
+ // Getter & Setter
+ // ===========================================================
+
+ public TouchOptions enableRunOnUpdateThread() {
+ return this.setRunOnUpdateThread(true);
+ }
+
+ public TouchOptions disableRunOnUpdateThread() {
+ return this.setRunOnUpdateThread(false);
+ }
+
+ public TouchOptions setRunOnUpdateThread(final boolean pRunOnUpdateThread) {
+ this.mRunOnUpdateThread = pRunOnUpdateThread;
+ return this;
+ }
+
+ /**
+ * Default: true
+ */
+ public boolean isRunOnUpdateThread() {
+ return this.mRunOnUpdateThread;
+ }
+
+ // ===========================================================
+ // Methods for/from SuperClass/Interfaces
+ // ===========================================================
+
+ // ===========================================================
+ // Methods
+ // ===========================================================
+
+ // ===========================================================
+ // Inner and Anonymous Classes
+ // ===========================================================
+}
diff --git a/AndEngine/src/org/anddev/andengine/engine/options/WakeLockOptions.java b/AndEngine/src/org/anddev/andengine/engine/options/WakeLockOptions.java
new file mode 100644
index 0000000..89f93ed
--- /dev/null
+++ b/AndEngine/src/org/anddev/andengine/engine/options/WakeLockOptions.java
@@ -0,0 +1,60 @@
+package org.anddev.andengine.engine.options;
+
+import android.os.PowerManager;
+
+/**
+ * @author Nicolas Gramlich
+ * @since 19:45:23 - 10.07.2010
+ */
+public enum WakeLockOptions {
+ // ===========================================================
+ // Elements
+ // ===========================================================
+
+ /** Screen is on at full brightness. Keyboard backlight is on at full brightness. Requires WAKE_LOCK permission! */
+ BRIGHT(PowerManager.FULL_WAKE_LOCK),
+ /** Screen is on at full brightness. Keyboard backlight will be allowed to go off. Requires WAKE_LOCK permission!*/
+ SCREEN_BRIGHT(PowerManager.SCREEN_BRIGHT_WAKE_LOCK),
+ /** Screen is on but may be dimmed. Keyboard backlight will be allowed to go off. Requires WAKE_LOCK permission!*/
+ SCREEN_DIM(PowerManager.SCREEN_DIM_WAKE_LOCK),
+ /** Screen is on at full brightness. Does not require WAKE_LOCK permission! */
+ SCREEN_ON(-1);
+
+ // ===========================================================
+ // Constants
+ // ===========================================================
+
+ // ===========================================================
+ // Fields
+ // ===========================================================
+
+ private final int mFlag;
+
+ // ===========================================================
+ // Constructors
+ // ===========================================================
+
+ private WakeLockOptions(final int pFlag) {
+ this.mFlag = pFlag;
+ }
+
+ // ===========================================================
+ // Getter & Setter
+ // ===========================================================
+
+ public int getFlag() {
+ return this.mFlag;
+ }
+
+ // ===========================================================
+ // Methods from SuperClass/Interfaces
+ // ===========================================================
+
+ // ===========================================================
+ // Methods
+ // ===========================================================
+
+ // ===========================================================
+ // Inner and Anonymous Classes
+ // ===========================================================
+}
diff --git a/AndEngine/src/org/anddev/andengine/engine/options/resolutionpolicy/BaseResolutionPolicy.java b/AndEngine/src/org/anddev/andengine/engine/options/resolutionpolicy/BaseResolutionPolicy.java
new file mode 100644
index 0000000..456aafe
--- /dev/null
+++ b/AndEngine/src/org/anddev/andengine/engine/options/resolutionpolicy/BaseResolutionPolicy.java
@@ -0,0 +1,46 @@
+package org.anddev.andengine.engine.options.resolutionpolicy;
+
+import android.view.View.MeasureSpec;
+
+/**
+ * @author Nicolas Gramlich
+ * @since 22:46:43 - 06.10.2010
+ */
+public abstract class BaseResolutionPolicy implements IResolutionPolicy {
+ // ===========================================================
+ // Constants
+ // ===========================================================
+
+ // ===========================================================
+ // Fields
+ // ===========================================================
+
+ // ===========================================================
+ // Constructors
+ // ===========================================================
+
+ // ===========================================================
+ // Getter & Setter
+ // ===========================================================
+
+ // ===========================================================
+ // Methods for/from SuperClass/Interfaces
+ // ===========================================================
+
+ protected static void throwOnNotMeasureSpecEXACTLY(final int pWidthMeasureSpec, final int pHeightMeasureSpec) {
+ final int specWidthMode = MeasureSpec.getMode(pWidthMeasureSpec);
+ final int specHeightMode = MeasureSpec.getMode(pHeightMeasureSpec);
+
+ if (specWidthMode != MeasureSpec.EXACTLY || specHeightMode != MeasureSpec.EXACTLY) {
+ throw new IllegalStateException("This IResolutionPolicy requires MeasureSpec.EXACTLY ! That means ");
+ }
+ }
+
+ // ===========================================================
+ // Methods
+ // ===========================================================
+
+ // ===========================================================
+ // Inner and Anonymous Classes
+ // ===========================================================
+}
diff --git a/AndEngine/src/org/anddev/andengine/engine/options/resolutionpolicy/FillResolutionPolicy.java b/AndEngine/src/org/anddev/andengine/engine/options/resolutionpolicy/FillResolutionPolicy.java
new file mode 100644
index 0000000..2871c8c
--- /dev/null
+++ b/AndEngine/src/org/anddev/andengine/engine/options/resolutionpolicy/FillResolutionPolicy.java
@@ -0,0 +1,49 @@
+package org.anddev.andengine.engine.options.resolutionpolicy;
+
+import org.anddev.andengine.opengl.view.RenderSurfaceView;
+
+import android.view.View.MeasureSpec;
+
+/**
+ * @author Nicolas Gramlich
+ * @since 11:22:48 - 29.03.2010
+ */
+public class FillResolutionPolicy extends BaseResolutionPolicy {
+ // ===========================================================
+ // Constants
+ // ===========================================================
+
+ // ===========================================================
+ // Fields
+ // ===========================================================
+
+ // ===========================================================
+ // Constructors
+ // ===========================================================
+
+ // ===========================================================
+ // Getter & Setter
+ // ===========================================================
+
+ // ===========================================================
+ // Methods for/from SuperClass/Interfaces
+ // ===========================================================
+
+ @Override
+ public void onMeasure(final RenderSurfaceView pRenderSurfaceView, final int pWidthMeasureSpec, final int pHeightMeasureSpec) {
+ BaseResolutionPolicy.throwOnNotMeasureSpecEXACTLY(pWidthMeasureSpec, pHeightMeasureSpec);
+
+ final int measuredWidth = MeasureSpec.getSize(pWidthMeasureSpec);
+ final int measuredHeight = MeasureSpec.getSize(pHeightMeasureSpec);
+
+ pRenderSurfaceView.setMeasuredDimensionProxy(measuredWidth, measuredHeight);
+ }
+
+ // ===========================================================
+ // Methods
+ // ===========================================================
+
+ // ===========================================================
+ // Inner and Anonymous Classes
+ // ===========================================================
+}
diff --git a/AndEngine/src/org/anddev/andengine/engine/options/resolutionpolicy/FixedResolutionPolicy.java b/AndEngine/src/org/anddev/andengine/engine/options/resolutionpolicy/FixedResolutionPolicy.java
new file mode 100644
index 0000000..5c15df1
--- /dev/null
+++ b/AndEngine/src/org/anddev/andengine/engine/options/resolutionpolicy/FixedResolutionPolicy.java
@@ -0,0 +1,50 @@
+package org.anddev.andengine.engine.options.resolutionpolicy;
+
+import org.anddev.andengine.opengl.view.RenderSurfaceView;
+
+/**
+ * @author Nicolas Gramlich
+ * @since 11:23:00 - 29.03.2010
+ */
+public class FixedResolutionPolicy extends BaseResolutionPolicy {
+ // ===========================================================
+ // Constants
+ // ===========================================================
+
+ // ===========================================================
+ // Fields
+ // ===========================================================
+
+ private final int mWidth;
+ private final int mHeight;
+
+ // ===========================================================
+ // Constructors
+ // ===========================================================
+
+ public FixedResolutionPolicy(final int pWidth, final int pHeight) {
+ this.mWidth = pWidth;
+ this.mHeight = pHeight;
+ }
+
+ // ===========================================================
+ // Getter & Setter
+ // ===========================================================
+
+ // ===========================================================
+ // Methods for/from SuperClass/Interfaces
+ // ===========================================================
+
+ @Override
+ public void onMeasure(final RenderSurfaceView pRenderSurfaceView, final int pWidthMeasureSpec, final int pHeightMeasureSpec) {
+ pRenderSurfaceView.setMeasuredDimensionProxy(this.mWidth, this.mHeight);
+ }
+
+ // ===========================================================
+ // Methods
+ // ===========================================================
+
+ // ===========================================================
+ // Inner and Anonymous Classes
+ // ===========================================================
+}
diff --git a/AndEngine/src/org/anddev/andengine/engine/options/resolutionpolicy/IResolutionPolicy.java b/AndEngine/src/org/anddev/andengine/engine/options/resolutionpolicy/IResolutionPolicy.java
new file mode 100644
index 0000000..3d4c11b
--- /dev/null
+++ b/AndEngine/src/org/anddev/andengine/engine/options/resolutionpolicy/IResolutionPolicy.java
@@ -0,0 +1,19 @@
+package org.anddev.andengine.engine.options.resolutionpolicy;
+
+import org.anddev.andengine.opengl.view.RenderSurfaceView;
+
+/**
+ * @author Nicolas Gramlich
+ * @since 11:02:35 - 29.03.2010
+ */
+public interface IResolutionPolicy {
+ // ===========================================================
+ // Constants
+ // ===========================================================
+
+ // ===========================================================
+ // Methods
+ // ===========================================================
+
+ public void onMeasure(final RenderSurfaceView pRenderSurfaceView, final int pWidthMeasureSpec, final int pHeightMeasureSpec);
+}
diff --git a/AndEngine/src/org/anddev/andengine/engine/options/resolutionpolicy/RatioResolutionPolicy.java b/AndEngine/src/org/anddev/andengine/engine/options/resolutionpolicy/RatioResolutionPolicy.java
new file mode 100644
index 0000000..dcb2536
--- /dev/null
+++ b/AndEngine/src/org/anddev/andengine/engine/options/resolutionpolicy/RatioResolutionPolicy.java
@@ -0,0 +1,72 @@
+package org.anddev.andengine.engine.options.resolutionpolicy;
+
+import org.anddev.andengine.opengl.view.RenderSurfaceView;
+
+import android.view.View.MeasureSpec;
+
+/**
+ * @author Nicolas Gramlich
+ * @since 11:23:00 - 29.03.2010
+ */
+public class RatioResolutionPolicy extends BaseResolutionPolicy {
+ // ===========================================================
+ // Constants
+ // ===========================================================
+
+ // ===========================================================
+ // Fields
+ // ===========================================================
+
+ private final float mRatio;
+
+ // ===========================================================
+ // Constructors
+ // ===========================================================
+
+ public RatioResolutionPolicy(final float pRatio) {
+ this.mRatio = pRatio;
+ }
+
+ public RatioResolutionPolicy(final float pWidthRatio, final float pHeightRatio) {
+ this.mRatio = pWidthRatio / pHeightRatio;
+ }
+
+ // ===========================================================
+ // Getter & Setter
+ // ===========================================================
+
+ // ===========================================================
+ // Methods for/from SuperClass/Interfaces
+ // ===========================================================
+
+ @Override
+ public void onMeasure(final RenderSurfaceView pRenderSurfaceView, final int pWidthMeasureSpec, final int pHeightMeasureSpec) {
+ BaseResolutionPolicy.throwOnNotMeasureSpecEXACTLY(pWidthMeasureSpec, pHeightMeasureSpec);
+
+ final int specWidth = MeasureSpec.getSize(pWidthMeasureSpec);
+ final int specHeight = MeasureSpec.getSize(pHeightMeasureSpec);
+
+ final float desiredRatio = this.mRatio;
+ final float realRatio = (float)specWidth / specHeight;
+
+ int measuredWidth;
+ int measuredHeight;
+ if(realRatio < desiredRatio) {
+ measuredWidth = specWidth;
+ measuredHeight = Math.round(measuredWidth / desiredRatio);
+ } else {
+ measuredHeight = specHeight;
+ measuredWidth = Math.round(measuredHeight * desiredRatio);
+ }
+
+ pRenderSurfaceView.setMeasuredDimensionProxy(measuredWidth, measuredHeight);
+ }
+
+ // ===========================================================
+ // Methods
+ // ===========================================================
+
+ // ===========================================================
+ // Inner and Anonymous Classes
+ // ===========================================================
+}
diff --git a/AndEngine/src/org/anddev/andengine/engine/options/resolutionpolicy/RelativeResolutionPolicy.java b/AndEngine/src/org/anddev/andengine/engine/options/resolutionpolicy/RelativeResolutionPolicy.java
new file mode 100644
index 0000000..a7e0c2a
--- /dev/null
+++ b/AndEngine/src/org/anddev/andengine/engine/options/resolutionpolicy/RelativeResolutionPolicy.java
@@ -0,0 +1,60 @@
+package org.anddev.andengine.engine.options.resolutionpolicy;
+
+import org.anddev.andengine.opengl.view.RenderSurfaceView;
+
+import android.view.View.MeasureSpec;
+
+/**
+ * @author Nicolas Gramlich
+ * @since 11:23:00 - 29.03.2010
+ */
+public class RelativeResolutionPolicy extends BaseResolutionPolicy {
+ // ===========================================================
+ // Constants
+ // ===========================================================
+
+ // ===========================================================
+ // Fields
+ // ===========================================================
+
+ private final float mWidthScale;
+ private final float mHeightScale;
+
+ // ===========================================================
+ // Constructors
+ // ===========================================================
+
+ public RelativeResolutionPolicy(final float pScale) {
+ this(pScale, pScale);
+ }
+
+ public RelativeResolutionPolicy(final float pWidthScale, final float pHeightScale) {
+ this.mWidthScale = pWidthScale;
+ this.mHeightScale = pHeightScale;
+ }
+
+ // ===========================================================
+ // Getter & Setter
+ // ===========================================================
+
+ // ===========================================================
+ // Methods for/from SuperClass/Interfaces
+ // ===========================================================
+ @Override
+ public void onMeasure(final RenderSurfaceView pRenderSurfaceView, final int pWidthMeasureSpec, final int pHeightMeasureSpec) {
+ BaseResolutionPolicy.throwOnNotMeasureSpecEXACTLY(pWidthMeasureSpec, pHeightMeasureSpec);
+
+ final int measuredWidth = (int)(MeasureSpec.getSize(pWidthMeasureSpec) * this.mWidthScale);
+ final int measuredHeight = (int)(MeasureSpec.getSize(pHeightMeasureSpec) * this.mHeightScale);
+
+ pRenderSurfaceView.setMeasuredDimensionProxy(measuredWidth, measuredHeight);
+ }
+
+ // ===========================================================
+ // Methods
+ // ===========================================================
+
+ // ===========================================================
+ // Inner and Anonymous Classes
+ // ===========================================================
+}
diff --git a/AndEngine/src/org/anddev/andengine/entity/Entity.java b/AndEngine/src/org/anddev/andengine/entity/Entity.java
new file mode 100644
index 0000000..b725177
--- /dev/null
+++ b/AndEngine/src/org/anddev/andengine/entity/Entity.java
@@ -0,0 +1,794 @@
+package org.anddev.andengine.entity;
+
+import java.util.ArrayList;
+import java.util.Comparator;
+
+import javax.microedition.khronos.opengles.GL10;
+
+import org.anddev.andengine.engine.camera.Camera;
+import org.anddev.andengine.engine.handler.IUpdateHandler;
+import org.anddev.andengine.engine.handler.UpdateHandlerList;
+import org.anddev.andengine.entity.layer.ZIndexSorter;
+import org.anddev.andengine.entity.modifier.EntityModifierList;
+import org.anddev.andengine.entity.modifier.IEntityModifier;
+import org.anddev.andengine.entity.modifier.IEntityModifier.IEntityModifierMatcher;
+import org.anddev.andengine.util.ParameterCallable;
+import org.anddev.andengine.util.SmartList;
+import org.anddev.andengine.util.Transformation;
+import org.anddev.andengine.util.constants.Constants;
+
+
+/**
+ * @author Nicolas Gramlich
+ * @since 12:00:48 - 08.03.2010
+ */
+public class Entity implements IEntity {
+ // ===========================================================
+ // Constants
+ // ===========================================================
+
+ private static final int CHILDREN_CAPACITY_DEFAULT = 4;
+ private static final int ENTITYMODIFIERS_CAPACITY_DEFAULT = 4;
+ private static final int UPDATEHANDLERS_CAPACITY_DEFAULT = 4;
+
+ private static final float[] VERTICES_SCENE_TO_LOCAL_TMP = new float[2];
+ private static final float[] VERTICES_LOCAL_TO_SCENE_TMP = new float[2];
+
+ private static final ParameterCallable0.0f (transparent) to 1.0f (opaque)
+ */
+ @Override
+ public void setAlpha(final float pAlpha) {
+ this.mAlpha = pAlpha;
+ }
+
+ /**
+ * @param pRed from 0.0f to 1.0f
+ * @param pGreen from 0.0f to 1.0f
+ * @param pBlue from 0.0f to 1.0f
+ */
+ @Override
+ public void setColor(final float pRed, final float pGreen, final float pBlue) {
+ this.mRed = pRed;
+ this.mGreen = pGreen;
+ this.mBlue = pBlue;
+ }
+
+ /**
+ * @param pRed from 0.0f to 1.0f
+ * @param pGreen from 0.0f to 1.0f
+ * @param pBlue from 0.0f to 1.0f
+ * @param pAlpha from 0.0f (transparent) to 1.0f (opaque)
+ */
+ @Override
+ public void setColor(final float pRed, final float pGreen, final float pBlue, final float pAlpha) {
+ this.mRed = pRed;
+ this.mGreen = pGreen;
+ this.mBlue = pBlue;
+ this.mAlpha = pAlpha;
+ }
+
+ @Override
+ public int getChildCount() {
+ if(this.mChildren == null) {
+ return 0;
+ }
+ return this.mChildren.size();
+ }
+
+ @Override
+ public IEntity getChild(final int pIndex) {
+ if(this.mChildren == null) {
+ return null;
+ }
+ return this.mChildren.get(pIndex);
+ }
+
+ @Override
+ public IEntity getFirstChild() {
+ if(this.mChildren == null) {
+ return null;
+ }
+ return this.mChildren.get(0);
+ }
+
+ @Override
+ public IEntity getLastChild() {
+ if(this.mChildren == null) {
+ return null;
+ }
+ return this.mChildren.get(this.mChildren.size() - 1);
+ }
+
+ @Override
+ public boolean detachSelf() {
+ final IEntity parent = this.mParent;
+ if(parent != null) {
+ return parent.detachChild(this);
+ } else {
+ return false;
+ }
+ }
+
+ @Override
+ public void detachChildren() {
+ if(this.mChildren == null) {
+ return;
+ }
+ this.mChildren.clear(PARAMETERCALLABLE_DETACHCHILD);
+ }
+
+ @Override
+ public void attachChild(final IEntity pEntity) {
+ if(this.mChildren == null) {
+ this.allocateChildren();
+ }
+
+ this.mChildren.add(pEntity);
+ pEntity.setParent(this);
+ pEntity.onAttached();
+ }
+
+ @Override
+ public IEntity findChild(final IEntityMatcher pEntityMatcher) {
+ if(this.mChildren == null) {
+ return null;
+ }
+ return this.mChildren.find(pEntityMatcher);
+ }
+
+ @Override
+ public void sortChildren() {
+ if(this.mChildren == null) {
+ return;
+ }
+ ZIndexSorter.getInstance().sort(this.mChildren);
+ }
+
+ @Override
+ public void sortChildren(final ComparatorpX/pY.
+ */
+ public TMXTile getTMXTileAt(final float pX, final float pY) {
+ final float[] localCoords = this.convertSceneToLocalCoordinates(pX, pY);
+ final TMXTiledMap tmxTiledMap = this.mTMXTiledMap;
+
+ final int tileColumn = (int)(localCoords[VERTEX_INDEX_X] / tmxTiledMap.getTileWidth());
+ if(tileColumn < 0 || tileColumn > this.mTileColumns - 1) {
+ return null;
+ }
+ final int tileRow = (int)(localCoords[VERTEX_INDEX_Y] / tmxTiledMap.getTileWidth());
+ if(tileRow < 0 || tileRow > this.mTileRows - 1) {
+ return null;
+ }
+
+ return this.mTMXTiles[tileRow][tileColumn];
+ }
+
+ public void addTMXLayerProperty(final TMXLayerProperty pTMXLayerProperty) {
+ this.mTMXLayerProperties.add(pTMXLayerProperty);
+ }
+
+ public TMXPropertiestrue if the event was handled (that means {@link IOnAreaTouchListener} of the {@link Scene} will not be fired!), otherwise false.
+ */
+ public boolean onAreaTouched(final TouchEvent pSceneTouchEvent, final float pTouchAreaLocalX, final float pTouchAreaLocalY);
+
+ // ===========================================================
+ // Inner and Anonymous Classes
+ // ===========================================================
+
+ public interface ITouchAreaMatcher extends IMatcherrepeating feature doesn't work.
+ */
+ public RepeatingSpriteBackground(final float pCameraWidth, final float pCameraHeight, final TextureManager pTextureManager, final ITextureSource pTextureSource) throws IllegalArgumentException {
+ this(pCameraWidth, pCameraHeight, pTextureManager, pTextureSource, 1);
+ }
+
+ public RepeatingSpriteBackground(final float pCameraWidth, final float pCameraHeight, final TextureManager pTextureManager, final ITextureSource pTextureSource, final float pScale) throws IllegalArgumentException {
+ super(null);
+ this.mScale = pScale;
+ this.mEntity = this.loadSprite(pCameraWidth, pCameraHeight, pTextureManager, pTextureSource);
+ }
+
+ // ===========================================================
+ // Getter & Setter
+ // ===========================================================
+
+ public Texture getTexture() {
+ return this.mTexture;
+ }
+
+ // ===========================================================
+ // Methods for/from SuperClass/Interfaces
+ // ===========================================================
+
+ // ===========================================================
+ // Methods
+ // ===========================================================
+
+ private Sprite loadSprite(final float pCameraWidth, final float pCameraHeight, final TextureManager pTextureManager, final ITextureSource pTextureSource) throws IllegalArgumentException {
+ this.mTexture = new Texture(pTextureSource.getWidth(), pTextureSource.getHeight(), TextureOptions.REPEATING_PREMULTIPLYALPHA);
+ final TextureRegion textureRegion = TextureRegionFactory.createFromSource(this.mTexture, pTextureSource, 0, 0);
+
+ final int width = Math.round(pCameraWidth / this.mScale);
+ final int height = Math.round(pCameraHeight / this.mScale);
+
+ textureRegion.setWidth(width);
+ textureRegion.setHeight(height);
+
+ pTextureManager.loadTexture(this.mTexture);
+
+ final Sprite sprite = new Sprite(0, 0, width, height, textureRegion);
+ sprite.setScaleCenter(0, 0);
+ sprite.setScale(this.mScale);
+ return sprite;
+ }
+
+ // ===========================================================
+ // Inner and Anonymous Classes
+ // ===========================================================
+}
diff --git a/AndEngine/src/org/anddev/andengine/entity/scene/background/SpriteBackground.java b/AndEngine/src/org/anddev/andengine/entity/scene/background/SpriteBackground.java
new file mode 100644
index 0000000..8417dc1
--- /dev/null
+++ b/AndEngine/src/org/anddev/andengine/entity/scene/background/SpriteBackground.java
@@ -0,0 +1,45 @@
+package org.anddev.andengine.entity.scene.background;
+
+import org.anddev.andengine.entity.sprite.BaseSprite;
+
+/**
+ * @author Nicolas Gramlich
+ * @since 14:01:43 - 19.07.2010
+ */
+public class SpriteBackground extends EntityBackground {
+ // ===========================================================
+ // Constants
+ // ===========================================================
+
+ // ===========================================================
+ // Fields
+ // ===========================================================
+
+ // ===========================================================
+ // Constructors
+ // ===========================================================
+
+ public SpriteBackground(final BaseSprite pBaseSprite) {
+ super(pBaseSprite);
+ }
+
+ public SpriteBackground(final float pRed, final float pGreen, final float pBlue, final BaseSprite pBaseSprite) {
+ super(pRed, pGreen, pBlue, pBaseSprite);
+ }
+
+ // ===========================================================
+ // Getter & Setter
+ // ===========================================================
+
+ // ===========================================================
+ // Methods for/from SuperClass/Interfaces
+ // ===========================================================
+
+ // ===========================================================
+ // Methods
+ // ===========================================================
+
+ // ===========================================================
+ // Inner and Anonymous Classes
+ // ===========================================================
+}
diff --git a/AndEngine/src/org/anddev/andengine/entity/scene/background/modifier/ColorModifier.java b/AndEngine/src/org/anddev/andengine/entity/scene/background/modifier/ColorModifier.java
new file mode 100644
index 0000000..75eebc9
--- /dev/null
+++ b/AndEngine/src/org/anddev/andengine/entity/scene/background/modifier/ColorModifier.java
@@ -0,0 +1,74 @@
+package org.anddev.andengine.entity.scene.background.modifier;
+
+import org.anddev.andengine.entity.scene.background.IBackground;
+import org.anddev.andengine.util.modifier.BaseTripleValueSpanModifier;
+import org.anddev.andengine.util.modifier.ease.IEaseFunction;
+
+/**
+ * @author Nicolas Gramlich
+ * @since 14:51:03 - 03.09.2010
+ */
+public class ColorModifier extends BaseTripleValueSpanModifiertrue when this object is visible by the {@link Camera}, false otherwise.
+ */
+ protected abstract boolean isCulled(final Camera pCamera);
+
+ @Override
+ protected void onManagedDraw(final GL10 pGL, final Camera pCamera) {
+ if(this.mCullingEnabled == false || this.isCulled(pCamera) == false) {
+ super.onManagedDraw(pGL, pCamera);
+ }
+ }
+
+ @Override
+ public void reset() {
+ super.reset();
+ this.mSourceBlendFunction = BLENDFUNCTION_SOURCE_DEFAULT;
+ this.mDestinationBlendFunction = BLENDFUNCTION_DESTINATION_DEFAULT;
+ }
+
+ // ===========================================================
+ // Methods
+ // ===========================================================
+
+ protected void onInitDraw(final GL10 pGL) {
+ GLHelper.setColor(pGL, this.mRed, this.mGreen, this.mBlue, this.mAlpha);
+
+ GLHelper.enableVertexArray(pGL);
+ GLHelper.blendFunction(pGL, this.mSourceBlendFunction, this.mDestinationBlendFunction);
+ }
+
+ protected void onApplyVertices(final GL10 pGL) {
+ if(GLHelper.EXTENSIONS_VERTEXBUFFEROBJECTS) {
+ final GL11 gl11 = (GL11)pGL;
+
+ this.getVertexBuffer().selectOnHardware(gl11);
+ GLHelper.vertexZeroPointer(gl11);
+ } else {
+ GLHelper.vertexPointer(pGL, this.getVertexBuffer().getFloatBuffer());
+ }
+ }
+
+ protected void updateVertexBuffer() {
+ this.onUpdateVertexBuffer();
+ }
+
+ // ===========================================================
+ // Inner and Anonymous Classes
+ // ===========================================================
+}
diff --git a/AndEngine/src/org/anddev/andengine/entity/sprite/AnimatedSprite.java b/AndEngine/src/org/anddev/andengine/entity/sprite/AnimatedSprite.java
new file mode 100644
index 0000000..5bbdc47
--- /dev/null
+++ b/AndEngine/src/org/anddev/andengine/entity/sprite/AnimatedSprite.java
@@ -0,0 +1,256 @@
+package org.anddev.andengine.entity.sprite;
+
+import java.util.Arrays;
+
+import org.anddev.andengine.opengl.texture.region.TiledTextureRegion;
+import org.anddev.andengine.opengl.vertex.RectangleVertexBuffer;
+import org.anddev.andengine.util.MathUtils;
+import org.anddev.andengine.util.constants.TimeConstants;
+
+public class AnimatedSprite extends TiledSprite implements TimeConstants {
+ // ===========================================================
+ // Constants
+ // ===========================================================
+
+ private static final int LOOP_CONTINUOUS = -1;
+
+ // ===========================================================
+ // Fields
+ // ===========================================================
+
+ private boolean mAnimationRunning;
+
+ private long mAnimationProgress;
+ private long mAnimationDuration;
+ private long[] mFrameEndsInNanoseconds;
+
+ private int mFirstTileIndex;
+ private int mInitialLoopCount;
+ private int mLoopCount;
+ private IAnimationListener mAnimationListener;
+
+ private int mFrameCount;
+ private int[] mFrames;
+
+ // ===========================================================
+ // Constructors
+ // ===========================================================
+
+ public AnimatedSprite(final float pX, final float pY, final TiledTextureRegion pTiledTextureRegion) {
+ super(pX, pY, pTiledTextureRegion);
+ }
+
+ public AnimatedSprite(final float pX, final float pY, final float pTileWidth, final float pTileHeight, final TiledTextureRegion pTiledTextureRegion) {
+ super(pX, pY, pTileWidth, pTileHeight, pTiledTextureRegion);
+ }
+
+ public AnimatedSprite(final float pX, final float pY, final TiledTextureRegion pTiledTextureRegion, final RectangleVertexBuffer pRectangleVertexBuffer) {
+ super(pX, pY, pTiledTextureRegion, pRectangleVertexBuffer);
+ }
+
+ public AnimatedSprite(final float pX, final float pY, final float pTileWidth, final float pTileHeight, final TiledTextureRegion pTiledTextureRegion, final RectangleVertexBuffer pRectangleVertexBuffer) {
+ super(pX, pY, pTileWidth, pTileHeight, pTiledTextureRegion, pRectangleVertexBuffer);
+ }
+
+ // ===========================================================
+ // Getter & Setter
+ // ===========================================================
+
+ public boolean isAnimationRunning() {
+ return this.mAnimationRunning;
+ }
+
+ // ===========================================================
+ // Methods for/from SuperClass/Interfaces
+ // ===========================================================
+
+ @Override
+ protected void onManagedUpdate(final float pSecondsElapsed) {
+ super.onManagedUpdate(pSecondsElapsed);
+ if(this.mAnimationRunning) {
+ final long nanoSecondsElapsed = (long) (pSecondsElapsed * TimeConstants.NANOSECONDSPERSECOND);
+ this.mAnimationProgress += nanoSecondsElapsed;
+
+ if(this.mAnimationProgress > this.mAnimationDuration) {
+ this.mAnimationProgress %= this.mAnimationDuration;
+ if(this.mInitialLoopCount != AnimatedSprite.LOOP_CONTINUOUS) {
+ this.mLoopCount--;
+ }
+ }
+
+ if(this.mInitialLoopCount == AnimatedSprite.LOOP_CONTINUOUS || this.mLoopCount >= 0) {
+ final int currentFrameIndex = this.calculateCurrentFrameIndex();
+
+ if(this.mFrames == null) {
+ this.setCurrentTileIndex(this.mFirstTileIndex + currentFrameIndex);
+ } else {
+ this.setCurrentTileIndex(this.mFrames[currentFrameIndex]);
+ }
+ } else {
+ this.mAnimationRunning = false;
+ if(this.mAnimationListener != null) {
+ this.mAnimationListener.onAnimationEnd(this);
+ }
+ }
+ }
+ }
+
+ // ===========================================================
+ // Methods
+ // ===========================================================
+
+ public void stopAnimation() {
+ this.mAnimationRunning = false;
+ }
+
+ public void stopAnimation(final int pTileIndex) {
+ this.mAnimationRunning = false;
+ this.setCurrentTileIndex(pTileIndex);
+ }
+
+ private int calculateCurrentFrameIndex() {
+ final long animationProgress = this.mAnimationProgress;
+ final long[] frameEnds = this.mFrameEndsInNanoseconds;
+ final int frameCount = this.mFrameCount;
+ for(int i = 0; i < frameCount; i++) {
+ if(frameEnds[i] > animationProgress) {
+ return i;
+ }
+ }
+
+ return frameCount - 1;
+ }
+
+ public AnimatedSprite animate(final long pFrameDurationEach) {
+ return this.animate(pFrameDurationEach, true);
+ }
+
+ public AnimatedSprite animate(final long pFrameDurationEach, final boolean pLoop) {
+ return this.animate(pFrameDurationEach, (pLoop) ? AnimatedSprite.LOOP_CONTINUOUS : 0, null);
+ }
+
+ public AnimatedSprite animate(final long pFrameDurationEach, final int pLoopCount) {
+ return this.animate(pFrameDurationEach, pLoopCount, null);
+ }
+
+ public AnimatedSprite animate(final long pFrameDurationEach, final boolean pLoop, final IAnimationListener pAnimationListener) {
+ return this.animate(pFrameDurationEach, (pLoop) ? AnimatedSprite.LOOP_CONTINUOUS : 0, pAnimationListener);
+ }
+
+ public AnimatedSprite animate(final long pFrameDurationEach, final int pLoopCount, final IAnimationListener pAnimationListener) {
+ final long[] frameDurations = new long[this.getTextureRegion().getTileCount()];
+ Arrays.fill(frameDurations, pFrameDurationEach);
+ return this.animate(frameDurations, pLoopCount, pAnimationListener);
+ }
+
+ public AnimatedSprite animate(final long[] pFrameDurations) {
+ return this.animate(pFrameDurations, true);
+ }
+
+ public AnimatedSprite animate(final long[] pFrameDurations, final boolean pLoop) {
+ return this.animate(pFrameDurations, (pLoop) ? AnimatedSprite.LOOP_CONTINUOUS : 0, null);
+ }
+
+ public AnimatedSprite animate(final long[] pFrameDurations, final int pLoopCount) {
+ return this.animate(pFrameDurations, pLoopCount, null);
+ }
+
+ public AnimatedSprite animate(final long[] pFrameDurations, final boolean pLoop, final IAnimationListener pAnimationListener) {
+ return this.animate(pFrameDurations, (pLoop) ? AnimatedSprite.LOOP_CONTINUOUS : 0, pAnimationListener);
+ }
+
+ public AnimatedSprite animate(final long[] pFrameDurations, final int pLoopCount, final IAnimationListener pAnimationListener) {
+ return this.animate(pFrameDurations, 0, this.getTextureRegion().getTileCount() - 1, pLoopCount, pAnimationListener);
+ }
+
+ public AnimatedSprite animate(final long[] pFrameDurations, final int pFirstTileIndex, final int pLastTileIndex, final boolean pLoop) {
+ return this.animate(pFrameDurations, pFirstTileIndex, pLastTileIndex, (pLoop) ? AnimatedSprite.LOOP_CONTINUOUS : 0, null);
+ }
+
+ public AnimatedSprite animate(final long[] pFrameDurations, final int pFirstTileIndex, final int pLastTileIndex, final int pLoopCount) {
+ return this.animate(pFrameDurations, pFirstTileIndex, pLastTileIndex, pLoopCount, null);
+ }
+
+ public AnimatedSprite animate(final long[] pFrameDurations, final int[] pFrames, final int pLoopCount) {
+ return this.animate(pFrameDurations, pFrames, pLoopCount, null);
+ }
+
+ /**
+ * Animate specifics frames
+ *
+ * @param pFrameDurations must have the same length as pFrames.
+ * @param pFrames indices of the frames to animate.
+ * @param pLoopCount
+ * @param pAnimationListener
+ */
+ public AnimatedSprite animate(final long[] pFrameDurations, final int[] pFrames, final int pLoopCount, final IAnimationListener pAnimationListener) {
+ final int frameCount = pFrames.length;
+ if(pFrameDurations.length != frameCount) {
+ throw new IllegalArgumentException("pFrameDurations must have the same length as pFrames.");
+ }
+
+ return this.init(pFrameDurations, frameCount, pFrames, 0, pLoopCount, pAnimationListener);
+ }
+
+ /**
+ * @param pFrameDurations
+ * must have the same length as pFirstTileIndex to
+ * pLastTileIndex.
+ * @param pFirstTileIndex
+ * @param pLastTileIndex
+ * @param pLoopCount
+ * @param pAnimationListener
+ */
+ public AnimatedSprite animate(final long[] pFrameDurations, final int pFirstTileIndex, final int pLastTileIndex, final int pLoopCount, final IAnimationListener pAnimationListener) {
+ if(pLastTileIndex - pFirstTileIndex < 1) {
+ throw new IllegalArgumentException("An animation needs at least two tiles to animate between.");
+ }
+
+ final int frameCount = (pLastTileIndex - pFirstTileIndex) + 1;
+ if(pFrameDurations.length != frameCount) {
+ throw new IllegalArgumentException("pFrameDurations must have the same length as pFirstTileIndex to pLastTileIndex.");
+ }
+
+ return this.init(pFrameDurations, frameCount, null, pFirstTileIndex, pLoopCount, pAnimationListener);
+ }
+
+ private AnimatedSprite init(final long[] pFrameDurations, final int frameCount, final int[] pFrames, final int pFirstTileIndex, final int pLoopCount, final IAnimationListener pAnimationListener) {
+ this.mFrameCount = frameCount;
+ this.mAnimationListener = pAnimationListener;
+ this.mInitialLoopCount = pLoopCount;
+ this.mLoopCount = pLoopCount;
+ this.mFrames = pFrames;
+ this.mFirstTileIndex = pFirstTileIndex;
+
+ if(this.mFrameEndsInNanoseconds == null || this.mFrameCount > this.mFrameEndsInNanoseconds.length) {
+ this.mFrameEndsInNanoseconds = new long[this.mFrameCount];
+ }
+
+ final long[] frameEndsInNanoseconds = this.mFrameEndsInNanoseconds;
+ MathUtils.arraySumInto(pFrameDurations, frameEndsInNanoseconds, TimeConstants.NANOSECONDSPERMILLISECOND);
+
+ final long lastFrameEnd = frameEndsInNanoseconds[this.mFrameCount - 1];
+ this.mAnimationDuration = lastFrameEnd;
+
+ this.mAnimationProgress = 0;
+ this.mAnimationRunning = true;
+
+ return this;
+ }
+
+ // ===========================================================
+ // Inner and Anonymous Classes
+ // ===========================================================
+
+ public static interface IAnimationListener {
+ // ===========================================================
+ // Constants
+ // ===========================================================
+
+ // ===========================================================
+ // Fields
+ // ===========================================================
+
+ public void onAnimationEnd(final AnimatedSprite pAnimatedSprite);
+ }
+}
diff --git a/AndEngine/src/org/anddev/andengine/entity/sprite/BaseSprite.java b/AndEngine/src/org/anddev/andengine/entity/sprite/BaseSprite.java
new file mode 100644
index 0000000..59f2c4e
--- /dev/null
+++ b/AndEngine/src/org/anddev/andengine/entity/sprite/BaseSprite.java
@@ -0,0 +1,89 @@
+package org.anddev.andengine.entity.sprite;
+
+import javax.microedition.khronos.opengles.GL10;
+
+import org.anddev.andengine.entity.primitive.BaseRectangle;
+import org.anddev.andengine.opengl.texture.region.BaseTextureRegion;
+import org.anddev.andengine.opengl.util.GLHelper;
+import org.anddev.andengine.opengl.vertex.RectangleVertexBuffer;
+
+/**
+ * @author Nicolas Gramlich
+ * @since 11:38:53 - 08.03.2010
+ */
+public abstract class BaseSprite extends BaseRectangle {
+ // ===========================================================
+ // Constants
+ // ===========================================================
+
+ // ===========================================================
+ // Fields
+ // ===========================================================
+
+ protected final BaseTextureRegion mTextureRegion;
+
+ // ===========================================================
+ // Constructors
+ // ===========================================================
+
+ public BaseSprite(final float pX, final float pY, final float pWidth, final float pHeight, final BaseTextureRegion pTextureRegion) {
+ super(pX, pY, pWidth, pHeight);
+
+ this.mTextureRegion = pTextureRegion;
+ this.initBlendFunction();
+ }
+
+ public BaseSprite(final float pX, final float pY, final float pWidth, final float pHeight, final BaseTextureRegion pTextureRegion, final RectangleVertexBuffer pRectangleVertexBuffer) {
+ super(pX, pY, pWidth, pHeight, pRectangleVertexBuffer);
+
+ this.mTextureRegion = pTextureRegion;
+ this.initBlendFunction();
+ }
+
+ // ===========================================================
+ // Getter & Setter
+ // ===========================================================
+
+ public BaseTextureRegion getTextureRegion() {
+ return this.mTextureRegion;
+ }
+
+ // ===========================================================
+ // Methods for/from SuperClass/Interfaces
+ // ===========================================================
+
+ @Override
+ public void reset() {
+ super.reset();
+
+ this.initBlendFunction();
+ }
+
+ @Override
+ protected void onInitDraw(final GL10 pGL) {
+ super.onInitDraw(pGL);
+ GLHelper.enableTextures(pGL);
+ GLHelper.enableTexCoordArray(pGL);
+ }
+
+ @Override
+ protected void onApplyTransformations(final GL10 pGL) {
+ super.onApplyTransformations(pGL);
+
+ this.mTextureRegion.onApply(pGL);
+ }
+
+ // ===========================================================
+ // Methods
+ // ===========================================================
+
+ private void initBlendFunction() {
+ if(this.mTextureRegion.getTexture().getTextureOptions().mPreMultipyAlpha) {
+ this.setBlendFunction(BLENDFUNCTION_SOURCE_PREMULTIPLYALPHA_DEFAULT, BLENDFUNCTION_DESTINATION_PREMULTIPLYALPHA_DEFAULT);
+ }
+ }
+
+ // ===========================================================
+ // Inner and Anonymous Classes
+ // ===========================================================
+}
diff --git a/AndEngine/src/org/anddev/andengine/entity/sprite/Sprite.java b/AndEngine/src/org/anddev/andengine/entity/sprite/Sprite.java
new file mode 100644
index 0000000..b10b406
--- /dev/null
+++ b/AndEngine/src/org/anddev/andengine/entity/sprite/Sprite.java
@@ -0,0 +1,59 @@
+package org.anddev.andengine.entity.sprite;
+
+import org.anddev.andengine.opengl.texture.region.TextureRegion;
+import org.anddev.andengine.opengl.vertex.RectangleVertexBuffer;
+
+/**
+ * @author Nicolas Gramlich
+ * @since 19:22:38 - 09.03.2010
+ */
+public class Sprite extends BaseSprite {
+ // ===========================================================
+ // Constants
+ // ===========================================================
+
+ // ===========================================================
+ // Fields
+ // ===========================================================
+
+ // ===========================================================
+ // Constructors
+ // ===========================================================
+
+ public Sprite(final float pX, final float pY, final TextureRegion pTextureRegion) {
+ super(pX, pY, pTextureRegion.getWidth(), pTextureRegion.getHeight(), pTextureRegion);
+ }
+
+ public Sprite(final float pX, final float pY, final float pWidth, final float pHeight, final TextureRegion pTextureRegion) {
+ super(pX, pY, pWidth, pHeight, pTextureRegion);
+ }
+
+ public Sprite(final float pX, final float pY, final TextureRegion pTextureRegion, final RectangleVertexBuffer pRectangleVertexBuffer) {
+ super(pX, pY, pTextureRegion.getWidth(), pTextureRegion.getHeight(), pTextureRegion, pRectangleVertexBuffer);
+ }
+
+ public Sprite(final float pX, final float pY, final float pWidth, final float pHeight, final TextureRegion pTextureRegion, final RectangleVertexBuffer pRectangleVertexBuffer) {
+ super(pX, pY, pWidth, pHeight, pTextureRegion, pRectangleVertexBuffer);
+ }
+
+ // ===========================================================
+ // Getter & Setter
+ // ===========================================================
+
+ // ===========================================================
+ // Methods for/from SuperClass/Interfaces
+ // ===========================================================
+
+ @Override
+ public TextureRegion getTextureRegion() {
+ return (TextureRegion)this.mTextureRegion;
+ }
+
+ // ===========================================================
+ // Methods
+ // ===========================================================
+
+ // ===========================================================
+ // Inner and Anonymous Classes
+ // ===========================================================
+}
diff --git a/AndEngine/src/org/anddev/andengine/entity/sprite/TiledSprite.java b/AndEngine/src/org/anddev/andengine/entity/sprite/TiledSprite.java
new file mode 100644
index 0000000..ca4e773
--- /dev/null
+++ b/AndEngine/src/org/anddev/andengine/entity/sprite/TiledSprite.java
@@ -0,0 +1,75 @@
+package org.anddev.andengine.entity.sprite;
+
+import org.anddev.andengine.opengl.texture.region.TiledTextureRegion;
+import org.anddev.andengine.opengl.vertex.RectangleVertexBuffer;
+
+/**
+ * @author Nicolas Gramlich
+ * @since 19:30:13 - 09.03.2010
+ */
+public class TiledSprite extends BaseSprite {
+ // ===========================================================
+ // Constants
+ // ===========================================================
+
+ // ===========================================================
+ // Fields
+ // ===========================================================
+
+ // ===========================================================
+ // Constructors
+ // ===========================================================
+
+ public TiledSprite(final float pX, final float pY, final TiledTextureRegion pTiledTextureRegion) {
+ super(pX, pY, pTiledTextureRegion.getTileWidth(), pTiledTextureRegion.getTileHeight(), pTiledTextureRegion);
+ }
+
+ public TiledSprite(final float pX, final float pY, final float pTileWidth, final float pTileHeight, final TiledTextureRegion pTiledTextureRegion) {
+ super(pX, pY, pTileWidth, pTileHeight, pTiledTextureRegion);
+ }
+
+ public TiledSprite(final float pX, final float pY, final TiledTextureRegion pTiledTextureRegion, final RectangleVertexBuffer pRectangleVertexBuffer) {
+ super(pX, pY, pTiledTextureRegion.getTileWidth(), pTiledTextureRegion.getTileHeight(), pTiledTextureRegion, pRectangleVertexBuffer);
+ }
+
+ public TiledSprite(final float pX, final float pY, final float pTileWidth, final float pTileHeight, final TiledTextureRegion pTiledTextureRegion, final RectangleVertexBuffer pRectangleVertexBuffer) {
+ super(pX, pY, pTileWidth, pTileHeight, pTiledTextureRegion, pRectangleVertexBuffer);
+ }
+
+ // ===========================================================
+ // Getter & Setter
+ // ===========================================================
+
+ // ===========================================================
+ // Methods for/from SuperClass/Interfaces
+ // ===========================================================
+
+ @Override
+ public TiledTextureRegion getTextureRegion() {
+ return (TiledTextureRegion)super.getTextureRegion();
+ }
+
+ // ===========================================================
+ // Methods
+ // ===========================================================
+
+ public int getCurrentTileIndex() {
+ return this.getTextureRegion().getCurrentTileIndex();
+ }
+
+ public void setCurrentTileIndex(final int pTileIndex) {
+ this.getTextureRegion().setCurrentTileIndex(pTileIndex);
+ }
+
+ public void setCurrentTileIndex(final int pTileColumn, final int pTileRow) {
+ this.getTextureRegion().setCurrentTileIndex(pTileColumn, pTileRow);
+ }
+
+ public void nextTile() {
+ this.getTextureRegion().nextTile();
+ }
+
+ // ===========================================================
+ // Inner and Anonymous Classes
+ // ===========================================================
+}
diff --git a/AndEngine/src/org/anddev/andengine/entity/text/ChangeableText.java b/AndEngine/src/org/anddev/andengine/entity/text/ChangeableText.java
new file mode 100644
index 0000000..c7512bd
--- /dev/null
+++ b/AndEngine/src/org/anddev/andengine/entity/text/ChangeableText.java
@@ -0,0 +1,90 @@
+package org.anddev.andengine.entity.text;
+
+import javax.microedition.khronos.opengles.GL10;
+
+import org.anddev.andengine.engine.camera.Camera;
+import org.anddev.andengine.opengl.font.Font;
+import org.anddev.andengine.opengl.vertex.TextVertexBuffer;
+import org.anddev.andengine.util.HorizontalAlign;
+import org.anddev.andengine.util.StringUtils;
+
+/**
+ * @author Nicolas Gramlich
+ * @since 18:07:06 - 08.07.2010
+ */
+public class ChangeableText extends Text {
+ // ===========================================================
+ // Constants
+ // ===========================================================
+
+ private static final String ELLIPSIS = "...";
+ private static final int ELLIPSIS_CHARACTER_COUNT = ELLIPSIS.length();
+
+ // ===========================================================
+ // Fields
+ // ===========================================================
+
+ private int mCharacterCountCurrentText;
+
+ // ===========================================================
+ // Constructors
+ // ===========================================================
+
+ public ChangeableText(final float pX, final float pY, final Font pFont, final String pText) {
+ this(pX, pY, pFont, pText, pText.length() - StringUtils.countOccurrences(pText, '\n'));
+ }
+
+ public ChangeableText(final float pX, final float pY, final Font pFont, final String pText, final int pCharactersMaximum) {
+ this(pX, pY, pFont, pText, HorizontalAlign.LEFT, pCharactersMaximum);
+ }
+
+ public ChangeableText(final float pX, final float pY, final Font pFont, final String pText, final HorizontalAlign pHorizontalAlign, final int pCharactersMaximum) {
+ super(pX, pY, pFont, pText, pHorizontalAlign, pCharactersMaximum);
+ this.mCharacterCountCurrentText = pText.length() - StringUtils.countOccurrences(pText, '\n');
+ }
+
+ // ===========================================================
+ // Getter & Setter
+ // ===========================================================
+
+ public void setText(final String pText) {
+ this.setText(pText, false);
+ }
+
+ /**
+ * @param pText
+ * @param pAllowEllipsis in the case pText is longer than pCharactersMaximum,
+ * which was passed to the constructor, the displayed text will end with an ellipsis ("...").
+ */
+ public void setText(final String pText, final boolean pAllowEllipsis) {
+ final int textCharacterCount = pText.length() - StringUtils.countOccurrences(pText, '\n');
+ if(textCharacterCount > this.mCharactersMaximum) {
+ if(pAllowEllipsis && this.mCharactersMaximum > ELLIPSIS_CHARACTER_COUNT) {
+ this.updateText(pText.substring(0, this.mCharactersMaximum - ELLIPSIS_CHARACTER_COUNT).concat(ELLIPSIS)); // TODO This allocation could maybe be avoided...
+ } else {
+ this.updateText(pText.substring(0, this.mCharactersMaximum)); // TODO This allocation could be avoided...
+ }
+ this.mCharacterCountCurrentText = this.mCharactersMaximum;
+ } else {
+ this.updateText(pText);
+ this.mCharacterCountCurrentText = textCharacterCount;
+ }
+ }
+
+ // ===========================================================
+ // Methods for/from SuperClass/Interfaces
+ // ===========================================================
+
+ @Override
+ protected void drawVertices(final GL10 pGL, final Camera pCamera) {
+ pGL.glDrawArrays(GL10.GL_TRIANGLES, 0, this.mCharacterCountCurrentText * TextVertexBuffer.VERTICES_PER_CHARACTER);
+ }
+
+ // ===========================================================
+ // Methods
+ // ===========================================================
+
+ // ===========================================================
+ // Inner and Anonymous Classes
+ // ===========================================================
+}
diff --git a/AndEngine/src/org/anddev/andengine/entity/text/Text.java b/AndEngine/src/org/anddev/andengine/entity/text/Text.java
new file mode 100644
index 0000000..391c3af
--- /dev/null
+++ b/AndEngine/src/org/anddev/andengine/entity/text/Text.java
@@ -0,0 +1,179 @@
+package org.anddev.andengine.entity.text;
+
+import javax.microedition.khronos.opengles.GL10;
+import javax.microedition.khronos.opengles.GL11;
+
+import org.anddev.andengine.engine.camera.Camera;
+import org.anddev.andengine.entity.shape.RectangularShape;
+import org.anddev.andengine.opengl.buffer.BufferObjectManager;
+import org.anddev.andengine.opengl.font.Font;
+import org.anddev.andengine.opengl.texture.buffer.TextTextureBuffer;
+import org.anddev.andengine.opengl.util.GLHelper;
+import org.anddev.andengine.opengl.vertex.TextVertexBuffer;
+import org.anddev.andengine.util.HorizontalAlign;
+import org.anddev.andengine.util.StringUtils;
+
+/**
+ * @author Nicolas Gramlich
+ * @since 10:54:59 - 03.04.2010
+ */
+public class Text extends RectangularShape {
+ // ===========================================================
+ // Constants
+ // ===========================================================
+
+ // ===========================================================
+ // Fields
+ // ===========================================================
+
+ private final TextTextureBuffer mTextTextureBuffer;
+
+ private String mText;
+ private String[] mLines;
+ private int[] mWidths;
+
+ private final Font mFont;
+
+ private int mMaximumLineWidth;
+
+ protected final int mCharactersMaximum;
+ protected final int mVertexCount;
+
+ // ===========================================================
+ // Constructors
+ // ===========================================================
+
+ public Text(final float pX, final float pY, final Font pFont, final String pText) {
+ this(pX, pY, pFont, pText, HorizontalAlign.LEFT);
+ }
+
+ public Text(final float pX, final float pY, final Font pFont, final String pText, final HorizontalAlign pHorizontalAlign) {
+ this(pX, pY, pFont, pText, pHorizontalAlign, pText.length() - StringUtils.countOccurrences(pText, '\n'));
+ }
+
+ protected Text(final float pX, final float pY, final Font pFont, final String pText, final HorizontalAlign pHorizontalAlign, final int pCharactersMaximum) {
+ super(pX, pY, 0, 0, new TextVertexBuffer(pCharactersMaximum, pHorizontalAlign, GL11.GL_STATIC_DRAW));
+
+ this.mCharactersMaximum = pCharactersMaximum;
+ this.mVertexCount = TextVertexBuffer.VERTICES_PER_CHARACTER * this.mCharactersMaximum;
+
+ this.mTextTextureBuffer = new TextTextureBuffer(2 * this.mVertexCount, GL11.GL_STATIC_DRAW);
+ BufferObjectManager.getActiveInstance().loadBufferObject(this.mTextTextureBuffer);
+ this.mFont = pFont;
+
+ this.updateText(pText);
+
+ this.initBlendFunction();
+ }
+
+ protected void updateText(final String pText) {
+ this.mText = pText;
+ final Font font = this.mFont;
+
+ this.mLines = StringUtils.split(this.mText, '\n', this.mLines);
+ final String[] lines = this.mLines;
+
+ final int lineCount = lines.length;
+ final boolean widthsReusable = this.mWidths != null && this.mWidths.length == lineCount;
+ if(widthsReusable == false) {
+ this.mWidths = new int[lineCount];
+ }
+ final int[] widths = this.mWidths;
+
+ int maximumLineWidth = 0;
+
+ for (int i = lineCount - 1; i >= 0; i--) {
+ widths[i] = font.getStringWidth(lines[i]);
+ maximumLineWidth = Math.max(maximumLineWidth, widths[i]);
+ }
+ this.mMaximumLineWidth = maximumLineWidth;
+
+ super.mWidth = this.mMaximumLineWidth;
+ final float width = super.mWidth;
+ super.mBaseWidth = width;
+
+ super.mHeight = lineCount * font.getLineHeight() + (lineCount - 1) * font.getLineGap();
+ final float height = super.mHeight;
+ super.mBaseHeight = height;
+
+ this.mRotationCenterX = width * 0.5f;
+ this.mRotationCenterY = height * 0.5f;
+
+ this.mScaleCenterX = this.mRotationCenterX;
+ this.mScaleCenterY = this.mRotationCenterY;
+
+ this.mTextTextureBuffer.update(font, lines);
+ this.updateVertexBuffer();
+ }
+
+ // ===========================================================
+ // Getter & Setter
+ // ===========================================================
+
+ public int getCharacterCount() {
+ return this.mCharactersMaximum;
+ }
+
+ @Override
+ public TextVertexBuffer getVertexBuffer() {
+ return (TextVertexBuffer)super.getVertexBuffer();
+ }
+
+ // ===========================================================
+ // Methods for/from SuperClass/Interfaces
+ // ===========================================================
+
+ @Override
+ protected void onInitDraw(final GL10 pGL) {
+ super.onInitDraw(pGL);
+ GLHelper.enableTextures(pGL);
+ GLHelper.enableTexCoordArray(pGL);
+ }
+
+ @Override
+ protected void drawVertices(final GL10 pGL, final Camera pCamera) {
+ pGL.glDrawArrays(GL10.GL_TRIANGLES, 0, this.mVertexCount);
+ }
+
+ @Override
+ protected void onUpdateVertexBuffer() {
+ final Font font = this.mFont;
+ if(font != null) {
+ this.getVertexBuffer().update(font, this.mMaximumLineWidth, this.mWidths, this.mLines);
+ }
+ }
+
+ @Override
+ protected void onApplyTransformations(final GL10 pGL) {
+ super.onApplyTransformations(pGL);
+ this.applyTexture(pGL);
+ }
+
+ // ===========================================================
+ // Methods
+ // ===========================================================
+
+ private void initBlendFunction() {
+ if(this.mFont.getTexture().getTextureOptions().mPreMultipyAlpha) {
+ this.setBlendFunction(BLENDFUNCTION_SOURCE_PREMULTIPLYALPHA_DEFAULT, BLENDFUNCTION_DESTINATION_PREMULTIPLYALPHA_DEFAULT);
+ }
+ }
+
+ private void applyTexture(final GL10 pGL) {
+ if(GLHelper.EXTENSIONS_VERTEXBUFFEROBJECTS) {
+ final GL11 gl11 = (GL11)pGL;
+
+ this.mTextTextureBuffer.selectOnHardware(gl11);
+
+ GLHelper.bindTexture(pGL, this.mFont.getTexture().getHardwareTextureID());
+ GLHelper.texCoordZeroPointer(gl11);
+ } else {
+ GLHelper.bindTexture(pGL, this.mFont.getTexture().getHardwareTextureID());
+ GLHelper.texCoordPointer(pGL, this.mTextTextureBuffer.getFloatBuffer());
+ }
+ }
+
+ // ===========================================================
+ // Inner and Anonymous Classes
+ // ===========================================================
+}
\ No newline at end of file
diff --git a/AndEngine/src/org/anddev/andengine/entity/text/TickerText.java b/AndEngine/src/org/anddev/andengine/entity/text/TickerText.java
new file mode 100644
index 0000000..79b34a5
--- /dev/null
+++ b/AndEngine/src/org/anddev/andengine/entity/text/TickerText.java
@@ -0,0 +1,107 @@
+package org.anddev.andengine.entity.text;
+
+import javax.microedition.khronos.opengles.GL10;
+
+import org.anddev.andengine.engine.camera.Camera;
+import org.anddev.andengine.opengl.font.Font;
+import org.anddev.andengine.opengl.vertex.TextVertexBuffer;
+import org.anddev.andengine.util.HorizontalAlign;
+
+/**
+ * @author Nicolas Gramlich
+ * @since 10:02:04 - 05.05.2010
+ */
+public class TickerText extends Text {
+ // ===========================================================
+ // Constants
+ // ===========================================================
+
+ // ===========================================================
+ // Fields
+ // ===========================================================
+
+ private float mCharactersPerSecond;
+
+ private int mCharactersVisible = 0;
+ private float mSecondsElapsed = 0;
+
+ private boolean mReverse = false;
+
+ private float mDuration;
+
+ // ===========================================================
+ // Constructors
+ // ===========================================================
+
+ public TickerText(final float pX, final float pY, final Font pFont, final String pText, final HorizontalAlign pHorizontalAlign, final float pCharactersPerSecond) {
+ super(pX, pY, pFont, pText, pHorizontalAlign);
+ this.setCharactersPerSecond(pCharactersPerSecond);
+ }
+
+ // ===========================================================
+ // Getter & Setter
+ // ===========================================================
+
+ public boolean isReverse() {
+ return this.mReverse;
+ }
+
+ public void setReverse(final boolean pReverse) {
+ this.mReverse = pReverse;
+ }
+
+ public float getCharactersPerSecond() {
+ return this.mCharactersPerSecond;
+ }
+
+ public void setCharactersPerSecond(final float pCharactersPerSecond) {
+ this.mCharactersPerSecond = pCharactersPerSecond;
+ this.mDuration = this.mCharactersMaximum * this.mCharactersPerSecond;
+ }
+
+ public int getCharactersVisible() {
+ return this.mCharactersVisible;
+ }
+
+ // ===========================================================
+ // Methods for/from SuperClass/Interfaces
+ // ===========================================================
+
+ @Override
+ protected void onManagedUpdate(final float pSecondsElapsed) {
+ super.onManagedUpdate(pSecondsElapsed);
+ if(this.mReverse){
+ if(this.mCharactersVisible < this.mCharactersMaximum){
+ this.mSecondsElapsed = Math.max(0, this.mSecondsElapsed - pSecondsElapsed);
+ this.mCharactersVisible = (int)(this.mSecondsElapsed * this.mCharactersPerSecond);
+ }
+ } else {
+ if(this.mCharactersVisible < this.mCharactersMaximum){
+ this.mSecondsElapsed = Math.min(this.mDuration, this.mSecondsElapsed + pSecondsElapsed);
+ this.mCharactersVisible = (int)(this.mSecondsElapsed * this.mCharactersPerSecond);
+ }
+ }
+ }
+
+ @Override
+ protected void drawVertices(final GL10 pGL, final Camera pCamera) {
+ pGL.glDrawArrays(GL10.GL_TRIANGLES, 0, this.mCharactersVisible * TextVertexBuffer.VERTICES_PER_CHARACTER);
+ }
+
+ @Override
+ public void reset() {
+ super.reset();
+
+ this.mCharactersVisible = 0;
+ this.mSecondsElapsed = 0;
+ this.mReverse = false;
+ }
+
+ // ===========================================================
+ // Methods
+ // ===========================================================
+
+ // ===========================================================
+ // Inner and Anonymous Classes
+ // ===========================================================
+}
diff --git a/AndEngine/src/org/anddev/andengine/entity/util/AverageFPSCounter.java b/AndEngine/src/org/anddev/andengine/entity/util/AverageFPSCounter.java
new file mode 100644
index 0000000..67e8bba
--- /dev/null
+++ b/AndEngine/src/org/anddev/andengine/entity/util/AverageFPSCounter.java
@@ -0,0 +1,64 @@
+package org.anddev.andengine.entity.util;
+
+import org.anddev.andengine.util.constants.TimeConstants;
+
+
+/**
+ * @author Nicolas Gramlich
+ * @since 19:52:31 - 09.03.2010
+ */
+public abstract class AverageFPSCounter extends FPSCounter implements TimeConstants {
+ // ===========================================================
+ // Constants
+ // ===========================================================
+
+ private static final float AVERAGE_DURATION_DEFAULT = 5;
+
+ // ===========================================================
+ // Fields
+ // ===========================================================
+
+ protected final float mAverageDuration;
+
+ // ===========================================================
+ // Constructors
+ // ===========================================================
+
+ public AverageFPSCounter() {
+ this(AVERAGE_DURATION_DEFAULT);
+ }
+
+ public AverageFPSCounter(final float pAverageDuration) {
+ this.mAverageDuration = pAverageDuration;
+ }
+
+ // ===========================================================
+ // Getter & Setter
+ // ===========================================================
+
+ // ===========================================================
+ // Methods for/from SuperClass/Interfaces
+ // ===========================================================
+
+ protected abstract void onHandleAverageDurationElapsed(final float pFPS);
+
+ @Override
+ public void onUpdate(final float pSecondsElapsed) {
+ super.onUpdate(pSecondsElapsed);
+
+ if(this.mSecondsElapsed > this.mAverageDuration){
+ this.onHandleAverageDurationElapsed(this.getFPS());
+
+ this.mSecondsElapsed -= this.mAverageDuration;
+ this.mFrames = 0;
+ }
+ }
+
+ // ===========================================================
+ // Methods
+ // ===========================================================
+
+ // ===========================================================
+ // Inner and Anonymous Classes
+ // ===========================================================
+}
diff --git a/AndEngine/src/org/anddev/andengine/entity/util/FPSCounter.java b/AndEngine/src/org/anddev/andengine/entity/util/FPSCounter.java
new file mode 100644
index 0000000..ca7c451
--- /dev/null
+++ b/AndEngine/src/org/anddev/andengine/entity/util/FPSCounter.java
@@ -0,0 +1,57 @@
+package org.anddev.andengine.entity.util;
+
+import org.anddev.andengine.engine.handler.IUpdateHandler;
+
+/**
+ * @author Nicolas Gramlich
+ * @since 19:52:31 - 09.03.2010
+ */
+public class FPSCounter implements IUpdateHandler {
+ // ===========================================================
+ // Constants
+ // ===========================================================
+
+ // ===========================================================
+ // Fields
+ // ===========================================================
+
+ protected float mSecondsElapsed;
+
+ protected int mFrames;
+
+ // ===========================================================
+ // Constructors
+ // ===========================================================
+
+ // ===========================================================
+ // Getter & Setter
+ // ===========================================================
+
+ public float getFPS() {
+ return this.mFrames / this.mSecondsElapsed;
+ }
+
+ // ===========================================================
+ // Methods for/from SuperClass/Interfaces
+ // ===========================================================
+
+ @Override
+ public void onUpdate(final float pSecondsElapsed) {
+ this.mFrames++;
+ this.mSecondsElapsed += pSecondsElapsed;
+ }
+
+ @Override
+ public void reset() {
+ this.mFrames = 0;
+ this.mSecondsElapsed = 0;
+ }
+
+ // ===========================================================
+ // Methods
+ // ===========================================================
+
+ // ===========================================================
+ // Inner and Anonymous Classes
+ // ===========================================================
+}
diff --git a/AndEngine/src/org/anddev/andengine/entity/util/FPSLogger.java b/AndEngine/src/org/anddev/andengine/entity/util/FPSLogger.java
new file mode 100644
index 0000000..9fff9a6
--- /dev/null
+++ b/AndEngine/src/org/anddev/andengine/entity/util/FPSLogger.java
@@ -0,0 +1,79 @@
+package org.anddev.andengine.entity.util;
+
+import org.anddev.andengine.util.Debug;
+
+/**
+ * @author Nicolas Gramlich
+ * @since 19:52:31 - 09.03.2010
+ */
+public class FPSLogger extends AverageFPSCounter {
+ // ===========================================================
+ // Constants
+ // ===========================================================
+
+ // ===========================================================
+ // Fields
+ // ===========================================================
+
+ protected float mShortestFrame = Float.MAX_VALUE;
+ protected float mLongestFrame = Float.MIN_VALUE;
+
+ // ===========================================================
+ // Constructors
+ // ===========================================================
+
+ public FPSLogger() {
+ super();
+ }
+
+ public FPSLogger(final float pAverageDuration) {
+ super(pAverageDuration);
+ }
+
+ // ===========================================================
+ // Getter & Setter
+ // ===========================================================
+
+ // ===========================================================
+ // Methods for/from SuperClass/Interfaces
+ // ===========================================================
+
+ @Override
+ protected void onHandleAverageDurationElapsed(final float pFPS) {
+ this.onLogFPS();
+
+ this.mLongestFrame = Float.MIN_VALUE;
+ this.mShortestFrame = Float.MAX_VALUE;
+ }
+
+ @Override
+ public void onUpdate(final float pSecondsElapsed) {
+ super.onUpdate(pSecondsElapsed);
+
+ this.mShortestFrame = Math.min(this.mShortestFrame, pSecondsElapsed);
+ this.mLongestFrame = Math.max(this.mLongestFrame, pSecondsElapsed);
+ }
+
+ @Override
+ public void reset() {
+ super.reset();
+
+ this.mShortestFrame = Float.MAX_VALUE;
+ this.mLongestFrame = Float.MIN_VALUE;
+ }
+
+ // ===========================================================
+ // Methods
+ // ===========================================================
+
+ protected void onLogFPS() {
+ Debug.d(String.format("FPS: %.2f (MIN: %.0f ms | MAX: %.0f ms)",
+ this.mFrames / this.mSecondsElapsed,
+ this.mShortestFrame * MILLISECONDSPERSECOND,
+ this.mLongestFrame * MILLISECONDSPERSECOND));
+ }
+
+ // ===========================================================
+ // Inner and Anonymous Classes
+ // ===========================================================
+}
diff --git a/AndEngine/src/org/anddev/andengine/entity/util/FrameCountCrasher.java b/AndEngine/src/org/anddev/andengine/entity/util/FrameCountCrasher.java
new file mode 100644
index 0000000..34b7cee
--- /dev/null
+++ b/AndEngine/src/org/anddev/andengine/entity/util/FrameCountCrasher.java
@@ -0,0 +1,69 @@
+package org.anddev.andengine.entity.util;
+
+import org.anddev.andengine.engine.handler.IUpdateHandler;
+import org.anddev.andengine.util.Debug;
+import org.anddev.andengine.util.constants.TimeConstants;
+
+/**
+ * @author Nicolas Gramlich
+ * @since 19:52:31 - 09.03.2010
+ */
+public class FrameCountCrasher implements IUpdateHandler, TimeConstants {
+ // ===========================================================
+ // Constants
+ // ===========================================================
+
+ // ===========================================================
+ // Fields
+ // ===========================================================
+
+ private int mFramesLeft;
+
+ private final float[] mFrameLengths;
+
+ // ===========================================================
+ // Constructors
+ // ===========================================================
+
+ public FrameCountCrasher(final int pFrameCount) {
+ this.mFramesLeft = pFrameCount;
+ this.mFrameLengths = new float[pFrameCount];
+ }
+
+ // ===========================================================
+ // Getter & Setter
+ // ===========================================================
+
+ // ===========================================================
+ // Methods for/from SuperClass/Interfaces
+ // ===========================================================
+
+ @Override
+ public void onUpdate(final float pSecondsElapsed) {
+ this.mFramesLeft--;
+
+ final float[] frameLengths = this.mFrameLengths;
+ if(this.mFramesLeft >= 0) {
+ frameLengths[this.mFramesLeft] = pSecondsElapsed;
+ } else {
+ for(int i = frameLengths.length - 1; i >= 0; i--) {
+ Debug.d("Elapsed: " + frameLengths[i]);
+ }
+
+ throw new RuntimeException();
+ }
+ }
+
+ @Override
+ public void reset() {
+
+ }
+
+ // ===========================================================
+ // Methods
+ // ===========================================================
+
+ // ===========================================================
+ // Inner and Anonymous Classes
+ // ===========================================================
+}
diff --git a/AndEngine/src/org/anddev/andengine/entity/util/FrameCounter.java b/AndEngine/src/org/anddev/andengine/entity/util/FrameCounter.java
new file mode 100644
index 0000000..a96509f
--- /dev/null
+++ b/AndEngine/src/org/anddev/andengine/entity/util/FrameCounter.java
@@ -0,0 +1,53 @@
+package org.anddev.andengine.entity.util;
+
+import org.anddev.andengine.engine.handler.IUpdateHandler;
+
+/**
+ * @author Nicolas Gramlich
+ * @since 11:00:55 - 22.06.2010
+ */
+public class FrameCounter implements IUpdateHandler {
+ // ===========================================================
+ // Constants
+ // ===========================================================
+
+ // ===========================================================
+ // Fields
+ // ===========================================================
+
+ private int mFrames;
+
+ // ===========================================================
+ // Constructors
+ // ===========================================================
+
+ // ===========================================================
+ // Getter & Setter
+ // ===========================================================
+
+ public int getFrames() {
+ return this.mFrames;
+ }
+
+ // ===========================================================
+ // Methods for/from SuperClass/Interfaces
+ // ===========================================================
+
+ @Override
+ public void onUpdate(final float pSecondsElapsed) {
+ this.mFrames++;
+ }
+
+ @Override
+ public void reset() {
+ this.mFrames = 0;
+ }
+
+ // ===========================================================
+ // Methods
+ // ===========================================================
+
+ // ===========================================================
+ // Inner and Anonymous Classes
+ // ===========================================================
+}
diff --git a/AndEngine/src/org/anddev/andengine/entity/util/ScreenCapture.java b/AndEngine/src/org/anddev/andengine/entity/util/ScreenCapture.java
new file mode 100644
index 0000000..7ee0382
--- /dev/null
+++ b/AndEngine/src/org/anddev/andengine/entity/util/ScreenCapture.java
@@ -0,0 +1,121 @@
+package org.anddev.andengine.entity.util;
+
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+
+import javax.microedition.khronos.opengles.GL10;
+
+import org.anddev.andengine.engine.camera.Camera;
+import org.anddev.andengine.entity.Entity;
+import org.anddev.andengine.entity.util.ScreenGrabber.IScreenGrabberCallback;
+import org.anddev.andengine.util.Debug;
+import org.anddev.andengine.util.StreamUtils;
+
+import android.graphics.Bitmap;
+import android.graphics.Bitmap.CompressFormat;
+
+/**
+ * @author Nicolas Gramlich
+ * @since 15:11:50 - 15.03.2010
+ */
+public class ScreenCapture extends Entity implements IScreenGrabberCallback {
+ // ===========================================================
+ // Constants
+ // ===========================================================
+
+ // ===========================================================
+ // Fields
+ // ===========================================================
+
+ private String mFilePath;
+
+ private final ScreenGrabber mScreenGrabber = new ScreenGrabber();
+
+ private IScreenCaptureCallback mScreenCaptureCallback;
+
+ // ===========================================================
+ // Constructors
+ // ===========================================================
+
+ // ===========================================================
+ // Getter & Setter
+ // ===========================================================
+
+ // ===========================================================
+ // Methods for/from SuperClass/Interfaces
+ // ===========================================================
+
+ @Override
+ protected void onManagedDraw(final GL10 pGL, final Camera pCamera) {
+ this.mScreenGrabber.onManagedDraw(pGL, pCamera);
+ }
+
+ @Override
+ protected void onManagedUpdate(final float pSecondsElapsed) {
+ /* Nothing */
+ }
+
+ @Override
+ public void reset() {
+ /* Nothing */
+ }
+
+ @Override
+ public void onScreenGrabbed(final Bitmap pBitmap) {
+ try {
+ ScreenCapture.saveCapture(pBitmap, this.mFilePath);
+ this.mScreenCaptureCallback.onScreenCaptured(this.mFilePath);
+ } catch (final FileNotFoundException e) {
+ this.mScreenCaptureCallback.onScreenCaptureFailed(this.mFilePath, e);
+ }
+ }
+
+ @Override
+ public void onScreenGrabFailed(final Exception pException) {
+ this.mScreenCaptureCallback.onScreenCaptureFailed(this.mFilePath, pException);
+ }
+
+ // ===========================================================
+ // Methods
+ // ===========================================================
+
+ public void capture(final int pCaptureWidth, final int pCaptureHeight, final String pFilePath, final IScreenCaptureCallback pScreenCaptureCallback) {
+ this.capture(0, 0, pCaptureWidth, pCaptureHeight, pFilePath, pScreenCaptureCallback);
+ }
+
+ public void capture(final int pCaptureX, final int pCaptureY, final int pCaptureWidth, final int pCaptureHeight, final String pFilePath, final IScreenCaptureCallback pScreencaptureCallback) {
+ this.mFilePath = pFilePath;
+ this.mScreenCaptureCallback = pScreencaptureCallback;
+ this.mScreenGrabber.grab(pCaptureX, pCaptureY, pCaptureWidth, pCaptureHeight, this);
+ }
+
+ private static void saveCapture(final Bitmap pBitmap, final String pFilePath) throws FileNotFoundException {
+ FileOutputStream fos = null;
+ try {
+ fos = new FileOutputStream(pFilePath);
+ pBitmap.compress(CompressFormat.PNG, 100, fos);
+
+ } catch (final FileNotFoundException e) {
+ StreamUtils.flushCloseStream(fos);
+ Debug.e("Error saving file to: " + pFilePath, e);
+ throw e;
+ }
+ }
+
+ // ===========================================================
+ // Inner and Anonymous Classes
+ // ===========================================================
+
+ public static interface IScreenCaptureCallback {
+ // ===========================================================
+ // Constants
+ // ===========================================================
+
+ // ===========================================================
+ // Methods
+ // ===========================================================
+
+ public void onScreenCaptured(final String pFilePath);
+ public void onScreenCaptureFailed(final String pFilePath, final Exception pException);
+ }
+}
diff --git a/AndEngine/src/org/anddev/andengine/entity/util/ScreenGrabber.java b/AndEngine/src/org/anddev/andengine/entity/util/ScreenGrabber.java
new file mode 100644
index 0000000..7219944
--- /dev/null
+++ b/AndEngine/src/org/anddev/andengine/entity/util/ScreenGrabber.java
@@ -0,0 +1,132 @@
+package org.anddev.andengine.entity.util;
+
+import java.nio.IntBuffer;
+
+import javax.microedition.khronos.opengles.GL10;
+
+import org.anddev.andengine.engine.camera.Camera;
+import org.anddev.andengine.entity.Entity;
+
+import android.graphics.Bitmap;
+import android.graphics.Bitmap.Config;
+
+/**
+ * @author Nicolas Gramlich
+ * @since 15:27:22 - 10.01.2011
+ */
+public class ScreenGrabber extends Entity {
+ // ===========================================================
+ // Constants
+ // ===========================================================
+
+ // ===========================================================
+ // Fields
+ // ===========================================================
+
+ private int mGrabX;
+ private int mGrabY;
+ private int mGrabWidth;
+ private int mGrabHeight;
+
+ private boolean mScreenGrabPending = false;
+ private IScreenGrabberCallback mScreenGrabCallback;
+
+ // ===========================================================
+ // Constructors
+ // ===========================================================
+
+ // ===========================================================
+ // Getter & Setter
+ // ===========================================================
+
+ // ===========================================================
+ // Methods for/from SuperClass/Interfaces
+ // ===========================================================
+
+ @Override
+ protected void onManagedDraw(final GL10 pGL, final Camera pCamera) {
+ if(this.mScreenGrabPending) {
+ try {
+ final Bitmap screenGrab = ScreenGrabber.grab(this.mGrabX, this.mGrabY, this.mGrabWidth, this.mGrabHeight, pGL);
+
+ this.mScreenGrabCallback.onScreenGrabbed(screenGrab);
+ } catch (final Exception e) {
+ this.mScreenGrabCallback.onScreenGrabFailed(e);
+ }
+
+ this.mScreenGrabPending = false;
+ }
+ }
+
+ @Override
+ protected void onManagedUpdate(final float pSecondsElapsed) {
+ /* Nothing */
+ }
+
+ @Override
+ public void reset() {
+ /* Nothing */
+ }
+
+ // ===========================================================
+ // Methods
+ // ===========================================================
+
+ public void grab(final int pGrabWidth, final int pGrabHeight, final IScreenGrabberCallback pScreenGrabCallback) {
+ this.grab(0, 0, pGrabWidth, pGrabHeight, pScreenGrabCallback);
+ }
+
+ public void grab(final int pGrabX, final int pGrabY, final int pGrabWidth, final int pGrabHeight, final IScreenGrabberCallback pScreenGrabCallback) {
+ this.mGrabX = pGrabX;
+ this.mGrabY = pGrabY;
+ this.mGrabWidth = pGrabWidth;
+ this.mGrabHeight = pGrabHeight;
+ this.mScreenGrabCallback = pScreenGrabCallback;
+
+ this.mScreenGrabPending = true;
+ }
+
+ private static Bitmap grab(final int pGrabX, final int pGrabY, final int pGrabWidth, final int pGrabHeight, final GL10 pGL) {
+ final int[] source = new int[pGrabWidth * (pGrabY + pGrabHeight)];
+ final IntBuffer sourceBuffer = IntBuffer.wrap(source);
+ sourceBuffer.position(0);
+
+ // TODO Check availability of OpenGL and GL10.GL_RGBA combinations that require less conversion operations.
+ // Note: There is (said to be) a bug with glReadPixels when 'y != 0', so we simply read starting from 'y == 0'.
+ pGL.glReadPixels(pGrabX, 0, pGrabWidth, pGrabY + pGrabHeight, GL10.GL_RGBA, GL10.GL_UNSIGNED_BYTE, sourceBuffer);
+
+ final int[] pixels = new int[pGrabWidth * pGrabHeight];
+
+ // Convert from RGBA_8888 (Which is actually ABGR as the whole buffer seems to be inverted) --> ARGB_8888
+ for (int y = 0; y < pGrabHeight; y++) {
+ for (int x = 0; x < pGrabWidth; x++) {
+ final int pixel = source[x + ((pGrabY + y) * pGrabWidth)];
+
+ final int blue = (pixel & 0x00FF0000) >> 16;
+ final int red = (pixel & 0x000000FF) << 16;
+ final int greenAlpha = pixel & 0xFF00FF00;
+
+ pixels[x + ((pGrabHeight - y - 1) * pGrabWidth)] = greenAlpha | red | blue;
+ }
+ }
+
+ return Bitmap.createBitmap(pixels, pGrabWidth, pGrabHeight, Config.ARGB_8888);
+ }
+
+ // ===========================================================
+ // Inner and Anonymous Classes
+ // ===========================================================
+
+ public static interface IScreenGrabberCallback {
+ // ===========================================================
+ // Constants
+ // ===========================================================
+
+ // ===========================================================
+ // Methods
+ // ===========================================================
+
+ public void onScreenGrabbed(final Bitmap pBitmap);
+ public void onScreenGrabFailed(final Exception pException);
+ }
+}
diff --git a/AndEngine/src/org/anddev/andengine/extension/physics/box2d/FixedStepPhysicsWorld.java b/AndEngine/src/org/anddev/andengine/extension/physics/box2d/FixedStepPhysicsWorld.java
new file mode 100644
index 0000000..4d9f59b
--- /dev/null
+++ b/AndEngine/src/org/anddev/andengine/extension/physics/box2d/FixedStepPhysicsWorld.java
@@ -0,0 +1,89 @@
+package org.anddev.andengine.extension.physics.box2d;
+
+import com.badlogic.gdx.math.Vector2;
+import com.badlogic.gdx.physics.box2d.World;
+
+/**
+ * A subclass of {@link PhysicsWorld} that tries to achieve a specific amount of steps per second.
+ * When the time since the last step is bigger long the steplength, additional steps are executed.
+ *
+ * @author Nicolas Gramlich
+ * @since 12:39:42 - 25.07.2010
+ */
+public class FixedStepPhysicsWorld extends PhysicsWorld {
+ // ===========================================================
+ // Constants
+ // ===========================================================
+
+ public static final int STEPSPERSECOND_DEFAULT = 60;
+
+ // ===========================================================
+ // Fields
+ // ===========================================================
+
+ private final float mTimeStep;
+ private final int mMaximumStepsPerUpdate;
+ private float mSecondsElapsedAccumulator;
+
+ // ===========================================================
+ // Constructors
+ // ===========================================================
+
+ public FixedStepPhysicsWorld(final int pStepsPerSecond, final Vector2 pGravity, final boolean pAllowSleep) {
+ this(pStepsPerSecond, Integer.MAX_VALUE, pGravity, pAllowSleep);
+ }
+
+ public FixedStepPhysicsWorld(final int pStepsPerSecond, final int pMaximumStepsPerUpdate, final Vector2 pGravity, final boolean pAllowSleep) {
+ super(pGravity, pAllowSleep);
+ this.mTimeStep = 1.0f / pStepsPerSecond;
+ this.mMaximumStepsPerUpdate = pMaximumStepsPerUpdate;
+ }
+
+ public FixedStepPhysicsWorld(final int pStepsPerSecond, final Vector2 pGravity, final boolean pAllowSleep, final int pVelocityIterations, final int pPositionIterations) {
+ this(pStepsPerSecond, Integer.MAX_VALUE, pGravity, pAllowSleep, pVelocityIterations, pPositionIterations);
+ }
+
+ public FixedStepPhysicsWorld(final int pStepsPerSecond, final int pMaximumStepsPerUpdate, final Vector2 pGravity, final boolean pAllowSleep, final int pVelocityIterations, final int pPositionIterations) {
+ super(pGravity, pAllowSleep, pVelocityIterations, pPositionIterations);
+ this.mTimeStep = 1.0f / pStepsPerSecond;
+ this.mMaximumStepsPerUpdate = pMaximumStepsPerUpdate;
+ }
+
+ // ===========================================================
+ // Getter & Setter
+ // ===========================================================
+
+ // ===========================================================
+ // Methods for/from SuperClass/Interfaces
+ // ===========================================================
+
+ @Override
+ public void onUpdate(final float pSecondsElapsed) {
+ this.mRunnableHandler.onUpdate(pSecondsElapsed);
+ this.mSecondsElapsedAccumulator += pSecondsElapsed;
+
+ final int velocityIterations = this.mVelocityIterations;
+ final int positionIterations = this.mPositionIterations;
+
+ final World world = this.mWorld;
+ final float stepLength = this.mTimeStep;
+
+ int stepsAllowed = this.mMaximumStepsPerUpdate;
+
+ while(this.mSecondsElapsedAccumulator >= stepLength && stepsAllowed > 0) {
+ world.step(stepLength, velocityIterations, positionIterations);
+ this.mSecondsElapsedAccumulator -= stepLength;
+ stepsAllowed--;
+ }
+
+ this.mPhysicsConnectorManager.onUpdate(pSecondsElapsed);
+ }
+
+ // ===========================================================
+ // Methods
+ // ===========================================================
+
+ // ===========================================================
+ // Inner and Anonymous Classes
+ // ===========================================================
+}
diff --git a/AndEngine/src/org/anddev/andengine/extension/physics/box2d/PhysicsConnector.java b/AndEngine/src/org/anddev/andengine/extension/physics/box2d/PhysicsConnector.java
new file mode 100644
index 0000000..06f11ef
--- /dev/null
+++ b/AndEngine/src/org/anddev/andengine/extension/physics/box2d/PhysicsConnector.java
@@ -0,0 +1,123 @@
+package org.anddev.andengine.extension.physics.box2d;
+
+import org.anddev.andengine.engine.handler.IUpdateHandler;
+import org.anddev.andengine.entity.shape.IShape;
+import org.anddev.andengine.extension.physics.box2d.util.constants.PhysicsConstants;
+import org.anddev.andengine.util.MathUtils;
+
+import com.badlogic.gdx.math.Vector2;
+import com.badlogic.gdx.physics.box2d.Body;
+
+/**
+ * @author Nicolas Gramlich
+ * @since 18:51:22 - 05.07.2010
+ */
+public class PhysicsConnector implements IUpdateHandler, PhysicsConstants {
+ // ===========================================================
+ // Constants
+ // ===========================================================
+
+ // ===========================================================
+ // Fields
+ // ===========================================================
+
+ protected final IShape mShape;
+ protected final Body mBody;
+
+ protected final float mShapeHalfBaseWidth;
+ protected final float mShapeHalfBaseHeight;
+
+ protected boolean mUpdatePosition;
+ protected boolean mUpdateRotation;
+ protected final float mPixelToMeterRatio;
+
+ // ===========================================================
+ // Constructors
+ // ===========================================================
+
+ public PhysicsConnector(final IShape pShape, final Body pBody) {
+ this(pShape, pBody, true, true);
+ }
+
+ public PhysicsConnector(final IShape pShape, final Body pBody, final float pPixelToMeterRatio) {
+ this(pShape, pBody, true, true, pPixelToMeterRatio);
+ }
+
+ public PhysicsConnector(final IShape pShape, final Body pBody, final boolean pUdatePosition, final boolean pUpdateRotation) {
+ this(pShape, pBody, pUdatePosition, pUpdateRotation, PIXEL_TO_METER_RATIO_DEFAULT);
+ }
+
+ public PhysicsConnector(final IShape pShape, final Body pBody, final boolean pUdatePosition, final boolean pUpdateRotation, final float pPixelToMeterRatio) {
+ this.mShape = pShape;
+ this.mBody = pBody;
+
+ this.mUpdatePosition = pUdatePosition;
+ this.mUpdateRotation = pUpdateRotation;
+ this.mPixelToMeterRatio = pPixelToMeterRatio;
+
+ this.mShapeHalfBaseWidth = pShape.getBaseWidth() * 0.5f;
+ this.mShapeHalfBaseHeight = pShape.getBaseHeight() * 0.5f;
+ }
+
+ // ===========================================================
+ // Getter & Setter
+ // ===========================================================
+
+ public IShape getShape() {
+ return this.mShape;
+ }
+
+ public Body getBody() {
+ return this.mBody;
+ }
+
+ public boolean isUpdatePosition() {
+ return this.mUpdatePosition;
+ }
+
+ public boolean isUpdateRotation() {
+ return this.mUpdateRotation;
+ }
+
+ public void setUpdatePosition(final boolean pUpdatePosition) {
+ this.mUpdatePosition = pUpdatePosition;
+ }
+
+ public void setUpdateRotation(final boolean pUpdateRotation) {
+ this.mUpdateRotation = pUpdateRotation;
+ }
+
+ // ===========================================================
+ // Methods for/from SuperClass/Interfaces
+ // ===========================================================
+
+ @Override
+ public void onUpdate(final float pSecondsElapsed) {
+ final IShape shape = this.mShape;
+ final Body body = this.mBody;
+
+ if(this.mUpdatePosition) {
+ final Vector2 position = body.getPosition();
+ final float pixelToMeterRatio = this.mPixelToMeterRatio;
+ shape.setPosition(position.x * pixelToMeterRatio - this.mShapeHalfBaseWidth, position.y * pixelToMeterRatio - this.mShapeHalfBaseHeight);
+ }
+
+ if(this.mUpdateRotation) {
+ final float angle = body.getAngle();
+ shape.setRotation(MathUtils.radToDeg(angle));
+ }
+ }
+
+ @Override
+ public void reset() {
+
+ }
+
+ // ===========================================================
+ // Methods
+ // ===========================================================
+
+ // ===========================================================
+ // Inner and Anonymous Classes
+ // ===========================================================
+}
diff --git a/AndEngine/src/org/anddev/andengine/extension/physics/box2d/PhysicsConnectorManager.java b/AndEngine/src/org/anddev/andengine/extension/physics/box2d/PhysicsConnectorManager.java
new file mode 100644
index 0000000..d7a0d1f
--- /dev/null
+++ b/AndEngine/src/org/anddev/andengine/extension/physics/box2d/PhysicsConnectorManager.java
@@ -0,0 +1,86 @@
+package org.anddev.andengine.extension.physics.box2d;
+
+import java.util.ArrayList;
+
+import org.anddev.andengine.engine.handler.IUpdateHandler;
+import org.anddev.andengine.entity.shape.IShape;
+
+import com.badlogic.gdx.physics.box2d.Body;
+
+/**
+ * @author Nicolas Gramlich
+ * @since 15:52:27 - 15.07.2010
+ */
+public class PhysicsConnectorManager extends ArrayList