Back to index

supertuxkart  0.5+dfsg1
camera.cpp
Go to the documentation of this file.
00001 //  $Id: camera.cpp 2111 2008-05-31 07:04:30Z cosmosninja $
00002 //
00003 //  SuperTuxKart - a fun racing game with go-kart
00004 //  Copyright (C) 2004-2005 Steve Baker <sjbaker1@airmail.net>
00005 //  Copyright (C) 2006 SuperTuxKart-Team, Steve Baker
00006 //
00007 //  This program is free software; you can redistribute it and/or
00008 //  modify it under the terms of the GNU General Public License
00009 //  as published by the Free Software Foundation; either version 2
00010 //  of the License, or (at your option) any later version.
00011 //
00012 //  This program is distributed in the hope that it will be useful,
00013 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
00014 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015 //  GNU General Public License for more details.
00016 //
00017 //  You should have received a copy of the GNU General Public License
00018 //  along with this program; if not, write to the Free Software
00019 //  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
00020 
00021 #include <plib/ssg.h>
00022 #include "world.hpp"
00023 #include "player_kart.hpp"
00024 #include "track_manager.hpp"
00025 #include "track.hpp"
00026 #include "camera.hpp"
00027 #include "user_config.hpp"
00028 #include "constants.hpp"
00029 
00030 Camera::Camera(int camera_index, const Kart* kart)
00031 {
00032     m_mode              = CM_NORMAL;
00033     m_context           = new ssgContext ;
00034     m_distance          = kart->getKartProperties()->getCameraDistance();
00035     m_kart              = kart;
00036 
00037     btVector3 start_pos = m_kart->getPos();
00038     sgSetVec3(m_current_pos.xyz, start_pos.getX(), start_pos.getY(), start_pos.getZ());
00039     sgSetVec3(m_current_pos.hpr, 0, 0, 0);
00040 
00041     // FIXME: clipping should be configurable for slower machines
00042     const Track* track  = world->getTrack();
00043     if (track->useFog())
00044         m_context -> setNearFar ( 0.05f, track->getFogEnd() ) ;
00045     else
00046         m_context -> setNearFar ( 0.05f, 1000.0f ) ;
00047 
00048     setScreenPosition(camera_index);
00049 }   // Camera
00050 
00051 // ----------------------------------------------------------------------------
00052 void Camera::setScreenPosition(int camera_index)
00053 {
00054     const int num_players = race_manager->getNumPlayers();
00055     assert(camera_index >= 0 && camera_index <= 3);
00056 
00057     if (num_players == 1)
00058     {
00059         m_context -> setFOV ( 75.0f, 0.0f ) ;
00060         m_x = 0.0f; m_y = 0.0f; m_w = 1.0f; m_h = 1.0f ;
00061     }
00062     else if (num_players == 2)
00063     {
00064         m_context -> setFOV ( 85.0f, 85.0f*3.0f/8.0f ) ;
00065         switch ( camera_index )
00066         {
00067         case 0 : m_x = 0.0f; m_y = 0.5f; m_w = 1.0f; m_h = 0.5f; break;
00068         case 1 : m_x = 0.0f; m_y = 0.0f; m_w = 1.0f; m_h = 0.5f; break;
00069         }
00070     }
00071     else if (num_players == 3)
00072     {
00073         m_context -> setFOV ( 50.0f, 0.0f );
00074         switch ( camera_index )
00075         {
00076         case 0 : m_x = 0.0f; m_y = 0.5f; m_w = 0.5f; m_h = 0.5f; break;
00077         case 1 : m_x = 0.5f; m_y = 0.5f; m_w = 0.5f; m_h = 0.5f; break;
00078         case 2 : m_x = 0.0f; m_y = 0.0f; m_w = 1.0f; m_h = 0.5f;
00079                  m_context -> setFOV ( 85.0f, 85.0f*3.0f/8.0f ); break;
00080         }
00081     }
00082     else if (num_players == 4)
00083     {
00084         m_context -> setFOV ( 50.0f, 0.0f );
00085         switch ( camera_index )
00086         {
00087         case 0 : m_x = 0.0f; m_y = 0.5f; m_w = 0.5f; m_h = 0.5f; break;
00088         case 1 : m_x = 0.5f; m_y = 0.5f; m_w = 0.5f; m_h = 0.5f; break;
00089         case 2 : m_x = 0.0f; m_y = 0.0f; m_w = 0.5f; m_h = 0.5f; break;
00090         case 3 : m_x = 0.5f; m_y = 0.0f; m_w = 0.5f; m_h = 0.5f; break;
00091         }
00092     }
00093     m_last_pitch = 0.0f;
00094 }  // setScreenPosition
00095 
00096 //-----------------------------------------------------------------------------
00097 void Camera::setMode(Mode mode)
00098 {
00099     m_mode       = mode;
00100     m_last_pitch = 0.0f;
00101     if(m_mode==CM_CLOSEUP)
00102         m_distance = 2.5f;
00103     else
00104         m_distance = m_kart->getKartProperties()->getCameraDistance();
00105 }   // setMode
00106 
00107 //-----------------------------------------------------------------------------
00111 void Camera::reset()
00112 {
00113     m_last_pitch = 0.0f;
00114 }   // reset
00115 
00116 //-----------------------------------------------------------------------------
00117 void Camera::update (float dt)
00118 {
00119     sgCoord kartcoord;
00120     const Kart *kart;
00121     
00122     // First define the position of the kart
00123     if(m_mode==CM_LEADER_MODE)
00124     {
00125         kart=world->getKart(0);
00126         sgCopyCoord(&kartcoord, kart->getCoord());
00127     }
00128     else
00129     {
00130         kart = m_kart;
00131         sgCopyCoord(&kartcoord, kart->getCoord());
00132 
00133         // Use the terrain pitch to avoid the camera following a wheelie the kart is doing
00134         kartcoord.hpr[1]=RAD_TO_DEGREE(m_kart->getTerrainPitch(DEGREE_TO_RAD(kartcoord.hpr[0])) );
00135         kartcoord.hpr[2] = 0;
00136         // Only adjust the pitch if it's not the first frame (which is indicated by having
00137         // dt=0). Otherwise the camera will change pitch during ready-set-go.
00138         if(dt>0)
00139         {
00140             // If the terrain pitch is 'significantly' different from the camera angle,
00141             // start adjusting the camera. This helps with steep declines, where
00142             // otherwise the track is not visible anymore.
00143             if(fabsf(kartcoord.hpr[1]-m_last_pitch)>1.0f) {
00144                 kartcoord.hpr[1] = m_last_pitch + (kartcoord.hpr[1]-m_last_pitch)*2.0f*dt;
00145             }
00146             else
00147             {
00148                 kartcoord.hpr[1]=m_last_pitch;
00149             }
00150         }   //  dt>0.0
00151         m_last_pitch = kartcoord.hpr[1];
00152     }   // m_mode!=CM_LEADER_MODE
00153     if(m_mode==CM_SIMPLE_REPLAY) kartcoord.hpr[0] = 0;
00154 
00155     // Set the camera position relative to the kart
00156     // --------------------------------------------
00157     sgMat4 cam_pos;
00158 
00159     // The reverse mode and the cam used in follow the leader mode (when a
00160     // kart has been eliminated) are facing backwards:
00161     bool reverse= m_mode==CM_REVERSE || m_mode==CM_LEADER_MODE;
00162     sgMakeTransMat4(cam_pos, 0.f, -m_distance, reverse ? 0.75f : 1.5f);
00163     
00164     // Set the camera rotation
00165     // -----------------------
00166     sgMat4 cam_rot;
00167     sgMakeRotMat4(cam_rot, reverse            ? 180.0f : 0.0f,
00168                            m_mode==CM_CLOSEUP ? -15.0f : -5.0f,
00169                            0);
00170     
00171     // Matrix that transforms stuff to kart-space
00172     sgMat4 tokart;
00173     sgMakeCoordMat4 (tokart, &kartcoord);
00174 
00175     sgMat4 relative;
00176     sgMultMat4(relative, cam_pos, cam_rot);
00177     sgMat4 result;
00178     sgMultMat4(result, tokart, relative);
00179 
00180     sgSetCoord(&m_current_pos, result);
00181 
00182     m_context -> setCamera (&m_current_pos) ;
00183 }   // update
00184 
00185 //-----------------------------------------------------------------------------
00186 void Camera::apply ()
00187 {
00188     int width  = user_config->m_width ;
00189     int height = user_config->m_height;
00190 
00191     glViewport ( (int)((float)width  * m_x),
00192                  (int)((float)height * m_y),
00193                  (int)((float)width  * m_w),
00194                  (int)((float)height * m_h) ) ;
00195 
00196     m_context -> makeCurrent () ;
00197 }   // apply
00198