package com.android.droidgraph.scene; import com.android.droidgraph.util.Vec3; /** * Not sure what I'm doing here, camera transformations are like multithreading, that is * NOT my forte xD But I pulled off multithreading, so here's to a little hope this works * as well. * * The camera is a singleton for the LOGIC thread, keeps the position of the OGL camera, * moves it in 3D space as required, and can transform screen to map coordinates. * * It's a singleton because the data here is needed and modified in quite a few different places, * and honestly everyone has a right to know where the hell the camera is. It is NOT so the render * thread can access directly. * * It's in the Logic thread because... * The render thread is sent a message if the camera changes. * The camera should not change much, just when the player cursors go out of it's field of view * or they are close enough to zoom in on them. That's why we can afford to message each position * change. * This also allows us to keep things consistent by doing logic calculations (where and when to move) * in the logic thread, while the render thread only get's told where to draw. * * TODO: Camera is only gonna work correctly for maps where width > height. Fix this by using max/min(w,h) * where appropriate. * * @author Ying * */ public class Camera { /** * Static singleton instance */ private static Camera instance = new Camera(); /** * Position in ogl coords of the camera */ private Vec3 pos; /** * Screen viewport height */ private int screenH; /** * Screen viewport width */ private int screenW; /** * Minimum camera z */ private int minZ; /** * Maximum camera z */ private int maxZ; /** * Minimum ratio for map/screen */ private float minRatio; /** * Maximum ratio for map/screen */ private float maxRatio; /** * Distance the camera must translate through if asked to move. * Used for interpolation */ private double distance; /** * Unitary direction vector for the camera if asked to move. * Used for interpolation */ private Vec3 direction; /** * Camera movement speed. */ private int speed; /** * Speed constant. */ private static final int NORMAL_SPEED = 5; /** * Prevents the instantiation of an object of the Camera class */ protected Camera() { pos = new Vec3(); screenH = 0; screenW = 0; minZ = 0; maxZ = 0; minRatio = 1; maxRatio = 0; direction = new Vec3(); distance = 0; speed = NORMAL_SPEED; } /** * Gets the singleton instance of the camera. Creates the camera if it's * the first time it's called. * * TODO: Check speed hit for having a sync * * @return the instance of the camera */ public static synchronized Camera Get() { return instance; } /** * It updates the camera. If necessary it interplolates it's movement in a straight line * in the this.direction for this.distance. */ public void Update() { if(HasToMove()) { double increment = Math.min(this.distance, this.speed); this.pos.Offset(this.direction.X()*increment, this.direction.Y()*increment, this.direction.Z()*increment); this.distance -= increment; } } /** * Initializes the screen size values * @param w is the width of the screen * @param h is the height of the screen */ public void SetScreenSize(int w, int h) { this.screenH = h; this.screenW = w; // Set initial z then: this.minZ = 2* this.screenH; } /** * Called to request the cursor to move to a specified position, in a straight line, to the max of it's speed. * @param destination is the point we want the Cursor to translate to */ private void MoveTo(Vec3 destination) { if(! this.pos.Equals(destination)) { // move in that direction MoveInDirection(this.pos.GetVectorTo(destination)); } } /** * Tells the cursor to move in a direction. * @param direction Non-unitary vector of the direction we want to move. * The length of the vector is taken to be the length of the path we want * to move along. */ private void MoveInDirection(Vec3 direction) { this.distance = direction.Length(); this.direction = direction; this.direction.Normalize(); } /** * Checks if the Cursor has to move * * @return True if it has to move, false if it doesn't. */ private boolean HasToMove() { if(this.direction == null) { return false; } if(this.distance == 0) { return false; } return true; } /** * Gets the screen width * @return screen width */ public int GetScreenWidth() { return this.screenW; } /** * Gets the screen height * @return screen height */ public int GetScreenHeight() { return this.screenH; } /** * Gets the camera x * @return x */ public int X() { return (int) this.pos.X(); } /** * Get the camera y * @return y */ public int Y() { return (int) this.pos.Y(); } /** * Get the camera z * @return z */ public int Z() { return (int) this.pos.Z(); } /** * Gets the camera position vector * @return the pos vector */ public Vec3 Position() {return this.pos; } /** * Gets the minimum z * @return minZ */ public int GetMinZ() { return this.minZ; } // /** // * Gets the maximum z // */ // public int GetMaxZ() { return 2*Preferences.Get().mapWidth; } }