~swag/armagetronad/0.2.9-sty+ct+ap-fork

« back to all changes in this revision

Viewing changes to src/engine/eCamera.cpp

  • Committer: luke-jr
  • Date: 2006-05-29 01:55:42 UTC
  • Revision ID: svn-v3-list-QlpoOTFBWSZTWZvbKhsAAAdRgAAQABK6798QIABURMgAAaeoNT1TxT1DQbKaeobXKiyAmlWT7Y5MkdJOtXDtB7w7DOGFBHiOBxaUIu7HQyyQSvxdyRThQkJvbKhs:7d95bf1e-0414-0410-9756-b78462a59f44:armagetronad%2Fbranches%2F0.2.8%2Farmagetronad:4612
Unify tags/branches of modules released together

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 
 
3
*************************************************************************
 
4
 
 
5
ArmageTron -- Just another Tron Lightcycle Game in 3D.
 
6
Copyright (C) 2000  Manuel Moos (manuel@moosnet.de)
 
7
 
 
8
**************************************************************************
 
9
 
 
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.
 
14
 
 
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.
 
19
 
 
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.
 
23
  
 
24
***************************************************************************
 
25
 
 
26
*/
 
27
 
 
28
#include "rSDL.h"
 
29
 
 
30
#include "eSensor.h"
 
31
#include "eCamera.h"
 
32
#include "rScreen.h"
 
33
#include "eGameObject.h"
 
34
#include "uInputQueue.h"
 
35
//#include "eTess.h"
 
36
#include "eTimer.h"
 
37
#include "tConfiguration.h"
 
38
#include "rSysdep.h"
 
39
#include "tConsole.h"
 
40
#include "ePlayer.h"
 
41
#include "eAdvWall.h"
 
42
#include "nConfig.h"
 
43
#include "eFloor.h"
 
44
#include "eGrid.h"
 
45
#include "eDebugLine.h"
 
46
#include "tMath.h"
 
47
#include "eNetGameObject.h"
 
48
 
 
49
// camera visibility settings
 
50
static REAL se_hitCacheSpeed = 1; // the speed the hit cache for external visibility targets recovers from hits
 
51
 
 
52
static REAL se_visibilityWallDistance = .5f; // the distance the visibility targets keep from walls
 
53
 
 
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
 
59
 
 
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 );
 
67
 
 
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 );
 
70
 
 
71
// allow cameras [player independent; gets transferred over the network]
 
72
static bool forbid_camera[CAMERA_COUNT];
 
73
 
 
74
class eInitForbidCamera
 
75
{
 
76
public:
 
77
    eInitForbidCamera()
 
78
    {
 
79
        // allow all cameras
 
80
        for ( int i = CAMERA_COUNT-1; i>=0; --i )
 
81
        {
 
82
            forbid_camera[i] = false;
 
83
        }
 
84
 
 
85
        // except the server custom camera
 
86
        forbid_camera[ CAMERA_SERVER_CUSTOM ] = true;
 
87
    }
 
88
};
 
89
static eInitForbidCamera se_initForbid;
 
90
 
 
91
// forbid smart camerea
 
92
static nSettingItem<bool> a_s
 
93
("CAMERA_FORBID_SMART",
 
94
 forbid_camera[CAMERA_SMART]);
 
95
 
 
96
// forbid internal camerea
 
97
static nSettingItem<bool> a_i
 
98
("CAMERA_FORBID_IN",
 
99
 forbid_camera[CAMERA_IN]);
 
100
 
 
101
// forbid custom camerea
 
102
static nSettingItem<bool> a_c
 
103
("CAMERA_FORBID_CUSTOM",
 
104
 forbid_camera[CAMERA_CUSTOM]);
 
105
 
 
106
// forbid custom camerea
 
107
static nSettingItem<bool> a_sc
 
108
("CAMERA_FORBID_SERVER_CUSTOM",
 
109
 forbid_camera[CAMERA_SERVER_CUSTOM]);
 
110
 
 
111
// forbid free camerea
 
112
static nSettingItem<bool> a_f
 
113
("CAMERA_FORBID_FREE",
 
114
 forbid_camera[CAMERA_FREE]);
 
115
 
 
116
// forbid fixed ext. camerea
 
117
static nSettingItem<bool> a_fe
 
118
("CAMERA_FORBID_FOLLOW",
 
119
 forbid_camera[CAMERA_FOLLOW]);
 
120
 
 
121
#ifndef DEDICATED
 
122
#include "rGL.h"
 
123
#endif
 
124
 
 
125
static REAL lastTime=0;
 
126
static const REAL rimDistance = 0.01f;
 
127
static const REAL rimDistanceHeight = 0.1f;
 
128
 
 
129
REAL se_cameraRise=0;
 
130
REAL se_cameraZ=10;
 
131
 
 
132
// List<eCamera> se_cameras;
 
133
 
 
134
uActionCamera eCamera::se_moveBack("MOVE_BACK",
 
135
                                   -10,
 
136
                                   uAction::uINPUT_ANALOG);
 
137
 
 
138
uActionCamera eCamera::se_moveForward("MOVE_FORWARD",
 
139
                                      -20,
 
140
                                      uAction::uINPUT_ANALOG);
 
141
 
 
142
uActionCamera eCamera::se_moveDown("MOVE_DOWN",
 
143
                                   -30,
 
144
                                   uAction::uINPUT_ANALOG);
 
145
 
 
146
uActionCamera eCamera::se_moveUp("MOVE_UP",
 
147
                                 -40,
 
148
                                 uAction::uINPUT_ANALOG);
 
149
 
 
150
 
 
151
uActionCamera eCamera::se_moveRight("MOVE_RIGHT",
 
152
                                    -50,
 
153
                                    uAction::uINPUT_ANALOG);
 
154
 
 
155
uActionCamera eCamera::se_moveLeft("MOVE_LEFT",
 
156
                                   -60,
 
157
                                   uAction::uINPUT_ANALOG);
 
158
 
 
159
uActionCamera eCamera::se_zoomOut("ZOOM_OUT",
 
160
                                  -70,
 
161
                                  uAction::uINPUT_ANALOG);
 
162
 
 
163
uActionCamera eCamera::se_zoomIn("ZOOM_IN",
 
164
                                 -80,
 
165
                                 uAction::uINPUT_ANALOG);
 
166
 
 
167
 
 
168
uActionCamera eCamera::se_glanceBack("GLANCE_BACK",-90);
 
169
 
 
170
uActionCamera eCamera::se_glanceRight("GLANCE_RIGHT",-100);
 
171
 
 
172
uActionCamera eCamera::se_glanceLeft("GLANCE_LEFT",-110);
 
173
 
 
174
 
 
175
uActionCamera eCamera::se_lookDown("BANK_DOWN",
 
176
                                   -120,
 
177
                                   uAction::uINPUT_ANALOG);
 
178
 
 
179
uActionCamera eCamera::se_lookUp("BANK_UP",
 
180
                                 -130,
 
181
                                 uAction::uINPUT_ANALOG);
 
182
 
 
183
uActionCamera eCamera::se_lookRight("LOOK_RIGHT",
 
184
                                    -140,
 
185
                                    uAction::uINPUT_ANALOG);
 
186
 
 
187
uActionCamera eCamera::se_lookLeft("LOOK_LEFT",
 
188
                                   -150,
 
189
                                   uAction::uINPUT_ANALOG);
 
190
 
 
191
 
 
192
uActionCamera eCamera::se_switchView("SWITCH_VIEW", -160);
 
193
 
 
194
 
 
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;
 
198
 
 
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);
 
202
 
 
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);
 
206
 
 
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);
 
210
 
 
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;
 
214
 
 
215
 
 
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);
 
224
 
 
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);
 
232
 
 
233
// turn speed of internal camera
 
234
static REAL s_inTurnSpeed=40;
 
235
static tSettingItem<REAL> s_iInTurnSpeed("CAMERA_IN_TURN_SPEED", s_inTurnSpeed);
 
236
 
 
237
bool eCamera::InterestingToWatch(eGameObject const *g){
 
238
    return g &&
 
239
           (g->Alive() ||
 
240
            (lastTime - g->deathTime<1));
 
241
}
 
