DOOM-3-BFG

DOOM 3 BFG Edition
Log | Files | Refs

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 }