3
*************************************************************************
5
ArmageTron -- Just another Tron Lightcycle Game in 3D.
6
Copyright (C) 2000 Manuel Moos (manuel@moosnet.de)
8
**************************************************************************
10
This program is free software; you can redistribute it and/or
11
modify it under the terms of the GNU General Public License
12
as published by the Free Software Foundation; either version 2
13
of the License, or (at your option) any later version.
15
This program is distributed in the hope that it will be useful,
16
but WITHOUT ANY WARRANTY; without even the implied warranty of
17
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18
GNU General Public License for more details.
20
You should have received a copy of the GNU Geeneral Public License
21
along with this program; if not, write to the Free Software
22
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
24
***************************************************************************
33
#include "eGameObject.h"
34
#include "uInputQueue.h"
37
#include "tConfiguration.h"
45
#include "eDebugLine.h"
47
#include "eNetGameObject.h"
49
// camera visibility settings
50
static REAL se_hitCacheSpeed = 1; // the speed the hit cache for external visibility targets recovers from hits
52
static REAL se_visibilityWallDistance = .5f; // the distance the visibility targets keep from walls
54
static REAL se_visibilitySpeed = 40; // speed with wich the visibility targets is brought into view
55
static REAL se_visibilityExtension = 1; // distance (measured in seconds, gets multiplied by speed) of the visibility targets from the watched object
56
static REAL se_visibilitySidewaysSkew = .5; // extra forward component of the sideways visibility targets
57
static bool se_visibilityLowerWall = true; // flag indicating whether walls should be lowerd when they block the view
58
static bool se_visibilityLowerWallSmart = false; // same specially for the smart camera
60
static tSettingItem<REAL> se_viscs("CAMERA_VISIBILITY_RECOVERY_SPEED", se_hitCacheSpeed );
61
static tSettingItem<REAL> se_viswd("CAMERA_VISIBILITY_WALL_DISTANCE", se_visibilityWallDistance );
62
static tSettingItem<REAL> se_viss("CAMERA_VISIBILITY_CLIP_SPEED", se_visibilitySpeed );
63
static tSettingItem<REAL> se_vise("CAMERA_VISIBILITY_EXTENSION", se_visibilityExtension );
64
static tSettingItem<REAL> se_vissk("CAMERA_VISIBILITY_SIDESKEW", se_visibilitySidewaysSkew );
65
static tSettingItem<bool> se_vislw("CAMERA_VISIBILITY_LOWER_WALL", se_visibilityLowerWall );
66
static tSettingItem<bool> se_vislws("CAMERA_VISIBILITY_LOWER_WALL_SMART", se_visibilityLowerWallSmart );
68
//static bool se_customGlance = true; // use the custom camera settings for glancing in the smart camera
69
//static tSettingItem<bool> se_cg("CAMERA_SMART_GLANCE_CUSTOM", se_customGlance );
71
// allow cameras [player independent; gets transferred over the network]
72
static bool forbid_camera[CAMERA_COUNT];
74
class eInitForbidCamera
80
for ( int i = CAMERA_COUNT-1; i>=0; --i )
82
forbid_camera[i] = false;
85
// except the server custom camera
86
forbid_camera[ CAMERA_SERVER_CUSTOM ] = true;
89
static eInitForbidCamera se_initForbid;
91
// forbid smart camerea
92
static nSettingItem<bool> a_s
93
("CAMERA_FORBID_SMART",
94
forbid_camera[CAMERA_SMART]);
96
// forbid internal camerea
97
static nSettingItem<bool> a_i
99
forbid_camera[CAMERA_IN]);
101
// forbid custom camerea
102
static nSettingItem<bool> a_c
103
("CAMERA_FORBID_CUSTOM",
104
forbid_camera[CAMERA_CUSTOM]);
106
// forbid custom camerea
107
static nSettingItem<bool> a_sc
108
("CAMERA_FORBID_SERVER_CUSTOM",
109
forbid_camera[CAMERA_SERVER_CUSTOM]);
111
// forbid free camerea
112
static nSettingItem<bool> a_f
113
("CAMERA_FORBID_FREE",
114
forbid_camera[CAMERA_FREE]);
116
// forbid fixed ext. camerea
117
static nSettingItem<bool> a_fe
118
("CAMERA_FORBID_FOLLOW",
119
forbid_camera[CAMERA_FOLLOW]);
125
static REAL lastTime=0;
126
static const REAL rimDistance = 0.01f;
127
static const REAL rimDistanceHeight = 0.1f;
129
REAL se_cameraRise=0;
132
// List<eCamera> se_cameras;
134
uActionCamera eCamera::se_moveBack("MOVE_BACK",
136
uAction::uINPUT_ANALOG);
138
uActionCamera eCamera::se_moveForward("MOVE_FORWARD",
140
uAction::uINPUT_ANALOG);
142
uActionCamera eCamera::se_moveDown("MOVE_DOWN",
144
uAction::uINPUT_ANALOG);
146
uActionCamera eCamera::se_moveUp("MOVE_UP",
148
uAction::uINPUT_ANALOG);
151
uActionCamera eCamera::se_moveRight("MOVE_RIGHT",
153
uAction::uINPUT_ANALOG);
155
uActionCamera eCamera::se_moveLeft("MOVE_LEFT",
157
uAction::uINPUT_ANALOG);
159
uActionCamera eCamera::se_zoomOut("ZOOM_OUT",
161
uAction::uINPUT_ANALOG);
163
uActionCamera eCamera::se_zoomIn("ZOOM_IN",
165
uAction::uINPUT_ANALOG);
168
uActionCamera eCamera::se_glanceBack("GLANCE_BACK",-90);
170
uActionCamera eCamera::se_glanceRight("GLANCE_RIGHT",-100);
172
uActionCamera eCamera::se_glanceLeft("GLANCE_LEFT",-110);
175
uActionCamera eCamera::se_lookDown("BANK_DOWN",
177
uAction::uINPUT_ANALOG);
179
uActionCamera eCamera::se_lookUp("BANK_UP",
181
uAction::uINPUT_ANALOG);
183
uActionCamera eCamera::se_lookRight("LOOK_RIGHT",
185
uAction::uINPUT_ANALOG);
187
uActionCamera eCamera::se_lookLeft("LOOK_LEFT",
189
uAction::uINPUT_ANALOG);
192
uActionCamera eCamera::se_switchView("SWITCH_VIEW", -160);
195
static REAL s_startFollowX = -30, s_startFollowY = -30, s_startFollowZ = 80;
196
static REAL s_startSmartX = 10, s_startSmartY = 30, s_startSmartZ = 2;
197
static REAL s_startFreeX = 10, s_startFreeY = -70, s_startFreeZ = 100;
199
static tSettingItem<REAL> s_foX("CAMERA_FOLLOW_START_X", s_startFollowX);
200
static tSettingItem<REAL> s_smX("CAMERA_SMART_START_X", s_startSmartX);
201
static tSettingItem<REAL> s_frX("CAMERA_FREE_START_X", s_startFreeX);
203
static tSettingItem<REAL> s_foY("CAMERA_FOLLOW_START_Y", s_startFollowY);
204
static tSettingItem<REAL> s_smY("CAMERA_SMART_START_Y", s_startSmartY);
205
static tSettingItem<REAL> s_frY("CAMERA_FREE_START_Y", s_startFreeY);
207
static tSettingItem<REAL> s_foZ("CAMERA_FOLLOW_START_Z", s_startFollowZ);
208
static tSettingItem<REAL> s_smZ("CAMERA_SMART_START_Z", s_startSmartZ);
209
static tSettingItem<REAL> s_frZ("CAMERA_FREE_START_Z", s_startFreeZ);
211
// custom camera displacement
212
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;
213
static REAL s_serverCustomBack = 30, s_serverCustomRise = 20, s_serverCustomBackSpeed = 0, s_serverCustomRiseSpeed = 0, s_serverCustomPitch = -.7, s_serverCustomTurnSpeed=-1, s_serverCustomTurnSpeed180 = 2;
216
static tSettingItem<REAL> s_iBack("CAMERA_CUSTOM_BACK", s_customBack);
217
static tSettingItem<REAL> s_iRise("CAMERA_CUSTOM_RISE", s_customRise);
218
static tSettingItem<REAL> s_iBackSpeed("CAMERA_CUSTOM_BACK_FROMSPEED", s_customBackSpeed);
219
static tSettingItem<REAL> s_iRiseSpeed("CAMERA_CUSTOM_RISE_FROMSPEED", s_customRiseSpeed);
220
static tSettingItem<REAL> s_iPitch("CAMERA_CUSTOM_PITCH", s_customPitch);
221
static tSettingItem<REAL> s_iZoom("CAMERA_CUSTOM_ZOOM", s_customZoom);
222
static tSettingItem<REAL> s_iCustomTurnSpeed("CAMERA_CUSTOM_TURN_SPEED", s_customTurnSpeed);
223
static tSettingItem<REAL> s_iCustomTurnSpeed180("CAMERA_CUSTOM_TURN_SPEED_180", s_customTurnSpeed180);
225
static nSettingItem<REAL> s_iSBack("CAMERA_SERVER_CUSTOM_BACK", s_serverCustomBack);
226
static nSettingItem<REAL> s_iSRise("CAMERA_SERVER_CUSTOM_RISE", s_serverCustomRise);
227
static nSettingItem<REAL> s_iSBackSpeed("CAMERA_SERVER_CUSTOM_BACK_FROMSPEED", s_serverCustomBackSpeed);
228
static nSettingItem<REAL> s_iSRiseSpeed("CAMERA_SERVER_CUSTOM_RISE_FROMSPEED", s_serverCustomRiseSpeed);
229
static nSettingItem<REAL> s_iSPitch("CAMERA_SERVER_CUSTOM_PITCH", s_serverCustomPitch);
230
static nSettingItem<REAL> s_iSCustomTurnSpeed("CAMERA_SERVER_CUSTOM_TURN_SPEED", s_serverCustomTurnSpeed);
231
static nSettingItem<REAL> s_iSCustomTurnSpeed180("CAMERA_SERVER_CUSTOM_TURN_SPEED_180", s_serverCustomTurnSpeed180);
233
// turn speed of internal camera
234
static REAL s_inTurnSpeed=40;
235
static tSettingItem<REAL> s_iInTurnSpeed("CAMERA_IN_TURN_SPEED", s_inTurnSpeed);
237
bool eCamera::InterestingToWatch(eGameObject const *g){
240
(lastTime - g->deathTime<1));
243
void eCamera::MyInit(){
245
mode=localPlayer->startCamera;
246
fov=localPlayer->startFOV;
249
// find center: the object our player controls
250
if (bool(netPlayer) && !center)
252
center = netPlayer->Object();
254
else if ( grid->gameObjectsInteresting.Len() > 0 )
256
// or an arbitrary game object
257
center = grid->gameObjectsInteresting[0];
260
// switch away from forbidden camera mode
261
if (forbid_camera[mode] && bool(netPlayer) && netPlayer->Object()==Center())
264
centerPos=eCoord(100,100);
268
centerPos = Center()->PredictPosition();
269
centerSpeedSmooth = Center()->Speed();
274
glanceDir_ = eCoord(1,0);
276
centerDirLast=centerDirSmooth=dir;
279
// foot=tNEW(eGameObject)(pos,dir,0);
281
lastrendertime=se_GameTime();
282
grid->cameras.Add(this,id);
283
// se_ResetVisibles(id);
284
smoothTurning=turning=0;
285
centerPosLast=CenterPos();
288
smartcamSkewSmooth=0;
289
smartcamIncamSmooth=1;
290
smartcamFrontSmooth=0;
292
for(int i = hitCacheSize-1; i>=0; --i)
297
case CAMERA_SERVER_CUSTOM:
303
pos=pos+dir.Turn(eCoord(s_startFollowX,s_startFollowY)) ;
307
pos=pos+dir.Turn(eCoord(s_startSmartX,s_startSmartY)) ;
311
pos=pos+dir.Turn(eCoord(s_startFreeX,s_startFreeY)) ;
318
if ( mode != CAMERA_IN && mode != CAMERA_CUSTOM && mode != CAMERA_SERVER_CUSTOM ){
320
REAL dist=REAL(sqrt(dir.NormSquared()));
321
if (dist<.001) dist=1;
323
rise=(CenterZ()-z)/dist;
326
glancingBack=glancingLeft=glancingRight=false;
327
glanceSmooth=glanceSmoothAbs=0;
332
const ePlayerNetID* eCamera::Player() const { return netPlayer; }
334
eCamera::eCamera(eGrid *g, rViewport *view,ePlayerNetID *p,
335
ePlayer *lp,eCamMode m)
336
:id(-1),grid(g),netPlayer(p),localPlayer(lp),
338
mode(m),pos(0,0),dir(1,0),top(0,0),
342
localPlayer=playerConfig[p->pID];
353
// se_cameras.Remove(this,id);
354
// se_ResetVisibles(se_cameras.Len());
355
// if (ID!=se_cameras.Len()) se_ResetVisibles(ID);
357
grid->cameras.Remove(this, id);
363
//static eGameObject *dummy=NULL;
365
eGameObject * eCamera::Center() const{
369
void eCamera::SwitchView(){
372
int count=CAMERA_COUNT * 2;
374
userCameraControl = 0;
376
// eCamMode pre=mode;
378
bool imp=true,global_imp=true,both_imp=true;
379
for (int i=CAMERA_COUNT-1;i>=0;i--){
380
if (!localPlayer || localPlayer->allowCam[i])
382
if (!forbid_camera[i] || !netPlayer || netPlayer->Object()!=Center())
384
if ((!forbid_camera[i] || !netPlayer || netPlayer->Object()!=Center())
385
&& (!localPlayer || localPlayer->allowCam[i]))
389
if (imp) con << "impossible to meet your needs.\n";
390
if (global_imp) con << "impossible to meet global needs.\n";
391
if (both_imp) con << "impossible to meet both needs.\n";
393
if (both_imp && !global_imp)
401
m = CAMERA_SERVER_CUSTOM;
402
mode = static_cast< eCamMode >( m );
406
while ((!imp && count > CAMERA_COUNT && localPlayer && !localPlayer->allowCam[mode])
407
|| (count >0 && !global_imp && forbid_camera[mode] &&
408
(bool( netPlayer ) && netPlayer->Object()==Center())));
410
if ( mode == CAMERA_IN || mode == CAMERA_CUSTOM || mode == CAMERA_SERVER_CUSTOM )
413
if(mode==CAMERA_SMART){
414
smartcamIncamSmooth=1;
416
pos=pos+dir.Turn(-1,.1);
420
bool eCamera::Act(uActionCamera *Act,REAL x){
421
eCoord objdir=CenterCamDir();
424
bool takeOverGlance = false;
425
if (eGameObject::se_turnLeft==*reinterpret_cast<uActionPlayer *>(Act)){
426
takeOverGlance = glancingLeft || glancingBack;
427
glancingBack=glancingLeft=false;
430
if (eGameObject::se_turnRight==*reinterpret_cast<uActionPlayer *>(Act)){
431
takeOverGlance = glancingRight || glancingBack;
432
glancingBack=glancingRight=false;
436
if ( takeOverGlance && /* mode != CAMERA_FOLLOW && */ mode != CAMERA_FREE )
438
// copy over position and direction, but reset glancing.
439
// this will keep the camera as it was before the turn.
440
dir = dir.Turn( glanceDir_ );
441
pos = Glance( pos, glanceDir_ );
446
eGameObject *cent=NULL;
447
if (se_GameTime() <= 0 )
449
if (netPlayer) cent=netPlayer->Object();
450
if (!InterestingToWatch(cent) && x>0)
454
REAL ll=0,lu=0,ml=0,mf=0,mu=0,zi=1;
456
if (se_lookLeft==*Act && x>0)
458
else if (se_lookRight==*Act && x>0)
460
else if (se_lookUp==*Act && x>0)
462
else if (se_lookDown==*Act && x>0)
464
else if (se_zoomIn==*Act && x>0)
466
else if (se_zoomOut==*Act && x>0)
469
else if (se_moveLeft==*Act && x>0)
471
else if (se_moveRight==*Act && x>0)
473
else if (se_moveForward==*Act && x>0)
475
else if (se_moveBack==*Act && x>0)
477
else if (se_moveUp==*Act && x>0)
479
else if (se_moveDown==*Act && x>0)
481
else if (se_switchView==*Act && x>0)
483
else if (se_glanceBack==*Act)
485
else if (se_glanceLeft==*Act)
487
else if (se_glanceRight==*Act)
493
userCameraControl+=sqrt(ll*ll+lu*lu+(1-zi)*(1-zi)+ml*ml+mf*mf+mu*mu)/20;
497
case CAMERA_SMART_IN:
503
case CAMERA_SERVER_CUSTOM:
516
// normal actions with the given data
517
dir=dir+dir.Turn(eCoord(0,ll*.2));
520
pos=pos+dir*mf*.25+dir.Turn(eCoord(0,ml*.25));
523
if (fov>120) fov=120;
530
case CAMERA_SMART_IN:
533
while (eCoord::F(dir,objdir)<-.51 && x>0){
534
dir=dir-objdir*(eCoord::F(dir,objdir)+.5);
535
dir=dir*(1/sqrt(dir.NormSquared()));
541
case CAMERA_SERVER_CUSTOM:
555
extern REAL upper_height,lower_height;
557
static bool se_ClampCamera( eCamMode mode )
559
return !(mode == CAMERA_SMART && se_GameTime() > -.5 ? se_visibilityLowerWallSmart : se_visibilityLowerWall);
562
//! Sensor class that moves the camera so the view is not blocked
563
class eCameraSensor: public eSensor
567
eCameraSensor(eGameObject *o,eCoord & camera, const eCoord & target )
568
:eSensor(o,o->Position(),camera-target), moved_(false),
569
camPos_(camera), target_(target), zLimit_(2), ratio_(0), camera_(0), lowerWall_( true )
571
#ifdef DEBUG_VISIBILITY_TARGETS
572
eDebugLine::SetColor( 1,1,1 );
573
eDebugLine::SetTimeout(.005);
574
eDebugLine::Draw( target, 0, target, 2 );
580
//! helper struct to get the best (smallest) position correction
586
//! try to improve the correction suggestion
587
void Improve( eCoord correctTo, REAL distance )
589
if ( this->distance > distance )
591
this->distance = distance;
592
this->correctTo = correctTo;
597
//! looks around the given wall (push the camera so that the ray
598
//! from the camera to the object passes beside the wall )
599
//! @param w the wall
600
//! @param direction whether to look "left" or "right" around the wall (relative to wall)
601
//! @param correction the correction suggestion to store the result in
602
//! @param heightLimit maximal height a wall may have before it counts as an obstacle
603
//! @param recursion maximum number of corners to follow the wall around
604
//! @param hardRecursion maximum number of walls to follow
605
void LookAround( eWall const * w, int direction, Correction & correction, REAL heightLimit, int recursion, int hardRecursion )
607
// abort if recursion is too deep aleready
608
if ( recursion < 0 || hardRecursion < 0 )
611
static int count = 0;
613
if ( count == 35390 )
616
// tell the wall that it is blocking the sight (if requested)
619
w->BlocksCamera( camera_, heightLimit );
622
// NULL pointer checks
623
if ( !w || !w->Edge() || !w->Edge()->Other() )
626
// project camera position a bit to the other side of the wall:
627
// get the two endpoints
628
eHalfEdge const * edge = (direction == 0 ? w->Edge() : w->Edge()->Other());
629
eCoord const & p1 = *edge->Point();
630
eCoord const & p2 = *edge->Other()->Point();
632
// it is ony valid if the order of points on an imaginary line is
633
// camPos_ -> p1 -> targtet_
634
// (otherwise, te wall is not blocking sight at all)
635
if ( !lowerWall_ && eCoord::F( camPos_ - p1, target_ - p1 ) > 0 )
638
// determine normal of target - p1 line
639
eCoord diff = target_ - p1;
641
eCoord normal = diff.Turn(0,-1);
643
// determine which side the other endpoint of the line lies on
644
REAL sideOther=eCoord::F(normal,p2-p1);
646
// find other walls that end in p1
648
bool wallContinues = false;
649
eHalfEdge const * run = edge;
656
if (!run || !run->Other() || run == edge)
659
if ( run->GetWall() || run->Other()->GetWall() )
661
// got one! determine its other entpoint
662
eCoord const & p3 = *run->Other()->Point();
664
// determine which side of the ray the other endpoint of the wall lies on
665
REAL side3=eCoord::F(normal,p3-p1);
667
// if it lies on the same side as p1, the edgepoint is an outline point
668
// and needs to be projected. If not, we need to recurse.
669
if ( side3 * sideOther < 0 )
671
wallContinues = true;
673
// only on corners the recursion level should be decreased
674
int recursion2 = recursion;
675
if ( fabs( (p2 - p1)*(p1 - p3) ) >= 10 * EPS * sqrt( (p1-p2).NormSquared() * (p1-p3).NormSquared() ) )
679
if ( run->GetWall() )
680
LookAround( run->GetWall(), 1, correction, heightLimit, recursion2, hardRecursion-1 );
681
else if ( run->Other()->GetWall() )
682
LookAround( run->Other()->GetWall(), 0, correction, heightLimit, recursion2, hardRecursion-1 );
688
// if recursion took place, don't project on this wall.
693
// No other wall found: project camera around this wall.
694
REAL side=eCoord::F(normal,camPos_-p1) * (1-ratio_);
695
correction.Improve( camPos_ - normal * side, fabs( side ) );
698
//! called when the sensor passes another wall
699
//! @param w the wall that is passed
700
//! @param time usually the game time of the event, here time simply is the fraction of the
701
//! distance from the object to the camera covered so far
702
//! @param alpha relative coordinate of the collision point on the wall
703
virtual void PassEdge(const eWall *w,REAL time,REAL alpha,int)
705
// determine the height limit (max. height at which walls will not be considered blockers)
708
objectZ = camera_->CenterCamZ() * 2;
709
REAL heightLimit = ( .5 * zLimit_ * time + objectZ * ( 1 - time ) );
711
// exit early if the wall does not obstruct view
712
if ( moved_ || !w || !owned->EdgeIsDangerous(w, time, alpha) || w->Height() <= heightLimit )
717
// project camera position a bit to the other side of the wall:
718
// get the two endpoints
719
eCoord const & p1 = w->EndPoint(0);
720
eCoord const & p2 = w->EndPoint(1);
722
// calculate wall normal
724
diff=diff*(1/w->Len());
725
eCoord normal=diff.Turn(0,-1);
728
REAL side=eCoord::F(normal,camPos_-p1);
730
// initialize correction suggestion; be very reluctant to project (it's confusing)
731
Correction correction;
732
correction.distance = fabs( side ) * 10;
733
correction.correctTo = camPos_ - normal*(side);
735
// try to look around the edge to the right and left instead
736
int recursion = lowerWall_? 0 : 2;
737
LookAround( w, 0, correction, heightLimit, recursion, 1000 );
738
LookAround( w, 1, correction, heightLimit, recursion, 1000 );
740
// execute the correction
743
moved_ = correction.distance > .001f;
744
camPos_ = correction.correctTo;
747
bool moved_; //!< flag indicating that the camera position was moved
749
inline eCameraSensor & SetZLimit( REAL const & zLimit ); //!< Sets height limit of walls to consider blockers
750
inline REAL const & GetZLimit( void ) const; //!< Gets height limit of walls to consider blockers
751
inline eCameraSensor const & GetZLimit( REAL & zLimit ) const; //!< Gets height limit of walls to consider blockers
752
inline eCameraSensor & SetRatio( REAL const & ratio ); //!< Sets mixing ratio of clipped position and old position
753
inline REAL const & GetRatio( void ) const; //!< Gets mixing ratio of clipped position and old position
754
inline eCameraSensor const & GetRatio( REAL & ratio ) const; //!< Gets mixing ratio of clipped position and old position
755
inline eCameraSensor & SetCamera( eCamera * camera ); //!< Sets the camera
756
inline eCamera * GetCamera( void ) const; //!< Gets the camera
757
inline eCameraSensor const & GetCamera( eCamera * & camera ) const; //!< Gets the camera
758
inline eCameraSensor & SetLowerWall( bool const & lowerWall ); //!< Sets flag to lower blocking walls instead of moving the camera
759
inline bool const & GetLowerWall( void ) const; //!< Gets flag to lower blocking walls instead of moving the camera
760
inline eCameraSensor const & GetLowerWall( bool & lowerWall ) const; //!< Gets flag to lower blocking walls instead of moving the camera
762
eCoord & camPos_; //!< the position of the camera
763
eCoord target_; //!< the position of the target
764
REAL zLimit_; //!< height limit of walls to consider blockers
765
REAL ratio_; //!< mixing ratio of clipped position and old position (0: perfect clipping, ->1: smooth clipping)
766
eCamera * camera_; //!< the camera
767
bool lowerWall_; //!< flag to lower blocking walls instead of moving the camera
770
// *******************************************************************************************
774
// *******************************************************************************************
776
//! @return height limit of walls to consider blockers
778
// *******************************************************************************************
780
REAL const & eCameraSensor::GetZLimit( void ) const
782
return this->zLimit_;
785
// *******************************************************************************************
789
// *******************************************************************************************
791
//! @param zLimit height limit of walls to consider blockers to fill
792
//! @return A reference to this to allow chaining
794
// *******************************************************************************************
796
eCameraSensor const & eCameraSensor::GetZLimit( REAL & zLimit ) const
798
zLimit = this->zLimit_;
802
// *******************************************************************************************
806
// *******************************************************************************************
808
//! @param zLimit height limit of walls to consider blockers to set
809
//! @return A reference to this to allow chaining
811
// *******************************************************************************************
813
eCameraSensor & eCameraSensor::SetZLimit( REAL const & zLimit )
815
this->zLimit_ = zLimit;
819
// *******************************************************************************************
823
// *******************************************************************************************
825
//! @return mixing ratio of clipped position and old position
827
// *******************************************************************************************
829
REAL const & eCameraSensor::GetRatio( void ) const
834
// *******************************************************************************************
838
// *******************************************************************************************
840
//! @param ratio mixing ratio of clipped position and old position to fill
841
//! @return A reference to this to allow chaining
843
// *******************************************************************************************
845
eCameraSensor const & eCameraSensor::GetRatio( REAL & ratio ) const
847
ratio = this->ratio_;
851
// *******************************************************************************************
855
// *******************************************************************************************
857
//! @param ratio mixing ratio of clipped position and old position to set
858
//! @return A reference to this to allow chaining
860
// *******************************************************************************************
862
eCameraSensor & eCameraSensor::SetRatio( REAL const & ratio )
864
this->ratio_ = ratio;
868
// *******************************************************************************************
872
// *******************************************************************************************
874
//! @return the camera
876
// *******************************************************************************************
878
eCamera * eCameraSensor::GetCamera( void ) const
880
return this->camera_;
883
// *******************************************************************************************
887
// *******************************************************************************************
889
//! @param camera the camera to fill
890
//! @return A reference to this to allow chaining
892
// *******************************************************************************************
894
eCameraSensor const & eCameraSensor::GetCamera( eCamera * & camera ) const
896
camera = this->camera_;
900
// *******************************************************************************************
904
// *******************************************************************************************
906
//! @param camera the camera to set
907
//! @return A reference to this to allow chaining
909
// *******************************************************************************************
911
eCameraSensor & eCameraSensor::SetCamera( eCamera * camera )
913
this->camera_ = camera;
917
// *******************************************************************************************
921
// *******************************************************************************************
923
//! @return flag to lower blocking walls instead of moving the camera
925
// *******************************************************************************************
927
bool const & eCameraSensor::GetLowerWall( void ) const
929
return this->lowerWall_;
932
// *******************************************************************************************
936
// *******************************************************************************************
938
//! @param lowerWall flag to lower blocking walls instead of moving the camera to fill
939
//! @return A reference to this to allow chaining
941
// *******************************************************************************************
943
eCameraSensor const & eCameraSensor::GetLowerWall( bool & lowerWall ) const
945
lowerWall = this->lowerWall_;
949
// *******************************************************************************************
953
// *******************************************************************************************
955
//! @param lowerWall flag to lower blocking walls instead of moving the camera to set
956
//! @return A reference to this to allow chaining
958
// *******************************************************************************************
960
eCameraSensor & eCameraSensor::SetLowerWall( bool const & lowerWall )
962
this->lowerWall_ = lowerWall;
966
// *******************************************************************************************
970
// *******************************************************************************************
976
// *******************************************************************************************
978
eCoord eCamera::Glance( eCoord const & in, eCoord const & glanceDir ) const
980
eCoord pos_diff=in-CenterPos();
981
if (mode != CAMERA_FREE)
983
pos_diff = pos_diff.Turn(glanceDir);
985
return pos_diff + CenterPos();
988
// *******************************************************************************************
992
// *******************************************************************************************
994
//! @param dt the timestep taken
996
// *******************************************************************************************
998
void eCamera::Bound( REAL dt )
1000
eCoord glancePos = Glance( pos, glanceDir_ );
1001
Bound( dt, glancePos );
1002
pos = Glance( glancePos, glanceDir_.Conj() );
1005
// *******************************************************************************************
1009
// *******************************************************************************************
1011
//! make sure CenterPos() + dirFromTarget is visible from pos
1012
//! @param ratio mixing ratio of old and best position: 0 means to take the best position, 1 to leave the old.
1013
//! @param pos the camera positon to clamp for visibility
1014
//! @param dirFromTarget the point CenterPos() + dirFromTarget is supposed to be visible
1015
//! @param hitCache if the caller persists this number, the real visibility target will not
1016
//! "snap" when it suddenly gets more room
1017
//! @return true if the camera position was moved
1019
// *******************************************************************************************
1021
bool eCamera::Bound( REAL ratio, eCoord & pos, eCoord const & dirFromTarget, REAL & hitCache )
1023
// the target position that should be visible
1024
eCoord target = CenterPos();
1026
// move it as requested, but not into walls
1027
if ( dirFromTarget.NormSquared() > 0.0001f )
1029
eSensor test( Center(), target, dirFromTarget );
1030
test.detect( hitCache );
1031
target = test.before_hit * (1-se_visibilityWallDistance) + target * se_visibilityWallDistance;
1032
hitCache = test.hit;
1035
// prepare camera clamping sensor
1036
eCameraSensor toObject( Center(), pos, target );
1037
toObject.SetZLimit( z ).SetRatio( ratio ).SetCamera( this );
1039
// if not glancing, switch from wall lowering to camera clipping if the user desires
1040
if ( !glancingBack && fabs( glanceSmooth ) < .001 )
1042
toObject.SetLowerWall( !se_ClampCamera(mode) );
1044
// clamp at outer boundary
1045
if ( !toObject.GetLowerWall() )
1047
REAL offset = rimDistance + rimDistanceHeight * z;
1048
eWallRim::Bound(pos,offset);
1053
toObject.detect( 1 );
1055
return toObject.moved_;
1058
// *******************************************************************************************
1062
// *******************************************************************************************
1064
//! @param dt the timestep taken
1065
//! @param pos the camera position to clamp for visibility
1067
// *******************************************************************************************
1069
void eCamera::Bound( REAL dt, eCoord & pos )
1071
// make sure the camera is above the floor and inside the rim eWalls
1075
// don't waste time on the internal cameras, they don't need clamping
1076
if(mode!=CAMERA_IN && mode !=CAMERA_SMART_IN )
1078
// the following is only meaningful if there is an active camera object
1081
// gently bring points in front of the cycle into view
1082
REAL smoothBound = 1/(1+se_visibilitySpeed*dt);
1083
eCoord direction = centerDirSmooth;
1084
//eCoord direction = Center()->Direction();
1085
//eCoord direction = CenterCamDir() + centerDirSmooth;
1086
direction.Normalize();
1087
// z-man: I can't yet decide which of the three direction calculations is best.
1089
Bound( smoothBound, pos, direction * ( CenterSpeed() * se_visibilityExtension ), hitCache_[0] );
1091
// Bound( smoothBound, pos, direction.Turn(se_visibilitySidewaysSkew, 1) * ( CenterSpeed() * se_visibilityExtension ), hitCache_[1] );
1092
// Bound( smoothBound, pos, direction.Turn(se_visibilitySidewaysSkew,-1) * ( CenterSpeed() * se_visibilityExtension ), hitCache_[2] );
1094
// force the object itself to be in full view, try several times
1097
while (goon && timeout > 0)
1102
REAL cache = 1; // no real cache needed here
1103
if ( Bound( 0, pos, eCoord(0,0), cache ) )
1112
if ((sr_upperSky) && z>upper_height-3)
1113
z=upper_height-3.0001;
1116
(se_BlackSky() || (sr_lowerSky && !sr_upperSky))&&
1118
z=lower_height-3.0001;
1122
bool eCamera::CenterIncamOnTurn(){
1124
return localPlayer->centerIncamOnTurn;
1128
bool eCamera::WhobbleIncam(){
1130
return localPlayer->wobbleIncam;
1134
bool eCamera::AutoSwitchIncam(){
1136
return localPlayer->autoSwitchIncam;
1141
static inline void makefinite(REAL &x,REAL y=2){if (!finite(x)) x=y;}
1142
static inline void makefinite(eCoord &x){makefinite(x.x);makefinite(x.y);}
1144
// Smart camera settings
1146
// distance scale for tests measured relative to cycle speed
1147
static REAL se_cameraSmartDistanceScale = .2;
1148
static tSettingItem< REAL > se_confCameraSmartDistanceScale( "CAMERA_SMART_DISTANCESCALE", se_cameraSmartDistanceScale );
1150
// minimal distance scale of tests in meters
1151
static REAL se_cameraSmartMinDistanceScale = 5.0;
1152
static tSettingItem< REAL > se_confCameraSmartMinDistanceScale( "CAMERA_SMART_MIN_DISTANCESCALE", se_cameraSmartMinDistanceScale );
1154
// minimal distance of the camera to the cycle in meters
1155
static REAL se_cameraSmartMinDistance = 10.0;
1156
static tSettingItem< REAL > se_confCameraSmartMinDistance( "CAMERA_SMART_MIN_DISTANCE", se_cameraSmartMinDistance );
1158
// typical cycle speed
1159
static REAL se_cameraSmartCycleSpeed = 20.0;
1160
static tSettingItem< REAL > se_confCameraSmartCycleSpeed( "CAMERA_SMART_CYCLESPEED", se_cameraSmartCycleSpeed );
1162
// typical height in speed units
1163
static REAL se_cameraSmartHeight = 2.0;
1164
static tSettingItem< REAL > se_confCameraSmartHeight( "CAMERA_SMART_HEIGHT", se_cameraSmartHeight );
1165
// typical height in speed units
1166
static REAL se_cameraSmartDistance = 4.0;
1167
static tSettingItem< REAL > se_confCameraSmartDistance( "CAMERA_SMART_DISTANCE", se_cameraSmartDistance );
1168
// extra factor for height
1169
static REAL se_cameraSmartHeightExtra = .5f;
1170
static tSettingItem< REAL > se_confCameraSmartHeightExtra( "CAMERA_SMART_HEIGHT_EXTRA", se_cameraSmartHeightExtra );
1172
// influence of turning
1173
static REAL se_cameraSmartHeightTurning = .5;
1174
static tSettingItem< REAL > se_confCameraSmartHeightTurning( "CAMERA_SMART_HEIGHT_TURNING", se_cameraSmartHeightTurning );
1176
// influence of grinding
1177
static REAL se_cameraSmartHeightGrinding = 0;
1178
static tSettingItem< REAL > se_confCameraSmartHeightGrinding( "CAMERA_SMART_HEIGHT_GRINDING", se_cameraSmartHeightGrinding );
1180
// influence of wall in front
1181
static REAL se_cameraSmartHeightObstacle = 1.0;
1182
static tSettingItem< REAL > se_confCameraSmartHeightObstacle( "CAMERA_SMART_HEIGHT_OBSTACLE", se_cameraSmartHeightObstacle );
1184
// factor moving the camera to the side if it is in front of the cycle
1185
static REAL se_cameraSmartAvoidFront = 10.0;
1186
static tSettingItem< REAL > se_confCameraSmartAvoidFront( "CAMERA_SMART_AVOID_FRONT", se_cameraSmartAvoidFront );
1188
// factor moving the camera to the side if it is in front of the cycle
1189
static REAL se_cameraSmartAvoidFront2 = 0.1;
1190
static tSettingItem< REAL > se_confCameraSmartAvoidFront2( "CAMERA_SMART_AVOID_FRONT2", se_cameraSmartAvoidFront2 );
1192
// amount of turning from grinding
1193
static REAL se_cameraSmartTurn = 5.0;
1194
static tSettingItem< REAL > se_confCameraSmartTurn( "CAMERA_SMART_TURN_GRINDING", se_cameraSmartTurn );
1196
// speed of center pos smoothing
1197
static REAL se_cameraSmartCenterPosSmooth = 6.0;
1198
static tSettingItem< REAL > se_confCameraSmartCenterPosSmooth( "CAMERA_SMART_CENTER_POS_SMOOTH", se_cameraSmartCenterPosSmooth );
1200
// speed of center dir smoothing
1201
static REAL se_cameraSmartCenterDirSmooth = 3.0;
1202
static tSettingItem< REAL > se_confCameraSmartCenterDirSmooth( "CAMERA_SMART_CENTER_DIR_SMOOTH", se_cameraSmartCenterDirSmooth );
1204
// amount of lookahead relative to speed
1205
static REAL se_cameraSmartCenterLookahead = .5;
1206
static tSettingItem< REAL > se_confCameraSmartCenterLookahead( "CAMERA_SMART_CENTER_LOOKAHEAD", se_cameraSmartCenterLookahead );
1208
// max amount of lookahead
1209
static REAL se_cameraSmartCenterMaxLookahead = 5;
1210
static tSettingItem< REAL > se_confCameraSmartCenterMaxLookahead( "CAMERA_SMART_CENTER_MAX_LOOKAHEAD", se_cameraSmartCenterMaxLookahead );
1216
static REAL se_cameraSmart =;
1217
static tSettingItem< REAL > se_confCameraSmart( "CAMERA_SMART", se_cameraSmart );
1221
bool displaying=false;
1223
void eCamera::Render(){
1231
//REAL ts=ArmageTronTimer-lastrendertime;
1232
lastrendertime=se_GameTime();
1235
makefinite(lastPos);
1240
makefinite(distance,0);
1241
makefinite(smartcamSkewSmooth);
1242
makefinite(smartcamFrontSmooth);
1243
makefinite(smartcamIncamSmooth);
1244
makefinite(centerDirSmooth);
1245
makefinite(centerPosSmooth);
1246
makefinite(centerPosLast);
1247
makefinite(centerIncam);
1248
makefinite(userCameraControl);
1249
makefinite(glanceSmooth,0);
1250
makefinite(turning);
1251
makefinite(smoothTurning);
1252
makefinite(glanceSmooth);
1254
makefinite(distance);
1255
makefinite(lastrendertime);
1258
eCoord glancedir=dir.Turn(1,glanceSmooth).Turn(1,glanceSmooth);
1259
glancedir=glancedir*(1/sqrt(glancedir.NormSquared()));
1261
glancedir=glancedir*(-1);
1263
eCoord pos_diff=pos-CenterPos();
1264
if (mode != CAMERA_FREE){
1265
pos_diff = pos_diff.Turn(dir.Conj());
1266
pos_diff = pos_diff.Turn(glancedir);
1268
pos_diff = pos_diff + CenterPos();
1271
eCoord pos_diff = Glance( pos, glanceDir_ );
1272
eCoord glancedir = dir.Turn( glanceDir_ );
1274
if (!se_ClampCamera(mode))
1282
if (rise<-100) rise=-100;
1283
if (rise>100) rise=100;
1285
// camera control logic
1291
// foot->Move(pos_diff,0,1);
1294
if (foot->currentFace)
1295
foot->currentFace->SetVisHeight(id,0);
1296
foot->Move(pos+dir*.01,0,1);
1297
if (foot->currentFace)
1298
foot->currentFace->SetVisHeight(id,0);
1301
distance+=sqrt((lastPos-pos_diff).NormSquared())*1.5;
1305
// eEdge::UpdateVisAll(id);
1308
glMatrixMode(GL_PROJECTION);
1310
glMatrixMode(GL_MODELVIEW);
1314
if(CenterCockpitFixedBefore()){
1315
vp->Perspective(fov,zNear,1E+20);
1341
glTranslatef(-pos_diff.x,-pos_diff.y,-z);
1342
glMatrixMode(GL_MODELVIEW);
1344
bool draw_center=((CenterPos()-pos).NormSquared()>1 ||
1345
fabs(CenterZ() - z)>1);
1347
tJUST_CONTROLLED_PTR< eGameObject > c=Center();
1348
if (!draw_center && c) c->RemoveFromList();
1350
eCoord poscopy = pos;
1351
zNear = - eWallRim::Bound( poscopy, 0.0f );
1355
grid->Render( this, id, zNear );
1358
if ( zNear < 0.0001f )
1363
if (c) c->RenderCockpitVirtual();
1364
if (!draw_center && c) c->AddToList();
1367
glDisable(GL_TEXTURE);
1370
glVertex3f(centerPosSmooth.x,centerPosSmooth.y,0);
1371
glVertex3f(centerPosSmooth.x,centerPosSmooth.y,10);
1375
CenterCockpitFixedAfter();
1382
void eCamera::SwitchCenter(int d){
1387
centerID = center->interestingID;
1390
if (centerID>=grid->gameObjectsInteresting.Len())
1393
centerID=grid->gameObjectsInteresting.Len()-1;
1395
int timeout=(grid->gameObjectsInteresting.Len()+1)*5;
1397
if (grid->gameObjectsInteresting.Len()>0){
1398
if (!InterestingToWatch(grid->gameObjectsInteresting(centerID)))
1399
grid->gameObjectsInteresting.Remove
1400
(grid->gameObjectsInteresting(centerID),
1401
grid->gameObjectsInteresting(centerID)->interestingID);
1407
centerID=grid->gameObjectsInteresting.Len()-1;
1408
if (centerID>=grid->gameObjectsInteresting.Len())
1411
}while(timeout >0 && grid->gameObjectsInteresting.Len()>0 &&
1413
!InterestingToWatch(grid->gameObjectsInteresting(centerID)));
1416
// con << "swtiched view from " << oldid << " to " << centerID << '\n';
1418
if ( centerID >= 0 && centerID < grid->gameObjectsInteresting.Len() )
1420
center = grid->gameObjectsInteresting(centerID);
1421
lastSwitch=lastTime;
1425
void eCamera::Timestep(REAL ts){
1427
if (!netPlayer && localPlayer)
1429
netPlayer = localPlayer->netPlayer;
1432
// the best center is always our own vehicle. Focus on it if possible.
1435
eGameObject * bestCenter = netPlayer->Object();
1436
if ( InterestingToWatch(bestCenter) )
1438
if ( bestCenter != center )
1440
center = bestCenter;
1441
// if ( mode != CAMERA_FREE )
1442
mode=localPlayer->startCamera;
1447
// determine camera custom parameters based on speed
1448
REAL customBack = 0, customRise = 0, customPitch = 0, customTurnSpeed = s_customTurnSpeed, customTurnSpeed180 = s_customTurnSpeed180;
1450
REAL speed = centerSpeedSmooth;
1451
if ( mode == CAMERA_SERVER_CUSTOM )
1453
customBack = s_serverCustomBack + speed * s_serverCustomBackSpeed;
1454
customRise = s_serverCustomRise + speed * s_serverCustomRiseSpeed;
1455
customPitch = s_serverCustomPitch;
1457
if ( s_serverCustomTurnSpeed >= 0 )
1459
customTurnSpeed = s_serverCustomTurnSpeed;
1460
customTurnSpeed180 = s_serverCustomTurnSpeed180;
1465
customBack = s_customBack + speed * s_customBackSpeed;
1466
customRise = s_customRise + speed * s_customRiseSpeed;
1467
customPitch = s_customPitch;
1471
// switch away from dead players
1472
if (lastSwitch>lastTime)
1473
lastSwitch=lastTime;
1474
if (!InterestingToWatch(Center()) && lastTime-lastSwitch>2){
1477
// Did not work as expected, more work needs to be done to reset the settings
1482
// mode=localPlayer->startCamera;
1490
// watch for turns of the center game object
1491
if ( fabs( centerDirLast * Center()->Direction() ) > .01 )
1494
centerDirLast = Center()->Direction();
1497
for(int i = hitCacheSize-1; i>=0; --i)
1499
hitCache_[i] += ts * se_hitCacheSpeed;
1500
if (hitCache_[i] > 1)
1504
// flag telling someone at the end of the function whether Bound() was already called
1507
eCoord objdir=CenterCamDir();
1509
#define GLANCE_SPEED 20
1512
glanceSmooth+=GLANCE_SPEED*ts;
1515
glanceSmooth-=GLANCE_SPEED*ts;
1517
glanceSmooth/=(1+GLANCE_SPEED*ts);
1518
glanceSmoothAbs/=(1+GLANCE_SPEED*ts);
1520
glanceDir_ = eCoord(1,glanceSmooth).Turn(1,glanceSmooth);
1521
glanceDir_.Normalize();
1523
glanceDir_=glanceDir_*(-1);
1525
// update center positions
1528
#define SMOOTH_SPEED 1
1529
centerSpeedSmooth = ( centerSpeedSmooth + Center()->Speed() * ts * SMOOTH_SPEED)/( 1 + ts * SMOOTH_SPEED );
1531
centerPos = Center()->PredictPosition();
1533
// move it a bit to the side (disabled for now, does not have the desired effect of making walls visible)
1534
//eCoord side = Center()->Direction().Turn(0,1);
1535
//REAL displace = eCoord::F( Center()->CamPos() - centerPos, side );
1536
//centerPos = centerPos + side * displace;
1538
centerPosSmooth=(centerPosSmooth+ CenterPos()*(ts*se_cameraSmartCenterPosSmooth))
1539
*(1/(1+ts*se_cameraSmartCenterPosSmooth));
1541
//centerPosSmooth=centerPosition();
1543
//REAL dist_from_center=sqrt((centerPos-pos).NormSquared()+
1544
//(CenterZ() - z)*(CenterZ() - z));
1546
if (!CenterAlive() && (mode==CAMERA_IN || mode==CAMERA_SMART_IN)){// || mode==CAMERA_CUSTOM || mode==CAMERA_SERVER_CUSTOM)){
1547
pos=pos-dir.Turn(eCoord(5,1));
1552
const REAL dirSmooth = se_cameraSmartCenterDirSmooth;
1553
centerDirSmooth=(centerDirSmooth+(CenterDir()*dirSmooth*ts))*
1554
(1/(1+dirSmooth*ts));
1556
// eCoord centerpos=centerPosSmooth+centerDirSmooth * ( this->CenterSpeed() * .05f );
1557
REAL speedFactor = se_GameTime() * this->CenterSpeed() * se_cameraSmartCenterLookahead;
1558
if ( speedFactor < 0.0f )
1562
if ( speedFactor > se_cameraSmartCenterMaxLookahead )
1564
speedFactor = se_cameraSmartCenterMaxLookahead;
1566
eCoord centerpos=centerPosSmooth + centerDirSmooth * speedFactor;
1569
#define SMART_INCAM_SPEED 1
1570
#define SMART_FRONT_SPEED 4
1572
userCameraControl/=(1+ts*5);
1573
#define maxcontrol 10
1574
if (userCameraControl>maxcontrol)
1575
userCameraControl=maxcontrol;
1577
smartcamFrontSmooth/=(1+SMART_FRONT_SPEED*ts);
1578
smartcamSkewSmooth/=(1+2*ts);
1579
smartcamIncamSmooth/=(1+SMART_INCAM_SPEED*ts);
1581
eCoord newpos=pos,newdir=dir;
1582
REAL newz=z,newrise=rise;
1584
eCoord usernewpos=pos;
1585
eCoord usernewdir=dir;
1587
REAL usernewrise=rise;
1589
REAL relax=se_cameraSmartDistance;//1 + 34/(CenterSpeed() + 1);
1590
// REAL wish_h=2*vp->UpDownFOV(fov)/60 * SpeedMultiplier();
1591
REAL wish_h=se_cameraSmartHeight*vp->UpDownFOV(fov)/60 * ( this->CenterSpeed() * .02 + SpeedMultiplier() );
1592
REAL min_dist=se_cameraSmartMinDistance;
1595
smoothTurning+=3*turning*ts;
1596
smoothTurning/=1+ts;
1599
if (smoothTurning>maxs) smoothTurning=maxs;
1606
// temporarily use free cam code if nothing interesting to watch exists
1607
eCamMode effectiveMode = mode;
1608
if (!InterestingToWatch(Center()))
1610
effectiveMode=CAMERA_FREE;
1613
switch (effectiveMode){
1620
case CAMERA_SMART_IN:
1622
case CAMERA_SERVER_CUSTOM:
1624
if (WhobbleIncam()){
1626
newpos=CenterCamPos();
1631
if (CenterIncamOnTurn() || mode==CAMERA_SMART_IN || mode == CAMERA_CUSTOM || mode == CAMERA_SERVER_CUSTOM )
1633
// fetch the relevant turning speed
1634
REAL turnSpeed = ( mode == CAMERA_IN || mode == CAMERA_SMART_IN ) ? s_inTurnSpeed : customTurnSpeed;
1636
eCoord cycleDir = CenterCycleDir();
1637
newdir=dir+cycleDir*(turnSpeed*ts);
1639
// test if we're looking against the current driving direction
1640
REAL wrongDirection = -eCoord::F( cycleDir, newdir );
1641
if ( Center() && wrongDirection > 0 )
1643
// if so, turn to the side using the last driving direction
1644
newdir = newdir + Center()->LastDirection()*(wrongDirection*ts*turnSpeed*s_customTurnSpeed180);
1650
if ( mode == CAMERA_IN || mode == CAMERA_SMART_IN )
1652
const REAL forwardCheck = .1;
1654
// cast ray forward; don't be too close to a wall
1655
eSensor forward( Center(), newpos, newdir );
1656
forward.detect( forwardCheck );
1659
REAL backwardCheck = ( forwardCheck - forward.hit ) * 2;
1660
eSensor backward( Center(), newpos, -newdir );
1661
backward.detect( backwardCheck );
1662
newpos = newpos - newdir * ( backward.hit * .5 );
1666
if (mode != CAMERA_CUSTOM && mode != CAMERA_SERVER_CUSTOM)
1670
if (newrise>2) newrise=2;
1671
if (newrise<-2) newrise=-2;
1678
if (mode==CAMERA_SMART_IN){
1681
REAL dist = CenterSpeed() * .2f;
1685
for(int i=0;i<2;i++){
1686
eSensor s(Center(),CenterPos(),CenterDir().Turn(1,2*i-1));
1690
smartcamIncamSmooth+=(space[0]+space[1])*ts*SMART_INCAM_SPEED/dist;
1692
if (smartcamIncamSmooth>.8){
1693
eSensor s(Center(),CenterPos(),CenterCycleDir());
1699
usernewpos=newpos=pos+dir.Turn(-1,.1);
1704
if (mode != CAMERA_CUSTOM && mode != CAMERA_SERVER_CUSTOM)
1707
while (eCoord::F(newdir,objdir)<-.5001 && x>0){
1708
newdir=newdir-objdir*(eCoord::F(newdir,objdir)+.5);
1709
newdir=newdir*(1/sqrt(newdir.NormSquared()));
1713
else if ( mode == CAMERA_CUSTOM || mode == CAMERA_SERVER_CUSTOM )
1715
REAL zoom = lastTime > 0 ? 1 : exp( s_customZoom * lastTime );
1717
newdir=newdir*(1/sqrt(newdir.NormSquared()));
1718
newpos = newpos - newdir * customBack * zoom;
1719
usernewpos = usernewpos + centerpos - centerPosLast;
1720
newrise = customPitch;
1721
newz = CenterCamZ() + customRise * zoom;
1727
REAL dist = CenterSpeed() * se_cameraSmartDistanceScale;
1728
if (dist < se_cameraSmartMinDistanceScale)
1729
dist = se_cameraSmartMinDistanceScale;
1733
for(int i=0;i<2;i++){
1734
eSensor s(Center(),CenterPos(),CenterDir().Turn(1,2*i-1));
1739
REAL slowFactor = this->CenterSpeed() / se_cameraSmartCycleSpeed;
1740
if ( slowFactor > 1.0f )
1745
eSensor front(Center(), CenterPos(), CenterDir());
1746
front.detect(dist * 4);
1747
REAL ff = (4 * dist - front.hit)/(3*dist);
1749
smartcamFrontSmooth+=ff*SMART_FRONT_SPEED*ts;
1751
smartcamSkewSmooth+=(space[0]-space[1])*ts * slowFactor;
1752
smartcamIncamSmooth+=(space[0]+space[1])*ts*SMART_INCAM_SPEED/dist;
1754
REAL sk = fabs(smartcamSkewSmooth)/5;
1758
REAL rf = .15+.1*smoothTurning - sk * .15 - .05 * smartcamFrontSmooth;
1764
// wish_h*=.5+1.5*smoothTurning + 2 * sk + smartcamFrontSmooth;
1765
wish_h*=se_cameraSmartHeightExtra + se_cameraSmartHeightTurning*smoothTurning + se_cameraSmartHeightGrinding * sk + smartcamFrontSmooth * se_cameraSmartHeightObstacle;
1766
min_dist/=3; // +smoothTurning;
1769
if (!CenterAlive()) wish_h+=3;
1770
REAL front=eCoord::F(pos-centerpos,CenterDir());
1771
side=((pos-centerpos)*CenterDir()) * front;
1772
//eCoord::F(pos-centerpos,CenterDir);
1773
eturn=ts/relax * (1 + .5 * smartcamFrontSmooth);
1774
if (side>0) eturn*=-1;
1778
// we do not want to look at the cycle front
1781
if (front>0){ // increase skew
1782
if (front>2.5) front=2.5;
1783
if (fabs(smartcamSkewSmooth)>1 || smartcamSkewSmooth*eturn>0)
1784
smartcamSkewSmooth*=(1+ts);
1785
if (fabs(smartcamSkewSmooth)<1)
1786
smartcamSkewSmooth -= se_cameraSmartAvoidFront * eturn;
1789
// skew = -Center()->LastDirection()*(front*dist*.2);
1792
if (se_GameTime()>0){
1793
newpos=pos + CenterDir().Turn(eCoord(0,eturn*se_cameraSmartAvoidFront2));
1794
newpos=newpos+CenterDir().Turn(0,-1)*smartcamSkewSmooth*ts*se_cameraSmartTurn;
1795
//newpos=newpos+skew*ts*5;
1796
newpos=newpos+centerpos*(ts/relax);
1797
newpos=newpos*(1/(1+ts/relax));
1800
newpos=pos+ (pos-centerpos).Turn(-ts*.5,ts*.5);
1803
if ( userCameraControl < .25 && se_ClampCamera(mode) )
1806
eCoord glancePos = Glance( newpos, glanceDir_ );
1807
Bound( ts, glancePos );
1808
newpos = Glance( glancePos, glanceDir_.Conj() );
1809
// Bound( ts, newpos );
1812
newz=newz+(CenterZ()+wish_h)*(ts/relax);
1813
newz=newz/(1+ts/relax);
1814
newdir=centerpos-newpos;
1815
REAL dist=sqrt(newdir.NormSquared());
1816
if (dist<.001) dist=.01;
1817
// newdir=dir+(centerDirSmooth*16+newdir)*ts;
1818
newdir=dir+newdir*ts*5.0;
1819
newdir=newdir*(1/sqrt(newdir.NormSquared()));
1822
//newpos=newpos-newdir*((min_dist-dist)*(min_dist-dist)*ts);
1823
REAL dz=(min_dist*min_dist-dist*dist-.5*z*z);
1828
REAL d=eCoord::F(newdir,centerpos - newpos);
1829
if (d<.0001) d=.0001;
1830
newrise=(CenterZ()-newz)/d;
1832
usernewpos=pos + centerpos - centerPosLast;
1833
// usernewdir=newdir;
1834
// usernewrise=newrise;
1836
// use custom camera settings when glancing
1837
if ( localPlayer && localPlayer->smartCustomGlance && ( glancingBack || glancingRight || glancingLeft || glanceSmoothAbs > .01 ))
1839
// update blending factor raw data
1840
REAL abs = fabs(glanceSmooth);
1841
glanceSmoothAbs = abs > glanceSmoothAbs ? abs : glanceSmoothAbs;
1843
// calculate blending factor c. c=0 will take the smart cam position, c=1 the custom cam.
1844
REAL b = 1 - glanceSmoothAbs;
1845
REAL c = 1 - b/(b + ts * GLANCE_SPEED);
1847
// override: go all the way when glancing back
1851
glanceSmoothAbs = 1;
1854
// the camera pitch is calculated anew every frame, blend it accordingly
1855
usernewrise = newrise = newrise * ( 1-glanceSmoothAbs) + customPitch * glanceSmoothAbs;
1857
// the other values are updated every frame, blend them softer
1858
if ( glancingBack || glancingRight || glancingLeft )
1860
usernewpos = newpos = pos * (1-c) + (CenterPos() - CenterCamDir() * customBack) * c;
1861
usernewz = newz = z * (1-c) + (CenterCamZ() + customRise) * c;
1863
newdir=centerpos-newpos;
1864
REAL dist=sqrt(newdir.NormSquared());
1865
if (dist<.001) dist=.01;
1866
usernewdir=newdir=newdir*(1/sqrt(newdir.NormSquared()));
1870
if (AutoSwitchIncam()){
1871
if (smartcamIncamSmooth<.7 && CenterAlive()){
1872
eSensor s(Center(),CenterPos(),CenterDir());
1875
usernewrise=newrise=0;
1876
mode=CAMERA_SMART_IN;
1877
usernewdir=newdir=objdir;
1882
if (smartcamIncamSmooth<.7)
1883
newz+=ts*(.7-smartcamIncamSmooth);
1887
case CAMERA_FOLLOW:{
1888
newpos=usernewpos=pos + centerpos - centerPosLast;
1890
newdir=centerpos-newpos;
1891
REAL dist=sqrt(newdir.NormSquared());
1892
newdir=newdir*(1/dist);
1893
newrise=(CenterZ()-newz)/dist;
1897
case CAMERA_FOLLOW:{
1898
// meriton's camera hack starts here
1899
#define mercamxydist 10
1901
eCoord t = pos - centerpos;
1903
t=t*(mercamxydist/sqrt(t.NormSquared()));
1904
newpos=usernewpos=centerpos+t;
1906
newdir=centerpos-newpos;
1908
dist=sqrt(newdir.NormSquared());
1909
newdir=newdir*(1/dist);
1910
newrise=(CenterZ()-newz)/dist; }
1918
// REAL ratio=1-exp(-100*exp(-userCameraControl)*ts);
1921
REAL ratio=1 - exp(-4*userCameraControl);
1927
// calcualte ratios under which user and automatic camera positions should be blended
1928
REAL aratio = exp(-4*userCameraControl);
1929
REAL ratio = 1 - aratio;
1932
pos=newpos*aratio + usernewpos*ratio;
1933
dir=newdir*aratio + usernewdir*ratio;
1934
z =newz *aratio + usernewz *ratio;
1936
// newrise rise is calculated anew every frame, use a different blending
1937
if (userCameraControl > .01)
1939
rise=newrise + (usernewrise-newrise)*exp(-ts/userCameraControl);
1946
// normalize direction
1947
dir=dir*(1/sqrt(dir.NormSquared()));
1949
centerPosLast=centerpos;
1951
// bound camera if that was not already done earlier
1952
if (!bound && se_ClampCamera(mode) )
1958
void eCamera::s_Timestep(eGrid *grid, REAL time){
1959
if (fabs(time-lastTime)>1) lastTime=time-.1;
1961
eDebugLine::Update(time-lastTime);
1963
for(int i=grid->cameras.Len()-1;i>=0;i--){
1964
//con << time-lastTime<< '\n';
1965
eCamera *c = grid->cameras(i);
1966
c->Timestep(time-lastTime);
1967
su_FetchAndStoreSDLInput();
1976
void eCamera::SoundMix(Uint8 *dest,unsigned int len){
1981
eGameObject *c=Center();
1982
for(int i=grid->gameObjects.Len()-1;i>=0;i--){
1983
eGameObject *go=grid->gameObjects(i);
1984
SoundMixGameObject(dest,len,go);
1987
SoundMixGameObject(dest,len,c);
1992
void eCamera::SoundMixGameObject(Uint8 *dest,unsigned int len,eGameObject *go){
1993
eCoord vec((go->pos-pos).Turn(dir.Conj()));
1994
REAL dist_squared=vec.NormSquared()+(z-go->z)*(z-go->z);
2000
REAL dist=sqrt(dist_squared);
2004
REAL l=(dist*.5+vec.y)/dist_squared;
2005
REAL r=(dist*.5-vec.y)/dist_squared;
2009
if (l>MAXVOL) l=MAXVOL;
2010
if (r>MAXVOL) r=MAXVOL;
2013
if (mode==CAMERA_IN || mode==CAMERA_SMART_IN)
2015
else if (mode!=CAMERA_FREE){
2021
go->SoundMix(dest,len,id,r,l);
2027
eCoord eCamera::CenterPos() const{
2031
eCoord eCamera::CenterCycleDir() const{
2035
eCoord eCamera::CenterDir() const{
2036
eGameObject *go=Center();
2038
return go->Direction() ;
2043
eCoord eCamera::CenterCamDir() const{
2044
eGameObject *go=Center();
2046
return go->CamDir() ;
2051
eCoord eCamera::CenterCamTop() const{
2052
eGameObject *go=Center();
2054
return go->CamTop();
2059
eCoord eCamera::CenterCamPos() const{
2060
eGameObject *go=Center();
2062
return go->CamPos();
2064
return eCoord(100,100);
2067
REAL eCamera::CenterCamZ() const{
2068
eGameObject *go=Center();
2075
REAL eCamera::CenterZ() const{
2076
eGameObject *go=Center();
2083
REAL eCamera::CenterSpeed() const{
2084
eGameObject *go=Center();
2092
bool eCamera::CenterAlive() const{
2093
eGameObject *go=Center();
2095
return go->Alive() ;
2101
bool eCamera::CenterCockpitFixedBefore() const{
2102
eGameObject *go=Center();
2104
return go->RenderCockpitFixedBefore();
2109
void eCamera::CenterCockpitFixedAfter() const{
2110
eGameObject *go=Center();
2112
go->RenderCockpitFixedAfter() ;