242
 
 
243
void eCamera::MyInit(){
 
244
    if (localPlayer){
 
245
        mode=localPlayer->startCamera;
 
246
        fov=localPlayer->startFOV;
 
247
    }
 
248
 
 
249
    // find center: the object our player controls
 
250
    if (bool(netPlayer) && !center)
 
251
    {
 
252
        center = netPlayer->Object();
 
253
    }
 
254
    else if ( grid->gameObjectsInteresting.Len() > 0 )
 
255
    {
 
256
        // or an arbitrary game object
 
257
        center = grid->gameObjectsInteresting[0];
 
258
    }
 
259
 
 
260
    // switch away from forbidden camera mode
 
261
    if (forbid_camera[mode] && bool(netPlayer) && netPlayer->Object()==Center())
 
262
        SwitchView();
 
263
 
 
264
    centerPos=eCoord(100,100);
 
265
    centerSpeedSmooth=0;
 
266
    if ( Center() )
 
267
    {
 
268
        centerPos = Center()->PredictPosition();
 
269
        centerSpeedSmooth = Center()->Speed();
 
270
    }
 
271
 
 
272
    pos=CenterPos();
 
273
    dir=CenterDir();
 
274
    glanceDir_ = eCoord(1,0);
 
275
    centerPosSmooth=pos;
 
276
    centerDirLast=centerDirSmooth=dir;
 
277
    lastPos=pos;
 
278
    zNear=0.1f;
 
279
    //  foot=tNEW(eGameObject)(pos,dir,0);
 
280
    distance=0;
 
281
    lastrendertime=se_GameTime();
 
282
    grid->cameras.Add(this,id);
 
283
    //  se_ResetVisibles(id);
 
284
    smoothTurning=turning=0;
 
285
    centerPosLast=CenterPos();
 
286
    userCameraControl=0;
 
287
    centerIncam=1;
 
288
    smartcamSkewSmooth=0;
 
289
    smartcamIncamSmooth=1;
 
290
    smartcamFrontSmooth=0;
 
291
 
 
292
    for(int i = hitCacheSize-1; i>=0; --i)
 
293
        hitCache_[i] = 1;
 
294
 
 
295
    switch (mode){
 
296
    case CAMERA_CUSTOM:
 
297
    case CAMERA_SERVER_CUSTOM:
 
298
    case CAMERA_IN:
 
299
        z=10;
 
300
        rise=0;
 
301
        break;
 
302
    case CAMERA_FOLLOW:
 
303
        pos=pos+dir.Turn(eCoord(s_startFollowX,s_startFollowY)) ;
 
304
        z=s_startFollowZ;
 
305
        break;
 
306
    case CAMERA_SMART:
 
307
        pos=pos+dir.Turn(eCoord(s_startSmartX,s_startSmartY)) ;
 
308
        z=s_startSmartZ;
 
309
        break;
 
310
    case CAMERA_FREE:
 
311
        pos=pos+dir.Turn(eCoord(s_startFreeX,s_startFreeY)) ;
 
312
        z=s_startFreeZ;
 
313
        break;
 
314
    default:
 
315
        break;
 
316
    }
 
317
 
 
318
    if ( mode != CAMERA_IN && mode != CAMERA_CUSTOM && mode != CAMERA_SERVER_CUSTOM ){
 
319
        dir=CenterPos()-pos;
 
320
        REAL dist=REAL(sqrt(dir.NormSquared()));
 
321
        if (dist<.001) dist=1;
 
322
        dir=dir*(1/dist);
 
323
        rise=(CenterZ()-z)/dist;
 
324
    }
 
325
 
 
326
    glancingBack=glancingLeft=glancingRight=false;
 
327
    glanceSmooth=glanceSmoothAbs=0;
 
328
 
 
329
    lastSwitch=-100;
 
330
}
 
331
 
 
332
const ePlayerNetID* eCamera::Player() const { return netPlayer; }
 
333
 
 
334
eCamera::eCamera(eGrid *g, rViewport *view,ePlayerNetID *p,
 
335
                 ePlayer *lp,eCamMode m)
 
336
        :id(-1),grid(g),netPlayer(p),localPlayer(lp),
 
337
        // centerID(0),
 
338
        mode(m),pos(0,0),dir(1,0),top(0,0),
 
339
vp(view){
 
340
    /*
 
341
      if (p->pID>=0)
 
342
      localPlayer=playerConfig[p->pID];
 
343
    */
 
344
    MyInit();
 
345
}
 
346
 
 
347
 
 
348
 
 
349
 
 
350
eCamera::~eCamera(){
 
351
    //  int ID=id;
 
352
    //  tDESTROY(foot);
 
353
    //  se_cameras.Remove(this,id);
 
354
    //  se_ResetVisibles(se_cameras.Len());
 
355
    //  if (ID!=se_cameras.Len()) se_ResetVisibles(ID);
 
356
 
 
357
    grid->cameras.Remove(this, id);
 
358
 
 
359
    tCHECK_DEST;
 
360
}
 
361
 
 
362
 
 
363
//static eGameObject *dummy=NULL;
 
364
 
 
365
eGameObject * eCamera::Center() const{
 
366
    return center;
 
367
}
 
368
 
 
369
void eCamera::SwitchView(){
 
370
    zNear = 0.01f;
 
371
 
 
372
    int count=CAMERA_COUNT * 2;
 
373
 
 
374
    userCameraControl = 0;
 
375
 
 
376
    //  eCamMode pre=mode;
 
377
 
 
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])
 
381
            imp=false;
 
382
        if (!forbid_camera[i] || !netPlayer || netPlayer->Object()!=Center())
 
383
            global_imp=false;
 
384
        if ((!forbid_camera[i] || !netPlayer || netPlayer->Object()!=Center())
 
385
                && (!localPlayer || localPlayer->allowCam[i]))
 
386
            both_imp=false;
 
387
    }
 
388
 
 
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";
 
392
 
 
393
    if (both_imp && !global_imp)
 
394
        imp=true;
 
395
 
 
396
    do{
 
397
        // rotate the mode
 
398
        int m = mode;
 
399
        m--;
 
400
        if ( m<0 )
 
401
            m = CAMERA_SERVER_CUSTOM;
 
402
        mode = static_cast< eCamMode >( m );
 
403
 
 
404
        count--;
 
405
    }
 
406
    while ((!imp && count > CAMERA_COUNT && localPlayer && !localPlayer->allowCam[mode])
 
407
            || (count >0 && !global_imp && forbid_camera[mode] &&
 
408
                (bool( netPlayer ) && netPlayer->Object()==Center())));
 
409
 
 
410
    if ( mode == CAMERA_IN || mode == CAMERA_CUSTOM || mode == CAMERA_SERVER_CUSTOM )
 
411
        rise=0;
 
412
 
 
413
    if(mode==CAMERA_SMART){
 
414
        smartcamIncamSmooth=1;
 
415
        z=z+1;
 
416
        pos=pos+dir.Turn(-1,.1);
 
417
    }
 
418
}
 
419
 
 
420
bool eCamera::Act(uActionCamera *Act,REAL x){
 
421
    eCoord objdir=CenterCamDir();
 
422
 
 
423
    int turn=0;
 
424
    bool takeOverGlance = false;
 
425
    if (eGameObject::se_turnLeft==*reinterpret_cast<uActionPlayer *>(Act)){
 
426
        takeOverGlance = glancingLeft || glancingBack;
 
427
        glancingBack=glancingLeft=false;
 
428
        turn=-1;
 
429
    }
 
430
    if (eGameObject::se_turnRight==*reinterpret_cast<uActionPlayer *>(Act)){
 
431
        takeOverGlance = glancingRight || glancingBack;
 
432
        glancingBack=glancingRight=false;
 
433
        turn=1;
 
434
    }
 
435
 
 
436
    if ( takeOverGlance && /* mode != CAMERA_FOLLOW && */ mode != CAMERA_FREE )
 
437
    {
 
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_ );
 
442
        glanceSmooth = 0;
 
443
    }
 
444
 
 
445
    if (turn){
 
446
        eGameObject *cent=NULL;
 
447
        if (se_GameTime() <= 0 )
 
448
            turning+=.5;
 
449
        if (netPlayer) cent=netPlayer->Object();
 
450
        if (!InterestingToWatch(cent) && x>0)
 
451
            SwitchCenter(turn);
 
452
    }
 
453
 
 
454
    REAL ll=0,lu=0,ml=0,mf=0,mu=0,zi=1;
 
455
 
 
456
    if (se_lookLeft==*Act && x>0)
 
457
        ll=x;
 
458
    else if (se_lookRight==*Act && x>0)
 
459
        ll=-x;
 
460
    else if (se_lookUp==*Act && x>0)
 
461
        lu=x;
 
462
    else if (se_lookDown==*Act && x>0)
 
463
        lu=-x;
 
464
    else if (se_zoomIn==*Act && x>0)
 
465
        zi*=1+zi*.1;
 
466
    else if (se_zoomOut==*Act && x>0)
 
467
        zi/=1+zi*.1;
 
468
 
 
469
    else if (se_moveLeft==*Act && x>0)
 
470
        ml=x;
 
471
    else if (se_moveRight==*Act && x>0)
 
472
        ml=-x;
 
473
    else if (se_moveForward==*Act && x>0)
 
474
        mf=x;
 
475
    else if (se_moveBack==*Act && x>0)
 
476
        mf=-x;
 
477
    else if (se_moveUp==*Act && x>0)
 
478
        mu=x;
 
479
    else if (se_moveDown==*Act && x>0)
 
480
        mu=-x;
 
481
    else if (se_switchView==*Act && x>0)
 
482
        SwitchView();
 
483
    else if (se_glanceBack==*Act)
 
484
        glancingBack=(x>0);
 
485
    else if (se_glanceLeft==*Act)
 
486
        glancingLeft=(x>0);
 
487
    else if (se_glanceRight==*Act)
 
488
        glancingRight=(x>0);
 
489
    else
 
490
        return false;
 
491
 
 
492
 
 
493
    userCameraControl+=sqrt(ll*ll+lu*lu+(1-zi)*(1-zi)+ml*ml+mf*mf+mu*mu)/20;
 
