#if !defined(CAMERA_H)
#define CAMERA_H

/****************************************************************************/
/** \class Camera
    \brief 
 Repraesentiert die Camera, bzw. das Auge des Spielers das in der Spitze 
 des Frustums sitzt. Konkret wird die Camera in der Map bewegt. Nach 
 einem 'Move' wird die Transformationsmatrix der Camera bezogen zum zum Ursprung 
 berechnet um anschliessend die Weltobjekte in das Frustum zu transformieren.

 Ausserdem testet die Camera vor jedem Move, ob der Spieler gegen eine Wand 
 gerannt ist:
 
 Bei den Kollsisionsabfragen wird aus dem aktuellen Standpunkt und dem naechsten 
 Standpunkt ein Strahl ermittelt. Schneidet dieser Strahl eine Tile, so hat eine 
 Kollision stattgefunden. Die Kamera darf sich dann NICHT zu diesem neuen Standpunkt 
 bewegen (man koennte dann ja durch Waende gehen) Um eine rel. langsame und weiche 
 Bewegung im Raum zu erreichen, ist die Distanz pro Step recht kurz. Daraus folgt, 
 das die Camera sich auch sehr nah an eine WALL annaehern kann, was aber zu Render-
 bzw. Clippingproblemen fuehrt. Deshalb wird fuer die Collisionsabfrage eine 
 groessere Distanz gefordert. Dazu gibt es hier die m_vecPosColl, m_vecDirColl und 
 m_stepColl. Fuer die Kollision gegen ein PORTAL muss allerdings wieder die normale 
 Schrittweite genommen werden, da sonst ein Portaluebergang zu frueh angezeigt wird, 
 obwohl die Camera sich mit dem naechsten Step noch in der alten Zone befindet. 

 MOVE_FORWARD  MOVE_BACKWARD MOVE_STOP
 MOVE_DOWN     MOVE_UP       MOVE_STOP
 STRAFE_LEFT   STRAFE_RIGHT  STRAFE_STOP
 ROTATE_LEFT   ROTATE_RIGHT  ROTATE_STOP
 
*****************************************************************************/
class Camera  
{
public:
   static Camera* getInstance();

protected:
	Camera();

private:
 static Camera* _instance;

public:
	
	virtual ~Camera();

enum STEP_DIR {STOP,
               STEP_FORWARD, STEP_BACKWARD, 
               STRAFE_LEFT,  STRAFE_RIGHT,
               STEP_LEFT,    STEP_RIGHT, 
               STEP_UP,      STEP_DOWN,
               ROTATE_LEFT,  ROTATE_RIGHT};

private:

 STEP_DIR m_moving;   // FORWARD, BACKWARD, STOP
 STEP_DIR m_lifting;  // UP,   DOWN, STOP
 STEP_DIR m_strafing; // LEFT, RIGHT, STOP
 STEP_DIR m_rotating; // LEFT, RIGHT, STOP


Vec m_vecPos;     // Standpunkt der Kamera
Vec m_vecDir;     // Blickrichtung der Kamera (Richtungsvektor mit einem Betrag = 1)

Vec m_vecPosNext;  // neuer Standpunkt der Kamera
Vec m_vecDirNext;  // neue Blickrichtung der Kamera (Richtungsvektor mit einem Betrag = 1)

Vec m_vecPosColl;  
Vec m_vecDirColl;

float m_stepColl; // Kollisionsdistanz
float m_stepAnim;

float m_step; // Schrittweite
int   m_turn; // Drehwinkel

int   m_zone;
int   m_HOG;  // Hoehe ueber Grund (typ TexturHeight / 2)

int   m_moverCount;
float m_moverDeltaY;    

public:
void action();

void move(STEP_DIR step);
STEP_DIR isMoving();

void lift(STEP_DIR step);
STEP_DIR isLifting();

void strafe(STEP_DIR step);
STEP_DIR isStrafing();

void rotate(STEP_DIR step);
STEP_DIR isRotating();

int getZone();
void setZone(int zone);
void setPos(float x, float y, float z);
void setDir(float x, float y, float z);
Vec& getPos();
Vec& getDir();
void stepForward();
void stepBackward();
void stepStrafeRight();
void stepStrafeLeft();
void stepUp();
void stepDown();
void stepTurnRight();
void stepTurnLeft();
void aimUp();
void aimDown();
void incMove();
bool collision(int typ, int dir);
float getLevel();
void dump();
void load(DataInputStream& dataIn);
void save(DataOutputStream& dataOut);
};
#endif // !defined(CAMERA_H)
