src/engine/eCamera.cpp

Go to the documentation of this file.
00001 /*
00002 
00003 *************************************************************************
00004 
00005 ArmageTron -- Just another Tron Lightcycle Game in 3D.
00006 Copyright (C) 2000  Manuel Moos (manuel@moosnet.de)
00007 
00008 **************************************************************************
00009 
00010 This program is free software; you can redistribute it and/or
00011 modify it under the terms of the GNU General Public License
00012 as published by the Free Software Foundation; either version 2
00013 of the License, or (at your option) any later version.
00014 
00015 This program is distributed in the hope that it will be useful,
00016 but WITHOUT ANY WARRANTY; without even the implied warranty of
00017 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018 GNU General Public License for more details.
00019 
00020 You should have received a copy of the GNU Geeneral Public License
00021 along with this program; if not, write to the Free Software
00022 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
00023 
00024 ***************************************************************************
00025 
00026 */
00027 
00028 // CHECK: consistent with project's logging policy?
00029 // define iff camera should log its state at every timestep
00030 // #define CAMERA_LOGGING
00031 
00032 #include "rSDL.h"
00033 
00034 #ifdef CAMERA_LOGGING
00035 #include <iostream>
00036 #endif
00037 
00038 #include "eSensor.h"
00039 #include "eCamera.h"
00040 #include "rScreen.h"
00041 #include "eGameObject.h"
00042 #include "uInputQueue.h"
00043 //#include "eTess.h"
00044 #include "eTimer.h"
00045 #include "tConfiguration.h"
00046 #include "rSysdep.h"
00047 #include "tConsole.h"
00048 #include "ePlayer.h"
00049 #include "eAdvWall.h"
00050 #include "nConfig.h"
00051 #include "eFloor.h"
00052 #include "eGrid.h"
00053 #include "eDebugLine.h"
00054 #include "tMath.h"
00055 #include "eNetGameObject.h"
00056 #include "nObserver.h"
00057 
00058 #include "eSoundMixer.h"
00059 #include "rViewport.h"
00060 
00061 // camera visibility settings
00062 static REAL se_hitCacheSpeed = 1; // the speed the hit cache for external visibility targets recovers from hits
00063 
00064 static REAL se_visibilityWallDistance = .5f; // the distance the visibility targets keep from walls
00065 
00066 static REAL se_visibilitySpeed = 40; // speed with wich the visibility targets is brought into view
00067 static REAL se_visibilityExtension = 1; // distance (measured in seconds, gets multiplied by speed) of the visibility targets from the watched object
00068 static REAL se_visibilitySidewaysSkew = .5; // extra forward component of the sideways visibility targets
00069 static bool se_visibilityLowerWall = true; // flag indicating whether walls should be lowerd when they block the view
00070 static bool se_visibilityLowerWallSmart = false; // same specially for the smart camera
00071 
00072 static tSettingItem<REAL> se_viscs("CAMERA_VISIBILITY_RECOVERY_SPEED", se_hitCacheSpeed );
00073 static tSettingItem<REAL> se_viswd("CAMERA_VISIBILITY_WALL_DISTANCE", se_visibilityWallDistance );
00074 static tSettingItem<REAL> se_viss("CAMERA_VISIBILITY_CLIP_SPEED", se_visibilitySpeed );
00075 static tSettingItem<REAL> se_vise("CAMERA_VISIBILITY_EXTENSION", se_visibilityExtension );
00076 static tSettingItem<REAL> se_vissk("CAMERA_VISIBILITY_SIDESKEW", se_visibilitySidewaysSkew );
00077 static tSettingItem<bool> se_vislw("CAMERA_VISIBILITY_LOWER_WALL", se_visibilityLowerWall );
00078 static tSettingItem<bool> se_vislws("CAMERA_VISIBILITY_LOWER_WALL_SMART", se_visibilityLowerWallSmart );
00079 
00080 //static bool se_customGlance = true; // use the custom camera settings for glancing in the smart camera
00081 //static tSettingItem<bool> se_cg("CAMERA_SMART_GLANCE_CUSTOM", se_customGlance );
00082 
00083 // allow cameras [player independent; gets transferred over the network]
00084 static bool forbid_camera[CAMERA_COUNT];
00085 
00086 class eInitForbidCamera
00087 {
00088 public:
00089     eInitForbidCamera()
00090     {
00091         // allow all cameras
00092         for ( int i = CAMERA_COUNT-1; i>=0; --i )
00093         {
00094             forbid_camera[i] = false;
00095         }
00096 
00097         // except the server custom camera
00098         forbid_camera[ CAMERA_SERVER_CUSTOM ] = true;
00099     }
00100 };
00101 static eInitForbidCamera se_initForbid;
00102 
00103 // forbid smart camera
00104 static nSettingItem<bool> a_s
00105 ("CAMERA_FORBID_SMART",
00106  forbid_camera[CAMERA_SMART]);
00107 
00108 // forbid internal camera
00109 static nSettingItem<bool> a_i
00110 ("CAMERA_FORBID_IN",
00111  forbid_camera[CAMERA_IN]);
00112 
00113 // forbid custom camera
00114 static nSettingItem<bool> a_c
00115 ("CAMERA_FORBID_CUSTOM",
00116  forbid_camera[CAMERA_CUSTOM]);
00117 
00118 // forbid custom camera
00119 static nSettingItem<bool> a_sc
00120 ("CAMERA_FORBID_SERVER_CUSTOM",
00121  forbid_camera[CAMERA_SERVER_CUSTOM]);
00122 
00123 // forbid free camera
00124 static nSettingItem<bool> a_f
00125 ("CAMERA_FORBID_FREE",
00126  forbid_camera[CAMERA_FREE]);
00127 
00128 // forbid fixed ext. camera
00129 static nSettingItem<bool> a_fe
00130 ("CAMERA_FORBID_FOLLOW",
00131  forbid_camera[CAMERA_FOLLOW]);
00132 
00133 // forbid meriton's camerea
00134 static nSettingItem<bool> a_ffe
00135 ("CAMERA_FORBID_MER",
00136  forbid_camera[CAMERA_MER]);
00137 
00138 #ifndef DEDICATED
00139 #include "rGL.h"
00140 #endif
00141 
00142 static REAL lastTime=0;
00143 static const REAL rimDistance = 0.01f;
00144 static const REAL rimDistanceHeight = 0.1f;
00145 
00146 REAL se_cameraRise=0;
00147 REAL se_cameraZ=10;
00148 
00149 // List<eCamera> se_cameras;
00150 
00151 uActionCamera eCamera::se_moveBack("MOVE_BACK",
00152                                    -10,
00153                                    uAction::uINPUT_ANALOG);
00154 
00155 uActionCamera eCamera::se_moveForward("MOVE_FORWARD",
00156                                       -20,
00157                                       uAction::uINPUT_ANALOG);
00158 
00159 uActionCamera eCamera::se_moveDown("MOVE_DOWN",
00160                                    -30,
00161                                    uAction::uINPUT_ANALOG);
00162 
00163 uActionCamera eCamera::se_moveUp("MOVE_UP",
00164                                  -40,
00165                                  uAction::uINPUT_ANALOG);
00166 
00167 
00168 uActionCamera eCamera::se_moveRight("MOVE_RIGHT",
00169                                     -50,
00170                                     uAction::uINPUT_ANALOG);
00171 
00172 uActionCamera eCamera::se_moveLeft("MOVE_LEFT",
00173                                    -60,
00174                                    uAction::uINPUT_ANALOG);
00175 
00176 uActionCamera eCamera::se_zoomOut("ZOOM_OUT",
00177                                   -70,
00178                                   uAction::uINPUT_ANALOG);
00179 
00180 uActionCamera eCamera::se_zoomIn("ZOOM_IN",
00181                                  -80,
00182                                  uAction::uINPUT_ANALOG);
00183 
00184 
00185 class uGlanceAction : public uActionCamera {
00186 public:
00187     eCoord const relDir;
00188     uGlanceAction(char const * name, int priority, eCoord const relativeDirection)
00189             : uActionCamera(name, priority), relDir(relativeDirection) {}
00190 };
00191 
00192 uGlanceAction eCamera::se_glance[eCamera::se_glances] = {
00193             uGlanceAction("GLANCE_FORWARD",-85,eCoord(1,0)), // CHECK: Want to change priority? I have no clue what it does, so I leave that to you ...
00194             uGlanceAction("GLANCE_BACK",-90,eCoord(-1,0)),
00195             uGlanceAction("GLANCE_RIGHT",-100,eCoord(0,-1)),
00196             uGlanceAction("GLANCE_LEFT",-110,eCoord(0,1))
00197         };
00198 
00199 
00200 
00201 uActionCamera eCamera::se_lookDown("BANK_DOWN",
00202                                    -120,
00203                                    uAction::uINPUT_ANALOG);
00204 
00205 uActionCamera eCamera::se_lookUp("BANK_UP",
00206                                  -130,
00207                                  uAction::uINPUT_ANALOG);
00208 
00209 uActionCamera eCamera::se_lookRight("LOOK_RIGHT",
00210                                     -140,
00211                                     uAction::uINPUT_ANALOG);
00212 
00213 uActionCamera eCamera::se_lookLeft("LOOK_LEFT",
00214                                    -150,
00215                                    uAction::uINPUT_ANALOG);
00216 
00217 
00218 uActionCamera eCamera::se_switchView("SWITCH_VIEW", -160);
00219 
00220 
00221 static REAL s_startFollowX = -30, s_startFollowY = -30, s_startFollowZ = 80;
00222 static REAL s_startSmartX = 10, s_startSmartY = 30, s_startSmartZ = 2;
00223 static REAL s_startFreeX =  10, s_startFreeY = -70, s_startFreeZ = 100;
00224 
00225 static tSettingItem<REAL> s_foX("CAMERA_FOLLOW_START_X", s_startFollowX);
00226 static tSettingItem<REAL> s_smX("CAMERA_SMART_START_X", s_startSmartX);
00227 static tSettingItem<REAL> s_frX("CAMERA_FREE_START_X", s_startFreeX);
00228 
00229 static tSettingItem<REAL> s_foY("CAMERA_FOLLOW_START_Y", s_startFollowY);
00230 static tSettingItem<REAL> s_smY("CAMERA_SMART_START_Y", s_startSmartY);
00231 static tSettingItem<REAL> s_frY("CAMERA_FREE_START_Y", s_startFreeY);
00232 
00233 static tSettingItem<REAL> s_foZ("CAMERA_FOLLOW_START_Z", s_startFollowZ);
00234 static tSettingItem<REAL> s_smZ("CAMERA_SMART_START_Z", s_startSmartZ);
00235 static tSettingItem<REAL> s_frZ("CAMERA_FREE_START_Z", s_startFreeZ);
00236 
00237 // custom camera displacement
00238 static REAL s_customBack = 30, s_customRise = 20, s_customBackSpeed = 0, s_customRiseSpeed = 0 , s_customPitch = -.7, s_customZoom = 0.5, s_customTurnSpeed=40, s_customTurnSpeed180 = 2;
00239 static REAL s_serverCustomBack = 30, s_serverCustomRise = 20, s_serverCustomBackSpeed = 0, s_serverCustomRiseSpeed = 0, s_serverCustomPitch = -.7, s_serverCustomTurnSpeed=-1, s_serverCustomTurnSpeed180 = 2;
00240 
00241 static tSettingItem<REAL> s_iBack("CAMERA_CUSTOM_BACK", s_customBack);
00242 static tSettingItem<REAL> s_iRise("CAMERA_CUSTOM_RISE", s_customRise);
00243 static tSettingItem<REAL> s_iBackSpeed("CAMERA_CUSTOM_BACK_FROMSPEED", s_customBackSpeed);
00244 static tSettingItem<REAL> s_iRiseSpeed("CAMERA_CUSTOM_RISE_FROMSPEED", s_customRiseSpeed);
00245 static tSettingItem<REAL> s_iPitch("CAMERA_CUSTOM_PITCH", s_customPitch);
00246 static tSettingItem<REAL> s_iZoom("CAMERA_CUSTOM_ZOOM", s_customZoom);
00247 static tSettingItem<REAL> s_iCustomTurnSpeed("CAMERA_CUSTOM_TURN_SPEED", s_customTurnSpeed);
00248 static tSettingItem<REAL> s_iCustomTurnSpeed180("CAMERA_CUSTOM_TURN_SPEED_180", s_customTurnSpeed180);
00249 
00250 static nSettingItem<REAL> s_iSBack("CAMERA_SERVER_CUSTOM_BACK", s_serverCustomBack);
00251 static nSettingItem<REAL> s_iSRise("CAMERA_SERVER_CUSTOM_RISE", s_serverCustomRise);
00252 static nSettingItem<REAL> s_iSBackSpeed("CAMERA_SERVER_CUSTOM_BACK_FROMSPEED", s_serverCustomBackSpeed);
00253 static nSettingItem<REAL> s_iSRiseSpeed("CAMERA_SERVER_CUSTOM_RISE_FROMSPEED", s_serverCustomRiseSpeed);
00254 static nSettingItem<REAL> s_iSPitch("CAMERA_SERVER_CUSTOM_PITCH", s_serverCustomPitch);
00255 static nSettingItem<REAL> s_iSCustomTurnSpeed("CAMERA_SERVER_CUSTOM_TURN_SPEED", s_serverCustomTurnSpeed);
00256 static nSettingItem<REAL> s_iSCustomTurnSpeed180("CAMERA_SERVER_CUSTOM_TURN_SPEED_180", s_serverCustomTurnSpeed180);
00257 
00258 // mercam configuration
00259 static REAL mercamxydist = 20;
00260 static REAL mercamz = 16;
00261 
00262 static tSettingItem<REAL> s_mercamxydist("CAMERA_MER_XYDIST",mercamxydist);
00263 static tSettingItem<REAL> s_mercamz("CAMERA_MER_Z",mercamz);
00264 
00265 // glancing configuration
00266 static int glanceMode = 2;
00267 static REAL glanceAngularVelocity = 4*M_PI; 
00268 static REAL glanceAngularVelocityBonus = 12.; 
00269 static REAL smartcamGlancingBack = 20;
00270 static REAL smartcamGlancingHeight = 10;
00271 
00272 static tSettingItem<int>  s_glanceMode("CAMERA_GLANCE_MODE",glanceMode);
00273 static tSettingItem<REAL> s_glanceRotSpeed("CAMERA_GLANCE_ANGULAR_VELOCITY",glanceAngularVelocity);
00274 static tSettingItem<REAL> s_glanceRotSpeedBonus("CAMERA_GLANCE_ANGULAR_VELOCITY_BONUS",glanceAngularVelocityBonus);
00275 static tSettingItem<REAL> s_smartcamGlanceBack("CAMERA_SMART_GLANCING_BACK",smartcamGlancingBack);
00276 static tSettingItem<REAL> s_smartcamGlanceHeight("CAMERA_SMART_GLANCING_HEIGHT",smartcamGlancingHeight);
00277 
00278 // turn speed of internal camera
00279 static REAL s_inTurnSpeed=40;
00280 static tSettingItem<REAL> s_iInTurnSpeed("CAMERA_IN_TURN_SPEED", s_inTurnSpeed);
00281 
00282 bool eCamera::InterestingToWatch(eGameObject const *g){
00283     return g &&
00284            (g->Alive() ||
00285             (lastTime - g->deathTime<1));
00286 }
00287 
00288 // CHECK: Move to "tmath.h"?
00293 inline REAL robust_acos(REAL arg) {
00294     if (arg>=1)
00295         return 0;
00296     else if (arg<=-1)
00297         return M_PI;
00298     else
00299         return acos(arg);
00300 }
00301 
00302 
00303 eCoord eCamera::nextDirIfGlancing(eCoord const & dir, eCoord const & targetDir, REAL ts) {
00304 
00305     switch (glanceMode) {
00306     case 0: {
00307             // glance keys rotate the camera with constant angular velocity
00308             REAL d = dir*targetDir;
00309             REAL arc = glanceAngularVelocity*ts;
00310             if (fabs(d)<arc && eCoord::F(dir,targetDir)>0) {
00311                 return targetDir;
00312             } else {
00313                 eCoord newdir = dir.Turn(1,(d>0) ? -arc : arc);
00314                 newdir.Normalize();
00315                 return newdir;
00316             }
00317             break;
00318     } case 1: {
00319             // glance keys rotate camera with angular velocity proportional to alpha
00320             // CHECK: You wanted to fix that trigonometry? Good luck :)
00321             REAL arc = robust_acos(eCoord::F(dir,targetDir)) * ts * glanceAngularVelocity / (M_PI_2);
00322             if (dir*targetDir>0)
00323                 arc=-arc;
00324             return dir.Turn(cos(arc),sin(arc));
00325     } case 2: {
00326             // glance keys rotate camera with angular velocity =
00327             // glanceAngularVelocity * ((alpha<PI/2) ? sin(alpha) : glanceAngularVelocityBonus)
00328             REAL arc = glanceAngularVelocity*ts;
00329             eCoord newdir;
00330             if (eCoord::F(dir,targetDir)>0) {
00331                 newdir = dir+targetDir*arc;
00332             } else if (dir*targetDir>0) {
00333                 newdir = dir.Turn(1,-arc*glanceAngularVelocityBonus);
00334             } else {
00335                 newdir = dir.Turn(1,arc*glanceAngularVelocityBonus);
00336             }
00337             newdir.Normalize();
00338             return newdir;
00339     } default:
00340         return targetDir;
00341     }
00342 }
00343 
00344 
00345 // pointer holding the last player watched actively
00346 static nObserverPtr< ePlayerNetID > se_watchedPlayer[ MAX_PLAYERS ];
00347 
00348 // returns the player a camera last watched for modification
00349 static nObserverPtr< ePlayerNetID > & se_GetWatchedPlayer( eCamera * cam )
00350 {
00351     static nObserverPtr< ePlayerNetID > dummy;
00352 
00353     ePlayer const * localPlayer = cam->LocalPlayer();
00354     if ( !localPlayer )
00355         return dummy;
00356 
00357     return se_watchedPlayer[ localPlayer->ID() ];
00358 }
00359 
00360 // returns the last watched game object
00361 static eGameObject * se_GetWatchedObject( eCamera * cam )
00362 {
00363     ePlayerNetID const * player = se_GetWatchedPlayer( cam );
00364     if ( player )
00365         return player->Object();
00366 
00367     return NULL;
00368 }
00369 
00370 static void se_SetWatchedObject( eCamera * cam, eGameObject * obj )
00371 {
00372     nObserverPtr< ePlayerNetID > & player = se_GetWatchedPlayer( cam );
00373 
00374     // switch the favorite player to watch if we switch away from him deliberately
00375     if ( !player || ( player->Object() && player->Object()->Alive() ) )
00376     {
00377         // determine the player that controls the object, a bit awkward...
00378         for ( int i = se_PlayerNetIDs.Len()-1; i>=0; --i )
00379         {
00380             ePlayerNetID * p = se_PlayerNetIDs(i);
00381             if ( p->Object() == obj )
00382                 player = p;
00383         }
00384     }
00385 }
00386 
00387 void eCamera::MyInit(){
00388     if (localPlayer){
00389         mode=localPlayer->startCamera; //PENDING:
00390         fov=localPlayer->startFOV;
00391     }
00392 
00393     // find center: the object our player controls
00394     if (bool(netPlayer) && !center)
00395     {
00396         center = netPlayer->Object();
00397     }
00398     else if ( grid->gameObjectsInteresting.Len() > 0 )
00399     {
00400         // or an arbitrary game object
00401         center = grid->gameObjectsInteresting[0];
00402     }
00403 
00404     // switch away from forbidden camera mode
00405     if (forbid_camera[mode] && bool(netPlayer) && netPlayer->Object()==Center())
00406         SwitchView();
00407 
00408     centerPos=eCoord(100,100);
00409     centerSpeedSmooth=0;
00410     if ( Center() )
00411     {
00412         centerPos = Center()->PredictPosition();
00413         centerSpeedSmooth = Center()->Speed();
00414     }
00415 
00416     pos=CenterPos();
00417     dir=CenterDir();
00418     centerPosSmooth=pos;
00419     centerDirLast=centerDirSmooth=dir;
00420     lastPos=pos;
00421     zNear=0.1f;
00422     //  foot=tNEW(eGameObject)(pos,dir,0);
00423     distance=0;
00424     lastrendertime=se_GameTime();
00425     grid->cameras.Add(this,id);
00426     //  se_ResetVisibles(id);
00427     smoothTurning=turning=0;
00428     centerPosLast=centerposLast=CenterPos();
00429     userCameraControl=0;
00430     centerIncam=1;
00431     smartcamSkewSmooth=0;
00432     smartcamIncamSmooth=1;
00433     smartcamFrontSmooth=0;
00434 
00435     for(int i = hitCacheSize-1; i>=0; --i)
00436         hitCache_[i] = 1;
00437 
00438     switch (mode){
00439     case CAMERA_CUSTOM:
00440     case CAMERA_SERVER_CUSTOM:
00441     case CAMERA_IN:
00442         z=10;
00443         rise=0;
00444         break;
00445     case CAMERA_FOLLOW:
00446         pos=pos+dir.Turn(eCoord(s_startFollowX,s_startFollowY)) ;
00447         z=s_startFollowZ;
00448         break;
00449     case CAMERA_SMART:
00450         pos=pos+dir.Turn(eCoord(s_startSmartX,s_startSmartY)) ;
00451         z=s_startSmartZ;
00452         break;
00453     case CAMERA_FREE:
00454         pos=pos+dir.Turn(eCoord(s_startFreeX,s_startFreeY)) ;
00455         z=s_startFreeZ;
00456         break;
00457     case CAMERA_MER:
00458         pos=pos-dir*mercamxydist;
00459         z=CenterZ();
00460         rise=0;
00461         break;
00462     case CAMERA_SMART_IN:
00463     case CAMERA_COUNT:
00464         break;
00465     }
00466 
00467     if ( mode != CAMERA_IN && mode != CAMERA_CUSTOM && mode != CAMERA_SERVER_CUSTOM ){
00468         dir=CenterPos()-pos;
00469         REAL dist=REAL(sqrt(dir.NormSquared()));
00470         if (dist<.001) dist=1;
00471         dir=dir*(1/dist);
00472         rise=(CenterZ()-z)/dist;
00473     }
00474 
00475     activeGlanceRequest=NULL;
00476 
00477     lastSwitch=-100;
00478 }
00479 
00480 const ePlayerNetID* eCamera::Player() const { return netPlayer; }
00481 const ePlayer* eCamera::LocalPlayer() const { return localPlayer; }
00482 
00483 eCamera::eCamera(eGrid *g, rViewport *view,ePlayerNetID *p,
00484                  ePlayer *lp,eCamMode m)
00485         :id(-1),grid(g),netPlayer(p),localPlayer(lp),
00486         // centerID(0),
00487         mode(m),pos(0,0),dir(1,0),top(0,0),
00488 vp(view){
00489     /*
00490       if (p->pID>=0)
00491       localPlayer=playerConfig[p->pID];
00492     */
00493     MyInit();
00494 }
00495 
00496 
00497 
00498 
00499 eCamera::~eCamera(){
00500     //  int ID=id;
00501     //  tDESTROY(foot);
00502     //  se_cameras.Remove(this,id);
00503     //  se_ResetVisibles(se_cameras.Len());
00504     //  if (ID!=se_cameras.Len()) se_ResetVisibles(ID);
00505 
00506     grid->cameras.Remove(this, id);
00507 
00508     tCHECK_DEST;
00509 }
00510 
00511 
00512 //static eGameObject *dummy=NULL;
00513 
00514 eGameObject * eCamera::Center() const{
00515     return center;
00516 }
00517 
00518 void eCamera::SwitchView(){
00519     zNear = 0.01f;
00520 
00521     int count=CAMERA_COUNT * 2;
00522 
00523     userCameraControl = 0;
00524 
00525     //  eCamMode pre=mode;
00526 
00527     bool imp=true,global_imp=true,both_imp=true;
00528     for (int i=CAMERA_COUNT-1;i>=0;i--){
00529         if (!localPlayer || localPlayer->allowCam[i])
00530             imp=false;
00531         if (!forbid_camera[i] || !netPlayer || netPlayer->Object()!=Center())
00532             global_imp=false;
00533         if ((!forbid_camera[i] || !netPlayer || netPlayer->Object()!=Center())
00534                 && (!localPlayer || localPlayer->allowCam[i]))
00535             both_imp=false;
00536     }
00537 
00538     if (imp) con << "impossible to meet your needs.\n";
00539     if (global_imp) con << "impossible to meet global needs.\n";
00540     if (both_imp) con << "impossible to meet both needs.\n";
00541 
00542     if (both_imp && !global_imp)
00543         imp=true;
00544 
00545     do{
00546         // rotate the mode
00547         int m = mode;
00548         m--;
00549         if ( m<0 )
00550             m = CAMERA_SERVER_CUSTOM;
00551         mode = static_cast< eCamMode >( m );
00552 
00553         count--;
00554     }
00555     while ((!imp && count > CAMERA_COUNT && localPlayer && !localPlayer->allowCam[mode])
00556             || (count >0 && !global_imp && forbid_camera[mode] &&
00557                 (bool( netPlayer ) && netPlayer->Object()==Center())));
00558 
00559     if ( mode == CAMERA_IN || mode == CAMERA_CUSTOM || mode == CAMERA_SERVER_CUSTOM )
00560         rise=0;
00561 
00562     if(mode==CAMERA_SMART){
00563         smartcamIncamSmooth=1;
00564         z=z+1;
00565         pos=pos+dir.Turn(-1,.1);
00566     }
00567 }
00568 
00569 bool eCamera::Act(uActionCamera *Act,REAL x){
00570     eCoord objdir=CenterCamDir();
00571 
00572     int turn=0;
00573     if (eGameObject::se_turnLeft==*reinterpret_cast<uActionPlayer *>(Act)){
00574         turn=-1;
00575     }
00576     if (eGameObject::se_turnRight==*reinterpret_cast<uActionPlayer *>(Act)){
00577         turn=1;
00578     }
00579 
00580     if (turn){
00581         eGameObject *cent=NULL;
00582         if (se_GameTime() <= 0 )
00583             turning+=.5;
00584         if (netPlayer) cent=netPlayer->Object();
00585         if (!InterestingToWatch(cent) && x>0)
00586         {
00587             SwitchCenter(turn);
00588             se_SetWatchedObject( this, center );
00589         }
00590     }
00591 
00592     REAL ll=0,lu=0,ml=0,mf=0,mu=0,zi=1;
00593 
00594     if (se_lookLeft==*Act && x>0)
00595         ll=x;
00596     else if (se_lookRight==*Act && x>0)
00597         ll=-x;
00598     else if (se_lookUp==*Act && x>0)
00599         lu=x;
00600     else if (se_lookDown==*Act && x>0)
00601         lu=-x;
00602     else if (se_zoomIn==*Act && x>0)
00603         zi*=1+zi*.1;
00604     else if (se_zoomOut==*Act && x>0)
00605         zi/=1+zi*.1;
00606 
00607     else if (se_moveLeft==*Act && x>0)
00608         ml=x;
00609     else if (se_moveRight==*Act && x>0)
00610         ml=-x;
00611     else if (se_moveForward==*Act && x>0)
00612         mf=x;
00613     else if (se_moveBack==*Act && x>0)
00614         mf=-x;
00615     else if (se_moveUp==*Act && x>0)
00616         mu=x;
00617     else if (se_moveDown==*Act && x>0)
00618         mu=-x;
00619     else if (se_switchView==*Act && x>0)
00620         SwitchView();
00621     else if (se_glance<=Act && Act < se_glance+se_glances) {
00622         uGlanceAction* ga = static_cast<uGlanceAction*>(Act);
00623         eGlanceRequest* gr = &glanceRequests[ga-se_glance];
00624         if (x>0) {
00625             eCoord baseDir = grid->GetDirection(grid->DirectionWinding(dir)); // CHECK: proper focal point?
00626             gr->dir = baseDir.Turn(ga->relDir);
00627             gr->Insert(activeGlanceRequest);
00628         } else {
00629             gr->Remove();
00630         }
00631     } else
00632         return false;
00633 
00634 
00635     userCameraControl+=sqrt(ll*ll+lu*lu+(1-zi)*(1-zi)+ml*ml+mf*mf+mu*mu)/20;
00636 
00637     switch(mode){
00638     case CAMERA_IN:
00639     case CAMERA_SMART_IN:
00640         lu+=mu*2;
00641         ll+=ml;
00642         mu=ml=0;
00643         break;
00644     case CAMERA_CUSTOM:
00645     case CAMERA_SERVER_CUSTOM:
00646     case CAMERA_FREE:
00647         break;
00648     case CAMERA_FOLLOW:
00649     case CAMERA_SMART:
00650     case CAMERA_MER:
00651         mu-=lu;
00652         ml-=ll;
00653         lu=ll=0;
00654         break;
00655     case CAMERA_COUNT:
00656         break;
00657     }
00658 
00659     // normal actions with the given data
00660     dir=dir+dir.Turn(eCoord(0,ll*.2));
00661     rise+=lu/80;
00662     z+=mu*.25;
00663     pos=pos+dir*mf*.25+dir.Turn(eCoord(0,ml*.25));
00664 
00665     fov/=zi;
00666     if (fov>120) fov=120;
00667 
00668     if (fov<30) fov=30;
00669 
00670 
00671     switch(mode){
00672     case CAMERA_IN:
00673     case CAMERA_SMART_IN:
00674         {
00675             int x=3;
00676             while (eCoord::F(dir,objdir)<-.51 && x>0){
00677                 dir=dir-objdir*(eCoord::F(dir,objdir)+.5);
00678                 dir=dir*(1/sqrt(dir.NormSquared()));
00679                 x--;
00680             }
00681         }
00682         break;
00683     case CAMERA_CUSTOM:
00684     case CAMERA_SERVER_CUSTOM:
00685     case CAMERA_FREE:
00686     case CAMERA_FOLLOW:
00687     case CAMERA_SMART:
00688     case CAMERA_MER:
00689         break;
00690     case CAMERA_COUNT:
00691         break;
00692     }
00693 
00694     Bound(0);
00695 
00696     return true;
00697 }
00698 
00699 extern REAL upper_height,lower_height;
00700 
00701 static bool se_ClampCamera( eCamMode mode )
00702 {
00703     return !(mode == CAMERA_SMART && se_GameTime() > -.5 ? se_visibilityLowerWallSmart : se_visibilityLowerWall);
00704 }
00705 
00707 class eCameraSensor: public eSensor
00708 {
00709 public:
00711     eCameraSensor(eGameObject *o,eCoord & camera, const eCoord & target )
00712             :eSensor(o,o->Position(),camera-target), moved_(false),
00713             camPos_(camera), target_(target), zLimit_(2), ratio_(0), camera_(0), lowerWall_( true )
00714     {
00715 #ifdef DEBUG_VISIBILITY_TARGETS
00716         eDebugLine::SetColor( 1,1,1 );
00717         eDebugLine::SetTimeout(.005);
00718         eDebugLine::Draw( target, 0, target, 2 );
00719 #endif
00720         Move( target,0,0 );
00721         //clip_ = true;
00722     }
00723 
00725     struct Correction
00726     {
00727         eCoord correctTo;
00728         REAL   distance;
00729 
00731         void Improve( eCoord correctTo, REAL distance )
00732         {
00733             if ( this->distance > distance )
00734             {
00735                 this->distance = distance;
00736                 this->correctTo = correctTo;
00737             }
00738         }
00739     };
00740 
00749     void LookAround( eWall const * w, int direction, Correction & correction, REAL heightLimit, int recursion, int hardRecursion )
00750     {
00751         // abort if recursion is too deep aleready
00752         if ( recursion < 0 || hardRecursion < 0 )
00753             return;
00754 
00755         static int count = 0;
00756         count ++;
00757         if ( count == 35390 )
00758             st_Breakpoint();
00759 
00760         // tell the wall that it is blocking the sight (if requested)
00761         if ( lowerWall_ )
00762         {
00763             w->BlocksCamera( camera_, heightLimit );
00764         }
00765 
00766         // NULL pointer checks
00767         if ( !w || !w->Edge() || !w->Edge()->Other() )
00768             return;
00769 
00770         // project camera position a bit to the other side of the wall:
00771         // get the two endpoints
00772         eHalfEdge const * edge = (direction == 0 ? w->Edge() : w->Edge()->Other());
00773         eCoord const & p1 = *edge->Point();
00774         eCoord const & p2 = *edge->Other()->Point();
00775 
00776         // it is ony valid if the order of points on an imaginary line is
00777         // camPos_ -> p1 -> targtet_
00778         // (otherwise, te wall is not blocking sight at all)
00779         if ( !lowerWall_ && eCoord::F( camPos_ - p1, target_ - p1 ) > 0 )
00780             return;
00781 
00782         // determine normal of target - p1 line
00783         eCoord diff = target_ - p1;
00784         diff.Normalize();
00785         eCoord normal = diff.Turn(0,-1);
00786 
00787         // determine which side the other endpoint of the line lies on
00788         REAL sideOther=eCoord::F(normal,p2-p1);
00789 
00790         // find other walls that end in p1
00791         {
00792             bool wallContinues = false;
00793             eHalfEdge const * run = edge;
00794             do
00795             {
00796                 run = run->Other();
00797                 if (run)
00798                     run = run->Next();
00799 
00800                 if (!run || !run->Other() || run == edge)
00801                     break;
00802 
00803                 if ( run->GetWall() || run->Other()->GetWall() )
00804                 {
00805                     // got one! determine its other entpoint
00806                     eCoord const & p3 = *run->Other()->Point();
00807 
00808                     // determine which side of the ray the other endpoint of the wall lies on
00809                     REAL side3=eCoord::F(normal,p3-p1);
00810 
00811                     // if it lies on the same side as p1, the edgepoint is an outline point
00812                     // and needs to be projected. If not, we need to recurse.
00813                     if ( side3 * sideOther < 0 )
00814                     {
00815                         wallContinues = true;
00816 
00817                         // only on corners the recursion level should be decreased
00818                         int recursion2 = recursion;
00819                         if ( fabs( (p2 - p1)*(p1 - p3) ) >= 10 * EPS * sqrt( (p1-p2).NormSquared() * (p1-p3).NormSquared() ) )
00820                             recursion2--;
00821 
00822                         // recurse
00823                         if ( run->GetWall() )
00824                             LookAround( run->GetWall(), 1, correction, heightLimit, recursion2, hardRecursion-1 );
00825                         else if ( run->Other()->GetWall() )
00826                             LookAround( run->Other()->GetWall(), 0, correction, heightLimit, recursion2, hardRecursion-1 );
00827                     }
00828                 }
00829             }
00830             while ( true );
00831 
00832             // if recursion took place, don't project on this wall.
00833             if ( wallContinues )
00834                 return;
00835         }
00836 
00837         // No other wall found: project camera around this wall.
00838         REAL side=eCoord::F(normal,camPos_-p1) * (1-ratio_);
00839         correction.Improve( camPos_ - normal * side, fabs( side ) );
00840     }
00841 
00847     virtual void PassEdge(const eWall *w,REAL time,REAL alpha,int)
00848     {
00849         // determine the height limit (max. height at which walls will not be considered blockers)
00850         REAL objectZ = 1.5;
00851         if ( camera_ )
00852             objectZ = camera_->CenterCamZ() * 2;
00853         REAL heightLimit = ( .5 * zLimit_ * time + objectZ * ( 1 - time ) );
00854 
00855         // exit early if the wall does not obstruct view
00856         if ( moved_ || !w || !owned->EdgeIsDangerous(w, time, alpha) || w->Height() <= heightLimit )
00857             return;
00858 
00859         heightLimit *= .5f;
00860 
00861         // project camera position a bit to the other side of the wall:
00862         // get the two endpoints
00863         eCoord const & p1 = w->EndPoint(0);
00864         eCoord const & p2 = w->EndPoint(1);
00865 
00866         // calculate wall normal
00867         eCoord diff=p2-p1;
00868         diff=diff*(1/w->Len());
00869         eCoord normal=diff.Turn(0,-1);
00870 
00871         // project
00872         REAL side=eCoord::F(normal,camPos_-p1);
00873 
00874         // initialize correction suggestion; be very reluctant to project (it's confusing)
00875         Correction correction;
00876         correction.distance = fabs( side ) * 10;
00877         correction.correctTo = camPos_ - normal*(side);
00878 
00879         // try to look around the edge to the right and left instead
00880         int recursion = lowerWall_? 0 : 2;
00881         LookAround( w, 0, correction, heightLimit, recursion, 1000 );
00882         LookAround( w, 1, correction, heightLimit, recursion, 1000 );
00883 
00884         // execute the correction
00885         if ( !lowerWall_ )
00886         {
00887             moved_ = correction.distance > .001f;
00888             camPos_ = correction.correctTo;
00889         }
00890     }
00891     bool moved_; 
00892 
00893     inline eCameraSensor & SetZLimit( REAL const & zLimit );       
00894     inline REAL const & GetZLimit( void ) const;                       
00895     inline eCameraSensor const & GetZLimit( REAL & zLimit ) const; 
00896     inline eCameraSensor & SetRatio( REAL const & ratio );             
00897     inline REAL const & GetRatio( void ) const;                    
00898     inline eCameraSensor const & GetRatio( REAL & ratio ) const;   
00899     inline eCameraSensor & SetCamera( eCamera * camera );                    
00900     inline eCamera * GetCamera( void ) const;                            
00901     inline eCameraSensor const & GetCamera( eCamera * & camera ) const;  
00902     inline eCameraSensor & SetLowerWall( bool const & lowerWall );           
00903     inline bool const & GetLowerWall( void ) const;                          
00904     inline eCameraSensor const & GetLowerWall( bool & lowerWall ) const; 
00905 private:
00906     eCoord & camPos_; 
00907     eCoord target_; 
00908     REAL zLimit_;   
00909     REAL ratio_;    
00910     eCamera * camera_; 
00911     bool lowerWall_; 
00912 };
00913 
00914 // *******************************************************************************************
00915 // *
00916 // *   GetZLimit
00917 // *
00918 // *******************************************************************************************
00922 // *******************************************************************************************
00923 
00924 REAL const & eCameraSensor::GetZLimit( void ) const
00925 {
00926     return this->zLimit_;
00927 }
00928 
00929 // *******************************************************************************************
00930 // *
00931 // *   GetZLimit
00932 // *
00933 // *******************************************************************************************
00938 // *******************************************************************************************
00939 
00940 eCameraSensor const & eCameraSensor::GetZLimit( REAL & zLimit ) const
00941 {
00942     zLimit = this->zLimit_;
00943     return *this;
00944 }
00945 
00946 // *******************************************************************************************
00947 // *
00948 // *   SetZLimit
00949 // *
00950 // *******************************************************************************************
00955 // *******************************************************************************************
00956 
00957 eCameraSensor & eCameraSensor::SetZLimit( REAL const & zLimit )
00958 {
00959     this->zLimit_ = zLimit;
00960     return *this;
00961 }
00962 
00963 // *******************************************************************************************
00964 // *
00965 // *   GetRatio
00966 // *
00967 // *******************************************************************************************
00971 // *******************************************************************************************
00972 
00973 REAL const & eCameraSensor::GetRatio( void ) const
00974 {
00975     return this->ratio_;
00976 }
00977 
00978 // *******************************************************************************************
00979 // *
00980 // *   GetRatio
00981 // *
00982 // *******************************************************************************************
00987 // *******************************************************************************************
00988 
00989 eCameraSensor const & eCameraSensor::GetRatio( REAL & ratio ) const
00990 {
00991     ratio = this->ratio_;
00992     return *this;
00993 }
00994 
00995 // *******************************************************************************************
00996 // *
00997 // *   SetRatio
00998 // *
00999 // *******************************************************************************************
01004 // *******************************************************************************************
01005 
01006 eCameraSensor & eCameraSensor::SetRatio( REAL const & ratio )
01007 {
01008     this->ratio_ = ratio;
01009     return *this;
01010 }
01011 
01012 // *******************************************************************************************
01013 // *
01014 // *   GetCamera
01015 // *
01016 // *******************************************************************************************
01020 // *******************************************************************************************
01021 
01022 eCamera * eCameraSensor::GetCamera( void ) const
01023 {
01024     return this->camera_;
01025 }
01026 
01027 // *******************************************************************************************
01028 // *
01029 // *   GetCamera
01030 // *
01031 // *******************************************************************************************
01036 // *******************************************************************************************
01037 
01038 eCameraSensor const & eCameraSensor::GetCamera( eCamera * & camera ) const
01039 {
01040     camera = this->camera_;
01041     return *this;
01042 }
01043 
01044 // *******************************************************************************************
01045 // *
01046 // *   SetCamera
01047 // *
01048 // *******************************************************************************************
01053 // *******************************************************************************************
01054 
01055 eCameraSensor & eCameraSensor::SetCamera( eCamera * camera )
01056 {
01057     this->camera_ = camera;
01058     return *this;
01059 }
01060 
01061 // *******************************************************************************************
01062 // *
01063 // *   GetLowerWall
01064 // *
01065 // *******************************************************************************************
01069 // *******************************************************************************************
01070 
01071 bool const & eCameraSensor::GetLowerWall( void ) const
01072 {
01073     return this->lowerWall_;
01074 }
01075 
01076 // *******************************************************************************************
01077 // *
01078 // *   GetLowerWall
01079 // *
01080 // *******************************************************************************************
01085 // *******************************************************************************************
01086 
01087 eCameraSensor const & eCameraSensor::GetLowerWall( bool & lowerWall ) const
01088 {
01089     lowerWall = this->lowerWall_;
01090     return *this;
01091 }
01092 
01093 // *******************************************************************************************
01094 // *
01095 // *   SetLowerWall
01096 // *
01097 // *******************************************************************************************
01102 // *******************************************************************************************
01103 
01104 eCameraSensor & eCameraSensor::SetLowerWall( bool const & lowerWall )
01105 {
01106     this->lowerWall_ = lowerWall;
01107     return *this;
01108 }
01109 
01110 
01111 // *******************************************************************************************
01112 // *
01113 // *   Bound
01114 // *
01115 // *******************************************************************************************
01119 // *******************************************************************************************
01120 
01121 void eCamera::Bound( REAL dt )
01122 {
01123     Bound( dt, pos );
01124 }
01125 
01126 // *******************************************************************************************
01127 // *
01128 // *   Bound
01129 // *
01130 // *******************************************************************************************
01140 // *******************************************************************************************
01141 
01142 bool eCamera::Bound( REAL ratio, eCoord & pos, eCoord const & dirFromTarget, REAL & hitCache )
01143 {
01144     // the target position that should be visible
01145     eCoord target = CenterPos();
01146 
01147     // move it as requested, but not into walls
01148     if ( dirFromTarget.NormSquared() > 0.0001f )
01149     {
01150         eSensor test( Center(), target, dirFromTarget );
01151         test.detect( hitCache );
01152         target = test.before_hit * (1-se_visibilityWallDistance) + target * se_visibilityWallDistance;
01153         hitCache = test.hit;
01154     }
01155 
01156     // prepare camera clamping sensor
01157     eCameraSensor toObject( Center(), pos, target );
01158     toObject.SetZLimit( z ).SetRatio( ratio ).SetCamera( this );
01159 
01160     // if not glancing, switch from wall lowering to camera clipping if the user desires
01161     // CHECK: the following if-statement should be a faithful translation of
01162     // if ( !glancingBack && fabs( glanceSmooth ) < .001 )
01163     if (!activeGlanceRequest)
01164     {
01165         toObject.SetLowerWall( !se_ClampCamera(mode) );
01166 
01167         // clamp at outer boundary
01168         if ( !toObject.GetLowerWall() )
01169         {
01170             REAL offset = rimDistance + rimDistanceHeight * z;
01171             eWallRim::Bound(pos,offset);
01172         }
01173     }
01174 
01175     // execute clamping
01176     toObject.detect( 1 );
01177 
01178     return toObject.moved_;
01179 }
01180 
01181 // *******************************************************************************************
01182 // *
01183 // *   Bound
01184 // *
01185 // *******************************************************************************************
01190 // *******************************************************************************************
01191 
01192 void eCamera::Bound( REAL dt, eCoord & pos )
01193 {
01194     // make sure the camera is above the floor and inside the rim eWalls
01195     if (z<.1)
01196         z=.1;
01197 
01198     // don't waste time on the internal cameras, they don't need clamping
01199     if(mode!=CAMERA_IN && mode !=CAMERA_SMART_IN )
01200     {
01201         // the following is only meaningful if there is an active camera object
01202         if ( Center() )
01203         {
01204             // gently bring points in front of the cycle into view
01205             REAL smoothBound = 1/(1+se_visibilitySpeed*dt);
01206             eCoord direction = centerDirSmooth;
01207             //eCoord direction = Center()->Direction();
01208             //eCoord direction = CenterCamDir() + centerDirSmooth;
01209             direction.Normalize();
01210             // z-man: I can't yet decide which of the three direction calculations is best.
01211 
01212             Bound( smoothBound, pos, direction * ( CenterSpeed() * se_visibilityExtension ), hitCache_[0] );
01213 
01214             //            Bound( smoothBound, pos, direction.Turn(se_visibilitySidewaysSkew, 1) * ( CenterSpeed() * se_visibilityExtension ), hitCache_[1] );
01215             //            Bound( smoothBound, pos, direction.Turn(se_visibilitySidewaysSkew,-1) * ( CenterSpeed() * se_visibilityExtension ), hitCache_[2] );
01216 
01217             // force the object itself to be in full view, try several times
01218             int timeout = 4;
01219             bool goon = true;
01220             while (goon && timeout > 0)
01221             {
01222                 --timeout;
01223                 goon = false;
01224 
01225                 REAL cache = 1; // no real cache needed here
01226                 if ( Bound( 0, pos, eCoord(0,0), cache ) )
01227                 {
01228                     goon = true;
01229                     break;
01230                 }
01231             }
01232         }
01233     }
01234     /*
01235       if ((sr_upperSky) && z>upper_height-3)
01236       z=upper_height-3.0001;
01237 
01238       if (
01239         (se_BlackSky() || (sr_lowerSky && !sr_upperSky))&&
01240         z>lower_height-3)
01241         z=lower_height-3.0001;
01242     */
01243 }
01244 
01245 bool eCamera::CenterIncamOnTurn(){
01246     if (localPlayer)
01247         return localPlayer->centerIncamOnTurn;
01248     else
01249         return false;
01250 }
01251 bool eCamera::WhobbleIncam(){
01252     if (localPlayer)
01253         return localPlayer->wobbleIncam;
01254     else
01255         return false;
01256 }
01257 bool eCamera::AutoSwitchIncam(){
01258     if (localPlayer)
01259         return localPlayer->autoSwitchIncam;
01260     else
01261         return false;
01262 }
01263 
01264 static inline void makefinite(REAL &x,REAL y=2){if (!finite(x)) x=y;}
01265 static inline void makefinite(eCoord &x){makefinite(x.x);makefinite(x.y);}
01266 
01267 // Smart camera settings
01268 
01269 // distance scale for tests measured relative to cycle speed
01270 static REAL se_cameraSmartDistanceScale = .2;
01271 static tSettingItem< REAL > se_confCameraSmartDistanceScale( "CAMERA_SMART_DISTANCESCALE", se_cameraSmartDistanceScale );
01272 
01273 // minimal distance scale of tests in meters
01274 static REAL se_cameraSmartMinDistanceScale = 5.0;
01275 static tSettingItem< REAL > se_confCameraSmartMinDistanceScale( "CAMERA_SMART_MIN_DISTANCESCALE", se_cameraSmartMinDistanceScale );
01276 
01277 // minimal distance of the camera to the cycle in meters
01278 static REAL se_cameraSmartMinDistance = 10.0;
01279 static tSettingItem< REAL > se_confCameraSmartMinDistance( "CAMERA_SMART_MIN_DISTANCE", se_cameraSmartMinDistance );
01280 
01281 // typical cycle speed
01282 static REAL se_cameraSmartCycleSpeed = 20.0;
01283 static tSettingItem< REAL > se_confCameraSmartCycleSpeed( "CAMERA_SMART_CYCLESPEED", se_cameraSmartCycleSpeed );
01284 
01285 // typical height in speed units
01286 static REAL se_cameraSmartHeight = 2.0;
01287 static tSettingItem< REAL > se_confCameraSmartHeight( "CAMERA_SMART_HEIGHT", se_cameraSmartHeight );
01288 // typical height in speed units
01289 static REAL se_cameraSmartDistance = 4.0;
01290 static tSettingItem< REAL > se_confCameraSmartDistance( "CAMERA_SMART_DISTANCE", se_cameraSmartDistance );
01291 // extra factor for height
01292 static REAL se_cameraSmartHeightExtra = .5f;
01293 static tSettingItem< REAL > se_confCameraSmartHeightExtra( "CAMERA_SMART_HEIGHT_EXTRA", se_cameraSmartHeightExtra );
01294 
01295 // influence of turning
01296 static REAL se_cameraSmartHeightTurning = .5;
01297 static tSettingItem< REAL > se_confCameraSmartHeightTurning( "CAMERA_SMART_HEIGHT_TURNING", se_cameraSmartHeightTurning );
01298 
01299 // influence of grinding
01300 static REAL se_cameraSmartHeightGrinding = 0;
01301 static tSettingItem< REAL > se_confCameraSmartHeightGrinding( "CAMERA_SMART_HEIGHT_GRINDING", se_cameraSmartHeightGrinding );
01302 
01303 // influence of wall in front
01304 static REAL se_cameraSmartHeightObstacle = 1.0;
01305 static tSettingItem< REAL > se_confCameraSmartHeightObstacle( "CAMERA_SMART_HEIGHT_OBSTACLE", se_cameraSmartHeightObstacle );
01306 
01307 // factor moving the camera to the side if it is in front of the cycle
01308 static REAL se_cameraSmartAvoidFront = 10.0;
01309 static tSettingItem< REAL > se_confCameraSmartAvoidFront( "CAMERA_SMART_AVOID_FRONT", se_cameraSmartAvoidFront );
01310 
01311 // factor moving the camera to the side if it is in front of the cycle
01312 static REAL se_cameraSmartAvoidFront2 = 0.1;
01313 static tSettingItem< REAL > se_confCameraSmartAvoidFront2( "CAMERA_SMART_AVOID_FRONT2", se_cameraSmartAvoidFront2 );
01314 
01315 // amount of turning from grinding
01316 static REAL se_cameraSmartTurn = 5.0;
01317 static tSettingItem< REAL > se_confCameraSmartTurn( "CAMERA_SMART_TURN_GRINDING", se_cameraSmartTurn );
01318 
01319 // speed of center pos smoothing
01320 static REAL se_cameraSmartCenterPosSmooth = 6.0;
01321 static tSettingItem< REAL > se_confCameraSmartCenterPosSmooth( "CAMERA_SMART_CENTER_POS_SMOOTH", se_cameraSmartCenterPosSmooth );
01322 
01323 // speed of center dir smoothing
01324 static REAL se_cameraSmartCenterDirSmooth = 3.0;
01325 static tSettingItem< REAL > se_confCameraSmartCenterDirSmooth( "CAMERA_SMART_CENTER_DIR_SMOOTH", se_cameraSmartCenterDirSmooth );
01326 
01327 // amount of lookahead relative to speed
01328 static REAL se_cameraSmartCenterLookahead = .5;
01329 static tSettingItem< REAL > se_confCameraSmartCenterLookahead( "CAMERA_SMART_CENTER_LOOKAHEAD", se_cameraSmartCenterLookahead );
01330 
01331 // max amount of lookahead
01332 static REAL se_cameraSmartCenterMaxLookahead = 5;
01333 static tSettingItem< REAL > se_confCameraSmartCenterMaxLookahead( "CAMERA_SMART_CENTER_MAX_LOOKAHEAD", se_cameraSmartCenterMaxLookahead );
01334 
01335 
01336 /*
01337 
01338 
01339 static REAL se_cameraSmart =;
01340 static tSettingItem< REAL > se_confCameraSmart( "CAMERA_SMART", se_cameraSmart );
01341 */
01342 
01343 static float se_cameraEyeDistance = 0; // .1 to .5 appear to be good values
01344 static tConfItem<float> secced("CAMERA_EYE_DISTANCE", se_cameraEyeDistance);
01345 
01346 static int se_cameraEye1Color = 1; // 001b (bgR)
01347 static tConfItem<int> sece1ca("CAMERA_EYE_1_COLOR", se_cameraEye1Color);
01348 static tConfItem<int> sece1cb("CAMERA_EYE_1_COLOUR", se_cameraEye1Color);
01349 
01350 static int se_cameraEye2Color = 6; // 110b (BGr)
01351 static tConfItem<int> sece2ca("CAMERA_EYE_2_COLOR", se_cameraEye2Color);
01352 static tConfItem<int> sece2cb("CAMERA_EYE_2_COLOUR", se_cameraEye2Color);
01353 
01354 static float se_cameraInMaxFocusDistance = .5; //factor of the current speed
01355 static tConfItem<float> secimfd("CAMERA_IN_MAX_FOCUS_DISTANCE", se_cameraInMaxFocusDistance);
01356 
01357 #ifndef DEDICATED
01358 bool displaying=false;
01359 
01360 void eCamera::Render(){
01361     if (!sr_glOut)
01362         return;
01363     displaying=true;
01364 
01365     se_cameraRise=rise;
01366     se_cameraZ=z;
01367 
01368     //REAL  ts=ArmageTronTimer-lastrendertime;
01369     lastrendertime=se_GameTime();
01370 
01371     makefinite(pos);
01372     makefinite(lastPos);
01373     makefinite(top);
01374     makefinite(dir);
01375     makefinite(rise,0);
01376     makefinite(z,2);
01377     makefinite(distance,0);
01378     makefinite(smartcamSkewSmooth);
01379     makefinite(smartcamFrontSmooth);
01380     makefinite(smartcamIncamSmooth);
01381     makefinite(centerDirSmooth);
01382     makefinite(centerPosSmooth);
01383     makefinite(centerPosLast);
01384     makefinite(centerIncam);
01385     makefinite(userCameraControl);
01386     makefinite(turning);
01387     makefinite(smoothTurning);
01388     makefinite(fov);
01389     makefinite(distance);
01390     makefinite(lastrendertime);
01391 
01392     /*
01393     eCoord glancedir=dir.Turn(1,glanceSmooth).Turn(1,glanceSmooth);
01394     glancedir=glancedir*(1/sqrt(glancedir.NormSquared()));
01395     if (glancingBack)
01396         glancedir=glancedir*(-1);
01397 
01398     eCoord pos_diff=pos-CenterPos();
01399     if (mode != CAMERA_FREE){
01400         pos_diff = pos_diff.Turn(dir.Conj());
01401         pos_diff = pos_diff.Turn(glancedir);
01402     }
01403     pos_diff = pos_diff + CenterPos();
01404     */
01405 
01406     // CHECK: is this still what you intend it to be?
01407     if (!se_ClampCamera(mode))
01408         Bound(0, pos);
01409 
01410     // Bound( dt );
01411 
01412     if (z>400) z=300;
01413     if (z<0) z=0;
01414 
01415     if (rise<-100) rise=-100;
01416     if (rise>100) rise=100;
01417 
01418     // camera control logic
01419     /*
01420       if (center)
01421       Timestep(ts);
01422     */
01423 
01424     //  foot->Move(pos_diff,0,1);
01425 
01426     /*
01427       if (foot->currentFace)
01428       foot->currentFace->SetVisHeight(id,0);
01429       foot->Move(pos+dir*.01,0,1);
01430       if (foot->currentFace)
01431       foot->currentFace->SetVisHeight(id,0);
01432     */
01433 
01434     distance+=sqrt((lastPos-pos).NormSquared())*1.5;
01435     lastPos=pos;
01436 
01437 #ifdef DEBUG
01438     //  eEdge::UpdateVisAll(id);
01439 #endif
01440 
01441     glMatrixMode(GL_PROJECTION);
01442     glLoadIdentity();
01443     glMatrixMode(GL_MODELVIEW);
01444     glLoadIdentity();
01445 
01446     if(CenterCockpitFixedBefore()){
01447         vp->Perspective(fov,zNear,1E+20,se_cameraEyeDistance/2.);
01448 
01449         gluLookAt(0,
01450                   0,
01451                   0,
01452 
01453                   dir.x,
01454                   dir.y,
01455                   rise,
01456 
01457                   top.x,top.y,
01458                   1);
01459 
01460         glTranslatef(-pos.x,-pos.y,-z);
01461         glMatrixMode(GL_MODELVIEW);
01462 
01463         bool draw_center=((CenterPos()-pos).NormSquared()>1 ||
01464                           fabs(CenterZ() - z)>1);
01465 
01466         tJUST_CONTROLLED_PTR< eGameObject > c=Center();
01467         if (!draw_center && c) c->RemoveFromList();
01468 
01469         eCoord poscopy = pos;
01470         zNear = - eWallRim::Bound( poscopy, 0.0f );
01471         if (zNear < -.1 )
01472             zNear = .1;
01473 
01474         if(se_cameraEyeDistance) {
01475             glColorMask(se_cameraEye1Color & 1, se_cameraEye1Color & 2, se_cameraEye1Color & 4, GL_TRUE);
01476         }
01477         grid->Render( this, id, zNear );
01478 
01479         zNear *= .3f;
01480         if ( zNear < 0.0001f )
01481         {
01482             zNear = 0.0001f;
01483         }
01484 
01485         if(se_cameraEyeDistance) {
01486             glClear(GL_DEPTH_BUFFER_BIT);
01487             glColorMask(se_cameraEye2Color & 1, se_cameraEye2Color & 2, se_cameraEye2Color & 4, GL_TRUE);
01488             glMatrixMode(GL_PROJECTION);
01489             glLoadIdentity();
01490             glMatrixMode(GL_MODELVIEW);
01491             glLoadIdentity();
01492 
01493             vp->Perspective(fov,zNear,1E+20,-se_cameraEyeDistance/2.);
01494 
01495             float offset = 0;
01496             if(mode == CAMERA_IN) {
01497                 eSensor test(Center(), Center()->Position(), Center()->Direction());
01498                 test.detect(se_cameraInMaxFocusDistance*Center()->Speed());
01499                 offset = test.hit;
01500             }
01501 
01502             gluLookAt(0,
01503                       0,
01504                       0,
01505 
01506                       dir.x,
01507                       dir.y,
01508                       rise,
01509 
01510                       top.x,top.y,
01511                       1);
01512 
01513             glTranslatef(-pos.x,-pos.y,-z);
01514             glMatrixMode(GL_MODELVIEW);
01515 
01516             draw_center=((CenterPos()-pos).NormSquared()>1 ||
01517                          fabs(CenterZ() - z)>1);
01518 
01519             tJUST_CONTROLLED_PTR< eGameObject > c=Center();
01520             if (!draw_center && c) c->RemoveFromList();
01521 
01522             eCoord poscopy = pos;
01523             zNear = - eWallRim::Bound( poscopy, 0.0f );
01524             if (zNear < -.1 )
01525                 zNear = .1;
01526 
01527             grid->Render( this, id, zNear );
01528 
01529             zNear *= .3f;
01530             if ( zNear < 0.0001f )
01531             {
01532                 zNear = 0.0001f;
01533             }
01534             glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
01535         }
01536 
01537         if (c) c->RenderCockpitVirtual();
01538         if (!draw_center && c) c->AddToList();
01539 
01540         /*
01541           glDisable(GL_TEXTURE);
01542           glColor3f(1,1,1);
01543           glBegin(GL_LINES);
01544           glVertex3f(centerPosSmooth.x,centerPosSmooth.y,0);
01545           glVertex3f(centerPosSmooth.x,centerPosSmooth.y,10);
01546           glEnd();
01547         */
01548 
01549         CenterCockpitFixedAfter();
01550     }
01551     displaying=false;
01552 }
01553 
01554 #endif
01555 
01556 void eCamera::SwitchCenter(int d){
01557     zNear = 0.01f;
01558 
01559     int centerID = 0;
01560     if (center)
01561         centerID = center->interestingID;
01562     center = NULL;
01563 
01564     if (centerID>=grid->gameObjectsInteresting.Len())
01565         centerID=0;
01566     if (centerID<0)
01567         centerID=grid->gameObjectsInteresting.Len()-1;
01568 
01569     int timeout=(grid->gameObjectsInteresting.Len()+1)*5;
01570     int oldid=centerID;
01571     if (grid->gameObjectsInteresting.Len()>0){
01572         if (!InterestingToWatch(grid->gameObjectsInteresting(centerID)))
01573             grid->gameObjectsInteresting.Remove
01574             (grid->gameObjectsInteresting(centerID),
01575              grid->gameObjectsInteresting(centerID)->interestingID);
01576         do{
01577             timeout--;
01578             centerID+=d;
01579 
01580             if (centerID<0)
01581                 centerID=grid->gameObjectsInteresting.Len()-1;
01582             if (centerID>=grid->gameObjectsInteresting.Len())
01583                 centerID=0;
01584 
01585         }while(timeout >0 && grid->gameObjectsInteresting.Len()>0 &&
01586                 oldid!=centerID &&
01587                 !InterestingToWatch(grid->gameObjectsInteresting(centerID)));
01588     }
01589     else centerID=0;
01590     // con << "swtiched view from " << oldid << " to " << centerID << '\n';
01591 
01592     if ( centerID >= 0 && centerID < grid->gameObjectsInteresting.Len() )
01593     {
01594         center = grid->gameObjectsInteresting(centerID);
01595         lastSwitch=lastTime;
01596     }
01597 }
01598 
01599 void eCamera::Timestep(REAL ts){
01600     // find net player
01601     if (!netPlayer && localPlayer)
01602     {
01603         netPlayer = localPlayer->netPlayer;
01604     }
01605 
01606     // the best center is always our own vehicle. Focus on it if possible.
01607     if (netPlayer)
01608     {
01609         eGameObject * bestCenter = netPlayer->Object();
01610         if ( InterestingToWatch(bestCenter) )
01611         {
01612             if ( bestCenter != center )
01613             {
01614                 center = bestCenter;
01615                 if ( mode != CAMERA_FREE )
01616                     mode=localPlayer->startCamera;
01617             }
01618         }
01619     }
01620 
01621     eCamMode newmode = mode;
01622 
01624     // compute suggestions for the next camera state using eCamMode newmode
01626 
01627     // determine camera custom parameters based on speed
01628     REAL customBack = 0, customRise = 0, customPitch = 0, customTurnSpeed = s_customTurnSpeed, customTurnSpeed180 = s_customTurnSpeed180;
01629     {
01630         REAL speed = centerSpeedSmooth;
01631         if ( newmode == CAMERA_SERVER_CUSTOM )
01632         {
01633             customBack = s_serverCustomBack + speed * s_serverCustomBackSpeed;
01634             customRise = s_serverCustomRise + speed * s_serverCustomRiseSpeed;
01635             customPitch = s_serverCustomPitch;
01636 
01637             if ( s_serverCustomTurnSpeed >= 0 )
01638             {
01639                 customTurnSpeed = s_serverCustomTurnSpeed;
01640                 customTurnSpeed180 = s_serverCustomTurnSpeed180;
01641             }
01642         }
01643         else
01644         {
01645             customBack = s_customBack + speed * s_customBackSpeed;
01646             customRise = s_customRise + speed * s_customRiseSpeed;
01647             customPitch = s_customPitch;
01648         }
01649     }
01650 
01651     // switch away from dead players
01652     if (lastSwitch>lastTime)
01653         lastSwitch=lastTime;
01654 
01655     if (!InterestingToWatch(Center()) && lastTime-lastSwitch>2 && (center==0 || lastTime-center->deathTime > 4)){ // CHECK: not glancing-related. gives the player a chance to analyse the cause of his death before the camera switches away.
01656         center = se_GetWatchedObject( this );
01657         if ( !center || !InterestingToWatch(center) )
01658             SwitchCenter(1);
01659 
01660         if (!InterestingToWatch(Center()))
01661         {
01662             newmode=CAMERA_FREE;
01663         }
01664         // Did not work as expected, more work needs to be done to reset the settings
01665         //        else
01666         //        {
01667         //            if (localPlayer)
01668         //            {
01669         //                mode=localPlayer->startCamera;
01670         //            }
01671         //        }
01672     }
01673 
01674     if (!Center())
01675         return;
01676 
01677     // watch for turns of the center game object
01678     if ( fabs( centerDirLast * Center()->Direction() ) > .01 )
01679     {
01680         turning+=.5;
01681         centerDirLast = Center()->Direction();
01682     }
01683 
01684     for(int i = hitCacheSize-1; i>=0; --i)
01685     {
01686         hitCache_[i] += ts * se_hitCacheSpeed;
01687         if (hitCache_[i] > 1)
01688             hitCache_[i] = 1;
01689     }
01690 
01691     // flag telling someone at the end of the function whether Bound() was already called
01692     bool bound = false;
01693 
01694     eCoord objdir=CenterCamDir();
01695 
01696     // update center positions
01697     if ( Center() )
01698     {
01699         #define SMOOTH_SPEED 1
01700         centerSpeedSmooth = ( centerSpeedSmooth + Center()->Speed() * ts * SMOOTH_SPEED)/( 1 + ts * SMOOTH_SPEED );
01701 
01702         centerPos = Center()->PredictPosition();
01703 
01704         // move it a bit to the side (disabled for now, does not have the desired effect of making walls visible)
01705         //eCoord side = Center()->Direction().Turn(0,1);
01706         //REAL displace = eCoord::F( Center()->CamPos() - centerPos, side );
01707         //centerPos = centerPos + side * displace;
01708     }
01709     centerPosSmooth=(centerPosSmooth+ CenterPos()*(ts*se_cameraSmartCenterPosSmooth))
01710                     *(1/(1+ts*se_cameraSmartCenterPosSmooth));
01711 
01712     //centerPosSmooth=centerPosition();
01713 
01714     //REAL dist_from_center=sqrt((centerPos-pos).NormSquared()+
01715     //(CenterZ() - z)*(CenterZ() - z));
01716 
01717     if (!CenterAlive() && (newmode==CAMERA_IN || newmode==CAMERA_SMART_IN)){// || newmode==CAMERA_CUSTOM || newmode==CAMERA_SERVER_CUSTOM)){
01718         pos=pos-dir.Turn(eCoord(5,1));
01719         z+=2;
01720         newmode=CAMERA_SMART;
01721     }
01722 
01723     const REAL dirSmooth = se_cameraSmartCenterDirSmooth;
01724     centerDirSmooth=(centerDirSmooth+(CenterDir()*dirSmooth*ts))*
01725                     (1/(1+dirSmooth*ts));
01726 
01727     //  eCoord centerpos=centerPosSmooth+centerDirSmooth * ( this->CenterSpeed() * .05f );
01728     REAL speedFactor = se_GameTime() * this->CenterSpeed() * se_cameraSmartCenterLookahead;
01729     if ( speedFactor < 0.0f )
01730     {
01731         speedFactor = 0.0f;
01732     }
01733     if ( speedFactor > se_cameraSmartCenterMaxLookahead )
01734     {
01735         speedFactor = se_cameraSmartCenterMaxLookahead;
01736     }
01737     eCoord centerpos=CenterPos(); //centerPosSmooth + centerDirSmooth * speedFactor;
01738     // CHECK: Smoothing disabled because it causes artifacts while glancing
01739 
01740     #define SMART_INCAM_SPEED 1
01741     #define SMART_FRONT_SPEED 4
01742 
01743     userCameraControl/=(1+ts*5);
01744     #define maxcontrol 10
01745     if (userCameraControl>maxcontrol)
01746         userCameraControl=maxcontrol;
01747 
01748     smartcamFrontSmooth/=(1+SMART_FRONT_SPEED*ts);
01749     smartcamSkewSmooth/=(1+2*ts);
01750     smartcamIncamSmooth/=(1+SMART_INCAM_SPEED*ts);
01751 
01752     eCoord newpos=pos,newdir=dir;
01753     REAL newz=z,newrise=rise;
01754 
01755     eCoord usernewpos=pos;
01756     eCoord usernewdir=dir;
01757     REAL usernewz=z;
01758     REAL usernewrise=rise;
01759 
01760     REAL relax=se_cameraSmartDistance;//1 + 34/(CenterSpeed() + 1);
01761     //  REAL wish_h=2*vp->UpDownFOV(fov)/60 * SpeedMultiplier();
01762     REAL wish_h=se_cameraSmartHeight*vp->UpDownFOV(fov)/60 * ( this->CenterSpeed() * .02 + SpeedMultiplier() );
01763     REAL min_dist=se_cameraSmartMinDistance;
01764 
01765     turning/=(1+2*ts);
01766     smoothTurning+=3*turning*ts;
01767     smoothTurning/=1+ts;
01768 
01769 #define maxs 5
01770     if (smoothTurning>maxs) smoothTurning=maxs;
01771 
01772     REAL side;
01773     REAL eturn;
01774 
01775     top=eCoord(0,0);
01776 
01777     // temporarily use free cam code if nothing interesting to watch exists
01778     eCamMode effectiveMode = mode;
01779     if (!InterestingToWatch(Center()))
01780     {
01781         effectiveMode=CAMERA_FREE;
01782     }
01783 
01784     switch (effectiveMode){
01785     case CAMERA_FREE:
01786         newpos=pos;
01787         newdir=dir;
01788         newz=z;
01789         newrise=rise;
01790         break;
01791     case CAMERA_SMART_IN:
01792     case CAMERA_CUSTOM:
01793     case CAMERA_SERVER_CUSTOM:
01794     case CAMERA_IN:
01795         if (WhobbleIncam()){
01796             top=CenterCamTop();
01797             newpos=CenterCamPos();
01798         }
01799         else
01800             newpos=CenterPos();
01801 
01802         if (CenterIncamOnTurn() || newmode==CAMERA_SMART_IN || newmode == CAMERA_CUSTOM || newmode == CAMERA_SERVER_CUSTOM )
01803         {
01804             // fetch the relevant turning speed
01805             REAL turnSpeed = ( newmode == CAMERA_IN || newmode == CAMERA_SMART_IN ) ? s_inTurnSpeed : customTurnSpeed;
01806 
01807             eCoord cycleDir = CenterCamDir();
01808             newdir=dir+cycleDir*(turnSpeed*ts);
01809 
01810             // test if we're looking against the current driving direction
01811             REAL wrongDirection = -eCoord::F( cycleDir, newdir );
01812             if ( Center() &&  wrongDirection > 0 )
01813             {
01814                 // if so, turn to the side using the last driving direction
01815                 newdir = newdir + Center()->LastDirection()*(wrongDirection*ts*turnSpeed*s_customTurnSpeed180);
01816             }
01817         }
01818         else
01819             newdir=dir;
01820 
01821         if ( newmode == CAMERA_IN || newmode == CAMERA_SMART_IN )
01822         {
01823             const REAL forwardCheck = .1;
01824 
01825             // cast ray forward; don't be too close to a wall
01826             eSensor forward( Center(), newpos, newdir );
01827             forward.detect( forwardCheck );
01828             if ( forward.ehit )
01829             {
01830                 REAL backwardCheck = ( forwardCheck - forward.hit ) * 2;
01831                 eSensor backward( Center(), newpos, -newdir );
01832                 backward.detect( backwardCheck );
01833                 newpos = newpos - newdir * ( backward.hit * .5 );
01834             }
01835         }
01836 
01837         if (newmode != CAMERA_CUSTOM && newmode != CAMERA_SERVER_CUSTOM)
01838         {
01839             newz=CenterCamZ();
01840             newrise=rise;
01841             if (newrise>2) newrise=2;
01842             if (newrise<-2) newrise=-2;
01843 
01844             usernewpos=newpos;
01845             usernewz=newz;
01846         }
01847 
01848 
01849         if (newmode==CAMERA_SMART_IN){
01850             REAL space[2];
01851 
01852             REAL dist = CenterSpeed() * .2f;
01853             if (dist < 5)
01854                 dist = 5;
01855 
01856             for(int i=0;i<2;i++){
01857                 eSensor s(Center(),CenterPos(),CenterDir().Turn(1,2*i-1));
01858                 s.detect(dist);
01859                 space[i]=s.hit;
01860             }
01861             smartcamIncamSmooth+=(space[0]+space[1])*ts*SMART_INCAM_SPEED/dist;
01862 
01863             if (smartcamIncamSmooth>.8){
01864                 eSensor s(Center(),CenterPos(),CenterCycleDir());
01865                 s.detect(5.5);
01866 
01867                 if (s.hit>5){
01868                     newmode=CAMERA_SMART;
01869                     usernewz=newz=z+.5;
01870                     usernewpos=newpos=pos+dir.Turn(-1,.1);
01871                 }
01872             }
01873         }
01874 
01875         if (newmode != CAMERA_CUSTOM && newmode != CAMERA_SERVER_CUSTOM)
01876         {
01877             int x=3;
01878             while (eCoord::F(newdir,objdir)<-.5001 && x>0){
01879                 newdir=newdir-objdir*(eCoord::F(newdir,objdir)+.5);
01880                 newdir=newdir*(1/sqrt(newdir.NormSquared()));
01881                 x--;
01882             }
01883         }
01884         else if ( newmode == CAMERA_CUSTOM || newmode == CAMERA_SERVER_CUSTOM )
01885         {
01886             REAL zoom = lastTime > 0 ? 1 : exp( s_customZoom * lastTime );
01887 
01888             newdir=newdir*(1/sqrt(newdir.NormSquared()));
01889             newpos     = newpos - newdir * customBack * zoom;
01890             usernewpos = usernewpos + CenterPos() - centerPosLast;
01891             newrise    = customPitch;
01892             newz       = CenterCamZ() + customRise * zoom;
01893         }
01894 
01895         break;
01896     case CAMERA_SMART:
01897         if (activeGlanceRequest) {
01898             newdir     = dir;
01899             newpos     = CenterPos()+newdir*smartcamGlancingBack;
01900             newz       = smartcamGlancingHeight;
01901             newrise    = (CenterZ()-newz)/smartcamGlancingBack;
01902         } else {
01903             REAL dist = CenterSpeed() * se_cameraSmartDistanceScale;
01904             if (dist < se_cameraSmartMinDistanceScale)
01905                 dist = se_cameraSmartMinDistanceScale;
01906 
01907             REAL space[2];
01908 
01909             for(int i=0;i<2;i++){
01910                 eSensor s(Center(),CenterPos(),CenterDir().Turn(1,2*i-1));
01911                 s.detect(dist);
01912                 space[i]=s.hit;
01913             }
01914 
01915             REAL slowFactor = this->CenterSpeed() / se_cameraSmartCycleSpeed;
01916             if ( slowFactor > 1.0f )
01917             {
01918                 slowFactor = 1.0f;
01919             }
01920 
01921             eSensor front(Center(), CenterPos(), CenterDir());
01922             front.detect(dist * 4);
01923             REAL ff = (4 * dist - front.hit)/(3*dist);
01924             ff *= ff;
01925             smartcamFrontSmooth+=ff*SMART_FRONT_SPEED*ts;
01926 
01927             smartcamSkewSmooth+=(space[0]-space[1])*ts * slowFactor;
01928             smartcamIncamSmooth+=(space[0]+space[1])*ts*SMART_INCAM_SPEED/dist;
01929 
01930             REAL sk = fabs(smartcamSkewSmooth)/5;
01931             if (sk > 1)
01932                 sk = 1;
01933 
01934             REAL rf = .15+.1*smoothTurning - sk * .15 - .05 * smartcamFrontSmooth;
01935             if (rf < .05)
01936                 rf = .05;
01937 
01938             relax*=rf;
01939             relax/=slowFactor;
01940             // wish_h*=.5+1.5*smoothTurning + 2 * sk + smartcamFrontSmooth;
01941             wish_h*=se_cameraSmartHeightExtra + se_cameraSmartHeightTurning*smoothTurning + se_cameraSmartHeightGrinding * sk + smartcamFrontSmooth * se_cameraSmartHeightObstacle;
01942             min_dist/=3; // +smoothTurning;
01943 
01944             {
01945                 if (!CenterAlive()) wish_h+=3;
01946                 REAL front=eCoord::F(pos-centerpos,CenterDir());
01947                 side=((pos-centerpos)*CenterDir()) * front;
01948                 //eCoord::F(pos-centerpos,CenterDir);
01949                 eturn=ts/relax * (1 + .5 * smartcamFrontSmooth);
01950                 if (side>0) eturn*=-1;
01951 
01952                 newz=z;
01953 
01954                 // we do not want to look at the cycle front
01955 
01956                 //eCoord skew;
01957                 if (front>0){ // increase skew
01958                     if (front>2.5) front=2.5;
01959                     if (fabs(smartcamSkewSmooth)>1 || smartcamSkewSmooth*eturn>0)
01960                         smartcamSkewSmooth*=(1+ts);
01961                     if (fabs(smartcamSkewSmooth)<1)
01962                         smartcamSkewSmooth -= se_cameraSmartAvoidFront * eturn;
01963                     newz+=ts*front*.1;
01964                     //if ( Center() )
01965                     //    skew = -Center()->LastDirection()*(front*dist*.2);
01966                 }
01967 
01968                 if (se_GameTime()>0){
01969                     newpos=pos + CenterDir().Turn(eCoord(0,eturn*se_cameraSmartAvoidFront2));
01970                     newpos=newpos+CenterDir().Turn(0,-1)*smartcamSkewSmooth*ts*se_cameraSmartTurn;
01971                     //newpos=newpos+skew*ts*5;
01972                     newpos=newpos+centerpos*(ts/relax);
01973                     newpos=newpos*(1/(1+ts/relax));
01974                 }
01975                 else{
01976                     newpos=pos+ (pos-centerpos).Turn(-ts*.5,ts*.5);
01977                 }
01978 
01979                 if ( userCameraControl < .25  && se_ClampCamera(newmode) )
01980                 {
01981                     bound = true;
01982                     Bound( ts, newpos );
01983                     // Bound( ts, newpos );
01984                 }
01985 
01986                 newz=newz+(CenterZ()+wish_h)*(ts/relax);
01987                 newz=newz/(1+ts/relax);
01988                 newdir=centerpos-newpos;
01989                 REAL dist=sqrt(newdir.NormSquared());
01990                 if (dist<.001) dist=.01;
01991                 //                                      newdir=dir+(centerDirSmooth*16+newdir)*ts;
01992                 newdir=dir+newdir*ts*5.0;
01993                 newdir=newdir*(1/sqrt(newdir.NormSquared()));
01994 
01995                 if (dist<min_dist){
01996                     //newpos=newpos-newdir*((min_dist-dist)*(min_dist-dist)*ts);
01997                     REAL dz=(min_dist*min_dist-dist*dist-.5*z*z);
01998                     if (dz>0)
01999                         newz+=dz*ts;
02000                 }
02001 
02002                 REAL d=eCoord::F(newdir,centerpos - newpos);
02003                 if (d<.0001) d=.0001;
02004                 newrise=(CenterZ()-newz)/d;
02005 
02006                 usernewpos=pos + centerpos - centerPosLast;
02007                 // usernewdir=newdir;
02008                 // usernewrise=newrise;
02009                 //
02010                 //                // use custom camera settings when glancing
02011                 //                if ( localPlayer && localPlayer->smartCustomGlance && ( glancingBack || glancingRight || glancingLeft || glanceSmoothAbs > .01 ))
02012                 //                {
02013                 //                    // update blending factor raw data
02014                 //                    REAL abs = fabs(glanceSmooth);
02015                 //                    glanceSmoothAbs = abs > glanceSmoothAbs ? abs : glanceSmoothAbs;
02016                 //
02017                 //                    // calculate blending factor c. c=0 will take the smart cam position, c=1 the custom cam.
02018                 //                    REAL b = 1 - glanceSmoothAbs;
02019                 //                    REAL c = 1 - b/(b + ts * GLANCE_SPEED);
02020                 //
02021                 //                    // override: go all the way when glancing back
02022                 //                    if ( glancingBack )
02023                 //                    {
02024                 //                        c = 1;
02025                 //                        glanceSmoothAbs = 1;
02026                 //                    }
02027                 //
02028                 //                    // the camera pitch is calculated anew every frame, blend it accordingly
02029                 //                    usernewrise = newrise = newrise * ( 1-glanceSmoothAbs) + customPitch * glanceSmoothAbs;
02030                 //
02031                 //                    // the other values are updated every frame, blend them softer
02032                 //                    if ( glancingBack || glancingRight || glancingLeft )
02033                 //                    {
02034                 //                        usernewpos  =  newpos = pos * (1-c) + (CenterPos() - CenterCamDir() * customBack) * c;
02035                 //                        usernewz    = newz    = z * (1-c) + (CenterCamZ() + customRise) * c;
02036                 //
02037                 //                        newdir=centerpos-newpos;
02038                 //                        REAL dist=sqrt(newdir.NormSquared());
02039                 //                        if (dist<.001) dist=.01;
02040                 //                        usernewdir=newdir=newdir*(1/sqrt(newdir.NormSquared()));
02041                 //                    }
02042                 //                }
02043 
02044                 if (AutoSwitchIncam()){
02045                     if (smartcamIncamSmooth<.7 && CenterAlive()){
02046                         eSensor s(Center(),CenterPos(),CenterDir());
02047                         s.detect(5.5);
02048                         if (s.hit>5){
02049                             usernewrise=newrise=0;
02050                             newmode=CAMERA_SMART_IN;
02051                             usernewdir=newdir=objdir;
02052                         }
02053                     }
02054                 }
02055                 else
02056                     if (smartcamIncamSmooth<.7)
02057                         newz+=ts*(.7-smartcamIncamSmooth);
02058             }
02059         }
02060         break;
02061     case CAMERA_FOLLOW:{
02062             newpos=usernewpos=pos + centerpos - centerposLast;
02063             newz=z;
02064             newdir=centerpos-newpos;
02065             REAL dist=sqrt(newdir.NormSquared());
02066             newdir=newdir*(1/dist);
02067             newrise=(CenterZ()-newz)/dist;
02068         }
02069         break;
02070     case CAMERA_MER: {
02071             // perform initial animation if lastTime<0
02072             REAL zoom = lastTime > 0 ? 1 : exp( s_customZoom * lastTime );
02073             REAL dist = mercamxydist*zoom;
02074 
02075             eCoord t = CenterPos()-pos;
02076             t.Normalize();
02077 
02078             // update camera state
02079             newpos  = usernewpos=CenterPos()-t*dist;
02080             newz    = CenterZ()*(1-zoom) +mercamz*zoom;
02081             newdir  = t;
02082             newrise = (CenterZ()-newz)/dist;
02083         }
02084         break;
02085     case CAMERA_COUNT:
02086         break;
02087     }
02088 
02090     // now that we have suggestions for the next camera state
02091     // we modify them to account for manual camera control
02092     // and then commit them
02094 
02095     if (activeGlanceRequest) {
02096         bool internal = mode==CAMERA_IN || mode==CAMERA_SMART_IN;
02097 
02098         if (internal) {
02099             pos  = newpos;
02100             dir  = nextDirIfGlancing(dir,activeGlanceRequest->dir,ts);
02101             z    = newz;
02102             rise = newrise;
02103         } else {
02104             REAL c = 5*ts;
02105             eCoord focusTarget     = (mode==CAMERA_SMART) ? centerpos     : CenterPos();
02106             eCoord focusTargetLast = (mode==CAMERA_SMART) ? centerposLast : centerPosLast;
02107 
02108             // reconstruct focal point
02109             //std::cout << (pos-centerpos).Norm()*rise+z << " ";
02110             REAL focusZ = (newpos-focusTarget).Norm()*newrise+newz;
02111             eCoord focus = dir*((focusZ-z)/rise) + pos;
02112 
02113             // move focal point towards focusTargetLast
02114             focus = focus * (1-c) + focusTargetLast * c;
02115 
02116             // rotate camera
02117             eCoord t = focus-pos;
02118             REAL tnorm = t.Norm();
02119             t.Normalize();
02120             t = nextDirIfGlancing(t,activeGlanceRequest->dir,ts);
02121 
02122             // advance time
02123             focus = focus + focusTarget - focusTargetLast;
02124 
02125             // adjust distance to camera
02126             tnorm = tnorm * (1-c) + (newpos-focusTarget).Norm() * c;
02127 
02128             // update camera state
02129             pos  = focus - t * tnorm;
02130             dir  = t;
02131             z    = z * (1-c) + newz * c;
02132             rise = (focusZ-z) / tnorm;
02133 
02134             //std::cout << activeGlanceRequest->dir << " " << t << " " << tnorm << "\t";
02135         }
02136 
02137     } else {
02138 
02139         /*
02140           REAL ratio=1 - exp(-4*userCameraControl);
02141           ratio*=ts;
02142           ratio*=100;
02143           ratio=exp(-ratio);
02144         */
02145 
02146         // calcualte ratios under which user and automatic camera positions should be blended
02147         REAL aratio = exp(-4*userCameraControl);
02148         REAL ratio = 1 - aratio;
02149 
02150         // blend
02151         pos=newpos*aratio + usernewpos*ratio;
02152         dir=newdir*aratio + usernewdir*ratio;
02153         z  =newz  *aratio + usernewz  *ratio;
02154 
02155         // newrise rise is calculated anew every frame, use a different blending
02156         if (userCameraControl > .01)
02157         {
02158             rise=newrise + (usernewrise-newrise)*exp(-ts/userCameraControl);
02159         }
02160         else
02161         {
02162             rise=newrise;
02163         }
02164 
02165         // normalize direction
02166         dir=dir*(1/sqrt(dir.NormSquared()));
02167     }
02168 
02169     #ifdef CAMERA_LOGGING
02170     std::cout << (activeGlanceRequest ? "g " : "  ") << (pos-CenterPos()).Norm() << " " << (newpos-CenterPos()).Norm() << " " << z << " " << rise << "\n";
02171     #endif
02172     dir.Normalize();
02173     centerposLast=centerpos;
02174     centerPosLast=CenterPos();
02175 
02176     // bound camera if that was not already done earlier
02177     if (!bound && se_ClampCamera(mode) ) // CHECK: That condition is affected by glancing?
02178         Bound( ts );
02179 }
02180 
02181 
02182 
02183 void eCamera::s_Timestep(eGrid *grid, REAL time){
02184     if (fabs(time-lastTime)>1) lastTime=time-.1;
02185     if (time>lastTime){
02186         eDebugLine::Update(time-lastTime);
02187 
02188         for(int i=grid->cameras.Len()-1;i>=0;i--){
02189             //con << time-lastTime<< '\n';
02190             eCamera *c = grid->cameras(i);
02191             c->Timestep(time-lastTime);
02192             su_FetchAndStoreSDLInput();
02193         }
02194         lastTime=time;
02195     }
02196 }
02197 
02198 
02199 #ifndef DEDICATED
02200 
02201 //void eCamera::SoundMix(Uint8 *dest,unsigned int len){
02202 //    if (!this)
02203 //        return;
02204 //
02205 //    if (id>=0){
02206 //        eGameObject *c=Center();
02207 //        for(int i=grid->gameObjects.Len()-1;i>=0;i--){
02208 //            eGameObject *go=grid->gameObjects(i);
02209 //            SoundMixGameObject(dest,len,go);
02210 //        }
02211 //        if (c && c->id<0)
02212 //            SoundMixGameObject(dest,len,c);
02213 //    }
02214 //}
02215 //
02216 //
02217 //void eCamera::SoundMixGameObject(Uint8 *dest,unsigned int len,eGameObject *go){
02218 //    eCoord vec((go->pos-pos).Turn(dir.Conj()));
02219 //    REAL dist_squared=vec.NormSquared()+(z-go->z)*(z-go->z);
02220 //
02221 //    //dist_squared*=.1;
02222 //    if (dist_squared<1)
02223 //        dist_squared=1;
02224 //
02225 //    REAL dist=sqrt(dist_squared);
02226 //
02227 //#define MAXVOL .4
02228 //
02229 //    REAL l=(dist*.5+vec.y)/dist_squared;
02230 //    REAL r=(dist*.5-vec.y)/dist_squared;
02231 //
02232 //    if (l<0) l=0;
02233 //    if (r<0) r=0;
02234 //    if (l>MAXVOL) l=MAXVOL;
02235 //    if (r>MAXVOL) r=MAXVOL;
02236 //
02237 //    if (go==Center()){
02238 //        if (mode==CAMERA_IN || mode==CAMERA_SMART_IN)
02239 //            l=r=.2;
02240 //        else if (mode!=CAMERA_FREE){
02241 //            l*=.9;
02242 //            r*=.9;
02243 //        }
02244 //    }
02245 //
02246 //    go->SoundMix(dest,len,id,r,l);
02247 //}
02248 
02249 
02250 #endif
02251 
02252 eCoord eCamera::CenterPos() const{
02253     return centerPos;
02254 }
02255 
02256 eCoord eCamera::CenterCycleDir() const{
02257     return CenterDir();
02258 }
02259 
02260 eCoord eCamera::CenterDir() const{
02261     eGameObject *go=Center();
02262     if (go)
02263         return go->Direction() ;
02264     else
02265         return eCoord(1,0);
02266 }
02267 
02268 eCoord eCamera::CenterCamDir() const{
02269     eGameObject *go=Center();
02270     if (go)
02271         return go->CamDir() ;
02272     else
02273         return eCoord(1,0);
02274 }
02275 
02276 eCoord eCamera::CenterCamTop() const{
02277     eGameObject *go=Center();
02278     if (go)
02279         return go->CamTop();
02280     else
02281         return eCoord(0,0);
02282 }
02283 
02284 eCoord eCamera::CenterCamPos() const{
02285     eGameObject *go=Center();
02286     if (go)
02287         return go->CamPos();
02288     else
02289         return eCoord(100,100);
02290 }
02291 
02292 REAL  eCamera::CenterCamZ() const{
02293     eGameObject *go=Center();
02294     if (go)
02295         return go-> CamZ();
02296     else
02297         return 1.5;
02298 }
02299 
02300 REAL  eCamera::CenterZ() const{
02301     eGameObject *go=Center();
02302     if (go)
02303         return go->z ;
02304     else
02305         return 1.5;
02306 }
02307 
02308 REAL  eCamera::CenterSpeed() const{
02309     eGameObject *go=Center();
02310     if (go)
02311         return go->Speed();
02312     else
02313         return 20;
02314 }
02315 
02316 
02317 bool eCamera::CenterAlive() const{
02318     eGameObject *go=Center();
02319     if (go)
02320         return go->Alive() ;
02321     else
02322         return false;
02323 }
02324 
02325 
02326 bool eCamera::CenterCockpitFixedBefore() const{
02327     eGameObject *go=Center();
02328     if (go)
02329         return go->RenderCockpitFixedBefore();
02330     else
02331         return true;
02332 }
02333 
02334 void eCamera::CenterCockpitFixedAfter() const{
02335     eGameObject *go=Center();
02336     if (go)
02337         go->RenderCockpitFixedAfter() ;
02338     else
02339         return;
02340 }
02341 
02342 

Generated on Sat Mar 15 22:55:44 2008 for Armagetron Advanced by  doxygen 1.5.4