494
 
 
495
    switch(mode){
 
496
    case CAMERA_IN:
 
497
    case CAMERA_SMART_IN:
 
498
        lu+=mu*2;
 
499
        ll+=ml;
 
500
        mu=ml=0;
 
501
        break;
 
502
    case CAMERA_CUSTOM:
 
503
    case CAMERA_SERVER_CUSTOM:
 
504
    case CAMERA_FREE:
 
505
        break;
 
506
    case CAMERA_FOLLOW:
 
507
    case CAMERA_SMART:
 
508
        mu-=lu;
 
509
        ml-=ll;
 
510
        lu=ll=0;
 
511
        break;
 
512
    case CAMERA_COUNT:
 
513
        break;
 
514
    }
 
515
 
 
516
    // normal actions with the given data
 
517
    dir=dir+dir.Turn(eCoord(0,ll*.2));
 
518
    rise+=lu/80;
 
519
    z+=mu*.25;
 
520
    pos=pos+dir*mf*.25+dir.Turn(eCoord(0,ml*.25));
 
521
 
 
522
    fov/=zi;
 
523
    if (fov>120) fov=120;
 
524
 
 
525
    if (fov<30) fov=30;
 
526
 
 
527
 
 
528
    switch(mode){
 
529
    case CAMERA_IN:
 
530
    case CAMERA_SMART_IN:
 
531
        {
 
532
            int x=3;
 
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()));
 
536
                x--;
 
537
            }
 
538
        }
 
539
        break;
 
540
    case CAMERA_CUSTOM:
 
541
    case CAMERA_SERVER_CUSTOM:
 
542
    case CAMERA_FREE:
 
543
    case CAMERA_FOLLOW:
 
544
    case CAMERA_SMART:
 
545
        break;
 
546
    case CAMERA_COUNT:
 
547
        break;
 
548
    }
 
549
 
 
550
    Bound(0);
 
551
 
 
552
    return true;
 
553
}
 
554
 
 
555
extern REAL upper_height,lower_height;
 
556
 
 
557
static bool se_ClampCamera( eCamMode mode )
 
558
{
 
559
    return !(mode == CAMERA_SMART && se_GameTime() > -.5 ? se_visibilityLowerWallSmart : se_visibilityLowerWall);
 
560
}
 
561
 
 
562
//! Sensor class that moves the camera so the view is not blocked
 
563
class eCameraSensor: public eSensor
 
564
{
 
565
public:
 
566
    //! constructor
 
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 )
 
570
    {
 
571
#ifdef DEBUG_VISIBILITY_TARGETS
 
572
        eDebugLine::SetColor( 1,1,1 );
 
573
        eDebugLine::SetTimeout(.005);
 
574
        eDebugLine::Draw( target, 0, target, 2 );
 
575
#endif
 
576
        Move( target,0,0 );
 
577
        //clip_ = true;
 
578
    }
 
579
 
 
580
    //! helper struct to get the best (smallest) position correction
 
581
    struct Correction
 
582
    {
 
583
        eCoord correctTo;
 
584
        REAL   distance;
 
585
 
 
586
        //! try to improve the correction suggestion
 
587
        void Improve( eCoord correctTo, REAL distance )
 
588
        {
 
589
            if ( this->distance > distance )
 
590
            {
 
591
                this->distance = distance;
 
592
                this->correctTo = correctTo;
 
593
            }
 
594
        }
 
595
    };
 
596
 
 
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 )
 
606
    {
 
607
        // abort if recursion is too deep aleready
 
608
        if ( recursion < 0 || hardRecursion < 0 )
 
609
            return;
 
610
 
 
611
        static int count = 0;
 
612
        count ++;
 
613
        if ( count == 35390 )
 
614
            st_Breakpoint();
 
615
 
 
616
        // tell the wall that it is blocking the sight (if requested)
 
617
        if ( lowerWall_ )
 
618
        {
 
619
            w->BlocksCamera( camera_, heightLimit );
 
620
        }
 
621
 
 
622
        // NULL pointer checks
 
623
        if ( !w || !w->Edge() || !w->Edge()->Other() )
 
624
            return;
 
625
 
 
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();
 
631
 
 
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 )
 
636
            return;
 
637
 
 
638
        // determine normal of target - p1 line
 
639
        eCoord diff = target_ - p1;
 
640
        diff.Normalize();
 
641
        eCoord normal = diff.Turn(0,-1);
 
642
 
 
643
        // determine which side the other endpoint of the line lies on
 
644
        REAL sideOther=eCoord::F(normal,p2-p1);
 
645
 
 
646
        // find other walls that end in p1
 
647
        {
 
648
            bool wallContinues = false;
 
649
            eHalfEdge const * run = edge;
 
650
            do
 
651
            {
 
652
                run = run->Other();
 
653
                if (run)
 
654
                    run = run->Next();
 
655
 
 
656
                if (!run || !run->Other() || run == edge)
 
657
                    break;
 
658
 
 
659
                if ( run->GetWall() || run->Other()->GetWall() )
 
660
                {
 
661
                    // got one! determine its other entpoint
 
662
                    eCoord const & p3 = *run->Other()->Point();
 
663
 
 
664
                    // determine which side of the ray the other endpoint of the wall lies on
 
665
                    REAL side3=eCoord::F(normal,p3-p1);
 
666
 
 
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 )
 
670
                    {
 
671
                        wallContinues = true;
 
672
 
 
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() ) )
 
676
                            recursion2--;
 
677
 
 
678
                        // recurse
 
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 );
 
683
                    }
 
684
                }
 
685
            }
 
686
            while ( true );
 
687
 
 
688
            // if recursion took place, don't project on this wall.
 
689
            if ( wallContinues )
 
690
                return;
 
691
        }
 
692
 
 
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 ) );
 
696
    }
 
697
 
 
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)
 
704
    {
 
705
        // determine the height limit (max. height at which walls will not be considered blockers)
 
706
        REAL objectZ = 1.5;
 
707
        if ( camera_ )
 
708
            objectZ = camera_->CenterCamZ() * 2;
 
709
        REAL heightLimit = ( .5 * zLimit_ * time + objectZ * ( 1 - time ) );
 
710
 
 
711
        // exit early if the wall does not obstruct view
 
712
        if ( moved_ || !w || !owned->EdgeIsDangerous(w, time, alpha) || w->Height() <= heightLimit )
 
713
            return;
 
714
 
 
715
        heightLimit *= .5f;
 
716
 
 
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);
 
721
 
 
722
        // calculate wall normal
 
723
        eCoord diff=p2-p1;
 
724
        diff=diff*(1/w->Len());
 
725
        eCoord normal=diff.Turn(0,-1);
 
726
 
 
727
        // project
 
728
        REAL side=eCoord::F(normal,camPos_-p1);
 
729
 
 
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);
 
734
 
 
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 );
 
739
 
 
740
        // execute the correction
 
741
        if ( !lowerWall_ )
 
742
        {
 
743
            moved_ = correction.distance > .001f;
 
744
            camPos_ = correction.correctTo;
 
745
        }
 
746
    }
 
747
    bool moved_; //!< flag indicating that the camera position was moved
 
748
 
 
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
 
761
private:
 
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
 
768
};
 
769
 
 
770
// *******************************************************************************************
 
771
// *
 
772
// *   GetZLimit
 
773
// *
 
774
// *******************************************************************************************
 
775
//!
 
776
//!        @return     height limit of walls to consider blockers
 
777
//!
 
778
// *******************************************************************************************
 
779
 
 
780
REAL const & eCameraSensor::GetZLimit( void ) const
 
781
{
 
782
    return this->zLimit_;
 
783
}
 
784
 
 
785
// *******************************************************************************************
 
786
// *
 
787
// *   GetZLimit
 
788
// *
 
789
// *******************************************************************************************
 
790
//!
 
791
//!        @param  zLimit  height limit of walls to consider blockers to fill
 
792
//!      @return     A reference to this to allow chaining
 
793
//!
 
794
// *******************************************************************************************
 
795
 
 
796
eCameraSensor const & eCameraSensor::GetZLimit( REAL & zLimit ) const
 
797
{
 
798
    zLimit = this->zLimit_;
 
799
    return *this;
 
800
}
 
801
 
 
802
// *******************************************************************************************
 
803
// *
 
804
// *   SetZLimit
 
805
// *
 
806
// *******************************************************************************************
 
807
//!
 
808
//!        @param  zLimit  height limit of walls to consider blockers to set
 
809
//!       @return     A reference to this to allow chaining
 
810
//!
 
811
// *******************************************************************************************
 
812
 
 
813
eCameraSensor & eCameraSensor::SetZLimit( REAL const & zLimit )
 
814
{
 
815
    this->zLimit_ = zLimit;
 
816
    return *this;
 
817
}
 
818
 
 
819
// *******************************************************************************************
 
820
// *
 
821
// *   GetRatio
 
822
// *
 
823
// *******************************************************************************************
 
824
//!
 
825
//!        @return     mixing ratio of clipped position and old position
 
826
//!
 
827
// *******************************************************************************************
 
828
 
 
829
REAL const & eCameraSensor::GetRatio( void ) const
 
830
{
 
831
    return this->ratio_;
 
832
}
 
833
 
 
834
// *******************************************************************************************
 
835
// *
 
836
// *   GetRatio
 
837
// *
 
