Camera.cpp (15849B)
1 /* 2 =========================================================================== 3 4 Doom 3 BFG Edition GPL Source Code 5 Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company. 6 7 This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code"). 8 9 Doom 3 BFG Edition 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 BFG Edition 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 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>. 21 22 In addition, the Doom 3 BFG Edition 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 BFG Edition 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() { 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() { 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() { 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() { 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() { 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 405 /* 406 =============== 407 idCameraAnim::Start 408 ================ 409 */ 410 void idCameraAnim::Start() { 411 cycle = spawnArgs.GetInt( "cycle" ); 412 if ( !cycle ) { 413 cycle = 1; 414 } 415 416 if ( g_debugCinematic.GetBool() ) { 417 gameLocal.Printf( "%d: '%s' start\n", gameLocal.framenum, GetName() ); 418 } 419 420 starttime = gameLocal.time; 421 gameLocal.SetCamera( this ); 422 BecomeActive( TH_THINK ); 423 424 // if the player has already created the renderview for this frame, have him update it again so that the camera starts this frame 425 if ( gameLocal.GetLocalPlayer()->GetRenderView()->time[TIME_GROUP2] == gameLocal.fast.time ) { 426 gameLocal.GetLocalPlayer()->CalculateRenderView(); 427 } 428 } 429 430 /* 431 ===================== 432 idCameraAnim::Stop 433 ===================== 434 */ 435 void idCameraAnim::Stop() { 436 if ( gameLocal.GetCamera() == this ) { 437 if ( g_debugCinematic.GetBool() ) { 438 gameLocal.Printf( "%d: '%s' stop\n", gameLocal.framenum, GetName() ); 439 } 440 441 BecomeInactive( TH_THINK ); 442 gameLocal.SetCamera( NULL ); 443 if ( threadNum ) { 444 idThread::ObjectMoveDone( threadNum, this ); 445 threadNum = 0; 446 } 447 ActivateTargets( activator.GetEntity() ); 448 } 449 } 450 451 /* 452 ===================== 453 idCameraAnim::Think 454 ===================== 455 */ 456 void idCameraAnim::Think() { 457 } 458 459 /* 460 ===================== 461 idCameraAnim::GetViewParms 462 ===================== 463 */ 464 void idCameraAnim::GetViewParms( renderView_t *view ) { 465 int realFrame; 466 int frame; 467 int frameTime; 468 float lerp; 469 float invlerp; 470 cameraFrame_t *camFrame; 471 int i; 472 int cut; 473 idQuat q1, q2, q3; 474 475 assert( view ); 476 if ( !view ) { 477 return; 478 } 479 480 if ( camera.Num() == 0 ) { 481 // we most likely are in the middle of a restore 482 // FIXME: it would be better to fix it so this doesn't get called during a restore 483 return; 484 } 485 486 SetTimeState ts( timeGroup ); 487 488 frameTime = ( gameLocal.time - starttime ) * frameRate; 489 frame = frameTime / 1000; 490 lerp = ( frameTime % 1000 ) * 0.001f; 491 492 // skip any frames where camera cuts occur 493 realFrame = frame; 494 cut = 0; 495 for( i = 0; i < cameraCuts.Num(); i++ ) { 496 if ( frame < cameraCuts[ i ] ) { 497 break; 498 } 499 frame++; 500 cut++; 501 } 502 503 if ( g_debugCinematic.GetBool() ) { 504 int prevFrameTime = ( gameLocal.previousTime - starttime ) * frameRate; 505 int prevFrame = prevFrameTime / 1000; 506 int prevCut; 507 508 prevCut = 0; 509 for( i = 0; i < cameraCuts.Num(); i++ ) { 510 if ( prevFrame < cameraCuts[ i ] ) { 511 break; 512 } 513 prevFrame++; 514 prevCut++; 515 } 516 517 if ( prevCut != cut ) { 518 gameLocal.Printf( "%d: '%s' cut %d\n", gameLocal.framenum, GetName(), cut ); 519 } 520 } 521 522 // clamp to the first frame. also check if this is a one frame anim. one frame anims would end immediately, 523 // but since they're mainly used for static cams anyway, just stay on it infinitely. 524 if ( ( frame < 0 ) || ( camera.Num() < 2 ) ) { 525 view->viewaxis = camera[ 0 ].q.ToQuat().ToMat3(); 526 view->vieworg = camera[ 0 ].t + offset; 527 view->fov_x = camera[ 0 ].fov; 528 } else if ( frame > camera.Num() - 2 ) { 529 if ( cycle > 0 ) { 530 cycle--; 531 } 532 533 if ( cycle != 0 ) { 534 // advance start time so that we loop 535 starttime += ( ( camera.Num() - cameraCuts.Num() ) * 1000 ) / frameRate; 536 GetViewParms( view ); 537 return; 538 } 539 540 Stop(); 541 if ( gameLocal.GetCamera() != NULL ) { 542 // we activated another camera when we stopped, so get it's viewparms instead 543 gameLocal.GetCamera()->GetViewParms( view ); 544 return; 545 } else { 546 // just use our last frame 547 camFrame = &camera[ camera.Num() - 1 ]; 548 view->viewaxis = camFrame->q.ToQuat().ToMat3(); 549 view->vieworg = camFrame->t + offset; 550 view->fov_x = camFrame->fov; 551 } 552 } else if ( lerp == 0.0f ) { 553 camFrame = &camera[ frame ]; 554 view->viewaxis = camFrame[ 0 ].q.ToMat3(); 555 view->vieworg = camFrame[ 0 ].t + offset; 556 view->fov_x = camFrame[ 0 ].fov; 557 } else { 558 camFrame = &camera[ frame ]; 559 invlerp = 1.0f - lerp; 560 q1 = camFrame[ 0 ].q.ToQuat(); 561 q2 = camFrame[ 1 ].q.ToQuat(); 562 q3.Slerp( q1, q2, lerp ); 563 view->viewaxis = q3.ToMat3(); 564 view->vieworg = camFrame[ 0 ].t * invlerp + camFrame[ 1 ].t * lerp + offset; 565 view->fov_x = camFrame[ 0 ].fov * invlerp + camFrame[ 1 ].fov * lerp; 566 } 567 568 gameLocal.CalcFov( view->fov_x, view->fov_x, view->fov_y ); 569 570 // setup the pvs for this frame 571 UpdatePVSAreas( view->vieworg ); 572 573 #if 0 574 static int lastFrame = 0; 575 static idVec3 lastFrameVec( 0.0f, 0.0f, 0.0f ); 576 if ( gameLocal.time != lastFrame ) { 577 gameRenderWorld->DebugBounds( colorCyan, idBounds( view->vieworg ).Expand( 16.0f ), vec3_origin, 1 ); 578 gameRenderWorld->DebugLine( colorRed, view->vieworg, view->vieworg + idVec3( 0.0f, 0.0f, 2.0f ), 10000, false ); 579 gameRenderWorld->DebugLine( colorCyan, lastFrameVec, view->vieworg, 10000, false ); 580 gameRenderWorld->DebugLine( colorYellow, view->vieworg + view->viewaxis[ 0 ] * 64.0f, view->vieworg + view->viewaxis[ 0 ] * 66.0f, 10000, false ); 581 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 ); 582 lastFrameVec = view->vieworg; 583 lastFrame = gameLocal.time; 584 } 585 #endif 586 587 if ( g_showcamerainfo.GetBool() ) { 588 gameLocal.Printf( "^5Frame: ^7%d/%d\n\n\n", realFrame + 1, camera.Num() - cameraCuts.Num() ); 589 } 590 } 591 592 /* 593 =============== 594 idCameraAnim::Event_Activate 595 ================ 596 */ 597 void idCameraAnim::Event_Activate( idEntity *_activator ) { 598 activator = _activator; 599 if ( thinkFlags & TH_THINK ) { 600 Stop(); 601 } else { 602 Start(); 603 } 604 } 605 606 /* 607 =============== 608 idCameraAnim::Event_Start 609 ================ 610 */ 611 void idCameraAnim::Event_Start() { 612 Start(); 613 } 614 615 /* 616 =============== 617 idCameraAnim::Event_Stop 618 ================ 619 */ 620 void idCameraAnim::Event_Stop() { 621 Stop(); 622 } 623 624 /* 625 ================ 626 idCameraAnim::Event_SetCallback 627 ================ 628 */ 629 void idCameraAnim::Event_SetCallback() { 630 if ( ( gameLocal.GetCamera() == this ) && !threadNum ) { 631 threadNum = idThread::CurrentThreadNum(); 632 idThread::ReturnInt( true ); 633 } else { 634 idThread::ReturnInt( false ); 635 } 636 }