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.RectangularShapeCollisionChecker;
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.primitive.Line;
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;
/**
* (c) 2010 Nicolas Gramlich
* (c) 2011 Zynga Inc.
*
* @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;
protected int mSurfaceX;
protected int mSurfaceY;
protected int mSurfaceWidth;
protected int mSurfaceHeight;
// ===========================================================
// 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 getWidthRaw() {
return this.mMaxX - this.mMinX;
}
public float getHeightRaw() {
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;
}
public int getSurfaceX() {
return this.mSurfaceX;
}
public int getSurfaceY() {
return this.mSurfaceY;
}
public int getSurfaceWidth() {
return this.mSurfaceWidth;
}
public int getSurfaceHeight() {
return this.mSurfaceHeight;
}
public void setSurfaceSize(final int pSurfaceX, final int pSurfaceY, final int pSurfaceWidth, final int pSurfaceHeight) {
this.mSurfaceX = pSurfaceX;
this.mSurfaceY = pSurfaceY;
this.mSurfaceWidth = pSurfaceWidth;
this.mSurfaceHeight = pSurfaceHeight;
}
public boolean isRotated() {
return this.mRotation != 0;
}
// ===========================================================
// Methods for/from SuperClass/Interfaces
// ===========================================================
@Override
public void onUpdate(final float pSecondsElapsed) {
if(this.mHUD != null) {
this.mHUD.onUpdate(pSecondsElapsed);
}
this.updateChaseEntity();
}
@Override
public void reset() {
}
// ===========================================================
// Methods
// ===========================================================
public void onDrawHUD(final GL10 pGL) {
if(this.mHUD != null) {
this.mHUD.onDraw(pGL, this);
}
}
public void updateChaseEntity() {
if(this.mChaseEntity != null) {
final float[] centerCoordinates = this.mChaseEntity.getSceneCenterCoordinates();
this.setCenter(centerCoordinates[VERTEX_INDEX_X], centerCoordinates[VERTEX_INDEX_Y]);
}
}
public boolean isLineVisible(final Line pLine) {
return RectangularShapeCollisionChecker.isVisible(this, pLine);
}
public boolean isRectangularShapeVisible(final RectangularShape pRectangularShape) {
return RectangularShapeCollisionChecker.isVisible(this, pRectangularShape);
}
public void onApplySceneMatrix(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 onApplySceneBackgroundMatrix(final GL10 pGL) {
GLHelper.setProjectionIdentityMatrix(pGL);
final float widthRaw = this.getWidthRaw();
final float heightRaw = this.getHeightRaw();
pGL.glOrthof(0, widthRaw, heightRaw, 0, this.mNearZ, this.mFarZ);
final float rotation = this.mRotation;
if(rotation != 0) {
this.applyRotation(pGL, widthRaw * 0.5f, heightRaw * 0.5f, rotation);
}
}
public void onApplyCameraSceneMatrix(final GL10 pGL) {
GLHelper.setProjectionIdentityMatrix(pGL);
final float widthRaw = this.getWidthRaw();
final float heightRaw = this.getHeightRaw();
pGL.glOrthof(0, widthRaw, heightRaw, 0, this.mNearZ, this.mFarZ);
final float cameraSceneRotation = this.mCameraSceneRotation;
if(cameraSceneRotation != 0) {
this.applyRotation(pGL, widthRaw * 0.5f, heightRaw * 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
// ===========================================================
}