838
// *******************************************************************************************
 
839
//!
 
840
//!        @param  ratio   mixing ratio of clipped position and old position to fill
 
841
//!       @return     A reference to this to allow chaining
 
842
//!
 
843
// *******************************************************************************************
 
844
 
 
845
eCameraSensor const & eCameraSensor::GetRatio( REAL & ratio ) const
 
846
{
 
847
    ratio = this->ratio_;
 
848
    return *this;
 
849
}
 
850
 
 
851
// *******************************************************************************************
 
852
// *
 
853
// *   SetRatio
 
854
// *
 
855
// *******************************************************************************************
 
856
//!
 
857
//!        @param  ratio   mixing ratio of clipped position and old position to set
 
858
//!        @return     A reference to this to allow chaining
 
859
//!
 
860
// *******************************************************************************************
 
861
 
 
862
eCameraSensor & eCameraSensor::SetRatio( REAL const & ratio )
 
863
{
 
864
    this->ratio_ = ratio;
 
865
    return *this;
 
866
}
 
867
 
 
868
// *******************************************************************************************
 
869
// *
 
870
// *   GetCamera
 
871
// *
 
872
// *******************************************************************************************
 
873
//!
 
874
//!        @return     the camera
 
875
//!
 
876
// *******************************************************************************************
 
877
 
 
878
eCamera * eCameraSensor::GetCamera( void ) const
 
879
{
 
880
    return this->camera_;
 
881
}
 
882
 
 
883
// *******************************************************************************************
 
884
// *
 
885
// *   GetCamera
 
886
// *
 
887
// *******************************************************************************************
 
888
//!
 
889
//!        @param  camera  the camera to fill
 
890
//!      @return     A reference to this to allow chaining
 
891
//!
 
892
// *******************************************************************************************
 
893
 
 
894
eCameraSensor const & eCameraSensor::GetCamera( eCamera * & camera ) const
 
895
{
 
896
    camera = this->camera_;
 
897
    return *this;
 
898
}
 
899
 
 
900
// *******************************************************************************************
 
901
// *
 
902
// *   SetCamera
 
903
// *
 
904
// *******************************************************************************************
 
905
//!
 
906
//!        @param  camera  the camera to set
 
907
//!       @return     A reference to this to allow chaining
 
908
//!
 
909
// *******************************************************************************************
 
910
 
 
911
eCameraSensor & eCameraSensor::SetCamera( eCamera * camera )
 
912
{
 
913
    this->camera_ = camera;
 
914
    return *this;
 
915
}
 
916
 
 
917
// *******************************************************************************************
 
918
// *
 
919
// *   GetLowerWall
 
920
// *
 
921
// *******************************************************************************************
 
922
//!
 
923
//!        @return     flag to lower blocking walls instead of moving the camera
 
924
//!
 
925
// *******************************************************************************************
 
926
 
 
927
bool const & eCameraSensor::GetLowerWall( void ) const
 
928
{
 
929
    return this->lowerWall_;
 
930
}
 
931
 
 
932
// *******************************************************************************************
 
933
// *
 
934
// *   GetLowerWall
 
935
// *
 
936
// *******************************************************************************************
 
937
//!
 
938
//!        @param  lowerWall   flag to lower blocking walls instead of moving the camera to fill
 
939
//!       @return     A reference to this to allow chaining
 
940
//!
 
941
// *******************************************************************************************
 
942
 
 
943
eCameraSensor const & eCameraSensor::GetLowerWall( bool & lowerWall ) const
 
944
{
 
945
    lowerWall = this->lowerWall_;
 
946
    return *this;
 
947
}
 
948
 
 
949
// *******************************************************************************************
 
950
// *
 
951
// *   SetLowerWall
 
952
// *
 
953
// *******************************************************************************************
 
954
//!
 
955
//!        @param  lowerWall   flag to lower blocking walls instead of moving the camera to set
 
956
//!        @return     A reference to this to allow chaining
 
957
//!
 
958
// *******************************************************************************************
 
959
 
 
960
eCameraSensor & eCameraSensor::SetLowerWall( bool const & lowerWall )
 
961
{
 
962
    this->lowerWall_ = lowerWall;
 
963
    return *this;
 
964
}
 
965
 
 
966
// *******************************************************************************************
 
967
// *
 
968
// *   Glance
 
969
// *
 
970
// *******************************************************************************************
 
971
//!
 
972
//!        @param  in
 
973
//!        @param  glanceDir
 
974
//!        @return
 
975
//!
 
976
// *******************************************************************************************
 
977
 
 
978
eCoord eCamera::Glance( eCoord const & in, eCoord const & glanceDir ) const
 
979
{
 
980
    eCoord pos_diff=in-CenterPos();
 
981
    if (mode != CAMERA_FREE)
 
982
    {
 
983
        pos_diff = pos_diff.Turn(glanceDir);
 
984
    }
 
985
    return pos_diff + CenterPos();
 
986
}
 
987
 
 
988
// *******************************************************************************************
 
989
// *
 
990
// *   Bound
 
991
// *
 
992
// *******************************************************************************************
 
993
//!
 
994
//!        @param  dt  the timestep taken
 
995
//!
 
996
// *******************************************************************************************
 
997
 
 
998
void eCamera::Bound( REAL dt )
 
999
{
 
1000
    eCoord glancePos = Glance( pos, glanceDir_ );
 
1001
    Bound( dt, glancePos );
 
1002
    pos = Glance( glancePos, glanceDir_.Conj() );
 
1003
}
 
1004
 
 
1005
// *******************************************************************************************
 
1006
// *
 
1007
// *   Bound
 
1008
// *
 
1009
// *******************************************************************************************
 
1010
//!
 
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
 
1018
//!
 
1019
// *******************************************************************************************
 
1020
 
 
1021
bool eCamera::Bound( REAL ratio, eCoord & pos, eCoord const & dirFromTarget, REAL & hitCache )
 
1022
{
 
1023
    // the target position that should be visible
 
1024
    eCoord target = CenterPos();
 
1025
 
 
1026
    // move it as requested, but not into walls
 
1027
    if ( dirFromTarget.NormSquared() > 0.0001f )
 
1028
    {
 
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;
 
1033
    }
 
1034
 
 
1035
    // prepare camera clamping sensor
 
1036
    eCameraSensor toObject( Center(), pos, target );
 
1037
    toObject.SetZLimit( z ).SetRatio( ratio ).SetCamera( this );
 
1038
 
 
1039
    // if not glancing, switch from wall lowering to camera clipping if the user desires
 
1040
    if ( !glancingBack && fabs( glanceSmooth ) < .001 )
 
1041
    {
 
1042
        toObject.SetLowerWall( !se_ClampCamera(mode) );
 
1043
 
 
1044
        // clamp at outer boundary
 
1045
        if ( !toObject.GetLowerWall() )
 
1046
        {
 
1047
            REAL offset = rimDistance + rimDistanceHeight * z;
 
1048
            eWallRim::Bound(pos,offset);
 
1049
        }
 
1050
    }
 
1051
 
 
1052
    // execute clamping
 
1053
    toObject.detect( 1 );
 
1054
 
 
1055
    return toObject.moved_;
 
1056
}
 
1057
 
 
1058
// *******************************************************************************************
 
1059
// *
 
1060
// *   Bound
 
1061
// *
 
1062
// *******************************************************************************************
 
1063
//!
 
1064
//!        @param  dt   the timestep taken
 
1065
//!        @param  pos  the camera position to clamp for visibility
 
1066
//!
 
1067
// *******************************************************************************************
 
1068
 
 
1069
void eCamera::Bound( REAL dt, eCoord & pos )
 
1070
{
 
1071
    // make sure the camera is above the floor and inside the rim eWalls
 
1072
    if (z<.1)
 
1073
        z=.1;
 
1074
 
 
1075
    // don't waste time on the internal cameras, they don't need clamping
 
1076
    if(mode!=CAMERA_IN && mode !=CAMERA_SMART_IN )
 
1077
    {
 
1078
        // the following is only meaningful if there is an active camera object
 
1079
        if ( Center() )
 
1080
        {
 
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.
 
1088
 
 
1089
            Bound( smoothBound, pos, direction * ( CenterSpeed() * se_visibilityExtension ), hitCache_[0] );
 
1090
 
 
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] );
 
1093
 
 
1094
            // force the object itself to be in full view, try several times
 
1095
            int timeout = 4;
 
1096
            bool goon = true;
 
1097
            while (goon && timeout > 0)
 
1098
            {
 
1099
                --timeout;
 
1100
                goon = false;
 
1101
 
 
1102
                REAL cache = 1; // no real cache needed here
 
1103
                if ( Bound( 0, pos, eCoord(0,0), cache ) )
 
1104
                {
 
1105
                    goon = true;
 
1106
                    break;
 
1107
                }
 
1108
            }
 
1109
        }
 
1110
    }
 
1111
    /*
 
1112
      if ((sr_upperSky) && z>upper_height-3)
 
1113
      z=upper_height-3.0001;
 
1114
 
 
1115
      if (
 
1116
        (se_BlackSky() || (sr_lowerSky && !sr_upperSky))&& 
 
1117
        z>lower_height-3)
 
1118
        z=lower_height-3.0001;
 
1119
    */
 
