1 //********************************************************************************************
2 //*
3 //*    This file is part of Egoboo.
4 //*
5 //*    Egoboo is free software: you can redistribute it and/or modify it
6 //*    under the terms of the GNU General Public License as published by
7 //*    the Free Software Foundation, either version 3 of the License, or
8 //*    (at your option) any later version.
9 //*
10 //*    Egoboo is distributed in the hope that it will be useful, but
11 //*    WITHOUT ANY WARRANTY; without even the implied warranty of
12 //*    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13 //*    General Public License for more details.
14 //*
15 //*    You should have received a copy of the GNU General Public License
16 //*    along with Egoboo.  If not, see <http://www.gnu.org/licenses/>.
17 //*
18 //********************************************************************************************
19 
20 /// @file camera.c
21 /// @brief Various functions related to how the game camera works.
22 /// @details
23 
24 #include "camera.h"
25 
26 #include "char.inl"
27 #include "mesh.inl"
28 
29 #include "input.h"
30 #include "graphic.h"
31 #include "network.h"
32 #include "controls_file.h"
33 
34 #include "egoboo_setup.h"
35 #include "egoboo.h"
36 
37 #include "SDL_extensions.h"
38 
39 //--------------------------------------------------------------------------------------------
40 //--------------------------------------------------------------------------------------------
41 
42 camera_t gCamera;
43 
44 //--------------------------------------------------------------------------------------------
45 //--------------------------------------------------------------------------------------------
46 // Camera control stuff
47 
48 //--------------------------------------------------------------------------------------------
camera_rotmesh__init()49 void camera_rotmesh__init()
50 {
51     // Matrix init stuff (from remove.c)
52     rotmesh_topside    = (( float )sdl_scr.x / sdl_scr.y ) * CAM_ROTMESH_TOPSIDE / ( 1.33333f );
53     rotmesh_bottomside = (( float )sdl_scr.x / sdl_scr.y ) * CAM_ROTMESH_BOTTOMSIDE / ( 1.33333f );
54     rotmesh_up         = (( float )sdl_scr.x / sdl_scr.y ) * CAM_ROTMESH_UP / ( 1.33333f );
55     rotmesh_down       = (( float )sdl_scr.x / sdl_scr.y ) * CAM_ROTMESH_DOWN / ( 1.33333f );
56 }
57 
58 //--------------------------------------------------------------------------------------------
camera_ctor(camera_t * pcam)59 camera_t * camera_ctor( camera_t * pcam )
60 {
61     /// @detalis BB@> initialize the camera structure
62 
63     fvec3_t   t1 = {{0, 0, 0}};
64     fvec3_t   t2 = {{0, 0, -1}};
65     fvec3_t   t3 = {{0, 1, 0}};
66 
67     memset( pcam, 0, sizeof( *pcam ) );
68 
69     pcam->move_mode = pcam->move_mode_old = CAM_PLAYER;
70     pcam->turn_mode = cfg.autoturncamera;
71 
72     pcam->swing        =  0;
73     pcam->swingrate    =  0;
74     pcam->swingamp     =  0;
75     pcam->pos.x        =  0;
76     pcam->pos.y        =  1500;
77     pcam->pos.z        =  1500;
78     pcam->zoom         =  1000;
79     pcam->zadd         =  800;
80     pcam->zaddgoto     =  800;
81     pcam->zgoto        =  800;
82     pcam->turn_z_rad   = -PI / 4.0f;
83     pcam->turn_z_one   = pcam->turn_z_rad / TWO_PI;
84     pcam->ori.facing_z = CLIP_TO_16BITS(( int )( pcam->turn_z_one * ( float )0x00010000 ) ) ;
85     pcam->turnadd      =  0;
86     pcam->sustain      =  0.60f;
87     pcam->turnupdown   = ( float )( PI / 4 );
88     pcam->roll         =  0;
89     pcam->motion_blur  =  0;
90 
91     pcam->mView       = pcam->mViewSave = ViewMatrix( t1.v, t2.v, t3.v, 0 );
92     pcam->mProjection = ProjectionMatrix( .001f, 2000.0f, ( float )( CAM_FOV * PI / 180 ) ); // 60 degree CAM_FOV
93     pcam->mProjection = MatrixMult( Translate( 0, 0, -0.999996f ), pcam->mProjection ); // Fix Z value...
94     pcam->mProjection = MatrixMult( ScaleXYZ( -1, -1, 100000 ), pcam->mProjection );  // HUK // ...'cause it needs it
95 
96     // [claforte] Fudge the values.
97     pcam->mProjection.v[10] /= 2.0f;
98     pcam->mProjection.v[11] /= 2.0f;
99 
100     camera_rotmesh__init();
101 
102     return pcam;
103 }
104 
105 //--------------------------------------------------------------------------------------------
106 //--------------------------------------------------------------------------------------------
dump_matrix(fmat_4x4_t a)107 void dump_matrix( fmat_4x4_t a )
108 {
109     /// @detalis ZZ@> dump a text representation of a 4x4 matrix to stdout
110 
111     int i; int j;
112 
113     for ( j = 0; j < 4; j++ )
114     {
115         printf( "  " );
116 
117         for ( i = 0; i < 4; i++ )
118         {
119             printf( "%f ", a.CNV( i, j ) );
120         }
121         printf( "\n" );
122     }
123 }
124 
125 //--------------------------------------------------------------------------------------------
126 //--------------------------------------------------------------------------------------------
camera_look_at(camera_t * pcam,float x,float y)127 void camera_look_at( camera_t * pcam, float x, float y )
128 {
129     /// @details ZZ@> This function makes the camera turn to face the character
130 
131     pcam->zgoto = pcam->zadd;
132     if ( 0 != pcam->turn_time )
133     {
134         pcam->turn_z_rad = ( 1.5f * PI ) - ATAN2( y - pcam->pos.y, x - pcam->pos.x );  // xgg
135     }
136 }
137 
138 //--------------------------------------------------------------------------------------------
camera_make_matrix(camera_t * pcam)139 void camera_make_matrix( camera_t * pcam )
140 {
141     /// @details ZZ@> This function sets pcam->mView to the camera's location and rotation
142 
143     float local_swingamp = pcam->swingamp;
144 
145     //Fade out the motion blur
146     if ( pcam->motion_blur > 0 )
147     {
148         pcam->motion_blur *= 0.99f; //Decay factor
149         if ( pcam->motion_blur < 0.001f ) pcam->motion_blur = 0;
150     }
151 
152     //Swing the camera if players are groggy and apply motion blur
153     if ( local_stats.grog_level > 0 )
154     {
155         float zoom_add;
156         pcam->swing = ( pcam->swing + 120 ) & 0x3FFF;
157         local_swingamp = MAX( local_swingamp, 0.175f );
158 
159         zoom_add = ( 0 == ((( int )local_stats.grog_level ) % 2 ) ? 1 : - 1 ) * CAM_TURN_KEY * local_stats.grog_level * 0.35f;
160         pcam->zaddgoto = CLIP( pcam->zaddgoto + zoom_add, CAM_ZADD_MIN, CAM_ZADD_MAX );
161         pcam->motion_blur = MIN( 1.00f, 0.5f + 0.03f * local_stats.grog_level );
162     }
163 
164     //Rotate camera if they are dazed and apply motion blur
165     if ( local_stats.daze_level > 0 )
166     {
167         pcam->turnadd = local_stats.daze_level * CAM_TURN_KEY * 0.5f;
168         pcam->motion_blur = MIN( 1.00f, 0.5f + 0.03f * local_stats.daze_level );
169     }
170 
171     //Apply camera swinging
172     pcam->mView = MatrixMult( Translate( pcam->pos.x, -pcam->pos.y, pcam->pos.z ), pcam->mViewSave );  // xgg
173     if ( local_swingamp > 0.001f )
174     {
175         pcam->roll = turntosin[pcam->swing] * local_swingamp;
176         pcam->mView = MatrixMult( RotateY( pcam->roll ), pcam->mView );
177     }
178 
179     // If the camera stops swinging for some reason, slowly return to original position
180     else if ( 0 != pcam->roll )
181     {
182         pcam->roll *= 0.9875f;            //Decay factor
183         pcam->mView = MatrixMult( RotateY( pcam->roll ), pcam->mView );
184 
185         // Come to a standstill at some point
186         if ( ABS( pcam->roll ) < 0.001f )
187         {
188             pcam->roll = 0;
189             pcam->swing = 0;
190         }
191     }
192 
193     pcam->mView = MatrixMult( RotateZ( pcam->turn_z_rad ), pcam->mView );
194     pcam->mView = MatrixMult( RotateX( pcam->turnupdown ), pcam->mView );
195 
196     //--- pre-compute some camera vectors
197     mat_getCamForward( pcam->mView.v, pcam->vfw.v );
198     fvec3_self_normalize( pcam->vfw.v );
199 
200     mat_getCamUp( pcam->mView.v, pcam->vup.v );
201     fvec3_self_normalize( pcam->vup.v );
202 
203     mat_getCamRight( pcam->mView.v, pcam->vrt.v );
204     fvec3_self_normalize( pcam->vrt.v );
205 }
206 
207 //--------------------------------------------------------------------------------------------
camera_adjust_angle(camera_t * pcam,float height)208 void camera_adjust_angle( camera_t * pcam, float height )
209 {
210     /// @details ZZ@> This function makes the camera look downwards as it is raised up
211 
212     float percentmin, percentmax;
213     if ( height < CAM_ZADD_MIN )  height = CAM_ZADD_MIN;
214 
215     percentmax = ( height - CAM_ZADD_MIN ) / ( float )( CAM_ZADD_MAX - CAM_ZADD_MIN );
216     percentmin = 1.0f - percentmax;
217 
218     pcam->turnupdown = (( CAM_UPDOWN_MIN * percentmin ) + ( CAM_UPDOWN_MAX * percentmax ) );
219     pcam->zoom = ( CAM_ZOOM_MIN * percentmin ) + ( CAM_ZOOM_MAX * percentmax );
220 }
221 
222 //--------------------------------------------------------------------------------------------
camera_move(camera_t * pcam,ego_mpd_t * pmesh)223 void camera_move( camera_t * pcam, ego_mpd_t * pmesh )
224 {
225     /// @details ZZ@> This function moves the camera
226 
227     Uint16 cnt;
228     float x, y, z, level, newx, newy, movex, movey;
229     Uint16 turnsin;
230 
231     if ( CAM_TURN_NONE != pcam->turn_mode )
232         pcam->turn_time = 255;
233     else if ( 0 != pcam->turn_time )
234         pcam->turn_time--;
235 
236     // the default camera motion is to do nothing
237     x     = pcam->track_pos.x;
238     y     = pcam->track_pos.y;
239     z     = pcam->track_pos.z;
240     level = 128 + mesh_get_level( pmesh, x, y );
241 
242     if ( CAM_FREE == pcam->move_mode )
243     {
244         // the keypad controls the camera
245         if ( SDLKEYDOWN( SDLK_KP8 ) )
246         {
247             pcam->track_pos.x -= pcam->mView.CNV( 0, 1 ) * 50;
248             pcam->track_pos.y -= pcam->mView.CNV( 1, 1 ) * 50;
249         }
250 
251         if ( SDLKEYDOWN( SDLK_KP2 ) )
252         {
253             pcam->track_pos.x += pcam->mView.CNV( 0, 1 ) * 50;
254             pcam->track_pos.y += pcam->mView.CNV( 1, 1 ) * 50;
255         }
256 
257         if ( SDLKEYDOWN( SDLK_KP4 ) )
258         {
259             pcam->track_pos.x += pcam->mView.CNV( 0, 0 ) * 50;
260             pcam->track_pos.y += pcam->mView.CNV( 1, 0 ) * 50;
261         }
262 
263         if ( SDLKEYDOWN( SDLK_KP6 ) )
264         {
265             pcam->track_pos.x -= pcam->mView.CNV( 0, 0 ) * 10;
266             pcam->track_pos.y -= pcam->mView.CNV( 1, 0 ) * 10;
267         }
268 
269         if ( SDLKEYDOWN( SDLK_KP7 ) )
270         {
271             pcam->turnadd += CAM_TURN_KEY;
272         }
273 
274         if ( SDLKEYDOWN( SDLK_KP9 ) )
275         {
276             pcam->turnadd -= CAM_TURN_KEY;
277         }
278 
279         pcam->track_pos.z = 128 + mesh_get_level( pmesh, pcam->track_pos.x, pcam->track_pos.y );
280     }
281     else if ( CAM_RESET == pcam->move_mode )
282     {
283         // a camera movement mode for re-focusing in on a bunch of players
284 
285         PLA_REF ipla;
286         fvec3_t sum_pos;
287         float   sum_wt, sum_level;
288 
289         sum_wt    = 0.0f;
290         sum_level = 0.0f;
291         fvec3_self_clear( sum_pos.v );
292 
293         for ( ipla = 0; ipla < MAX_PLAYER; ipla++ )
294         {
295             chr_t * pchr;
296 
297             pchr = pla_get_pchr( ipla );
298             if ( NULL == pchr || !pchr->alive ) continue;
299 
300             sum_pos.x += pchr->pos.x;
301             sum_pos.y += pchr->pos.y;
302             sum_pos.z += pchr->pos.z + pchr->chr_min_cv.maxs[OCT_Z] * 0.9f;
303             sum_level += pchr->enviro.level;
304             sum_wt    += 1.0f;
305         }
306 
307         // if any of the characters is doing anything
308         if ( sum_wt > 0.0f )
309         {
310             x     = sum_pos.x / sum_wt;
311             y     = sum_pos.y / sum_wt;
312             z     = sum_pos.z / sum_wt;
313             level = sum_level / sum_wt;
314         }
315     }
316     else if ( CAM_PLAYER == pcam->move_mode )
317     {
318         // a camera mode for focusing in on the players that are actually doing something.
319         // "Show me the drama!"
320 
321         PLA_REF ipla;
322         chr_t * local_chr_ptrs[MAX_PLAYER];
323         int local_chr_count = 0;
324 
325         // count the number of local players, first
326         local_chr_count = 0;
327         for ( ipla = 0; ipla < MAX_PLAYER; ipla++ )
328         {
329             chr_t * pchr;
330 
331             pchr = pla_get_pchr( ipla );
332             if ( NULL == pchr || !pchr->alive ) continue;
333 
334             local_chr_ptrs[local_chr_count] = pchr;
335             local_chr_count++;
336         }
337 
338         if ( 0 == local_chr_count )
339         {
340             // do nothing
341         }
342         else if ( 1 == local_chr_count )
343         {
344             // copy from the one character
345 
346             x = local_chr_ptrs[0]->pos.x;
347             y = local_chr_ptrs[0]->pos.y;
348             z = local_chr_ptrs[0]->pos.z;
349             level = local_chr_ptrs[0]->enviro.level;
350         }
351         else
352         {
353             // use the characer's "activity" to average the position the camera is viewing
354 
355             fvec3_t sum_pos;
356             float   sum_wt, sum_level;
357 
358             sum_wt    = 0.0f;
359             sum_level = 0.0f;
360             fvec3_self_clear( sum_pos.v );
361 
362             for ( cnt = 0; cnt < local_chr_count; cnt++ )
363             {
364                 chr_t * pchr;
365                 float weight1, weight2, weight;
366 
367                 // we JUST checked the validity of these characters. No need to do it again?
368                 pchr = local_chr_ptrs[ cnt ];
369 
370                 // weight it by the character's velocity^2, so that
371                 // inactive characters don't control the camera
372                 weight1 = fvec3_dot_product( pchr->vel.v, pchr->vel.v );
373 
374                 // make another weight based on button-pushing
375                 weight2 = ( 0 == pchr->latch.b ) ? 0 : 127;
376 
377                 // I would weight this by the amount of damage that the character just sustained,
378                 // but there is no real way to do this?
379 
380                 // get the maximum effect
381                 weight =  MAX( weight1, weight2 );
382 
383                 // The character is on foot
384                 sum_pos.x += pchr->pos.x * weight;
385                 sum_pos.y += pchr->pos.y * weight;
386                 sum_pos.z += pchr->pos.z * weight;
387                 sum_level += pchr->enviro.level * weight;
388                 sum_wt    += weight;
389             }
390 
391             // if any of the characters is doing anything
392             if ( sum_wt > 0 )
393             {
394                 x = sum_pos.x / sum_wt;
395                 y = sum_pos.y / sum_wt;
396                 z = sum_pos.z / sum_wt;
397                 level = sum_level / sum_wt;
398             }
399         }
400     }
401 
402     if ( CAM_RESET == pcam->move_mode )
403     {
404         // just set the position
405         pcam->track_pos.x = x;
406         pcam->track_pos.y = y;
407         pcam->track_pos.z = z;
408         pcam->track_level = level;
409 
410         // reset the camera mode
411         pcam->move_mode = pcam->move_mode_old;
412     }
413     else
414     {
415         // smoothly interpolate the camera tracking position
416         pcam->track_pos.x = 0.9f * pcam->track_pos.x + 0.1f * x;
417         pcam->track_pos.y = 0.9f * pcam->track_pos.y + 0.1f * y;
418         pcam->track_pos.z = 0.9f * pcam->track_pos.z + 0.1f * z;
419         pcam->track_level = 0.9f * pcam->track_level + 0.1f * level;
420     }
421 
422     pcam->turnadd = pcam->turnadd * pcam->sustain;
423     pcam->zadd    = 0.9f * pcam->zadd  + 0.1f * pcam->zaddgoto;
424     pcam->pos.z   = 0.9f * pcam->pos.z + 0.1f * pcam->zgoto;
425 
426     // Camera controls
427     if ( CAM_TURN_GOOD == pcam->turn_mode && 1 == local_numlpla )
428     {
429         if ( mous.on )
430         {
431             if ( !control_is_pressed( INPUT_DEVICE_MOUSE,  CONTROL_CAMERA ) )
432             {
433                 pcam->turnadd -= ( mous.x * 0.5f );
434             }
435         }
436 
437         if ( keyb.on )
438         {
439             pcam->turnadd += ( control_is_pressed( INPUT_DEVICE_KEYBOARD,  CONTROL_LEFT ) - control_is_pressed( INPUT_DEVICE_KEYBOARD,  CONTROL_RIGHT ) ) * CAM_TURN_KEY;
440         }
441 
442         if ( joy[0].on )
443         {
444             if ( !control_is_pressed( INPUT_DEVICE_JOY_A, CONTROL_CAMERA ) )
445             {
446                 pcam->turnadd -= joy[0].x * CAM_TURN_JOY;
447             }
448         }
449 
450         if ( joy[1].on )
451         {
452             if ( !control_is_pressed( INPUT_DEVICE_JOY_B, CONTROL_CAMERA ) )
453             {
454                 pcam->turnadd -= joy[1].x * CAM_TURN_JOY;
455             }
456         }
457     }
458     else
459     {
460         if ( mous.on )
461         {
462             if ( control_is_pressed( INPUT_DEVICE_MOUSE,  CONTROL_CAMERA ) )
463             {
464                 pcam->turnadd += ( mous.x / 3.0f );
465                 pcam->zaddgoto += ( float ) mous.y / 3.0f;
466                 if ( pcam->zaddgoto < CAM_ZADD_MIN )  pcam->zaddgoto = CAM_ZADD_MIN;
467                 if ( pcam->zaddgoto > CAM_ZADD_MAX )  pcam->zaddgoto = CAM_ZADD_MAX;
468 
469                 pcam->turn_time = CAM_TURN_TIME;  // Sticky turn...
470             }
471         }
472 
473         // JoyA camera controls
474         if ( joy[0].on )
475         {
476             if ( control_is_pressed( INPUT_DEVICE_JOY_A, CONTROL_CAMERA ) )
477             {
478                 pcam->turnadd += joy[0].x * CAM_TURN_JOY;
479                 pcam->zaddgoto += joy[0].y * CAM_TURN_JOY;
480                 if ( pcam->zaddgoto < CAM_ZADD_MIN )  pcam->zaddgoto = CAM_ZADD_MIN;
481                 if ( pcam->zaddgoto > CAM_ZADD_MAX )  pcam->zaddgoto = CAM_ZADD_MAX;
482 
483                 pcam->turn_time = CAM_TURN_TIME;  // Sticky turn...
484             }
485         }
486 
487         // JoyB camera controls
488         if ( joy[1].on )
489         {
490             if ( control_is_pressed( INPUT_DEVICE_JOY_B, CONTROL_CAMERA ) )
491             {
492                 pcam->turnadd += joy[1].x * CAM_TURN_JOY;
493                 pcam->zaddgoto += joy[1].y * CAM_TURN_JOY;
494                 if ( pcam->zaddgoto < CAM_ZADD_MIN )  pcam->zaddgoto = CAM_ZADD_MIN;
495                 if ( pcam->zaddgoto > CAM_ZADD_MAX )  pcam->zaddgoto = CAM_ZADD_MAX;
496 
497                 pcam->turn_time = CAM_TURN_TIME;  // Sticky turn...
498             }
499         }
500     }
501 
502     // Keyboard camera controls
503     if ( keyb.on )
504     {
505         if ( control_is_pressed( INPUT_DEVICE_KEYBOARD,  CONTROL_CAMERA_LEFT ) || control_is_pressed( INPUT_DEVICE_KEYBOARD,  CONTROL_CAMERA_RIGHT ) )
506         {
507             pcam->turnadd += ( control_is_pressed( INPUT_DEVICE_KEYBOARD,  CONTROL_CAMERA_LEFT ) - control_is_pressed( INPUT_DEVICE_KEYBOARD,  CONTROL_CAMERA_RIGHT ) ) * CAM_TURN_KEY;
508             pcam->turn_time = CAM_TURN_TIME;  // Sticky turn...
509         }
510 
511         if ( control_is_pressed( INPUT_DEVICE_KEYBOARD,  CONTROL_CAMERA_IN ) || control_is_pressed( INPUT_DEVICE_KEYBOARD,  CONTROL_CAMERA_OUT ) )
512         {
513             pcam->zaddgoto += ( control_is_pressed( INPUT_DEVICE_KEYBOARD,  CONTROL_CAMERA_OUT ) - control_is_pressed( INPUT_DEVICE_KEYBOARD,  CONTROL_CAMERA_IN ) ) * CAM_TURN_KEY;
514             if ( pcam->zaddgoto < CAM_ZADD_MIN )  pcam->zaddgoto = CAM_ZADD_MIN;
515             if ( pcam->zaddgoto > CAM_ZADD_MAX )  pcam->zaddgoto = CAM_ZADD_MAX;
516         }
517     }
518 
519     pcam->pos.x -= ( float )( pcam->mView.CNV( 0, 0 ) ) * pcam->turnadd; // xgg
520     pcam->pos.y += ( float )( pcam->mView.CNV( 1, 0 ) ) * -pcam->turnadd;
521 
522     // Center on target for doing rotation...
523     if ( 0 != pcam->turn_time )
524     {
525         pcam->center.x = pcam->center.x * 0.9f + pcam->track_pos.x * 0.1f;
526         pcam->center.y = pcam->center.y * 0.9f + pcam->track_pos.y * 0.1f;
527     }
528 
529     // Create a tolerance area for walking without camera movement
530     x = pcam->track_pos.x - pcam->pos.x;
531     y = pcam->track_pos.y - pcam->pos.y;
532     newx = -( pcam->mView.CNV( 0, 0 ) * x + pcam->mView.CNV( 1, 0 ) * y ); // newx = -(pcam->mView(0,0) * x + pcam->mView(1,0) * y);
533     newy = -( pcam->mView.CNV( 0, 1 ) * x + pcam->mView.CNV( 1, 1 ) * y ); // newy = -(pcam->mView(0,1) * x + pcam->mView(1,1) * y);
534 
535     // Get ready to scroll...
536     movex = 0;
537     movey = 0;
538 
539     // Adjust for camera height...
540     z = ( CAM_TRACK_X_AREA_LOW  * ( CAM_ZADD_MAX - pcam->zadd ) ) +
541         ( CAM_TRACK_X_AREA_HIGH * ( pcam->zadd - CAM_ZADD_MIN ) );
542     z = z / ( CAM_ZADD_MAX - CAM_ZADD_MIN );
543     if ( newx < -z )
544     {
545         // Scroll left
546         movex += ( newx + z );
547     }
548     if ( newx > z )
549     {
550         // Scroll right
551         movex += ( newx - z );
552     }
553 
554     // Adjust for camera height...
555     z = ( CAM_TRACK_Y_AREA_MINLOW  * ( CAM_ZADD_MAX - pcam->zadd ) ) +
556         ( CAM_TRACK_Y_AREA_MINHIGH * ( pcam->zadd - CAM_ZADD_MIN ) );
557     z = z / ( CAM_ZADD_MAX - CAM_ZADD_MIN );
558     if ( newy < z )
559     {
560         // Scroll down
561         movey -= ( newy - z );
562     }
563     else
564     {
565         // Adjust for camera height...
566         z = ( CAM_TRACK_Y_AREA_MAXLOW  * ( CAM_ZADD_MAX - pcam->zadd ) ) +
567             ( CAM_TRACK_Y_AREA_MAXHIGH * ( pcam->zadd - CAM_ZADD_MIN ) );
568         z = z / ( CAM_ZADD_MAX - CAM_ZADD_MIN );
569         if ( newy > z )
570         {
571             // Scroll up
572             movey -= ( newy - z );
573         }
574     }
575 
576     turnsin = TO_TURN( pcam->ori.facing_z );
577     pcam->center.x += movex * turntocos[ turnsin & TRIG_TABLE_MASK ] + movey * turntosin[ turnsin & TRIG_TABLE_MASK ];
578     pcam->center.y += -movex * turntosin[ turnsin & TRIG_TABLE_MASK ] + movey * turntocos[ turnsin & TRIG_TABLE_MASK ];
579 
580     // Finish up the camera
581     camera_look_at( pcam, pcam->center.x, pcam->center.y );
582     pcam->pos.x = ( float ) pcam->center.x + ( pcam->zoom * SIN( pcam->turn_z_rad ) );
583     pcam->pos.y = ( float ) pcam->center.y + ( pcam->zoom * COS( pcam->turn_z_rad ) );
584 
585     camera_adjust_angle( pcam, pcam->pos.z );
586 
587     camera_make_matrix( pcam );
588 
589     pcam->turn_z_one = ( pcam->turn_z_rad ) / ( TWO_PI );
590     pcam->ori.facing_z     = CLIP_TO_16BITS( FLOAT_TO_FP16( pcam->turn_z_one ) );
591 }
592 
593 //--------------------------------------------------------------------------------------------
camera_reset(camera_t * pcam,ego_mpd_t * pmesh)594 void camera_reset( camera_t * pcam, ego_mpd_t * pmesh )
595 {
596     /// @details ZZ@> This function makes sure the camera starts in a suitable position
597 
598     pcam->swing        = 0;
599     pcam->pos.x        = pmesh->gmem.edge_x / 2;
600     pcam->pos.y        = pmesh->gmem.edge_y / 2;
601     pcam->pos.z        = 1500;
602     pcam->zoom         = 1000;
603     pcam->center.x     = pcam->pos.x;
604     pcam->center.y     = pcam->pos.y;
605     pcam->track_pos.x  = pcam->pos.x;
606     pcam->track_pos.y  = pcam->pos.y;
607     pcam->track_pos.z  = 1500;
608     pcam->turnadd      = 0;
609     pcam->track_level  = 0;
610     pcam->zadd         = 1500;
611     pcam->zaddgoto     = CAM_ZADD_MAX;
612     pcam->zgoto        = 1500;
613     pcam->turn_z_rad   = -PI / 4.0f;
614     pcam->turn_z_one   = pcam->turn_z_rad / TWO_PI;
615     pcam->ori.facing_z = CLIP_TO_16BITS(( int )( pcam->turn_z_one * ( float )0x00010000 ) ) ;
616     pcam->turnupdown   = PI / 4.0f;
617     pcam->roll         = 0;
618 
619     // make sure you are looking at the players
620     camera_reset_target( pcam, pmesh );
621 }
622 
623 //--------------------------------------------------------------------------------------------
camera_reset_target(camera_t * pcam,ego_mpd_t * pmesh)624 bool_t camera_reset_target( camera_t * pcam, ego_mpd_t * pmesh )
625 {
626     // @details BB@> Force the camera to focus in on the players. Should be called any time there is
627     //               a "change of scene". With the new velocity-tracking of the camera, this would include
628     //               things like character respawns, adding new players, etc.
629 
630     int turn_mode_save;
631 
632     if ( NULL == pcam ) return bfalse;
633 
634     turn_mode_save = pcam->turn_mode;
635 
636     // set an identity matrix.
637     pcam->mView = IdentityMatrix();
638 
639     // specify the modes that will make the camera point at the players
640     pcam->turn_mode = CAM_TURN_AUTO;
641     pcam->move_mode = CAM_RESET;
642 
643     // If you use CAM_RESET, camera_move() automatically restores pcam->move_mode
644     // to its default setting
645     camera_move( pcam, pmesh );
646 
647     // fix the center position
648     pcam->center.x = pcam->track_pos.x;
649     pcam->center.y = pcam->track_pos.y;
650 
651     // restore the turn mode
652     pcam->turn_mode = turn_mode_save;
653     pcam->turn_time = 0;
654 
655     return btrue;
656 }
657