/* orxonox - the future of 3D-vertical-scrollers Copyright (C) 2004 orx This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. ### File Specific: main-programmer: Christian Meyer co-programmer: Benjamin Grauer */ #define DEBUG_SPECIAL_MODULE DEBUG_MODULE_WORLD_ENTITY #include "camera.h" #include "key_mapper.h" #include "glincl.h" #include "util/loading/load_param.h" #include "world_entity.h" #include "vector.h" #include "targets.h" #include "track/track.h" #include "script_class.h" ObjectListDefinition(Camera); CREATE_SCRIPTABLE_CLASS(Camera, addMethod("setAbsCoor", Executor3(&PNode::setAbsCoor)) ->addMethod("getAbsCoorX", Executor0ret(&PNode::getAbsCoorX)) ->addMethod("getAbsCoorY", Executor0ret(&PNode::getAbsCoorY)) ->addMethod("getAbsCoorZ", Executor0ret(&PNode::getAbsCoorZ)) ); /** * creates a Camera */ Camera::Camera() { this->registerObject(this, Camera::_objectList); this->init(); } Camera::Camera(const TiXmlElement* root) { this->registerObject(this, Camera::_objectList); if( root != NULL) this->loadParams(root); this->init(); } /** * default destructor */ Camera::~Camera() {} void Camera::init() { this->toList( OM_COMMON); //this->setName("camera"); this->target = new CameraTarget(); this->target->masta=this; this->subscribeEvent(ES_GAME, KeyMapper::PEV_VIEW0); this->subscribeEvent(ES_GAME, KeyMapper::PEV_VIEW1); this->subscribeEvent(ES_GAME, KeyMapper::PEV_VIEW2); this->subscribeEvent(ES_GAME, KeyMapper::PEV_VIEW3); this->subscribeEvent(ES_GAME, KeyMapper::PEV_VIEW4); this->subscribeEvent(ES_GAME, KeyMapper::PEV_VIEW5); //this->setFovy(90); this->setAspectRatio(1.33f); this->setClipRegion(.1, 10000); this->viewTopFovy = 60; this->viewNormalFovy = 90; this->viewFrontFovy = 120; this->viewRightFovy = 90; this->viewLeftFovy = 90; this->viewTopDistance = 70; this->viewNormalDistance = 10; this->viewFrontDistance = 4; this->viewRightDistance = 10; this->viewLeftDistance = 10; this->setViewMode(Camera::ViewNormal); this->setParentMode(PNODE_ALL); this->eventHandling = true; //add to track if(this->entityTrack) this->setParent(this->entityTrack->getTrackNode()); } /** * focuses the Camera onto a Target * @param target the new PNode the Camera should look at. */ void Camera::lookAt(PNode* target) { this->target->setParentSoft(target,0.2); } /** * @returns The PNode of the Target (from there you can get position and so on */ PNode* Camera::getTargetNode() const { return (PNode*)this->target; } void Camera::setTargetNode(PNode* target) { this->target->setParent(target); } /** * sets a new AspectRatio * @param aspectRatio the new aspect ratio to set (width / height) */ void Camera::setAspectRatio(float aspectRatio) { this->aspectRatio = aspectRatio; } /** * Sets a new clipping region * @param nearClip The near clip plane * @param farClip The far clip plane */ void Camera::setClipRegion(float nearClip, float farClip) { this->nearClip = nearClip; this->farClip = farClip; } /** * sets the new VideoMode and initializes iteration to it. * @param mode the mode to change to. */ void Camera::setViewMode(ViewMode mode) { currentMode = mode; switch (mode) { default: case Camera::ViewNormal: { this->fovy = viewNormalFovy; this->toFovy = viewNormalFovy; //this->fovy = 60; //this->toFovy = 60; this->setRelCoorSoft(-2.0/3.0 * this->viewNormalDistance, 1.0/3.0 * this->viewNormalDistance, 0); this->target->setRelCoorSoft(0,0,0); break; } case Camera::ViewBehind: break; case Camera::ViewFront: { this->fovy = viewFrontFovy; this->toFovy = viewFrontFovy; this->setRelCoorSoft(this->viewFrontDistance, 0, 0, 5); this->target->setRelCoorSoft(Vector(10,0,0), 5); break; } case Camera::ViewLeft: { this->fovy = viewLeftFovy; this->toFovy = viewLeftFovy; this->setRelCoorSoft(0, 1, -viewLeftDistance, .5); this->target->setRelCoorSoft(0,0,0); break; } case Camera::ViewRight: { this->fovy = viewRightFovy; this->toFovy = viewRightFovy; this->setRelCoorSoft(Vector(0, 1, viewRightDistance), 0.5); this->target->setRelCoorSoft(0,0,0); break; } case Camera::ViewTop: { this->fovy= viewTopFovy; this->toFovy = viewTopFovy; this->setRelCoor(Vector(-0.05, this->viewTopDistance , 0)); this->target->setRelCoor(0,0,0); } } } /** * Updates the position of the camera. * @param dt: The time that elapsed. */ void Camera::tick(float dt) { //update frustum plane this->viewVector = (this->target->getAbsCoor() - this->getAbsCoor()).getNormalized(); this->frustumPlane = Plane(this->viewVector, this->getAbsCoor() + this->viewVector * 0.1); this->upVector = this->getAbsDirV(); // iteration for fovy float tmpFovy = (this->toFovy - this->fovy); if (fabsf(tmpFovy) > 0.01) this->fovy += tmpFovy * fabsf(dt); if(this->entityTrack) this->entityTrack->tick(dt); //iterate(float dt, translate, target) target->translate(dt); } void Camera::draw() const { if( this->entityTrack != NULL) this->entityTrack->drawGraph(); } /** * initialize rendering perspective according to this camera * * This is called immediately before the rendering cycle starts, it sets all global * rendering options as well as the GL_PROJECTION matrix according to the camera. */ void Camera::apply () { // switching to Projection Matrix glMatrixMode (GL_PROJECTION); glLoadIdentity (); gluPerspective(this->fovy, this->aspectRatio, this->nearClip, this->farClip); // setting up the perspective // speed-up feature glMatrixMode (GL_MODELVIEW); glLoadIdentity(); } void Camera::project() { Vector cameraPosition = this->getAbsCoor(); Vector targetPosition = this->target->getAbsCoor(); //Setting the Camera Eye, lookAt and up Vectors gluLookAt(cameraPosition.x, cameraPosition.y, cameraPosition.z, targetPosition.x, targetPosition.y, targetPosition.z, this->upVector.x, this->upVector.y, this->upVector.z); } /** * processes an event * @param event: the event to process */ void Camera::process(const Event &event) { if (eventHandling == true) { if( event.type == KeyMapper::PEV_VIEW0) { this->setViewMode(Camera::ViewNormal); } else if( event.type == KeyMapper::PEV_VIEW1) { this->setViewMode(Camera::ViewBehind); } else if( event.type == KeyMapper::PEV_VIEW2) { this->setViewMode(Camera::ViewFront); } else if( event.type == KeyMapper::PEV_VIEW3) { this->setViewMode(Camera::ViewLeft); } else if( event.type == KeyMapper::PEV_VIEW4) { this->setViewMode(Camera::ViewRight); } else if( event.type == KeyMapper::PEV_VIEW5) { this->setViewMode(Camera::ViewTop); } } } void Camera::loadParams(const TiXmlElement* root) { // Do the PNode loading stuff WorldEntity::loadParams(root); LoadParam(root, "viewTopFovy", this, Camera, setViewTopFovy); LoadParam(root, "viewFrontFovy", this, Camera, setViewFrontFovy); LoadParam(root, "viewLeftFovy", this, Camera, setViewLeftFovy); LoadParam(root, "viewRightFovy", this, Camera, setViewRightFovy); LoadParam(root, "viewBehindFovy", this, Camera, setViewBehindFovy); LoadParam(root, "viewNormalFovy", this, Camera, setViewNormalFovy); LoadParam(root, "viewTopDistance", this, Camera, setViewTopDistance); LoadParam(root, "viewFrontDistance", this, Camera, setViewFrontDistance); LoadParam(root, "viewLeftDistance", this, Camera, setViewLeftDistance); LoadParam(root, "viewRightDistance", this, Camera, setViewRightDistance); LoadParam(root, "viewBehindDistance", this, Camera, setViewBehindDistance); LoadParam(root, "viewNormalDistance", this, Camera, setViewNormalDistance); } void Camera::setViewTopFovy(float fovy) { this->viewTopFovy = fovy; } void Camera::setViewFrontFovy(float fovy) { this->viewFrontFovy = fovy; } void Camera::setViewLeftFovy(float fovy) { this->viewLeftFovy = fovy; } void Camera::setViewRightFovy(float fovy) { this->viewRightFovy = fovy; } void Camera::setViewBehindFovy(float fovy) { this->viewBehindFovy = fovy; } void Camera::setViewNormalFovy(float fovy) { this->viewNormalFovy = fovy; } void Camera::setViewTopDistance(float Distance) { this->viewTopDistance = Distance; } void Camera::setViewFrontDistance(float Distance) { this->viewFrontDistance = Distance; } void Camera::setViewLeftDistance(float Distance) { this->viewLeftDistance = Distance; } void Camera::setViewRightDistance(float Distance) { this->viewRightDistance = Distance; } void Camera::setViewBehindDistance(float Distance) { this->viewBehindDistance = Distance; } void Camera::setViewNormalDistance(float Distance) { this->viewNormalDistance = Distance; } void Camera::glLookAt(float eyex, float eyey, float eyez, float centerx, float centery, float centerz, float upx, float upy, float upz) { //Vector* eye=new Vector(eyex, eyey, eyez); Vector* center=new Vector (centerx, centery, centerz); Vector* up=new Vector(upx, upy, upz); center->x-=eyex; center->y-=eyey; center->z-=eyez; center->normalize(); up->normalize(); Vector* s = VectorProd(center, up); Vector* u = VectorProd(s, center); GLfloat Matrix[]={s->x, s->y, s->z, 0, u->x, u->y, u->z, 0, -center->x, -center->y, -center->z, 0, 0, 0, 0, 1}; glMultMatrixf(Matrix); glTranslated(-eyex, -eyey, -eyez); delete center; delete up; delete s; delete u; } Vector* Camera::VectorProd(Vector* v1, Vector* v2) { Vector* temp= new Vector(); temp->x=v1->y * v2->z - v1->z * v2->y; temp->y=v1->z * v2->x - v1->x * v2->z; temp->z=v1->x * v2->y - v1->y * v2->x; return temp; } /////////////////// // CAMERA-TARGET // /////////////////// //REATE_FACTORY(CameraTarget); ObjectListDefinition(CameraTarget); CameraTarget::CameraTarget() { this->registerObject(this, CameraTarget::_objectList); // this->setParentMode(PNODE_MOVEMENT); this->speed=1; translateTo.x=0; translateTo.y=0; translateTo.z=0; rotateBy.x=0; rotateBy.y=0; rotateBy.z=0; target=createStick(); } void CameraTarget::detach() { masta->setParentSoft(target); masta->getTargetNode()->setParentSoft(target); } PNode* CameraTarget::createStick() { return new Targets(); } void CameraTarget::atach(PNode* object) { masta->setParentSoft(object); masta->getTargetNode()->setParentSoft(object); } Vector CameraTarget::iterate(float dt, const Vector* Target, const Vector* cam) { Vector tmpVec; tmpVec= (*Target - *cam); tmpVec.normalize(); return tmpVec; } void CameraTarget::translate(float dt) { if (fabs(translateTo.len() - (target->getAbsCoor()).len()) >= 11 ) { Vector tmpVec= iterate(dt, &translateTo, &(masta->getAbsCoor())); target->shiftCoor(speed*tmpVec.x, speed*tmpVec.y, speed*tmpVec.z); } } Vector * CameraTarget::rotate(Vector* newPos, float speed) { } void CameraTarget::jump(float x, float y, float z) { target->setAbsCoor(x,y,z); } void CameraTarget::trans(float x, float y, float z) { Vector tmpVec=Vector(x,y,z); if( this->getParent()) this->getParent()->setRelCoor(this->getParent()->getRelCoor()); translateNow(&tmpVec); } void CameraTarget::translateNow(Vector* vec) { translateTo=*vec; } void CameraTarget::changeSpeed(float speed) { if (speed!=0) this->speed=speed; return; } bool CameraTarget::isDone() { if (fabs(translateTo.len() - (target->getAbsCoor()).len()) >= 11 ) return 0; else return 1; }