1120
}
 
1121
 
 
1122
bool eCamera::CenterIncamOnTurn(){
 
1123
    if (localPlayer)
 
1124
        return localPlayer->centerIncamOnTurn;
 
1125
    else
 
1126
        return false;
 
1127
}
 
1128
bool eCamera::WhobbleIncam(){
 
1129
    if (localPlayer)
 
1130
        return localPlayer->wobbleIncam;
 
1131
    else
 
1132
        return false;
 
1133
}
 
1134
bool eCamera::AutoSwitchIncam(){
 
1135
    if (localPlayer)
 
1136
        return localPlayer->autoSwitchIncam;
 
1137
    else
 
1138
        return false;
 
1139
}
 
1140
 
 
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);}
 
1143
 
 
1144
// Smart camera settings
 
1145
 
 
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 );
 
1149
 
 
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 );
 
1153
 
 
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 );
 
1157
 
 
1158
// typical cycle speed
 
1159
static REAL se_cameraSmartCycleSpeed = 20.0;
 
1160
static tSettingItem< REAL > se_confCameraSmartCycleSpeed( "CAMERA_SMART_CYCLESPEED", se_cameraSmartCycleSpeed );
 
1161
 
 
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 );
 
1171
 
 
1172
// influence of turning
 
1173
static REAL se_cameraSmartHeightTurning = .5;
 
1174
static tSettingItem< REAL > se_confCameraSmartHeightTurning( "CAMERA_SMART_HEIGHT_TURNING", se_cameraSmartHeightTurning );
 
1175
 
 
1176
// influence of grinding
 
1177
static REAL se_cameraSmartHeightGrinding = 0;
 
1178
static tSettingItem< REAL > se_confCameraSmartHeightGrinding( "CAMERA_SMART_HEIGHT_GRINDING", se_cameraSmartHeightGrinding );
 
1179
 
 
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 );
 
1183
 
 
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 );
 
1187
 
 
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 );
 
1191
 
 
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 );
 
1195
 
 
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 );
 
1199
 
 
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 );
 
1203
 
 
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 );
 
1207
 
 
1208
// max amount of lookahead
 
1209
static REAL se_cameraSmartCenterMaxLookahead = 5;
 
1210
static tSettingItem< REAL > se_confCameraSmartCenterMaxLookahead( "CAMERA_SMART_CENTER_MAX_LOOKAHEAD", se_cameraSmartCenterMaxLookahead );
 
1211
 
 
1212
 
 
1213
/*
 
1214
 
 
1215
 
 
1216
static REAL se_cameraSmart =;
 
1217
static tSettingItem< REAL > se_confCameraSmart( "CAMERA_SMART", se_cameraSmart );
 
1218
*/
 
1219
 
 
1220
#ifndef DEDICATED
 
1221
bool displaying=false;
 
1222
 
 
1223
void eCamera::Render(){
 
1224
    if (!sr_glOut)
 
1225
        return;
 
1226
    displaying=true;
 
1227
 
 
1228
    se_cameraRise=rise;
 
1229
    se_cameraZ=z;
 
1230
 
 
1231
    //REAL  ts=ArmageTronTimer-lastrendertime;
 
1232
    lastrendertime=se_GameTime();
 
1233
 
 
1234
    makefinite(pos);
 
1235
    makefinite(lastPos);
 
1236
    makefinite(top);
 
1237
    makefinite(dir);
 
1238
    makefinite(rise,0);
 
1239
    makefinite(z,2);
 
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);
 
1253
    makefinite(fov);
 
1254
    makefinite(distance);
 
1255
    makefinite(lastrendertime);
 
1256
 
 
1257
    /*
 
1258
    eCoord glancedir=dir.Turn(1,glanceSmooth).Turn(1,glanceSmooth);
 
1259
    glancedir=glancedir*(1/sqrt(glancedir.NormSquared()));
 
1260
    if (glancingBack)
 
1261
        glancedir=glancedir*(-1);
 
1262
 
 
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);
 
1267
    }
 
1268
    pos_diff = pos_diff + CenterPos();
 
1269
    */
 
1270
 
 
1271
    eCoord pos_diff = Glance( pos, glanceDir_ );
 
1272
    eCoord glancedir = dir.Turn( glanceDir_ );
 
1273
 
 
1274
    if (!se_ClampCamera(mode))
 
1275
        Bound(0, pos_diff);
 
1276
 
 
1277
    // Bound( dt );
 
1278
 
 
1279
    if (z>400) z=300;
 
1280
    if (z<0) z=0;
 
1281
 
 
1282
    if (rise<-100) rise=-100;
 
1283
    if (rise>100) rise=100;
 
1284
 
 
1285
    // camera control logic
 
1286
    /*
 
1287
      if (center)
 
1288
      Timestep(ts);
 
1289
    */
 
1290
 
 
1291
    //  foot->Move(pos_diff,0,1);
 
1292
 
 
1293
    /*
 
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);
 
1299
    */
 
1300
 
 
1301
    distance+=sqrt((lastPos-pos_diff).NormSquared())*1.5;
 
1302
    lastPos=pos_diff;
 
1303
 
 
1304
#ifdef DEBUG
 
1305
    //  eEdge::UpdateVisAll(id);
 
1306
#endif
 
1307
 
 
1308
    glMatrixMode(GL_PROJECTION);
 
1309
    glLoadIdentity();
 
1310
    glMatrixMode(GL_MODELVIEW);
 
1311
    glLoadIdentity();
 
1312
 
 
1313
 
 
1314
    if(CenterCockpitFixedBefore()){
 
1315
        vp->Perspective(fov,zNear,1E+20);
 
1316
 
 
1317
        /*
 
1318
          gluLookAt(pos.x,
 
1319
             pos.y,
 
1320
             z,
 
1321
             
 
1322
             pos.x+dir.x,
 
1323
             pos.y+dir.y,
 
1324
             z+rise,
 
1325
             
 
1326
             top.x,top.y,
 
1327
             1);
 
1328
        */
 
1329
 
 
1330
        gluLookAt(0,
 
1331
                  0,
 
1332
                  0,
 
1333
 
 
1334
                  glancedir.x,
 
1335
                  glancedir.y,
 
1336
                  rise,
 
1337
 
 
1338
                  top.x,top.y,
 
1339
                  1);
 
1340
 
 
1341
        glTranslatef(-pos_diff.x,-pos_diff.y,-z);
 
1342
        glMatrixMode(GL_MODELVIEW);
 
1343
 
 
1344
        bool draw_center=((CenterPos()-pos).NormSquared()>1 ||
 
1345
                          fabs(CenterZ() - z)>1);
 
1346
 
 
1347
        tJUST_CONTROLLED_PTR< eGameObject > c=Center();
 
1348
        if (!draw_center && c) c->RemoveFromList();
 
1349
 
 
1350
        eCoord poscopy = pos;
 
1351
        zNear = - eWallRim::Bound( poscopy, 0.0f );
 
1352
        if (zNear < -.1 )
 
1353
            zNear = .1;
 
1354
 
 
1355
        grid->Render( this, id, zNear );
 
1356
 
 
1357
        zNear *= .3f;
 
1358
        if ( zNear < 0.0001f )
 
1359
        {
 
1360
            zNear = 0.0001f;
 
1361
        }
 
1362
 
 
1363
        if (c) c->RenderCockpitVirtual();
 
1364
        if (!draw_center && c) c->AddToList();
 
1365
 
 
1366
        /*
 
1367
          glDisable(GL_TEXTURE);
 
1368
          glColor3f(1,1,1);
 
1369
          glBegin(GL_LINES);
 
1370
          glVertex3f(centerPosSmooth.x,centerPosSmooth.y,0);
 
1371
          glVertex3f(centerPosSmooth.x,centerPosSmooth.y,10);
 
1372
          glEnd();
 
1373
        */
 
1374
 
 
1375
        CenterCockpitFixedAfter();
 
1376
    }
 
1377
    displaying=false;
 
1378
}
 
1379
 
 
1380
#endif
 
1381
 
 
1382
void eCamera::SwitchCenter(int d){
 
1383
    zNear = 0.01f;
 
1384
 
 
1385
    int centerID = 0;
 
1386
    if (center)
 
1387
        centerID = center->interestingID;
 
1388
    center = NULL;
 
1389
 
 
1390
    if (centerID>=grid->gameObjectsInteresting.Len())
 
1391
        centerID=0;
 
1392
    if (centerID<0)
 
1393
        centerID=grid->gameObjectsInteresting.Len()-1;
 
1394
 
 
1395
    int timeout=(grid->gameObjectsInteresting.Len()+1)*5;
 
1396
    int oldid=centerID;
 
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);
 
1402
        do{
 
1403
            timeout--;
 
1404
            centerID+=d;
 
1405
 
 
1406
            if (centerID<0)
 
1407
                centerID=grid->gameObjectsInteresting.Len()-1;
 
1408
            if (centerID>=grid->gameObjectsInteresting.Len())
 
1409
                centerID=0;
 
1410
 
 
1411
        }while(timeout >0 && grid->gameObjectsInteresting.Len()>0 &&
 
1412
                oldid!=centerID &&
 
1413
                !InterestingToWatch(grid->gameObjectsInteresting(centerID)));
 
