]> icculus.org git repositories - icculus/iodoom3.git/blob - neo/d3xp/Camera.cpp
hello world
[icculus/iodoom3.git] / neo / d3xp / Camera.cpp
1 /*
2 ===========================================================================
3
4 Doom 3 GPL Source Code
5 Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. 
6
7 This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).  
8
9 Doom 3 Source Code is free software: you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
13
14 Doom 3 Source Code is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with Doom 3 Source Code.  If not, see <http://www.gnu.org/licenses/>.
21
22 In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code.  If not, please request a copy in writing from id Software at the address below.
23
24 If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
25
26 ===========================================================================
27 */
28
29 #include "../idlib/precompiled.h"
30 #pragma hdrstop
31
32 #include "Game_local.h"
33
34 /*
35 ===============================================================================
36
37   idCamera
38
39   Base class for cameras
40
41 ===============================================================================
42 */
43
44 ABSTRACT_DECLARATION( idEntity, idCamera )
45 END_CLASS
46
47 /*
48 =====================
49 idCamera::Spawn
50 =====================
51 */
52 void idCamera::Spawn( void ) {
53 }
54
55 /*
56 =====================
57 idCamera::GetRenderView
58 =====================
59 */
60 renderView_t *idCamera::GetRenderView() {
61         renderView_t *rv = idEntity::GetRenderView();
62         GetViewParms( rv );
63         return rv;
64 }
65
66 /***********************************************************************
67
68   idCameraView
69
70 ***********************************************************************/
71 const idEventDef EV_Camera_SetAttachments( "<getattachments>", NULL );
72
73 CLASS_DECLARATION( idCamera, idCameraView )
74         EVENT( EV_Activate,                             idCameraView::Event_Activate )
75         EVENT( EV_Camera_SetAttachments, idCameraView::Event_SetAttachments )
76 END_CLASS
77
78
79 /*
80 ===============
81 idCameraView::idCameraView
82 ================
83 */
84 idCameraView::idCameraView() {
85         fov = 90.0f;
86         attachedTo = NULL;
87         attachedView = NULL;
88 }
89
90 /*
91 ===============
92 idCameraView::Save
93 ================
94 */
95 void idCameraView::Save( idSaveGame *savefile ) const {
96         savefile->WriteFloat( fov );
97         savefile->WriteObject( attachedTo );
98         savefile->WriteObject( attachedView );
99 }
100
101 /*
102 ===============
103 idCameraView::Restore
104 ================
105 */
106 void idCameraView::Restore( idRestoreGame *savefile ) {
107         savefile->ReadFloat( fov );
108         savefile->ReadObject( reinterpret_cast<idClass *&>( attachedTo ) );
109         savefile->ReadObject( reinterpret_cast<idClass *&>( attachedView ) );
110 }
111
112 /*
113 ===============
114 idCameraView::Event_SetAttachments
115 ================
116 */
117 void idCameraView::Event_SetAttachments(  ) {
118         SetAttachment( &attachedTo, "attachedTo" );
119         SetAttachment( &attachedView, "attachedView" );
120 }
121
122 /*
123 ===============
124 idCameraView::Event_Activate
125 ================
126 */
127 void idCameraView::Event_Activate( idEntity *activator ) {
128         if (spawnArgs.GetBool("trigger")) {
129                 if (gameLocal.GetCamera() != this) {
130                         if ( g_debugCinematic.GetBool() ) {
131                                 gameLocal.Printf( "%d: '%s' start\n", gameLocal.framenum, GetName() );
132                         }
133
134                         gameLocal.SetCamera(this);
135                 } else {
136                         if ( g_debugCinematic.GetBool() ) {
137                                 gameLocal.Printf( "%d: '%s' stop\n", gameLocal.framenum, GetName() );
138                         }
139                         gameLocal.SetCamera(NULL);
140                 }
141         }
142 }
143
144 /*
145 =====================
146 idCameraView::Stop
147 =====================
148 */
149 void idCameraView::Stop( void ) {
150         if ( g_debugCinematic.GetBool() ) {
151                 gameLocal.Printf( "%d: '%s' stop\n", gameLocal.framenum, GetName() );
152         }
153         gameLocal.SetCamera(NULL);
154         ActivateTargets( gameLocal.GetLocalPlayer() );
155 }
156
157
158 /*
159 =====================
160 idCameraView::Spawn
161 =====================
162 */
163 void idCameraView::SetAttachment( idEntity **e, const char *p  ) {
164         const char *cam = spawnArgs.GetString( p );
165         if ( strlen ( cam ) ) {
166                 *e = gameLocal.FindEntity( cam );
167         }
168 }
169
170
171 /*
172 =====================
173 idCameraView::Spawn
174 =====================
175 */
176 void idCameraView::Spawn( void ) {
177         // if no target specified use ourself
178         const char *cam = spawnArgs.GetString("cameraTarget");
179         if ( strlen ( cam ) == 0) {
180                 spawnArgs.Set("cameraTarget", spawnArgs.GetString("name"));
181         }
182         fov = spawnArgs.GetFloat("fov", "90");
183
184         PostEventMS( &EV_Camera_SetAttachments, 0 );
185
186         UpdateChangeableSpawnArgs(NULL);
187 }
188
189 /*
190 =====================
191 idCameraView::GetViewParms
192 =====================
193 */
194 void idCameraView::GetViewParms( renderView_t *view ) {
195         assert( view );
196         
197         if (view == NULL) {
198                 return;
199         }
200
201         idVec3 dir;
202         idEntity *ent;
203
204         if ( attachedTo ) {
205                 ent = attachedTo;
206         } else {
207                 ent = this;
208         }
209
210         view->vieworg = ent->GetPhysics()->GetOrigin();
211         if ( attachedView ) {
212                 dir = attachedView->GetPhysics()->GetOrigin() - view->vieworg;
213                 dir.Normalize();
214                 view->viewaxis = dir.ToMat3();
215         } else {
216                 view->viewaxis = ent->GetPhysics()->GetAxis();
217         }
218         
219         gameLocal.CalcFov( fov, view->fov_x, view->fov_y );
220 }
221
222 /*
223 ===============================================================================
224
225   idCameraAnim
226
227 ===============================================================================
228 */
229
230 const idEventDef EV_Camera_Start( "start", NULL );
231 const idEventDef EV_Camera_Stop( "stop", NULL );
232
233 CLASS_DECLARATION( idCamera, idCameraAnim )
234         EVENT( EV_Thread_SetCallback,   idCameraAnim::Event_SetCallback )
235         EVENT( EV_Camera_Stop,                  idCameraAnim::Event_Stop )
236         EVENT( EV_Camera_Start,                 idCameraAnim::Event_Start )
237         EVENT( EV_Activate,                             idCameraAnim::Event_Activate )
238 END_CLASS
239
240
241 /*
242 =====================
243 idCameraAnim::idCameraAnim
244 =====================
245 */
246 idCameraAnim::idCameraAnim() {
247         threadNum = 0;
248         offset.Zero();
249         frameRate = 0;
250         cycle = 1;
251         starttime = 0;
252         activator = NULL;
253
254 }
255
256 /*
257 =====================
258 idCameraAnim::~idCameraAnim
259 =====================
260 */
261 idCameraAnim::~idCameraAnim() {
262         if ( gameLocal.GetCamera() == this ) {
263                 gameLocal.SetCamera( NULL );
264         }
265 }
266
267 /*
268 ===============
269 idCameraAnim::Save
270 ================
271 */
272 void idCameraAnim::Save( idSaveGame *savefile ) const {
273         savefile->WriteInt( threadNum );
274         savefile->WriteVec3( offset );
275         savefile->WriteInt( frameRate );
276         savefile->WriteInt( starttime );
277         savefile->WriteInt( cycle );
278         activator.Save( savefile );
279 }
280
281 /*
282 ===============
283 idCameraAnim::Restore
284 ================
285 */
286 void idCameraAnim::Restore( idRestoreGame *savefile ) {
287         savefile->ReadInt( threadNum );
288         savefile->ReadVec3( offset );
289         savefile->ReadInt( frameRate );
290         savefile->ReadInt( starttime );
291         savefile->ReadInt( cycle );
292         activator.Restore( savefile );
293
294         LoadAnim();
295 }
296
297 /*
298 =====================
299 idCameraAnim::Spawn
300 =====================
301 */
302 void idCameraAnim::Spawn( void ) {
303         if ( spawnArgs.GetVector( "old_origin", "0 0 0", offset ) ) {
304                 offset = GetPhysics()->GetOrigin() - offset;
305         } else {
306                 offset.Zero();
307         }
308
309         // always think during cinematics
310         cinematic = true;
311
312         LoadAnim();
313 }
314
315 /*
316 ================
317 idCameraAnim::Load
318 ================
319 */
320 void idCameraAnim::LoadAnim( void ) {
321         int                     version;
322         idLexer         parser( LEXFL_ALLOWPATHNAMES | LEXFL_NOSTRINGESCAPECHARS | LEXFL_NOSTRINGCONCAT );
323         idToken         token;
324         int                     numFrames;
325         int                     numCuts;
326         int                     i;
327         idStr           filename;
328         const char      *key;
329
330         key = spawnArgs.GetString( "anim" );
331         if ( !key ) {
332                 gameLocal.Error( "Missing 'anim' key on '%s'", name.c_str() );
333         }
334
335         filename = spawnArgs.GetString( va( "anim %s", key ) );
336         if ( !filename.Length() ) {
337                 gameLocal.Error( "Missing 'anim %s' key on '%s'", key, name.c_str() );
338         }
339
340         filename.SetFileExtension( MD5_CAMERA_EXT );
341         if ( !parser.LoadFile( filename ) ) {
342                 gameLocal.Error( "Unable to load '%s' on '%s'", filename.c_str(), name.c_str() );
343         }
344
345         cameraCuts.Clear();
346         cameraCuts.SetGranularity( 1 );
347         camera.Clear();
348         camera.SetGranularity( 1 );
349
350         parser.ExpectTokenString( MD5_VERSION_STRING );
351         version = parser.ParseInt();
352         if ( version != MD5_VERSION ) {
353                 parser.Error( "Invalid version %d.  Should be version %d\n", version, MD5_VERSION );
354         }
355
356         // skip the commandline
357         parser.ExpectTokenString( "commandline" );
358         parser.ReadToken( &token );
359
360         // parse num frames
361         parser.ExpectTokenString( "numFrames" );
362         numFrames = parser.ParseInt();
363         if ( numFrames <= 0 ) {
364                 parser.Error( "Invalid number of frames: %d", numFrames );
365         }
366
367         // parse framerate
368         parser.ExpectTokenString( "frameRate" );
369         frameRate = parser.ParseInt();
370         if ( frameRate <= 0 ) {
371                 parser.Error( "Invalid framerate: %d", frameRate );
372         }
373
374         // parse num cuts
375         parser.ExpectTokenString( "numCuts" );
376         numCuts = parser.ParseInt();
377         if ( ( numCuts < 0 ) || ( numCuts > numFrames ) ) {
378                 parser.Error( "Invalid number of camera cuts: %d", numCuts );
379         }
380
381         // parse the camera cuts
382         parser.ExpectTokenString( "cuts" );
383         parser.ExpectTokenString( "{" );
384         cameraCuts.SetNum( numCuts );
385         for( i = 0; i < numCuts; i++ ) {
386                 cameraCuts[ i ] = parser.ParseInt();
387                 if ( ( cameraCuts[ i ] < 1 ) || ( cameraCuts[ i ] >= numFrames ) ) {
388                         parser.Error( "Invalid camera cut" );
389                 }
390         }
391         parser.ExpectTokenString( "}" );
392
393         // parse the camera frames
394         parser.ExpectTokenString( "camera" );
395         parser.ExpectTokenString( "{" );
396         camera.SetNum( numFrames );
397         for( i = 0; i < numFrames; i++ ) {
398                 parser.Parse1DMatrix( 3, camera[ i ].t.ToFloatPtr() );
399                 parser.Parse1DMatrix( 3, camera[ i ].q.ToFloatPtr() );
400                 camera[ i ].fov = parser.ParseFloat();
401         }
402         parser.ExpectTokenString( "}" );
403
404 #if 0
405         if ( !gameLocal.GetLocalPlayer() ) {
406                 return;
407         }
408
409         idDebugGraph gGraph;
410         idDebugGraph tGraph;
411         idDebugGraph qGraph;
412         idDebugGraph dtGraph;
413         idDebugGraph dqGraph;
414         gGraph.SetNumSamples( numFrames );
415         tGraph.SetNumSamples( numFrames );
416         qGraph.SetNumSamples( numFrames );
417         dtGraph.SetNumSamples( numFrames );
418         dqGraph.SetNumSamples( numFrames );
419
420         gameLocal.Printf( "\n\ndelta vec:\n" );
421         float diff_t, last_t, t;
422         float diff_q, last_q, q;
423         diff_t = last_t = 0.0f;
424         diff_q = last_q = 0.0f;
425         for( i = 1; i < numFrames; i++ ) {
426                 t = ( camera[ i ].t - camera[ i - 1 ].t ).Length();
427                 q = ( camera[ i ].q.ToQuat() - camera[ i - 1 ].q.ToQuat() ).Length();
428                 diff_t = t - last_t;
429                 diff_q = q - last_q;
430                 gGraph.AddValue( ( i % 10 ) == 0 );
431                 tGraph.AddValue( t );
432                 qGraph.AddValue( q );
433                 dtGraph.AddValue( diff_t );
434                 dqGraph.AddValue( diff_q );
435
436                 gameLocal.Printf( "%d: %.8f  :  %.8f,     %.8f  :  %.8f\n", i, t, diff_t, q, diff_q  );
437                 last_t = t;
438                 last_q = q;
439         }
440
441         gGraph.Draw( colorBlue, 300.0f );
442         tGraph.Draw( colorOrange, 60.0f );
443         dtGraph.Draw( colorYellow, 6000.0f );
444         qGraph.Draw( colorGreen, 60.0f );
445         dqGraph.Draw( colorCyan, 6000.0f );
446 #endif
447 }
448
449 /*
450 ===============
451 idCameraAnim::Start
452 ================
453 */
454 void idCameraAnim::Start( void ) {
455         cycle = spawnArgs.GetInt( "cycle" );
456         if ( !cycle ) {
457                 cycle = 1;
458         }
459
460         if ( g_debugCinematic.GetBool() ) {
461                 gameLocal.Printf( "%d: '%s' start\n", gameLocal.framenum, GetName() );
462         }
463
464         starttime = gameLocal.time;
465         gameLocal.SetCamera( this );
466         BecomeActive( TH_THINK );
467
468         // if the player has already created the renderview for this frame, have him update it again so that the camera starts this frame
469         if ( gameLocal.GetLocalPlayer()->GetRenderView()->time == gameLocal.time ) {
470                 gameLocal.GetLocalPlayer()->CalculateRenderView();
471         }
472 }
473
474 /*
475 =====================
476 idCameraAnim::Stop
477 =====================
478 */
479 void idCameraAnim::Stop( void ) {
480         if ( gameLocal.GetCamera() == this ) {
481                 if ( g_debugCinematic.GetBool() ) {
482                         gameLocal.Printf( "%d: '%s' stop\n", gameLocal.framenum, GetName() );
483                 }
484
485                 BecomeInactive( TH_THINK );
486                 gameLocal.SetCamera( NULL );
487                 if ( threadNum ) {
488                         idThread::ObjectMoveDone( threadNum, this );
489                         threadNum = 0;
490                 }
491                 ActivateTargets( activator.GetEntity() );
492         }
493 }
494
495 /*
496 =====================
497 idCameraAnim::Think
498 =====================
499 */
500 void idCameraAnim::Think( void ) {
501         int frame;
502         int frameTime;
503
504         if ( thinkFlags & TH_THINK ) {
505                 // check if we're done in the Think function when the cinematic is being skipped (idCameraAnim::GetViewParms isn't called when skipping cinematics).
506                 if ( !gameLocal.skipCinematic ) {
507                         return;
508                 }
509
510                 if ( camera.Num() < 2 ) {
511                         // 1 frame anims never end
512                         return;
513                 }
514
515                 if ( frameRate == USERCMD_HZ ) {
516                         frameTime       = gameLocal.time - starttime;
517                         frame           = frameTime / gameLocal.msec;
518                 } else {
519                         frameTime       = ( gameLocal.time - starttime ) * frameRate;
520                         frame           = frameTime / 1000;
521                 }
522                 
523                 if ( frame > camera.Num() + cameraCuts.Num() - 2 ) {
524                         if ( cycle > 0 ) {
525                                 cycle--;
526                         }
527
528                         if ( cycle != 0 ) {
529                                 // advance start time so that we loop
530                                 starttime += ( ( camera.Num() - cameraCuts.Num() ) * 1000 ) / frameRate;
531                         } else {
532                                 Stop();
533                         }
534                 }
535         }
536 }
537
538 /*
539 =====================
540 idCameraAnim::GetViewParms
541 =====================
542 */
543 void idCameraAnim::GetViewParms( renderView_t *view ) {
544         int                             realFrame;
545         int                             frame;
546         int                             frameTime;
547         float                   lerp;
548         float                   invlerp;
549         cameraFrame_t   *camFrame;
550         int                             i;
551         int                             cut;
552         idQuat                  q1, q2, q3;
553
554         assert( view );
555         if ( !view ) {
556                 return;
557         }
558
559         if ( camera.Num() == 0 ) {
560                 // we most likely are in the middle of a restore
561                 // FIXME: it would be better to fix it so this doesn't get called during a restore
562                 return;
563         }
564
565 #ifdef _D3XP
566         SetTimeState ts( timeGroup );
567 #endif
568
569         if ( frameRate == USERCMD_HZ ) {
570                 frameTime       = gameLocal.time - starttime;
571                 frame           = frameTime / gameLocal.msec;
572                 lerp            = 0.0f;
573         } else {
574                 frameTime       = ( gameLocal.time - starttime ) * frameRate;
575                 frame           = frameTime / 1000;
576                 lerp            = ( frameTime % 1000 ) * 0.001f;
577         }
578
579         // skip any frames where camera cuts occur
580         realFrame = frame;
581         cut = 0;
582         for( i = 0; i < cameraCuts.Num(); i++ ) {
583                 if ( frame < cameraCuts[ i ] ) {
584                         break;
585                 }
586                 frame++;
587                 cut++;
588         }
589
590         if ( g_debugCinematic.GetBool() ) {
591                 int prevFrameTime       = ( gameLocal.time - starttime - gameLocal.msec ) * frameRate;
592                 int prevFrame           = prevFrameTime / 1000;
593                 int prevCut;
594
595                 prevCut = 0;
596                 for( i = 0; i < cameraCuts.Num(); i++ ) {
597                         if ( prevFrame < cameraCuts[ i ] ) {
598                                 break;
599                         }
600                         prevFrame++;
601                         prevCut++;
602                 }
603
604                 if ( prevCut != cut ) {
605                         gameLocal.Printf( "%d: '%s' cut %d\n", gameLocal.framenum, GetName(), cut );
606                 }
607         }
608
609         // clamp to the first frame.  also check if this is a one frame anim.  one frame anims would end immediately,
610         // but since they're mainly used for static cams anyway, just stay on it infinitely.
611         if ( ( frame < 0 ) || ( camera.Num() < 2 ) ) {
612                 view->viewaxis = camera[ 0 ].q.ToQuat().ToMat3();
613                 view->vieworg = camera[ 0 ].t + offset;
614                 view->fov_x = camera[ 0 ].fov;
615         } else if ( frame > camera.Num() - 2 ) {
616                 if ( cycle > 0 ) {
617                         cycle--;
618                 }
619
620                 if ( cycle != 0 ) {
621                         // advance start time so that we loop
622                         starttime += ( ( camera.Num() - cameraCuts.Num() ) * 1000 ) / frameRate;
623                         GetViewParms( view );
624                         return;
625                 }
626
627                 Stop();
628                 if ( gameLocal.GetCamera() != NULL ) {
629                         // we activated another camera when we stopped, so get it's viewparms instead
630                         gameLocal.GetCamera()->GetViewParms( view );
631                         return;
632                 } else {
633                         // just use our last frame
634                         camFrame = &camera[ camera.Num() - 1 ];
635                         view->viewaxis = camFrame->q.ToQuat().ToMat3();
636                         view->vieworg = camFrame->t + offset;
637                         view->fov_x = camFrame->fov;
638                 }
639         } else if ( lerp == 0.0f ) {
640                 camFrame = &camera[ frame ];
641                 view->viewaxis = camFrame[ 0 ].q.ToMat3();
642                 view->vieworg = camFrame[ 0 ].t + offset;
643                 view->fov_x = camFrame[ 0 ].fov;
644         } else {
645                 camFrame = &camera[ frame ];
646                 invlerp = 1.0f - lerp;
647                 q1 = camFrame[ 0 ].q.ToQuat();
648                 q2 = camFrame[ 1 ].q.ToQuat();
649                 q3.Slerp( q1, q2, lerp );
650                 view->viewaxis = q3.ToMat3();
651                 view->vieworg = camFrame[ 0 ].t * invlerp + camFrame[ 1 ].t * lerp + offset;
652                 view->fov_x = camFrame[ 0 ].fov * invlerp + camFrame[ 1 ].fov * lerp;
653         }
654
655         gameLocal.CalcFov( view->fov_x, view->fov_x, view->fov_y );
656
657         // setup the pvs for this frame
658         UpdatePVSAreas( view->vieworg );
659         
660 #if 0
661         static int lastFrame = 0;
662         static idVec3 lastFrameVec( 0.0f, 0.0f, 0.0f );
663         if ( gameLocal.time != lastFrame ) {
664                 gameRenderWorld->DebugBounds( colorCyan, idBounds( view->vieworg ).Expand( 16.0f ), vec3_origin, gameLocal.msec );
665                 gameRenderWorld->DebugLine( colorRed, view->vieworg, view->vieworg + idVec3( 0.0f, 0.0f, 2.0f ), 10000, false );
666                 gameRenderWorld->DebugLine( colorCyan, lastFrameVec, view->vieworg, 10000, false );
667                 gameRenderWorld->DebugLine( colorYellow, view->vieworg + view->viewaxis[ 0 ] * 64.0f, view->vieworg + view->viewaxis[ 0 ] * 66.0f, 10000, false );
668                 gameRenderWorld->DebugLine( colorOrange, view->vieworg + view->viewaxis[ 0 ] * 64.0f, view->vieworg + view->viewaxis[ 0 ] * 64.0f + idVec3( 0.0f, 0.0f, 2.0f ), 10000, false );
669                 lastFrameVec = view->vieworg;
670                 lastFrame = gameLocal.time;
671         }
672 #endif
673
674         if ( g_showcamerainfo.GetBool() ) {
675                 gameLocal.Printf( "^5Frame: ^7%d/%d\n\n\n", realFrame + 1, camera.Num() - cameraCuts.Num() );
676         }
677 }
678
679 /*
680 ===============
681 idCameraAnim::Event_Activate
682 ================
683 */
684 void idCameraAnim::Event_Activate( idEntity *_activator ) {
685         activator = _activator;
686         if ( thinkFlags & TH_THINK ) {
687                 Stop();
688         } else {
689                 Start();
690         }
691 }
692
693 /*
694 ===============
695 idCameraAnim::Event_Start
696 ================
697 */
698 void idCameraAnim::Event_Start( void ) {
699         Start();
700 }
701
702 /*
703 ===============
704 idCameraAnim::Event_Stop
705 ================
706 */
707 void idCameraAnim::Event_Stop( void ) {
708         Stop();
709 }
710
711 /*
712 ================
713 idCameraAnim::Event_SetCallback
714 ================
715 */
716 void idCameraAnim::Event_SetCallback( void ) {
717         if ( ( gameLocal.GetCamera() == this ) && !threadNum ) {
718                 threadNum = idThread::CurrentThreadNum();
719                 idThread::ReturnInt( true );
720         } else {
721                 idThread::ReturnInt( false );
722         }
723 }