/* ************************************************************************* ArmageTron -- Just another Tron Lightcycle Game in 3D. Copyright (C) 2000 Manuel Moos (manuel@moosnet.de) ************************************************************************** This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU Geeneral Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *************************************************************************** */ #include "eSensor.h" #include "eCamera.h" #include "rScreen.h" #include "eGameObject.h" #include "uInputQueue.h" //#include "eTess.h" #include "eTimer.h" #include "tConfiguration.h" #include "rSysdep.h" #include "tConsole.h" #include "ePlayer.h" #include "eAdvWall.h" #include "nConfig.h" #include "eFloor.h" #include "eGrid.h" #include "eDebugLine.h" #include "tMath.h" // allow cameras [player independent; gets transferred over the network] static bool forbid_camera[CAMERA_COUNT]; class eInitForbidCamera { public: eInitForbidCamera() { // allow all cameras for ( int i = CAMERA_COUNT-1; i>=0; --i ) { forbid_camera[i] = false; } // except the server custom camera forbid_camera[ CAMERA_SERVER_CUSTOM ] = true; } }; static eInitForbidCamera se_initForbid; // forbid smart camerea static nSettingItem a_s ("CAMERA_FORBID_SMART", forbid_camera[CAMERA_SMART]); // forbid internal camerea static nSettingItem a_i ("CAMERA_FORBID_IN", forbid_camera[CAMERA_IN]); // forbid custom camerea static nSettingItem a_c ("CAMERA_FORBID_CUSTOM", forbid_camera[CAMERA_CUSTOM]); // forbid custom camerea static nSettingItem a_sc ("CAMERA_FORBID_SERVER_CUSTOM", forbid_camera[CAMERA_SERVER_CUSTOM]); // forbid free camerea static nSettingItem a_f ("CAMERA_FORBID_FREE", forbid_camera[CAMERA_FREE]); // forbid fixed ext. camerea static nSettingItem a_fe ("CAMERA_FORBID_FOLLOW", forbid_camera[CAMERA_FOLLOW]); #ifndef DEDICATED #include "rGL.h" #endif static REAL lastTime=0; static const REAL rimDistance = 0.01f; static const REAL rimDistanceHeight = 0.1f; REAL se_cameraRise=0; REAL se_cameraZ=10; // List se_cameras; uActionCamera eCamera::se_moveBack("MOVE_BACK", -10, uAction::uINPUT_ANALOG); uActionCamera eCamera::se_moveForward("MOVE_FORWARD", -20, uAction::uINPUT_ANALOG); uActionCamera eCamera::se_moveDown("MOVE_DOWN", -30, uAction::uINPUT_ANALOG); uActionCamera eCamera::se_moveUp("MOVE_UP", -40, uAction::uINPUT_ANALOG); uActionCamera eCamera::se_moveRight("MOVE_RIGHT", -50, uAction::uINPUT_ANALOG); uActionCamera eCamera::se_moveLeft("MOVE_LEFT", -60, uAction::uINPUT_ANALOG); uActionCamera eCamera::se_zoomOut("ZOOM_OUT", -70, uAction::uINPUT_ANALOG); uActionCamera eCamera::se_zoomIn("ZOOM_IN", -80, uAction::uINPUT_ANALOG); uActionCamera eCamera::se_glanceBack("GLANCE_BACK",-90); uActionCamera eCamera::se_glanceRight("GLANCE_RIGHT",-100); uActionCamera eCamera::se_glanceLeft("GLANCE_LEFT",-110); uActionCamera eCamera::se_lookDown("BANK_DOWN", -120, uAction::uINPUT_ANALOG); uActionCamera eCamera::se_lookUp("BANK_UP", -130, uAction::uINPUT_ANALOG); uActionCamera eCamera::se_lookRight("LOOK_RIGHT", -140, uAction::uINPUT_ANALOG); uActionCamera eCamera::se_lookLeft("LOOK_LEFT", -150, uAction::uINPUT_ANALOG); uActionCamera eCamera::se_switchView("SWITCH_VIEW", -160); static REAL s_startFollowX = -30, s_startFollowY = -30, s_startFollowZ = 80; static REAL s_startSmartX = 10, s_startSmartY = 30, s_startSmartZ = 2; static REAL s_startFreeX = 10, s_startFreeY = -70, s_startFreeZ = 100; static tSettingItem s_foX("CAMERA_FOLLOW_START_X", s_startFollowX); static tSettingItem s_smX("CAMERA_SMART_START_X", s_startSmartX); static tSettingItem s_frX("CAMERA_FREE_START_X", s_startFreeX); static tSettingItem s_foY("CAMERA_FOLLOW_START_Y", s_startFollowY); static tSettingItem s_smY("CAMERA_SMART_START_Y", s_startSmartY); static tSettingItem s_frY("CAMERA_FREE_START_Y", s_startFreeY); static tSettingItem s_foZ("CAMERA_FOLLOW_START_Z", s_startFollowZ); static tSettingItem s_smZ("CAMERA_SMART_START_Z", s_startSmartZ); static tSettingItem s_frZ("CAMERA_FREE_START_Z", s_startFreeZ); // custom camera displacement static REAL s_customBack = 20, s_customRise = 50, s_customPitch = -4; static REAL s_serverCustomBack = 20, s_serverCustomRise = 20, s_serverCustomPitch = -1; static tSettingItem s_iBack("CAMERA_CUSTOM_BACK", s_customBack); static tSettingItem s_iRise("CAMERA_CUSTOM_RISE", s_customRise); static tSettingItem s_iPitch("CAMERA_CUSTOM_PITCH", s_customPitch); static nSettingItem s_iSBack("CAMERA_SERVER_CUSTOM_BACK", s_serverCustomBack); static nSettingItem s_iSRise("CAMERA_SERVER_CUSTOM_RISE", s_serverCustomRise); static nSettingItem s_iSPitch("CAMERA_SERVER_CUSTOM_PITCH", s_serverCustomPitch); bool eCamera::InterestingToWatch(eGameObject *g){ return g && (g->Alive() || (lastTime - g->deathTime<1)); } void eCamera::MyInit(){ if (localPlayer){ mode=localPlayer->startCamera; fov=localPlayer->startFOV; } if (forbid_camera[mode]) SwitchView(); pos=CenterPos(); dir=CenterDir(); centerPosSmooth=pos; centerDirSmooth=dir; lastPos=pos; zNear=0.1f; // foot=tNEW(eGameObject)(pos,dir,0); distance=0; lastrendertime=se_GameTime(); grid->cameras.Add(this,id); // se_ResetVisibles(id); smoothTurning=turning=0; centerPosLast=CenterPos(); userCameraControl=0; centerIncam=1; smartcamSkewSmooth=0; smartcamIncamSmooth=1; smartcamFrontSmooth=0; switch (mode){ case CAMERA_CUSTOM: case CAMERA_SERVER_CUSTOM: case CAMERA_IN: z=10; rise=0; break; case CAMERA_FOLLOW: pos=pos+dir.Turn(eCoord(s_startFollowX,s_startFollowY)) ; z=s_startFollowZ; break; case CAMERA_SMART: pos=pos+dir.Turn(eCoord(s_startSmartX,s_startSmartY)) ; z=s_startSmartZ; break; case CAMERA_FREE: pos=pos+dir.Turn(eCoord(s_startFreeX,s_startFreeY)) ; z=s_startFreeZ; break; default: break; } if ( mode != CAMERA_IN && mode != CAMERA_CUSTOM && mode != CAMERA_SERVER_CUSTOM ){ dir=CenterPos()-pos; REAL dist=REAL(sqrt(dir.NormSquared())); if (dist<.001) dist=1; dir=dir*(1/dist); rise=(CenterZ()-z)/dist; } glancingBack=glancingLeft=glancingRight=false; glanceSmooth=0; } const ePlayerNetID* eCamera::Player() const { return netPlayer; } eCamera::eCamera(eGrid *g, rViewport *view,ePlayerNetID *p, ePlayer *lp,eCamMode m) :id(-1),grid(g),netPlayer(p),localPlayer(lp), centerID(0), mode(m),pos(0,0),dir(1,0),top(0,0), vp(view){ /* if (p->pID>=0) localPlayer=playerConfig[p->pID]; */ MyInit(); } eCamera::~eCamera(){ // int ID=id; // tDESTROY(foot); // se_cameras.Remove(this,id); // se_ResetVisibles(se_cameras.Len()); // if (ID!=se_cameras.Len()) se_ResetVisibles(ID); grid->cameras.Remove(this, id); tCHECK_DEST; } //static eGameObject *dummy=NULL; eGameObject *eCamera::Center() const{ eGameObject *ret=NULL; if (netPlayer) ret=netPlayer->Object(); if (InterestingToWatch(ret)){ centerID=ret->id; if (centerID<0) centerID=0; if (centerID>=grid->gameObjectsInteresting.Len()) centerID=grid->gameObjectsInteresting.Len()-1; return ret; } else{ /* if (eGameObject::gameObjectsInteresting.Len()>1) && dummy){ delete dummy; dummy=NULL; } if (eGameObject::gameObjectsInteresting.Len()<=0){ if (!dummy){ dummy=tNEW(eGameObject)(eCoord(300,300),eCoord(1,0)); dummy->Kill(); eGameObject::gameObjectsInteresting.Add(dummy,dummy->interestingID); eGameObject::gameObjects.Remove(dummy,dummy->id); } } */ if (centerID<0) centerID=0; if (centerID>=grid->gameObjectsInteresting.Len()) centerID=grid->gameObjectsInteresting.Len()-1; if (centerID>=0) return grid->gameObjectsInteresting(centerID); else return NULL; } } void eCamera::SwitchView(){ zNear = 0.01f; int count=CAMERA_COUNT * 2; userCameraControl = 0; // eCamMode pre=mode; bool imp=true,global_imp=true,both_imp=true; for (int i=CAMERA_COUNT-1;i>=0;i--){ if (!localPlayer || localPlayer->allowCam[i]) imp=false; if (!forbid_camera[i] || !netPlayer || netPlayer->Object()!=Center()) global_imp=false; if ((!forbid_camera[i] || !netPlayer || netPlayer->Object()!=Center()) && (!localPlayer || localPlayer->allowCam[i])) both_imp=false; } if (imp) con << "impossible to meet your needs.\n"; if (global_imp) con << "impossible to meet global needs.\n"; if (both_imp) con << "impossible to meet both needs.\n"; if (both_imp && !global_imp) imp=true; do{ // rotate the mode int m = mode; m--; if ( m<0 ) m = CAMERA_SERVER_CUSTOM; mode = static_cast< eCamMode >( m ); count--; } while ((!imp && count > CAMERA_COUNT && localPlayer && !localPlayer->allowCam[mode]) || (count >0 && !global_imp && forbid_camera[mode] && (bool( netPlayer ) && netPlayer->Object()==Center()))); if ( mode == CAMERA_IN || mode == CAMERA_CUSTOM || mode == CAMERA_SERVER_CUSTOM ) rise=0; if(mode==CAMERA_SMART){ smartcamIncamSmooth=1; z=z+1; pos=pos+dir.Turn(-1,.1); } } bool eCamera::Act(uActionCamera *Act,REAL x){ eCoord objdir=CenterCamDir(); int turn=0; if (eGameObject::se_turnLeft==*reinterpret_cast(Act)){ glancingBack=glancingLeft=false; turn=-1; } if (eGameObject::se_turnRight==*reinterpret_cast(Act)){ glancingBack=glancingRight=false; turn=1; } if (turn){ turning+=.5; eGameObject *cent=NULL; if (netPlayer) cent=netPlayer->Object(); if (!InterestingToWatch(cent) && x>0) SwitchCenter(turn); } REAL ll=0,lu=0,ml=0,mf=0,mu=0,zi=1; if (se_lookLeft==*Act && x>0) ll=x; else if (se_lookRight==*Act && x>0) ll=-x; else if (se_lookUp==*Act && x>0) lu=x; else if (se_lookDown==*Act && x>0) lu=-x; else if (se_zoomIn==*Act && x>0) zi*=1+zi*.1; else if (se_zoomOut==*Act && x>0) zi/=1+zi*.1; else if (se_moveLeft==*Act && x>0) ml=x; else if (se_moveRight==*Act && x>0) ml=-x; else if (se_moveForward==*Act && x>0) mf=x; else if (se_moveBack==*Act && x>0) mf=-x; else if (se_moveUp==*Act && x>0) mu=x; else if (se_moveDown==*Act && x>0) mu=-x; else if (se_switchView==*Act && x>0) SwitchView(); else if (se_glanceBack==*Act) glancingBack=(x>0); else if (se_glanceLeft==*Act) glancingLeft=(x>0); else if (se_glanceRight==*Act) glancingRight=(x>0); else return false; userCameraControl+=sqrt(ll*ll+lu*lu+(1-zi)*(1-zi)+ml*ml+mf*mf+mu*mu)/20; switch(mode){ case CAMERA_IN: case CAMERA_SMART_IN: lu+=mu*2; ll+=ml; mu=ml=0; break; case CAMERA_CUSTOM: case CAMERA_SERVER_CUSTOM: case CAMERA_FREE: break; case CAMERA_FOLLOW: case CAMERA_SMART: mu-=lu; ml-=ll; lu=ll=0; break; case CAMERA_COUNT: break; } // normal actions with the given data dir=dir+dir.Turn(eCoord(0,ll*.2)); rise+=lu/80; z+=mu*.25; pos=pos+dir*mf*.25+dir.Turn(eCoord(0,ml*.25)); fov/=zi; if (fov>120) fov=120; if (fov<30) fov=30; switch(mode){ case CAMERA_IN: case CAMERA_SMART_IN: { int x=3; while (eCoord::F(dir,objdir)<-.51 && x>0){ dir=dir-objdir*(eCoord::F(dir,objdir)+.5); dir=dir*(1/sqrt(dir.NormSquared())); x--; } } break; case CAMERA_CUSTOM: case CAMERA_SERVER_CUSTOM: case CAMERA_FREE: case CAMERA_FOLLOW: case CAMERA_SMART: break; case CAMERA_COUNT: break; } Bound(); return true; } extern REAL upper_height,lower_height; void eCamera::Bound(){ // make sure the camera is above the floor and inside the rim eWalls if (z<.1) z=.1; if(mode!=CAMERA_IN && mode !=CAMERA_SMART_IN && eWallRim::IsBound(CenterPos())) eWallRim::Bound(pos,rimDistance + rimDistanceHeight * z ); /* if ((sr_upperSky) && z>upper_height-3) z=upper_height-3.0001; if ( (se_BlackSky() || (sr_lowerSky && !sr_upperSky))&& z>lower_height-3) z=lower_height-3.0001; */ } bool eCamera::CenterIncamOnTurn(){ if (localPlayer) return localPlayer->centerIncamOnTurn; else return false; } bool eCamera::WhobbleIncam(){ if (localPlayer) return localPlayer->wobbleIncam; else return false; } bool eCamera::AutoSwitchIncam(){ if (localPlayer) return localPlayer->autoSwitchIncam; else return false; } static inline void makefinite(REAL &x,REAL y=2){if (!finite(x)) x=y;} static inline void makefinite(eCoord &x){makefinite(x.x);makefinite(x.y);} #ifndef DEDICATED bool displaying=false; void eCamera::Render(){ if (!sr_glOut) return; displaying=true; se_cameraRise=rise; se_cameraZ=z; //REAL ts=ArmageTronTimer-lastrendertime; lastrendertime=se_GameTime(); makefinite(pos); makefinite(lastPos); makefinite(top); makefinite(dir); makefinite(rise,0); makefinite(z,2); makefinite(distance,0); makefinite(smartcamSkewSmooth); makefinite(smartcamFrontSmooth); makefinite(smartcamIncamSmooth); makefinite(centerDirSmooth); makefinite(centerPosSmooth); makefinite(centerPosLast); makefinite(centerIncam); makefinite(userCameraControl); makefinite(glanceSmooth,0); makefinite(turning); makefinite(smoothTurning); makefinite(glanceSmooth); makefinite(fov); makefinite(distance); makefinite(lastrendertime); eCoord glancedir=dir.Turn(1,glanceSmooth).Turn(1,glanceSmooth); glancedir=glancedir*(1/sqrt(glancedir.NormSquared())); if (glancingBack) glancedir=glancedir*(-1); eCoord pos_diff=pos-CenterPos(); if (mode != CAMERA_FREE){ pos_diff = pos_diff.Turn(dir.Conj()); pos_diff = pos_diff.Turn(glancedir); } pos_diff = pos_diff + CenterPos(); if (eWallRim::IsBound(CenterPos())) eWallRim::Bound(pos_diff, rimDistance + rimDistanceHeight * z ); if (z>400) z=300; if (z<0) z=0; if (rise<-100) rise=-100; if (rise>100) rise=100; // camera control logic /* if (center) Timestep(ts); */ // foot->Move(pos_diff,0,1); /* if (foot->currentFace) foot->currentFace->SetVisHeight(id,0); foot->Move(pos+dir*.01,0,1); if (foot->currentFace) foot->currentFace->SetVisHeight(id,0); */ distance+=sqrt((lastPos-pos_diff).NormSquared())*1.5; lastPos=pos_diff; #ifdef DEBUG // eEdge::UpdateVisAll(id); #endif glMatrixMode(GL_PROJECTION); glLoadIdentity(); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); if(CenterCockpitFixedBefore()){ vp->Perspective(fov,zNear,1E+20); /* gluLookAt(pos.x, pos.y, z, pos.x+dir.x, pos.y+dir.y, z+rise, top.x,top.y, 1); */ gluLookAt(0, 0, 0, glancedir.x, glancedir.y, rise, top.x,top.y, 1); glTranslatef(-pos_diff.x,-pos_diff.y,-z); glMatrixMode(GL_MODELVIEW); bool draw_center=((CenterPos()-pos).NormSquared()>1 || fabs(CenterZ() - z)>1); eGameObject *c=Center(); if (!draw_center && c) c->RemoveFromList(); eCoord poscopy = pos; zNear = - eWallRim::Bound( poscopy, 0.0f ); grid->Render( this, id, zNear ); zNear *= .3f; if ( zNear < 0.0001f ) { zNear = 0.0001f; } if (c) c->RenderCockpitVirtual(); if (!draw_center && c) c->AddToList(); /* glDisable(GL_TEXTURE); glColor3f(1,1,1); glBegin(GL_LINES); glVertex3f(centerPosSmooth.x,centerPosSmooth.y,0); glVertex3f(centerPosSmooth.x,centerPosSmooth.y,10); glEnd(); */ CenterCockpitFixedAfter(); } displaying=false; } #endif void eCamera::SwitchCenter(int d){ zNear = 0.01f; lastSwitch=lastTime; if (centerID>=grid->gameObjectsInteresting.Len()) centerID=0; if (centerID<0) centerID=grid->gameObjectsInteresting.Len()-1; int timeout=(grid->gameObjectsInteresting.Len()+1)*5; int oldid=centerID; if (grid->gameObjectsInteresting.Len()>0){ if (!InterestingToWatch(grid->gameObjectsInteresting(centerID))) grid->gameObjectsInteresting.Remove (grid->gameObjectsInteresting(centerID), grid->gameObjectsInteresting(centerID)->interestingID); do{ timeout--; centerID+=d; if (centerID<0) centerID=grid->gameObjectsInteresting.Len()-1; if (centerID>=grid->gameObjectsInteresting.Len()) centerID=0; }while(timeout >0 && grid->gameObjectsInteresting.Len()>0 && oldid!=centerID && !InterestingToWatch(grid->gameObjectsInteresting(centerID))); } else centerID=0; // con << "swtiched view from " << oldid << " to " << centerID << '\n'; } void eCamera::Timestep(REAL ts){ if (!Center()) return; eCoord objdir=CenterCamDir(); #define GLANCE_SPEED 20 if (glancingLeft) glanceSmooth+=GLANCE_SPEED*ts; if (glancingRight) glanceSmooth-=GLANCE_SPEED*ts; glanceSmooth/=(1+GLANCE_SPEED*ts); centerPosSmooth=(centerPosSmooth+ CenterPos()*(ts*6)) *(1/(1+ts*6)); //centerPosSmooth=centerPosition(); //REAL dist_from_center=sqrt((centerPos-pos).NormSquared()+ //(CenterZ() - z)*(CenterZ() - z)); if (lastSwitch>lastTime) lastSwitch=lastTime; eGameObject *cent=NULL; if (netPlayer) cent=netPlayer->Object(); if (!InterestingToWatch(Center()) && lastTime-lastSwitch>2){ SwitchCenter(1); if (!InterestingToWatch(Center())) mode=CAMERA_FREE; } if (!CenterAlive() && (mode==CAMERA_IN || mode==CAMERA_SMART_IN || mode==CAMERA_CUSTOM || mode==CAMERA_SERVER_CUSTOM)){ pos=pos-dir.Turn(eCoord(5,1)); z+=2; mode=CAMERA_SMART; } const REAL dirSmooth = 3.0f; centerDirSmooth=(centerDirSmooth+(CenterDir()*dirSmooth*ts))* (1/(1+dirSmooth*ts)); // eCoord centerpos=centerPosSmooth+centerDirSmooth * ( this->CenterSpeed() * .05f ); REAL speedFactor = se_GameTime() * this->CenterSpeed() * .5f; if ( speedFactor < 0.0f ) { speedFactor = 0.0f; } if ( speedFactor > 5.0f ) { speedFactor = 5.0f; } eCoord centerpos=centerPosSmooth+centerDirSmooth * speedFactor; #define SMART_INCAM_SPEED 1 #define SMART_FRONT_SPEED 4 userCameraControl/=(1+ts*5); #define maxcontrol 10 if (userCameraControl>maxcontrol) userCameraControl=maxcontrol; smartcamFrontSmooth/=(1+SMART_FRONT_SPEED*ts); smartcamSkewSmooth/=(1+2*ts); smartcamIncamSmooth/=(1+SMART_INCAM_SPEED*ts); eCoord newpos=pos,newdir=dir; REAL newz=z,newrise=rise; eCoord usernewpos=pos; eCoord usernewdir=dir; REAL usernewz=z; REAL usernewrise=rise; REAL relax=4;//1 + 34/(CenterSpeed() + 1); // REAL wish_h=2*vp->UpDownFOV(fov)/60 * SpeedMultiplier(); REAL wish_h=2*vp->UpDownFOV(fov)/60 * ( this->CenterSpeed() * .02 + SpeedMultiplier() ); REAL min_dist=10; turning/=(1+2*ts); smoothTurning+=3*turning*ts; smoothTurning/=1+ts; #define maxs 5 if (smoothTurning>maxs) smoothTurning=maxs; REAL side; REAL eturn; top=eCoord(0,0); switch (mode){ case CAMERA_FREE: newpos=pos; newdir=dir; newz=z; newrise=rise; break; case CAMERA_SMART_IN: case CAMERA_CUSTOM: case CAMERA_SERVER_CUSTOM: case CAMERA_IN: if (WhobbleIncam()){ top=CenterCamTop(); newpos=CenterCamPos(); } else newpos=CenterPos(); if (CenterIncamOnTurn() || mode==CAMERA_SMART_IN) newdir=dir+(CenterCycleDir())*40*ts; else newdir=dir; if (mode != CAMERA_CUSTOM && mode != CAMERA_SERVER_CUSTOM) { newz=CenterCamZ(); newrise=rise; if (newrise>2) newrise=2; if (newrise<-2) newrise=-2; usernewpos=newpos; usernewz=newz; } if (mode==CAMERA_SMART_IN){ REAL space[2]; REAL dist = CenterSpeed() * .2f; if (dist < 5) dist = 5; for(int i=0;i<2;i++){ eSensor s(Center(),CenterPos(),CenterDir().Turn(1,2*i-1)); s.detect(dist); space[i]=s.hit; } smartcamIncamSmooth+=(space[0]+space[1])*ts*SMART_INCAM_SPEED/dist; if (smartcamIncamSmooth>.8){ eSensor s(Center(),CenterPos(),CenterCycleDir()); s.detect(5.5); if (s.hit>5){ mode=CAMERA_SMART; usernewz=newz=z+.5; usernewpos=newpos=pos+dir.Turn(-1,.1); } } } if (mode != CAMERA_CUSTOM && mode != CAMERA_SERVER_CUSTOM) { int x=3; while (eCoord::F(newdir,objdir)<-.5001 && x>0){ newdir=newdir-objdir*(eCoord::F(newdir,objdir)+.5); newdir=newdir*(1/sqrt(newdir.NormSquared())); x--; } } else if ( mode == CAMERA_CUSTOM ) { newdir=newdir*(1/sqrt(newdir.NormSquared())); newpos = newpos - newdir * s_customBack; usernewpos = usernewpos + centerpos - centerPosLast; newrise = s_customPitch; newz = CenterCamZ() + s_customRise; } else if ( mode == CAMERA_SERVER_CUSTOM ) { newdir=newdir*(1/sqrt(newdir.NormSquared())); newpos = newpos - newdir * s_serverCustomBack; usernewpos = usernewpos + centerpos - centerPosLast; newrise = s_serverCustomPitch; newz = CenterCamZ() + s_serverCustomRise; } break; case CAMERA_SMART: { REAL dist = CenterSpeed() * .2f; if (dist < 5) dist = 5; REAL space[2]; for(int i=0;i<2;i++){ eSensor s(Center(),CenterPos(),CenterDir().Turn(1,2*i-1)); s.detect(dist); space[i]=s.hit; } REAL slowFactor = this->CenterSpeed() * .05;; if ( slowFactor > 1.0f ) { slowFactor = 1.0f; } eSensor front(Center(), CenterPos(), CenterDir()); front.detect(dist * 4); REAL ff = (4 * dist - front.hit)/(3*dist); ff *= ff; smartcamFrontSmooth+=ff*SMART_FRONT_SPEED*ts; smartcamSkewSmooth+=(space[0]-space[1])*ts * slowFactor; smartcamIncamSmooth+=(space[0]+space[1])*ts*SMART_INCAM_SPEED/dist; REAL sk = fabs(smartcamSkewSmooth)/5; if (sk > 1) sk = 1; REAL rf = .15+.1*smoothTurning - sk * .15 - .05 * smartcamFrontSmooth; if (rf < .05) rf = .05; relax*=rf; relax/=slowFactor; // wish_h*=.5+1.5*smoothTurning + 2 * sk + smartcamFrontSmooth; wish_h*=.5+0.5*smoothTurning + 2 * sk + smartcamFrontSmooth; min_dist/=3; // +smoothTurning; { if (!CenterAlive()) wish_h+=3; REAL front=eCoord::F(pos-centerpos,CenterDir()); side=((pos-centerpos)*CenterDir()) * front; //eCoord::F(pos-centerpos,CenterDir); eturn=ts/relax * (1 + .5 * smartcamFrontSmooth); if (side>0) eturn*=-1; newz=z; // we do not want to look at the cycle front if (front>0){ // increase skew if (front>2.5) front=2.5; if (fabs(smartcamSkewSmooth)>1 || smartcamSkewSmooth*eturn>0) smartcamSkewSmooth*=(1+ts); if (fabs(smartcamSkewSmooth)<1) smartcamSkewSmooth -= 10 * eturn; newz+=ts*front*.1; } if (se_GameTime()>0){ newpos=pos + CenterDir().Turn(eCoord(0,eturn*.1)); newpos=newpos+CenterDir().Turn(0,-1)*smartcamSkewSmooth*ts*5; newpos=newpos+centerpos*(ts/relax); newpos=newpos*(1/(1+ts/relax)); } else{ newpos=pos+ (pos-centerpos).Turn(-ts*.5,ts*.5); } newz=newz+(CenterZ()+wish_h)*(ts/relax); newz=newz/(1+ts/relax); newdir=centerpos-newpos; REAL dist=sqrt(newdir.NormSquared()); if (dist<.001) dist=.01; // newdir=dir+(centerDirSmooth*16+newdir)*ts; newdir=dir+newdir*ts*5.0; newdir=newdir*(1/sqrt(newdir.NormSquared())); if (dist0) newz+=dz*ts; } REAL d=eCoord::F(newdir,centerpos - newpos); if (d<.0001) d=.0001; newrise=(CenterZ()-newz)/d; usernewpos=pos + centerpos - centerPosLast; usernewdir=newdir; usernewrise=newrise; if (AutoSwitchIncam()){ if (smartcamIncamSmooth<.7 && CenterAlive()){ eSensor s(Center(),CenterPos(),CenterDir()); s.detect(5.5); if (s.hit>5){ usernewrise=newrise=0; mode=CAMERA_SMART_IN; usernewdir=newdir=objdir; } } } else if (smartcamIncamSmooth<.7) newz+=ts*(.7-smartcamIncamSmooth); } } break; case CAMERA_FOLLOW:{ newpos=usernewpos=pos + centerpos - centerPosLast; newz=z; newdir=centerpos-newpos; REAL dist=sqrt(newdir.NormSquared()); newdir=newdir*(1/dist); newrise=(CenterZ()-newz)/dist; } break; default: break; } // REAL ratio=1-exp(-100*exp(-userCameraControl)*ts); /* REAL ratio=1 - exp(-4*userCameraControl); ratio*=ts; ratio*=100; ratio=exp(-ratio); */ REAL ratio=1 - exp(-4*userCameraControl); pos=newpos*(1-ratio) + usernewpos*ratio; dir=newdir*(1-ratio) + usernewdir*ratio; z =newz *(1-ratio) + usernewz *ratio; rise=newrise*(1-ratio) + usernewrise*ratio; dir=dir*(1/sqrt(dir.NormSquared())); centerPosLast=centerpos; Bound(); } void eCamera::s_Timestep(eGrid *grid, REAL time){ if (fabs(time-lastTime)>1) lastTime=time-.1; if (time>lastTime){ eDebugLine::Update(time-lastTime); for(int i=grid->cameras.Len()-1;i>=0;i--){ //con << time-lastTime<< '\n'; eCamera *c = grid->cameras(i); c->Timestep(time-lastTime); su_FetchAndStoreSDLInput(); } lastTime=time; } } #ifndef DEDICATED void eCamera::SoundMix(Uint8 *dest,unsigned int len){ if (!this) return; if (id>=0){ eGameObject *c=Center(); for(int i=grid->gameObjects.Len()-1;i>=0;i--){ eGameObject *go=grid->gameObjects(i); SoundMixGameObject(dest,len,go); } if (c && c->id<0) SoundMixGameObject(dest,len,c); } } void eCamera::SoundMixGameObject(Uint8 *dest,unsigned int len,eGameObject *go){ eCoord vec((go->pos-pos).Turn(dir.Conj())); REAL dist_squared=vec.NormSquared()+(z-go->z)*(z-go->z); //dist_squared*=.1; if (dist_squared<1) dist_squared=1; REAL dist=sqrt(dist_squared); #define MAXVOL .4 REAL l=(dist*.5+vec.y)/dist_squared; REAL r=(dist*.5-vec.y)/dist_squared; if (l<0) l=0; if (r<0) r=0; if (l>MAXVOL) l=MAXVOL; if (r>MAXVOL) r=MAXVOL; if (go==Center()){ if (mode==CAMERA_IN || mode==CAMERA_SMART_IN) l=r=.2; else if (mode!=CAMERA_FREE){ l*=.9; r*=.9; } } go->SoundMix(dest,len,id,r,l); } #endif eCoord eCamera::CenterPos(){ eGameObject *go=Center(); if (go) return go->Position(); // return go->PredictPosition() ; else { return eCoord(100,100); } } eCoord eCamera::CenterCycleDir(){ return CenterDir(); } eCoord eCamera::CenterDir(){ eGameObject *go=Center(); if (go) return go->Direction() ; else return eCoord(1,0); } eCoord eCamera::CenterCamDir(){ eGameObject *go=Center(); if (go) return go->CamDir() ; else return eCoord(1,0); } eCoord eCamera::CenterCamTop(){ eGameObject *go=Center(); if (go) return go->CamTop(); else return eCoord(0,0); } eCoord eCamera::CenterCamPos(){ eGameObject *go=Center(); if (go) return go->CamPos(); else return eCoord(100,100); } REAL eCamera::CenterCamZ(){ eGameObject *go=Center(); if (go) return go-> CamZ(); else return 1.5; } REAL eCamera::CenterZ(){ eGameObject *go=Center(); if (go) return go->z ; else return 1.5; } REAL eCamera::CenterSpeed(){ eGameObject *go=Center(); if (go) return go->Speed(); else return 20; } bool eCamera::CenterAlive(){ eGameObject *go=Center(); if (go) return go->Alive() ; else return false; } bool eCamera::CenterCockpitFixedBefore(){ eGameObject *go=Center(); if (go) return go->RenderCockpitFixedBefore(); else return true; } void eCamera::CenterCockpitFixedAfter(){ eGameObject *go=Center(); if (go) go->RenderCockpitFixedAfter() ; else return; }