1414
    }
 
1415
    else centerID=0;
 
1416
    // con << "swtiched view from " << oldid << " to " << centerID << '\n';
 
1417
 
 
1418
    if ( centerID >= 0 && centerID < grid->gameObjectsInteresting.Len() )
 
1419
    {
 
1420
        center = grid->gameObjectsInteresting(centerID);
 
1421
        lastSwitch=lastTime;
 
1422
    }
 
1423
}
 
1424
 
 
1425
void eCamera::Timestep(REAL ts){
 
1426
    // find net player
 
1427
    if (!netPlayer && localPlayer)
 
1428
    {
 
1429
        netPlayer = localPlayer->netPlayer;
 
1430
    }
 
1431
 
 
1432
    // the best center is always our own vehicle. Focus on it if possible.
 
1433
    if (netPlayer)
 
1434
    {
 
1435
        eGameObject * bestCenter = netPlayer->Object();
 
1436
        if ( InterestingToWatch(bestCenter) )
 
1437
        {
 
1438
            if ( bestCenter != center )
 
1439
            {
 
1440
                center = bestCenter;
 
1441
                // if ( mode != CAMERA_FREE )
 
1442
                mode=localPlayer->startCamera;
 
1443
            }
 
1444
        }
 
1445
    }
 
1446
 
 
1447
    // determine camera custom parameters based on speed
 
1448
    REAL customBack = 0, customRise = 0, customPitch = 0, customTurnSpeed = s_customTurnSpeed, customTurnSpeed180 = s_customTurnSpeed180;
 
1449
    {
 
1450
        REAL speed = centerSpeedSmooth;
 
1451
        if ( mode == CAMERA_SERVER_CUSTOM )
 
1452
        {
 
1453
            customBack = s_serverCustomBack + speed * s_serverCustomBackSpeed;
 
1454
            customRise = s_serverCustomRise + speed * s_serverCustomRiseSpeed;
 
1455
            customPitch = s_serverCustomPitch;
 
1456
 
 
1457
            if ( s_serverCustomTurnSpeed >= 0 )
 
1458
            {
 
1459
                customTurnSpeed = s_serverCustomTurnSpeed;
 
1460
                customTurnSpeed180 = s_serverCustomTurnSpeed180;
 
1461
            }
 
1462
        }
 
1463
        else
 
1464
        {
 
1465
            customBack = s_customBack + speed * s_customBackSpeed;
 
1466
            customRise = s_customRise + speed * s_customRiseSpeed;
 
1467
            customPitch = s_customPitch;
 
1468
        }
 
1469
    }
 
1470
 
 
1471
    // switch away from dead players
 
1472
    if (lastSwitch>lastTime)
 
1473
        lastSwitch=lastTime;
 
1474
    if (!InterestingToWatch(Center()) && lastTime-lastSwitch>2){
 
1475
        SwitchCenter(1);
 
1476
 
 
1477
        // Did not work as expected, more work needs to be done to reset the settings
 
1478
        //        else
 
1479
        //        {
 
1480
        //            if (localPlayer)
 
1481
        //            {
 
1482
        //                mode=localPlayer->startCamera;
 
1483
        //            }
 
1484
        //        }
 
1485
    }
 
1486
 
 
1487
    if (!Center())
 
1488
        return;
 
1489
 
 
1490
    // watch for turns of the center game object
 
1491
    if ( fabs( centerDirLast * Center()->Direction() ) > .01 )
 
1492
    {
 
1493
        turning+=.5;
 
1494
        centerDirLast = Center()->Direction();
 
1495
    }
 
1496
 
 
1497
    for(int i = hitCacheSize-1; i>=0; --i)
 
1498
    {
 
1499
        hitCache_[i] += ts * se_hitCacheSpeed;
 
1500
        if (hitCache_[i] > 1)
 
1501
            hitCache_[i] = 1;
 
1502
    }
 
1503
 
 
1504
    // flag telling someone at the end of the function whether Bound() was already called
 
1505
    bool bound = false;
 
1506
 
 
1507
    eCoord objdir=CenterCamDir();
 
1508
 
 
1509
#define GLANCE_SPEED 20
 
1510
 
 
1511
    if (glancingLeft)
 
1512
        glanceSmooth+=GLANCE_SPEED*ts;
 
1513
 
 
1514
    if (glancingRight)
 
1515
        glanceSmooth-=GLANCE_SPEED*ts;
 
1516
 
 
1517
    glanceSmooth/=(1+GLANCE_SPEED*ts);
 
1518
    glanceSmoothAbs/=(1+GLANCE_SPEED*ts);
 
1519
 
 
1520
    glanceDir_ = eCoord(1,glanceSmooth).Turn(1,glanceSmooth);
 
1521
    glanceDir_.Normalize();
 
1522
    if (glancingBack)
 
1523
        glanceDir_=glanceDir_*(-1);
 
1524
 
 
1525
    // update center positions
 
1526
    if ( Center() )
 
1527
    {
 
1528
        #define SMOOTH_SPEED 1
 
1529
        centerSpeedSmooth = ( centerSpeedSmooth + Center()->Speed() * ts * SMOOTH_SPEED)/( 1 + ts * SMOOTH_SPEED );
 
1530
 
 
1531
        centerPos = Center()->PredictPosition();
 
1532
 
 
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;
 
1537
    }
 
1538
    centerPosSmooth=(centerPosSmooth+ CenterPos()*(ts*se_cameraSmartCenterPosSmooth))
 
1539
                    *(1/(1+ts*se_cameraSmartCenterPosSmooth));
 
1540
 
 
1541
    //centerPosSmooth=centerPosition();
 
1542
 
 
1543
    //REAL dist_from_center=sqrt((centerPos-pos).NormSquared()+
 
1544
    //(CenterZ() - z)*(CenterZ() - z));
 
1545
 
 
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));
 
1548
        z+=2;
 
1549
        mode=CAMERA_SMART;
 
1550
    }
 
1551
 
 
1552
    const REAL dirSmooth = se_cameraSmartCenterDirSmooth;
 
1553
    centerDirSmooth=(centerDirSmooth+(CenterDir()*dirSmooth*ts))*
 
1554
                    (1/(1+dirSmooth*ts));
 
1555
 
 
1556
    //  eCoord centerpos=centerPosSmooth+centerDirSmooth * ( this->CenterSpeed() * .05f );
 
1557
    REAL speedFactor = se_GameTime() * this->CenterSpeed() * se_cameraSmartCenterLookahead;
 
1558
    if ( speedFactor < 0.0f )
 
1559
    {
 
1560
        speedFactor = 0.0f;
 
1561
    }
 
1562
    if ( speedFactor > se_cameraSmartCenterMaxLookahead )
 
1563
    {
 
1564
        speedFactor = se_cameraSmartCenterMaxLookahead;
 
1565
    }
 
1566
    eCoord centerpos=centerPosSmooth + centerDirSmooth * speedFactor;
 
1567
 
 
1568
 
 
1569
#define SMART_INCAM_SPEED 1
 
1570
#define SMART_FRONT_SPEED 4
 
1571
 
 
1572
    userCameraControl/=(1+ts*5);
 
1573
#define maxcontrol 10
 
1574
    if (userCameraControl>maxcontrol)
 
1575
        userCameraControl=maxcontrol;
 
1576
 
 
1577
    smartcamFrontSmooth/=(1+SMART_FRONT_SPEED*ts);
 
1578
    smartcamSkewSmooth/=(1+2*ts);
 
1579
    smartcamIncamSmooth/=(1+SMART_INCAM_SPEED*ts);
 
1580
 
 
1581
    eCoord newpos=pos,newdir=dir;
 
1582
    REAL newz=z,newrise=rise;
 
1583
 
 
1584
    eCoord usernewpos=pos;
 
1585
    eCoord usernewdir=dir;
 
1586
    REAL usernewz=z;
 
1587
    REAL usernewrise=rise;
 
1588
 
 
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;
 
1593
 
 
1594
    turning/=(1+2*ts);
 
1595
    smoothTurning+=3*turning*ts;
 
1596
    smoothTurning/=1+ts;
 
1597
 
 
1598
#define maxs 5
 
1599
    if (smoothTurning>maxs) smoothTurning=maxs;
 
1600
 
 
1601
    REAL side;
 
1602
    REAL eturn;
 
1603
 
 
1604
    top=eCoord(0,0);
 
1605
 
 
1606
    // temporarily use free cam code if nothing interesting to watch exists
 
1607
    eCamMode effectiveMode = mode;
 
1608
    if (!InterestingToWatch(Center()))
 
1609
    {
 
1610
        effectiveMode=CAMERA_FREE;
 
1611
    }
 
1612
 
 
1613
    switch (effectiveMode){
 
1614
    case CAMERA_FREE:
 
1615
        newpos=pos;
 
1616
        newdir=dir;
 
1617
        newz=z;
 
1618
        newrise=rise;
 
1619
        break;
 
1620
    case CAMERA_SMART_IN:
 
1621
    case CAMERA_CUSTOM:
 
1622
    case CAMERA_SERVER_CUSTOM:
 
1623
    case CAMERA_IN:
 
1624
        if (WhobbleIncam()){
 
1625
            top=CenterCamTop();
 
1626
            newpos=CenterCamPos();
 
1627
        }
 
1628
        else
 
1629
            newpos=CenterPos();
 
1630
 
 
1631
        if (CenterIncamOnTurn() || mode==CAMERA_SMART_IN || mode == CAMERA_CUSTOM || mode == CAMERA_SERVER_CUSTOM )
 
1632
        {
 
1633
            // fetch the relevant turning speed
 
1634
            REAL turnSpeed = ( mode == CAMERA_IN || mode == CAMERA_SMART_IN ) ? s_inTurnSpeed : customTurnSpeed;
 
1635
 
 
1636
            eCoord cycleDir = CenterCycleDir();
 
1637
            newdir=dir+cycleDir*(turnSpeed*ts);
 
1638
 
 
1639
            // test if we're looking against the current driving direction
 
1640
            REAL wrongDirection = -eCoord::F( cycleDir, newdir );
 
1641
            if ( Center() &&  wrongDirection > 0 )
 
1642
            {
 
1643
                // if so, turn to the side using the last driving direction
 
1644
                newdir = newdir + Center()->LastDirection()*(wrongDirection*ts*turnSpeed*s_customTurnSpeed180);
 
1645
            }
 
1646
        }
 
1647
        else
 
1648
            newdir=dir;
 
1649
 
 
1650
        if ( mode == CAMERA_IN || mode == CAMERA_SMART_IN )
 
1651
        {
 
1652
            const REAL forwardCheck = .1;
 
1653
 
 
1654
            // cast ray forward; don't be too close to a wall
 
1655
            eSensor forward( Center(), newpos, newdir );
 
1656
            forward.detect( forwardCheck );
 
1657
            if ( forward.ehit )
 
1658
            {
 
1659
                REAL backwardCheck = ( forwardCheck - forward.hit ) * 2;
 
1660
                eSensor backward( Center(), newpos, -newdir );
 
1661
                backward.detect( backwardCheck );
 
1662
                newpos = newpos - newdir * ( backward.hit * .5 );
 
1663
            }
 
1664
        }
 
1665
 
 
1666
        if (mode != CAMERA_CUSTOM && mode != CAMERA_SERVER_CUSTOM)
 
1667
        {
 
1668
            newz=CenterCamZ();
 
1669
            newrise=rise;
 
1670
            if (newrise>2) newrise=2;
 
1671
            if (newrise<-2) newrise=-2;
 
1672
 
 
1673
            usernewpos=newpos;
 
1674
            usernewz=newz;
 
1675
        }
 
1676
 
 
1677
 
 
1678
        if (mode==CAMERA_SMART_IN){
 
1679
            REAL space[2];
 
1680
 
 
1681
            REAL dist = CenterSpeed() * .2f;
 
1682
            if (dist < 5)
 
1683
                dist = 5;
 
1684
 
 
1685
            for(int i=0;i<2;i++){
 
1686
                eSensor s(Center(),CenterPos(),CenterDir().Turn(1,2*i-1));
 
1687
                s.detect(dist);
 
1688
                space[i]=s.hit;
 
1689
            }
 
1690
            smartcamIncamSmooth+=(space[0]+space[1])*ts*SMART_INCAM_SPEED/dist;
 
1691
 
 
1692
            if (smartcamIncamSmooth>.8){
 
1693
                eSensor s(Center(),CenterPos(),CenterCycleDir());
 
1694
                s.detect(5.5);
 
1695
 
 
1696
                if (s.hit>5){
 
1697
                    mode=CAMERA_SMART;
 
1698
                    usernewz=newz=z+.5;
 
1699
                    usernewpos=newpos=pos+dir.Turn(-1,.1);
 
1700
                }
 
1701
            }
 
1702
        }
 
1703
 
 
1704
        if (mode != CAMERA_CUSTOM && mode != CAMERA_SERVER_CUSTOM)
 
1705
        {
 
1706
            int x=3;
 
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()));
 
1710
                x--;
 
1711
            }
 
1712
        }
 
1713
        else if ( mode == CAMERA_CUSTOM || mode == CAMERA_SERVER_CUSTOM )
 
1714
        {
 
1715
            REAL zoom = lastTime > 0 ? 1 : exp( s_customZoom * lastTime );
 
1716
 
 
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;
 
1722
        }
 
1723
 
 
1724
        break;
 
1725
    case CAMERA_SMART:
 
1726
        {
 
1727
            REAL dist = CenterSpeed() * se_cameraSmartDistanceScale;
 
1728
            if (dist < se_cameraSmartMinDistanceScale)
 
1729
                dist = se_cameraSmartMinDistanceScale;
 
1730
 
 
1731
            REAL space[2];
 
1732
 
 
1733
            for(int i=0;i<2;i++){
 
1734
                eSensor s(Center(),CenterPos(),CenterDir().Turn(1,2*i-1));
 
1735
                s.detect(dist);
 
1736
                space[i]=s.hit;
 
1737
            }
 
1738
 
 
1739
            REAL slowFactor = this->CenterSpeed() / se_cameraSmartCycleSpeed;
 
1740
            if ( slowFactor > 1.0f )
 
1741
            {
 
1742
                slowFactor = 1.0f;
 
1743
            }
 
1744
 
 
1745
            eSensor front(Center(), CenterPos(), CenterDir());
 
1746
            front.detect(dist * 4);
 
1747
            REAL ff = (4 * dist - front.hit)/(3*dist);
 
1748
            ff *= ff;
 
1749
            smartcamFrontSmooth+=ff*SMART_FRONT_SPEED*ts;
 
1750
 
 
1751
            smartcamSkewSmooth+=(space[0]-space[1])*ts * slowFactor;
 
1752
            smartcamIncamSmooth+=(space[0]+space[1])*ts*SMART_INCAM_SPEED/dist;
 
1753
 
 
1754
            REAL sk = fabs(smartcamSkewSmooth)/5;
 
1755
            if (sk > 1)
 
1756
                sk = 1;
 
1757
 
 
1758
            REAL rf = .15+.1*smoothTurning - sk * .15 - .05 * smartcamFrontSmooth;
 
1759
            if (rf < .05)
 
1760
                rf = .05;
 
1761
 
 
1762
            relax*=rf;
 
1763
            relax/=slowFactor;
 
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;
 
1767
 
 
1768
            {
 
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;
 
1775
 
 
1776
                newz=z;
 
1777
 
 
1778
                // we do not want to look at the cycle front
 
1779
 
 
1780
                //eCoord skew;
 
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;
 
1787
                    newz+=ts*front*.1;
 
1788
                    //if ( Center() )
 
1789
                    //    skew = -Center()->LastDirection()*(front*dist*.2);
 
1790
                }
 
1791
 
 
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));
 
1798
                }
 
1799
                else{
 
1800
                    newpos=pos+ (pos-centerpos).Turn(-ts*.5,ts*.5);
 
1801
                }
 
1802
 
 
1803
                if ( userCameraControl < .25  && se_ClampCamera(mode) )
 
1804
                {
 
1805
                    bound = true;
 
1806
                    eCoord glancePos = Glance( newpos, glanceDir_ );
 
1807
                    Bound( ts, glancePos );
 
1808
                    newpos = Glance( glancePos, glanceDir_.Conj() );
 
1809
                    // Bound( ts, newpos );
 
1810
                }
 
1811
 
 
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()));
 
1820
 
 
1821
                if (dist<min_dist){
 
1822
                    //newpos=newpos-newdir*((min_dist-dist)*(min_dist-dist)*ts);
 
1823
                    REAL dz=(min_dist*min_dist-dist*dist-.5*z*z);
 
1824
                    if (dz>0)
 
1825
                        newz+=dz*ts;
 
1826
                }
 
1827
 
 
1828
                REAL d=eCoord::F(newdir,centerpos - newpos);
 
1829
                if (d<.0001) d=.0001;
 
1830
                newrise=(CenterZ()-newz)/d;
 
1831
 
 
1832
                usernewpos=pos + centerpos - centerPosLast;
 
1833
                // usernewdir=newdir;
 
1834
                // usernewrise=newrise;
 
1835
 
 
1836
                // use custom camera settings when glancing
 
1837
                if ( localPlayer && localPlayer->smartCustomGlance && ( glancingBack || glancingRight || glancingLeft || glanceSmoothAbs > .01 ))
 
1838
                {
 
1839
                    // update blending factor raw data
 
1840
                    REAL abs = fabs(glanceSmooth);
 
1841
                    glanceSmoothAbs = abs > glanceSmoothAbs ? abs : glanceSmoothAbs;
 
1842
 
 
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);
 
1846
 
 
1847
                    // override: go all the way when glancing back
 
1848
                    if ( glancingBack )
 
1849
                    {
 
1850
                        c = 1;
 
1851
                        glanceSmoothAbs = 1;
 
1852
                    }
 
1853
 
 
1854
                    // the camera pitch is calculated anew every frame, blend it accordingly
 
1855
                    usernewrise = newrise = newrise * ( 1-glanceSmoothAbs) + customPitch * glanceSmoothAbs;
 
1856
 
 
1857
                    // the other values are updated every frame, blend them softer
 
1858
                    if ( glancingBack || glancingRight || glancingLeft )
 
1859
                    {
 
1860
                        usernewpos  =  newpos = pos * (1-c) + (CenterPos() - CenterCamDir() * customBack) * c;
 
1861
                        usernewz    = newz    = z * (1-c) + (CenterCamZ() + customRise) * c;
 
1862
 
 
1863
                        newdir=centerpos-newpos;
 
1864
                        REAL dist=sqrt(newdir.NormSquared());
 
1865
                        if (dist<.001) dist=.01;
 
1866
                        usernewdir=newdir=newdir*(1/sqrt(newdir.NormSquared()));
 
1867
                    }
 
1868
                }
 
1869
 
 
1870
                if (AutoSwitchIncam()){
 
1871
                    if (smartcamIncamSmooth<.7 && CenterAlive()){
 
1872
                        eSensor s(Center(),CenterPos(),CenterDir());
 
1873
                        s.detect(5.5);
 
1874
                        if (s.hit>5){
 
1875
                            usernewrise=newrise=0;
 
1876
                            mode=CAMERA_SMART_IN;
 
1877
                            usernewdir=newdir=objdir;
 
1878
                        }
 
1879
                    }
 
1880
                }
 
1881
                else
 
1882
                    if (smartcamIncamSmooth<.7)
 
1883
                        newz+=ts*(.7-smartcamIncamSmooth);
 
1884
            }
 
1885
        }
 
1886
        break;
 
1887
    case CAMERA_FOLLOW:{
 
1888
            newpos=usernewpos=pos + centerpos - centerPosLast;
 
1889
            newz=z;
 
1890
            newdir=centerpos-newpos;
 
1891
            REAL dist=sqrt(newdir.NormSquared());
 
1892
            newdir=newdir*(1/dist);
 
1893
            newrise=(CenterZ()-newz)/dist;
 
1894
        }
 
1895
        break;
 
1896
        /*
 
1897
        case CAMERA_FOLLOW:{
 
1898
           // meriton's camera hack starts here
 
1899
        #define mercamxydist 10 
 
1900
        #define mercamz 5 
 
1901
           eCoord t = pos - centerpos;
 
1902
 
 
1903
           t=t*(mercamxydist/sqrt(t.NormSquared()));
 
1904
           newpos=usernewpos=centerpos+t;
 
1905
           newz=mercamz; //z;
 
1906
           newdir=centerpos-newpos;
 
1907
           REAL
 
1908
           dist=sqrt(newdir.NormSquared());
 
1909
           newdir=newdir*(1/dist);
 
1910
           newrise=(CenterZ()-newz)/dist;       }
 
1911
        break;
 
1912
        */
 
1913
    default:
 
1914
        break;
 
1915
    }
 
1916
 
 
1917
 
 
1918
    // REAL ratio=1-exp(-100*exp(-userCameraControl)*ts);
 
1919
 
 
1920
    /*
 
1921
      REAL ratio=1 - exp(-4*userCameraControl);
 
1922
      ratio*=ts;
 
1923
      ratio*=100;
 
1924
      ratio=exp(-ratio);
 
1925
    */
 
1926
 
 
1927
    // calcualte ratios under which user and automatic camera positions should be blended
 
1928
    REAL aratio = exp(-4*userCameraControl);
 
1929
    REAL ratio = 1 - aratio;
 
1930
 
 
1931
    // blend
 
1932
    pos=newpos*aratio + usernewpos*ratio;
 
1933
    dir=newdir*aratio + usernewdir*ratio;
 
1934
    z  =newz  *aratio + usernewz  *ratio;
 
1935
 
 
1936
    // newrise rise is calculated anew every frame, use a different blending
 
1937
    if (userCameraControl > .01)
 
1938
    {
 
1939
        rise=newrise + (usernewrise-newrise)*exp(-ts/userCameraControl);
 
1940
    }
 
1941
    else
 
1942
    {
 
1943
        rise=newrise;
 
1944
    }
 
1945
 
 
1946
    // normalize direction
 
1947
    dir=dir*(1/sqrt(dir.NormSquared()));
 
1948
 
 
1949
    centerPosLast=centerpos;
 
1950
 
 
1951
    // bound camera if that was not already done earlier
 
1952
    if (!bound && se_ClampCamera(mode) )
 
1953
        Bound( ts );
 
1954
}
 
1955
 
 
1956
 
 
1957
 
 
1958
void eCamera::s_Timestep(eGrid *grid, REAL time){
 
1959
    if (fabs(time-lastTime)>1) lastTime=time-.1;
 
1960
    if (time>lastTime){
 
1961
        eDebugLine::Update(time-lastTime);
 
1962
 
 
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();
 
1968
        }
 
1969
        lastTime=time;
 
1970
    }
 
1971
}
 
1972
 
 
1973
 
 
1974
#ifndef DEDICATED
 
1975
 
 
1976
void eCamera::SoundMix(Uint8 *dest,unsigned int len){
 
1977
    if (!this)
 
1978
        return;
 
1979
 
 
1980
    if (id>=0){
 
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);
 
1985
        }
 
1986
        if (c && c->id<0)
 
1987
            SoundMixGameObject(dest,len,c);
 
1988
    }
 
1989
}
 
1990
 
 
1991
 
 
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);
 
1995
 
 
1996
    //dist_squared*=.1;
 
1997
    if (dist_squared<1)
 
1998
        dist_squared=1;
 
1999
 
 
2000
    REAL dist=sqrt(dist_squared);
 
2001
 
 
2002
#define MAXVOL .4
 
2003
 
 
2004
    REAL l=(dist*.5+vec.y)/dist_squared;
 
2005
    REAL r=(dist*.5-vec.y)/dist_squared;
 
2006
 
 
2007
    if (l<0) l=0;
 
2008
    if (r<0) r=0;
 
2009
    if (l>MAXVOL) l=MAXVOL;
 
2010
    if (r>MAXVOL) r=MAXVOL;
 
2011
 
 
2012
    if (go==Center()){
 
2013
        if (mode==CAMERA_IN || mode==CAMERA_SMART_IN)
 
2014
            l=r=.2;
 
2015
        else if (mode!=CAMERA_FREE){
 
2016
            l*=.9;
 
2017
            r*=.9;
 
2018
        }
 
2019
    }
 
2020
 
 
2021
    go->SoundMix(dest,len,id,r,l);
 
2022
}
 
2023
 
 
2024
 
 
2025
#endif
 
2026
 
 
2027
eCoord eCamera::CenterPos() const{
 
2028
    return centerPos;
 
2029
}
 
2030
 
 
2031
eCoord eCamera::CenterCycleDir() const{
 
2032
    return CenterDir();
 
2033
}
 
2034
 
 
2035
eCoord eCamera::CenterDir() const{
 
2036
    eGameObject *go=Center();
 
2037
    if (go)
 
2038
        return go->Direction() ;
 
2039
    else
 
2040
        return eCoord(1,0);
 
2041
}
 
2042
 
 
2043
eCoord eCamera::CenterCamDir() const{
 
2044
    eGameObject *go=Center();
 
2045
    if (go)
 
2046
        return go->CamDir() ;
 
2047
    else
 
2048
        return eCoord(1,0);
 
2049
}
 
2050
 
 
2051
eCoord eCamera::CenterCamTop() const{
 
2052
    eGameObject *go=Center();
 
2053
    if (go)
 
2054
        return go->CamTop();
 
2055
    else
 
2056
        return eCoord(0,0);
 
2057
}
 
2058
 
 
2059
eCoord eCamera::CenterCamPos() const{
 
2060
    eGameObject *go=Center();
 
2061
    if (go)
 
2062
        return go->CamPos();
 
2063
    else
 
2064
        return eCoord(100,100);
 
2065
}
 
2066
 
 
2067
REAL  eCamera::CenterCamZ() const{
 
2068
    eGameObject *go=Center();
 
2069
    if (go)
 
2070
        return go-> CamZ();
 
2071
    else
 
2072
        return 1.5;
 
2073
}
 
2074
 
 
2075
REAL  eCamera::CenterZ() const{
 
2076
    eGameObject *go=Center();
 
2077
    if (go)
 
2078
        return go->z ;
 
2079
    else
 
2080
        return 1.5;
 
2081
}
 
2082
 
 
2083
REAL  eCamera::CenterSpeed() const{
 
2084
    eGameObject *go=Center();
 
2085
    if (go)
 
2086
        return go->Speed();
 
2087
    else
 
2088
        return 20;
 
2089
}
 
2090
 
 
2091
 
 
2092
bool eCamera::CenterAlive() const{
 
2093
    eGameObject *go=Center();
 
2094
    if (go)
 
2095
        return go->Alive() ;
 
2096
    else
 
2097
        return false;
 
2098
}
 
2099
 
 
2100
 
 
2101
bool eCamera::CenterCockpitFixedBefore() const{
 
2102
    eGameObject *go=Center();
 
2103
    if (go)
 
2104
        return go->RenderCockpitFixedBefore();
 
2105
    else
 
2106
        return true;
 
2107
}
 
2108
 
 
2109
void eCamera::CenterCockpitFixedAfter() const{
 
2110
    eGameObject *go=Center();
 
2111
    if (go)
 
2112
        go->RenderCockpitFixedAfter() ;
 
2113
    else
 
2114
        return;
 
2115
}
 
2116
 
 
2117