home *** CD-ROM | disk | FTP | other *** search
/ GameStar 2006 March / Gamestar_82_2006-03_dvd.iso / DVDStar / Editace / quake4_sdkv10.exe / source / game / Camera.cpp < prev    next >
C/C++ Source or Header  |  2005-11-14  |  56KB  |  2,258 lines

  1. #include "../idlib/precompiled.h"
  2. #pragma hdrstop
  3.  
  4. #include "Game_local.h"
  5.  
  6. /*
  7. ===============================================================================
  8.  
  9.   idCamera
  10.  
  11.   Base class for cameras
  12.  
  13. ===============================================================================
  14. */
  15.  
  16. ABSTRACT_DECLARATION( idEntity, idCamera )
  17. END_CLASS
  18.  
  19. /*
  20. =====================
  21. idCamera::Spawn
  22. =====================
  23. */
  24. void idCamera::Spawn( void ) {
  25. }
  26.  
  27. /*
  28. =====================
  29. idCamera::GetRenderView
  30. =====================
  31. */
  32. renderView_t *idCamera::GetRenderView() {
  33.     renderView_t *rv = idEntity::GetRenderView();
  34.     GetViewParms( rv );
  35.     return rv;
  36. }
  37.  
  38. /***********************************************************************
  39.  
  40.   idCameraView
  41.  
  42. ***********************************************************************/
  43. const idEventDef EV_Camera_SetAttachments( "<getattachments>", NULL );
  44.  
  45. // RAVEN BEGIN
  46. // bdube: added events
  47. const idEventDef EV_SetFOV    (     "setFOV", "f" );
  48. const idEventDef EV_GetFOV        ( "getFOV", NULL, 'f' );
  49. const idEventDef EV_BlendFOV    ( "blendFOV", "fff");
  50. // RAVEN END
  51.  
  52. CLASS_DECLARATION( idCamera, idCameraView )
  53.     EVENT( EV_Activate,                idCameraView::Event_Activate )
  54.     EVENT( EV_Camera_SetAttachments, idCameraView::Event_SetAttachments )
  55.  
  56. // RAVEN BEGIN
  57. // bdube: added events
  58.     EVENT( EV_SetFOV,                idCameraView::Event_SetFOV )
  59.     EVENT( EV_BlendFOV,                idCameraView::Event_BlendFOV )
  60.     EVENT( EV_GetFOV,                idCameraView::Event_GetFOV )
  61. // RAVEN END
  62. END_CLASS
  63.  
  64. /*
  65. ===============
  66. idCameraView::idCameraView
  67. ================
  68. */
  69. idCameraView::idCameraView() {
  70. // RAVEN BEGIN
  71. // bdube: interpolate fov
  72. // scork: get it from the cvar, don't assume 90
  73.     fov.Init ( gameLocal.time, 0, g_fov.GetFloat(), g_fov.GetFloat() );
  74. // RAVEN END
  75.     attachedTo = NULL;
  76.     attachedView = NULL;
  77. }
  78.  
  79. /*
  80. ===============
  81. idCameraView::Save
  82. ================
  83. */
  84. void idCameraView::Save( idSaveGame *savefile ) const {
  85. // RAVEN BEGIN
  86. // bdube: fov interpolated now
  87.     savefile->WriteInt( fov.GetDuration() );
  88.     savefile->WriteInt( fov.GetStartTime() );
  89.     savefile->WriteFloat( fov.GetStartValue() );
  90.     savefile->WriteFloat( fov.GetEndValue() );
  91. // RAVEN END
  92.     savefile->WriteObject( attachedTo );
  93.     savefile->WriteObject( attachedView );
  94. }
  95.  
  96. /*
  97. ===============
  98. idCameraView::Restore
  99. ================
  100. */
  101. void idCameraView::Restore( idRestoreGame *savefile ) {
  102. // RAVEN BEGIN
  103. // bdube: fov interpolated now
  104.     int set;
  105.     float setf;
  106.     savefile->ReadInt( set );
  107.     fov.SetDuration( set );
  108.     savefile->ReadInt( set );
  109.     fov.SetStartTime( set );
  110.     savefile->ReadFloat( setf );
  111.     fov.SetStartValue( setf );
  112.     savefile->ReadFloat( setf );
  113.     fov.SetEndValue( setf );
  114. // RAVEN END
  115.     savefile->ReadObject( reinterpret_cast<idClass *&>( attachedTo ) );
  116.     savefile->ReadObject( reinterpret_cast<idClass *&>( attachedView ) );
  117. }
  118.  
  119. /*
  120. ===============
  121. idCameraView::Event_SetAttachments
  122. ================
  123. */
  124. void idCameraView::Event_SetAttachments(  ) {
  125.     SetAttachment( &attachedTo, "attachedTo" );
  126.     SetAttachment( &attachedView, "attachedView" );
  127. }
  128.  
  129. /*
  130. ===============
  131. idCameraView::Event_Activate
  132. ================
  133. */
  134. void idCameraView::Event_Activate( idEntity *activator ) {
  135.     if (spawnArgs.GetBool("trigger")) {
  136.         if (gameLocal.GetCamera() != this) {
  137.             if ( g_debugCinematic.GetBool() ) {
  138.                 gameLocal.Printf( "%d: '%s' start\n", gameLocal.framenum, GetName() );
  139.             }
  140.  
  141.             gameLocal.SetCamera(this);
  142.         } else {
  143.             if ( g_debugCinematic.GetBool() ) {
  144.                 gameLocal.Printf( "%d: '%s' stop\n", gameLocal.framenum, GetName() );
  145.             }
  146.             gameLocal.SetCamera(NULL);
  147.         }
  148.     }
  149. }
  150.  
  151. /*
  152. =====================
  153. idCameraView::Stop
  154. =====================
  155. */
  156. void idCameraView::Stop( void ) {
  157.     if ( g_debugCinematic.GetBool() ) {
  158.         gameLocal.Printf( "%d: '%s' stop\n", gameLocal.framenum, GetName() );
  159.     }
  160.     gameLocal.SetCamera(NULL);
  161.     ActivateTargets( gameLocal.GetLocalPlayer() );
  162. }
  163.  
  164. // RAVEN BEGIN
  165. // bdube: added events
  166. /*
  167. =====================
  168. idCameraView::Event_SetFOV
  169. =====================
  170. */
  171. void idCameraView::Event_SetFOV ( float newfov ) 
  172. {
  173.     fov.Init ( gameLocal.time, 0, newfov, newfov );
  174. }
  175.  
  176. /*
  177. =====================
  178. idCameraView::Event_BlendFOV
  179. =====================
  180. */
  181. void idCameraView::Event_BlendFOV ( float beginFOV, float endFOV, float blendTime )
  182. {
  183.     fov.Init ( gameLocal.time, SEC2MS(blendTime), beginFOV, endFOV );
  184. }
  185.  
  186. /*
  187. =====================
  188. idCameraView::Event_GetFOV
  189. =====================
  190. */
  191. void idCameraView::Event_GetFOV() 
  192. {
  193.     idThread::ReturnFloat(fov.GetCurrentValue(gameLocal.time));
  194. }
  195. // RAVEN END
  196.  
  197. /*
  198. =====================
  199. idCameraView::Spawn
  200. =====================
  201. */
  202. void idCameraView::SetAttachment( idEntity **e, const char *p  ) {
  203.     const char *cam = spawnArgs.GetString( p );
  204.     if ( strlen ( cam ) ) {
  205.         *e = gameLocal.FindEntity( cam );
  206.     }
  207. }
  208.  
  209.  
  210. /*
  211. =====================
  212. idCameraView::Spawn
  213. =====================
  214. */
  215. void idCameraView::Spawn( void ) {
  216.     // if no target specified use ourself
  217.     const char *cam = spawnArgs.GetString("cameraTarget");
  218.     if ( strlen ( cam ) == 0) {
  219.         spawnArgs.Set("cameraTarget", spawnArgs.GetString("name"));
  220.     }
  221. // RAVEN BEGIN
  222. // bdube: interpolate fov
  223. // scork: ... but default from the cvar, not hardwired 90
  224.     fov.Init ( gameLocal.time, 0, spawnArgs.GetFloat("fov", va("%f",g_fov.GetFloat())), spawnArgs.GetFloat("fov", va("%f",g_fov.GetFloat())) );
  225. // RAVEN END
  226.  
  227.     PostEventMS( &EV_Camera_SetAttachments, 0 );
  228.  
  229.     UpdateChangeableSpawnArgs(NULL);
  230. }
  231.  
  232. /*
  233. =====================
  234. idCamera::RenderView
  235. =====================
  236. */
  237. void idCameraView::GetViewParms( renderView_t *view ) {
  238.     assert( view );
  239.     
  240.     if (view == NULL) {
  241.         return;
  242.     }
  243.  
  244.     idVec3 dir;
  245.     idEntity *ent;
  246.  
  247.     if ( attachedTo ) {
  248.         ent = attachedTo;
  249.     } else {
  250.         ent = this;
  251.     }
  252.  
  253.     view->vieworg = ent->GetPhysics()->GetOrigin();
  254.     if ( attachedView ) {
  255.         dir = attachedView->GetPhysics()->GetOrigin() - view->vieworg;
  256.         dir.Normalize();
  257.         view->viewaxis = dir.ToMat3();
  258.     } else {
  259.         view->viewaxis = ent->GetPhysics()->GetAxis();
  260.     }
  261.     
  262. // RAVEN BEGIN
  263. // bdube: interpolate fov
  264.     gameLocal.CalcFov( fov.GetCurrentValue ( gameLocal.time ), view->fov_x, view->fov_y );
  265. // RAVEN END
  266. }
  267.  
  268.  
  269.  
  270.  
  271.  
  272.  
  273.  
  274.  
  275.  
  276. // RAVEN BEGIN
  277. // rjohnson: camera is now contained in a def for frame commands
  278.  
  279. /***********************************************************************
  280.  
  281.     rvCameraAnimation
  282.  
  283. ***********************************************************************/
  284. /*
  285. =====================
  286. rvCameraAnimation::rvCameraAnimation
  287. =====================
  288. */
  289. rvCameraAnimation::rvCameraAnimation( void ) {
  290.     frameRate = 0;
  291. }
  292.  
  293. /*
  294. =====================
  295. rvCameraAnimation::rvCameraAnimation
  296. =====================
  297. */
  298. rvCameraAnimation::rvCameraAnimation( const idDeclCameraDef *cameraDef, const rvCameraAnimation *anim ) {
  299.     cameraCuts = anim->cameraCuts;
  300.     camera = anim->camera;
  301.     frameLookup = anim->frameLookup;
  302.     frameCommands = anim->frameCommands;
  303.     frameRate = anim->frameRate;
  304.     name = anim->name;
  305.     realname = anim->realname;
  306. }
  307.  
  308. /*
  309. =====================
  310. rvCameraAnimation::~rvCameraAnimation
  311. =====================
  312. */
  313. rvCameraAnimation::~rvCameraAnimation( void ) {
  314. }
  315.  
  316. /*
  317. =====================
  318. rvCameraAnimation::Name
  319. =====================
  320. */
  321. const char *rvCameraAnimation::Name( void ) const {
  322.     return name;
  323. }
  324.  
  325. /*
  326. =====================
  327. rvCameraAnimation::FullName
  328. =====================
  329. */
  330. const char *rvCameraAnimation::FullName( void ) const {
  331.     return realname;
  332. }
  333.  
  334. /*
  335. =====================
  336. rvCameraAnimation::NumFrames
  337. =====================
  338. */
  339. int    rvCameraAnimation::NumFrames( void ) const { 
  340.     return camera.Num();
  341. }
  342.  
  343. /*
  344. =====================
  345. rvCameraAnimation::NumCuts
  346. =====================
  347. */
  348. int    rvCameraAnimation::NumCuts( void ) const { 
  349.     return cameraCuts.Num();
  350. }
  351.  
  352. void rvCameraAnimation::SetAnim( const idDeclCameraDef *cameraDef, const char *sourcename, const char *animname, idStr filename ) {
  353.     int            version;
  354.     idLexer        parser( LEXFL_ALLOWPATHNAMES | LEXFL_NOSTRINGESCAPECHARS | LEXFL_NOSTRINGCONCAT );
  355.     idToken        token;
  356.     int            numFrames;
  357.     int            numCuts;
  358.     int            i;
  359.  
  360.     filename.SetFileExtension( MD5_CAMERA_EXT );
  361.     if ( !parser.LoadFile( filename ) ) {
  362.         gameLocal.Error( "Unable to load '%s' on '%s'", filename.c_str(), name.c_str() );
  363.     }
  364.  
  365.     cameraCuts.Clear();
  366.     cameraCuts.SetGranularity( 1 );
  367.     camera.Clear();
  368.     camera.SetGranularity( 1 );
  369.  
  370.     parser.ExpectTokenString( MD5_VERSION_STRING );
  371.     version = parser.ParseInt();
  372.     if ( version != MD5_VERSION ) {
  373.         parser.Error( "Invalid version %d.  Should be version %d\n", version, MD5_VERSION );
  374.     }
  375.  
  376.     // skip the commandline
  377.     parser.ExpectTokenString( "commandline" );
  378.     parser.ReadToken( &token );
  379.  
  380.     // parse num frames
  381.     parser.ExpectTokenString( "numFrames" );
  382.     numFrames = parser.ParseInt();
  383.     if ( numFrames <= 0 ) {
  384.         parser.Error( "Invalid number of frames: %d", numFrames );
  385.     }
  386.  
  387.     // parse framerate
  388.     parser.ExpectTokenString( "frameRate" );
  389.     frameRate = parser.ParseInt();
  390.     if ( frameRate <= 0 ) {
  391.         parser.Error( "Invalid framerate: %d", frameRate );
  392.     }
  393.  
  394.     // parse num cuts
  395.     parser.ExpectTokenString( "numCuts" );
  396.     numCuts = parser.ParseInt();
  397.     if ( ( numCuts < 0 ) || ( numCuts > numFrames ) ) {
  398.         parser.Error( "Invalid number of camera cuts: %d", numCuts );
  399.     }
  400.  
  401.     // parse the camera cuts
  402.     parser.ExpectTokenString( "cuts" );
  403.     parser.ExpectTokenString( "{" );
  404.     cameraCuts.SetNum( numCuts );
  405.     for( i = 0; i < numCuts; i++ ) {
  406.         cameraCuts[ i ] = parser.ParseInt();
  407.         if ( ( cameraCuts[ i ] < 1 ) || ( cameraCuts[ i ] >= numFrames ) ) {
  408.             parser.Error( "Invalid camera cut" );
  409.         }
  410.     }
  411.     parser.ExpectTokenString( "}" );
  412.  
  413.     // parse the camera frames
  414.     parser.ExpectTokenString( "camera" );
  415.     parser.ExpectTokenString( "{" );
  416.     camera.SetNum( numFrames );
  417.     for( i = 0; i < numFrames; i++ ) {
  418.         parser.Parse1DMatrix( 3, camera[ i ].t.ToFloatPtr() );
  419.         parser.Parse1DMatrix( 3, camera[ i ].q.ToFloatPtr() );
  420.         camera[ i ].fov = parser.ParseFloat();
  421.     }
  422.     parser.ExpectTokenString( "}" );
  423.  
  424. #if 0
  425.     if ( !gameLocal.GetLocalPlayer() ) {
  426.         return;
  427.     }
  428.  
  429.     idDebugGraph gGraph;
  430.     idDebugGraph tGraph;
  431.     idDebugGraph qGraph;
  432.     idDebugGraph dtGraph;
  433.     idDebugGraph dqGraph;
  434.     gGraph.SetNumSamples( numFrames );
  435.     tGraph.SetNumSamples( numFrames );
  436.     qGraph.SetNumSamples( numFrames );
  437.     dtGraph.SetNumSamples( numFrames );
  438.     dqGraph.SetNumSamples( numFrames );
  439.  
  440.     gameLocal.Printf( "\n\ndelta vec:\n" );
  441.     float diff_t, last_t, t;
  442.     float diff_q, last_q, q;
  443.     diff_t = last_t = 0.0f;
  444.     diff_q = last_q = 0.0f;
  445.     for( i = 1; i < numFrames; i++ ) {
  446.         t = ( camera[ i ].t - camera[ i - 1 ].t ).Length();
  447.         q = ( camera[ i ].q.ToQuat() - camera[ i - 1 ].q.ToQuat() ).Length();
  448.         diff_t = t - last_t;
  449.         diff_q = q - last_q;
  450.         gGraph.AddValue( ( i % 10 ) == 0 );
  451.         tGraph.AddValue( t );
  452.         qGraph.AddValue( q );
  453.         dtGraph.AddValue( diff_t );
  454.         dqGraph.AddValue( diff_q );
  455.  
  456.         gameLocal.Printf( "%d: %.8f  :  %.8f,     %.8f  :  %.8f\n", i, t, diff_t, q, diff_q  );
  457.         last_t = t;
  458.         last_q = q;
  459.     }
  460.  
  461.     gGraph.Draw( colorBlue, 300.0f );
  462.     tGraph.Draw( colorOrange, 60.0f );
  463.     dtGraph.Draw( colorYellow, 6000.0f );
  464.     qGraph.Draw( colorGreen, 60.0f );
  465.     dqGraph.Draw( colorCyan, 6000.0f );
  466. #endif
  467. }
  468.  
  469. /*
  470. =====================
  471. rvCameraAnimation::AddFrameCommand
  472.  
  473. Returns NULL if no error.
  474. =====================
  475. */
  476. const char *rvCameraAnimation::AddFrameCommand( const idDeclCameraDef *cameraDef, const idList<int>& frames, idLexer &src, const idDict *def ) {
  477.     int                    i;
  478.     int                    index;
  479.     idStr                text;
  480.     idStr                funcname;
  481.     frameCommand_t        fc;
  482.     idToken                token;
  483.  
  484.     memset( &fc, 0, sizeof( fc ) );
  485.  
  486.     if( !src.ReadTokenOnLine( &token ) ) {
  487.         return "Unexpected end of line";
  488.     }
  489.  
  490.     if ( token == "call" ) {
  491.         if( !src.ReadTokenOnLine( &token ) ) {
  492.             return "Unexpected end of line";
  493.         }
  494.         fc.type = FC_SCRIPTFUNCTION;
  495.         fc.function = gameLocal.program.FindFunction( token );
  496.         if ( !fc.function ) {
  497.             return va( "Function '%s' not found", token.c_str() );
  498.         }
  499.     } else if ( token == "object_call" ) {
  500.         if( !src.ReadTokenOnLine( &token ) ) {
  501.             return "Unexpected end of line";
  502.         }
  503.         fc.type = FC_SCRIPTFUNCTIONOBJECT;
  504.         fc.string = new idStr( token );
  505.     } else if ( token == "event" ) {
  506.         if( !src.ReadTokenOnLine( &token ) ) {
  507.             return "Unexpected end of line";
  508.         }
  509.         fc.type = FC_EVENTFUNCTION;
  510.         const idEventDef *ev = idEventDef::FindEvent( token );
  511.         if ( !ev ) {
  512.             return va( "Event '%s' not found", token.c_str() );
  513.         }
  514.         if ( ev->GetNumArgs() != 0 ) {
  515.             return va( "Event '%s' has arguments", token.c_str() );
  516.         }
  517.         fc.string = new idStr( token );
  518.     }
  519. // RAVEN BEGIN
  520. // abahr:
  521.     else if( token == "eventArgs" ) {
  522.         src.ParseRestOfLine( token );
  523.         if( token.Length() <= 0 ) {
  524.             return "Unexpected end of line";
  525.         }
  526.  
  527.         fc.type = FC_EVENTFUNCTION_ARGS;
  528.         fc.parmList = new idList<idStr>();
  529.         token.Split( *fc.parmList, ' ' );
  530.         fc.event = idEventDef::FindEvent( (*fc.parmList)[0] );
  531.         if( !fc.event ) {
  532.             SAFE_DELETE_PTR( fc.parmList );
  533.             return va( "Event '%s' not found", (*fc.parmList)[0].c_str() );
  534.         }
  535.         
  536.         fc.parmList->RemoveIndex( 0 );
  537.     }
  538. // RAVEN END
  539.     else if ( token == "sound" ) {
  540.         if( !src.ReadTokenOnLine( &token ) ) {
  541.             return "Unexpected end of line";
  542.         }
  543.         fc.type = FC_SOUND;
  544.         if ( !token.Cmpn( "snd_", 4 ) ) {
  545.             fc.string = new idStr( token );
  546.         } else {
  547.             fc.soundShader = declManager->FindSound( token );
  548.             if ( fc.soundShader->GetState() == DS_DEFAULTED ) {
  549.                 gameLocal.Warning( "Sound '%s' not found", token.c_str() );
  550.             }
  551.         }
  552.     } else if ( token == "sound_voice" ) {
  553.         if( !src.ReadTokenOnLine( &token ) ) {
  554.             return "Unexpected end of line";
  555.         }
  556.         fc.type = FC_SOUND_VOICE;
  557.         if ( !token.Cmpn( "snd_", 4 ) ) {
  558.             fc.string = new idStr( token );
  559.         } else {
  560.             fc.soundShader = declManager->FindSound( token );
  561.             if ( fc.soundShader->GetState() == DS_DEFAULTED ) {
  562.                 gameLocal.Warning( "Sound '%s' not found", token.c_str() );
  563.             }
  564.         }
  565.     } else if ( token == "sound_voice2" ) {
  566.         if( !src.ReadTokenOnLine( &token ) ) {
  567.             return "Unexpected end of line";
  568.         }
  569.         fc.type = FC_SOUND_VOICE2;
  570.         if ( !token.Cmpn( "snd_", 4 ) ) {
  571.             fc.string = new idStr( token );
  572.         } else {
  573.             fc.soundShader = declManager->FindSound( token );
  574.             if ( fc.soundShader->GetState() == DS_DEFAULTED ) {
  575.                 gameLocal.Warning( "Sound '%s' not found", token.c_str() );
  576.             }
  577.         }
  578.     } else if ( token == "sound_body" ) {
  579.         if( !src.ReadTokenOnLine( &token ) ) {
  580.             return "Unexpected end of line";
  581.         }
  582.         fc.type = FC_SOUND_BODY;
  583.         if ( !token.Cmpn( "snd_", 4 ) ) {
  584.             fc.string = new idStr( token );
  585.         } else {
  586.             fc.soundShader = declManager->FindSound( token );
  587.             if ( fc.soundShader->GetState() == DS_DEFAULTED ) {
  588.                 gameLocal.Warning( "Sound '%s' not found", token.c_str() );
  589.             }
  590.         }
  591.     } else if ( token == "sound_body2" ) {
  592.         if( !src.ReadTokenOnLine( &token ) ) {
  593.             return "Unexpected end of line";
  594.         }
  595.         fc.type = FC_SOUND_BODY2;
  596.         if ( !token.Cmpn( "snd_", 4 ) ) {
  597.             fc.string = new idStr( token );
  598.         } else {
  599.             fc.soundShader = declManager->FindSound( token );
  600.             if ( fc.soundShader->GetState() == DS_DEFAULTED ) {
  601.                 gameLocal.Warning( "Sound '%s' not found", token.c_str() );
  602.             }
  603.         }
  604.     } else if ( token == "sound_body3" ) {
  605.         if( !src.ReadTokenOnLine( &token ) ) {
  606.             return "Unexpected end of line";
  607.         }
  608.         fc.type = FC_SOUND_BODY3;
  609.         if ( !token.Cmpn( "snd_", 4 ) ) {
  610.             fc.string = new idStr( token );
  611.         } else {
  612.             fc.soundShader = declManager->FindSound( token );
  613.             if ( fc.soundShader->GetState() == DS_DEFAULTED ) {
  614.                 gameLocal.Warning( "Sound '%s' not found", token.c_str() );
  615.             }
  616.         }
  617.     } else if ( token == "sound_weapon" ) {
  618.         if( !src.ReadTokenOnLine( &token ) ) {
  619.             return "Unexpected end of line";
  620.         }
  621.         fc.type = FC_SOUND_WEAPON;
  622.         if ( !token.Cmpn( "snd_", 4 ) ) {
  623.             fc.string = new idStr( token );
  624.         } else {
  625.             fc.soundShader = declManager->FindSound( token );
  626.             if ( fc.soundShader->GetState() == DS_DEFAULTED ) {
  627.                 gameLocal.Warning( "Sound '%s' not found", token.c_str() );
  628.             }
  629.         }
  630.     } else if ( token == "sound_global" ) {
  631.         if( !src.ReadTokenOnLine( &token ) ) {
  632.             return "Unexpected end of line";
  633.         }
  634.         fc.type = FC_SOUND_GLOBAL;
  635.         if ( !token.Cmpn( "snd_", 4 ) ) {
  636.             fc.string = new idStr( token );
  637.         } else {
  638.             fc.soundShader = declManager->FindSound( token );
  639.             if ( fc.soundShader->GetState() == DS_DEFAULTED ) {
  640.                 gameLocal.Warning( "Sound '%s' not found", token.c_str() );
  641.             }
  642.         }
  643.     } else if ( token == "sound_item" ) {
  644.         if( !src.ReadTokenOnLine( &token ) ) {
  645.             return "Unexpected end of line";
  646.         }
  647.         fc.type = FC_SOUND_ITEM;
  648.         if ( !token.Cmpn( "snd_", 4 ) ) {
  649.             fc.string = new idStr( token );
  650.         } else {
  651.             fc.soundShader = declManager->FindSound( token );
  652.             if ( fc.soundShader->GetState() == DS_DEFAULTED ) {
  653.                 gameLocal.Warning( "Sound '%s' not found", token.c_str() );
  654.             }
  655.         }
  656.     } else if ( token == "sound_chatter" ) {
  657.         if( !src.ReadTokenOnLine( &token ) ) {
  658.             return "Unexpected end of line";
  659.         }
  660.         fc.type = FC_SOUND_CHATTER;
  661.         if ( !token.Cmpn( "snd_", 4 ) ) {
  662.             fc.string = new idStr( token );
  663.         } else {
  664.             fc.soundShader = declManager->FindSound( token );
  665.             if ( fc.soundShader->GetState() == DS_DEFAULTED ) {
  666.                 gameLocal.Warning( "Sound '%s' not found", token.c_str() );
  667.             }
  668.         }
  669.     } else if ( token == "skin" ) {
  670.         if( !src.ReadTokenOnLine( &token ) ) {
  671.             return "Unexpected end of line";
  672.         }
  673.         fc.type = FC_SKIN;
  674.         if ( token == "none" ) {
  675.             fc.skin = NULL;
  676.         } else {
  677.             fc.skin = declManager->FindSkin( token );
  678.             if ( !fc.skin ) {
  679.                 return va( "Skin '%s' not found", token.c_str() );
  680.             }
  681.         }
  682.     } else if ( token == "fx" ) {
  683. // RAVEN BEGIN
  684. // bdube: use Raven effect system
  685.         fc.type = FC_FX;        
  686.  
  687.         // Get the effect name
  688.         if ( !src.ReadTokenOnLine( &token ) ) {
  689.             return va( "missing effect name" );
  690.         }
  691.         
  692.         // Effect is indirect if it starts with fx_
  693.         if ( !idStr::Icmpn ( token, "fx_", 3 ) ) {
  694.             fc.string = new idStr ( token );
  695.         } else {
  696.             fc.effect = ( const idDecl * )declManager->FindEffect( token );
  697.         }
  698.         
  699.         // Joint specified?
  700.         if ( src.ReadTokenOnLine ( &token ) ) {
  701.             fc.joint = new idStr ( token );
  702.         }
  703.         
  704.         // End joint specified?
  705.         if ( src.ReadTokenOnLine ( &token ) ) {
  706.             fc.joint2 = new idStr ( token );
  707.         }
  708. // RAVEN END
  709.     } else if ( token == "trigger" ) {
  710.         if( !src.ReadTokenOnLine( &token ) ) {
  711.             return "Unexpected end of line";
  712.         }
  713.         fc.type = FC_TRIGGER;
  714.         fc.string = new idStr( token );
  715. // RAVEN BEGIN
  716. // bdube: not using
  717. /*
  718.     } else if ( token == "triggerSmokeParticle" ) {
  719.         if( !src.ReadTokenOnLine( &token ) ) {
  720.             return "Unexpected end of line";
  721.         }
  722.         fc.type = FC_TRIGGER_SMOKE_PARTICLE;
  723.         fc.string = new idStr( token );
  724. */
  725. // RAVEN END
  726.     } else if ( token == "direct_damage" ) {
  727.         if( !src.ReadTokenOnLine( &token ) ) {
  728.             return "Unexpected end of line";
  729.         }
  730.         fc.type = FC_DIRECTDAMAGE;
  731.         if ( !gameLocal.FindEntityDef( token.c_str(), false ) ) {
  732.             return va( "Unknown entityDef '%s'", token.c_str() );
  733.         }
  734.         fc.string = new idStr( token );
  735.     } else if ( token == "muzzle_flash" ) {
  736. /*        if( !src.ReadTokenOnLine( &token ) ) {
  737.             return "Unexpected end of line";
  738.         }
  739.         if ( ( token != "" ) && !modelDef->FindJoint( token ) ) {
  740.             return va( "Joint '%s' not found", token.c_str() );
  741.         }
  742.         fc.type = FC_MUZZLEFLASH;
  743.         fc.string = new idStr( token );*/
  744.     } else if ( token == "muzzle_flash" ) {
  745.         fc.type = FC_MUZZLEFLASH;
  746.         fc.string = new idStr( "" );
  747.     } else if ( token == "footstep" ) {
  748.         fc.type = FC_FOOTSTEP;
  749.     } else if ( token == "leftfoot" ) {
  750.         fc.type = FC_LEFTFOOT;
  751.     } else if ( token == "rightfoot" ) {
  752.         fc.type = FC_RIGHTFOOT;
  753.     } else if ( token == "enableEyeFocus" ) {
  754.         fc.type = FC_ENABLE_EYE_FOCUS;
  755.     } else if ( token == "disableEyeFocus" ) {
  756.         fc.type = FC_DISABLE_EYE_FOCUS;
  757.     } else if ( token == "disableGravity" ) {
  758.         fc.type = FC_DISABLE_GRAVITY;
  759.     } else if ( token == "enableGravity" ) {
  760.         fc.type = FC_ENABLE_GRAVITY;
  761.     } else if ( token == "jump" ) {
  762.         fc.type = FC_JUMP;
  763.     } else if ( token == "enableClip" ) {
  764.         fc.type = FC_ENABLE_CLIP;
  765.     } else if ( token == "disableClip" ) {
  766.         fc.type = FC_DISABLE_CLIP;
  767.     } else if ( token == "enableWalkIK" ) {
  768.         fc.type = FC_ENABLE_WALK_IK;
  769.     } else if ( token == "disableWalkIK" ) {
  770.         fc.type = FC_DISABLE_WALK_IK;
  771.     } else if ( token == "enableLegIK" ) {
  772.         if( !src.ReadTokenOnLine( &token ) ) {
  773.             return "Unexpected end of line";
  774.         }
  775.         fc.type = FC_ENABLE_LEG_IK;
  776.         fc.index = atoi( token );
  777.     } else if ( token == "disableLegIK" ) {
  778.         if( !src.ReadTokenOnLine( &token ) ) {
  779.             return "Unexpected end of line";
  780.         }
  781.         fc.type = FC_DISABLE_LEG_IK;
  782.         fc.index = atoi( token );
  783.     } else if ( token == "recordDemo" ) {
  784.         fc.type = FC_RECORDDEMO;
  785.         if( src.ReadTokenOnLine( &token ) ) {
  786.             fc.string = new idStr( token );
  787.         }
  788.     } else if ( token == "aviGame" ) {
  789.         fc.type = FC_AVIGAME;
  790.         if( src.ReadTokenOnLine( &token ) ) {
  791.             fc.string = new idStr( token );
  792.         }
  793. // RAVEN BEGIN
  794. // bdube: added script commands
  795.     } else if ( token == "ai_enablePain" ) {
  796.         fc.type = FC_AI_ENABLE_PAIN;
  797.     } else if ( token == "ai_disablePain" ) {
  798.         fc.type = FC_AI_DISABLE_PAIN;
  799.     } else if ( token == "ai_enableDamage" ) {
  800.         fc.type = FC_AI_ENABLE_DAMAGE;
  801.     } else if ( token == "ai_disableDamage" ) {
  802.         fc.type = FC_AI_DISABLE_DAMAGE;
  803.     } else if ( token == "ai_lockEnemyOrigin" ) {
  804.         fc.type = FC_AI_LOCKENEMYORIGIN;
  805.     } else if ( token == "ai_attack" ) {
  806.         fc.type = FC_AI_ATTACK;
  807.  
  808.         // Name of attack
  809.         if( !src.ReadTokenOnLine( &token ) ) {
  810.             return "Unexpected end of line while looking for attack Name";
  811.         }
  812.         fc.string = new idStr( token );
  813.  
  814.         // Joint to attack from
  815.         if( !src.ReadTokenOnLine( &token ) ) {
  816.             return "Unexpected end of line while looking for attack joint";
  817.         }
  818.         fc.joint = new idStr( token );        
  819.     } else if ( token == "ai_attack_melee" ) {
  820.         if( !src.ReadTokenOnLine( &token ) ) {
  821.             return "Unexpected end of line while looking for melee attack name";
  822.         }
  823.         fc.type = FC_AI_ATTACK_MELEE;
  824.         fc.string = new idStr( token );
  825.     } else if ( token == "guievent" )  {
  826.         fc.type = FC_GUIEVENT;
  827.         if( src.ReadTokenOnLine( &token ) ) 
  828.         {
  829.             fc.string = new idStr( token );
  830.         }
  831.     } else if ( token == "speak" )  {
  832.         fc.type = FC_AI_SPEAK;
  833.         if( src.ReadTokenOnLine( &token ) ) {
  834.             fc.string = new idStr( token );
  835.         }
  836. // RAVEN END
  837.     } else {
  838.         return va( "Unknown command '%s'", token.c_str() );
  839.     }
  840.  
  841.     // check if we've initialized the frame loopup table
  842.     if ( !frameLookup.Num() ) {
  843.         // we haven't, so allocate the table and initialize it
  844.         frameLookup.SetGranularity( 1 );
  845.         frameLookup.SetNum( camera.Num() );
  846.         for( i = 0; i < frameLookup.Num(); i++ ) {
  847.             frameLookup[ i ].num = 0;
  848.             frameLookup[ i ].firstCommand = 0;
  849.         }
  850.     }
  851.  
  852. // RAVEN BEGIN
  853. // bdube: support multiple frames
  854.     for ( int ii = 0; ii < frames.Num(); ii ++ ) {
  855.         int framenum = frames[ii];    
  856.  
  857. // mekberg: error out of frame command is out of range.
  858. //            -1 because we don't want commands on the loop frame.
  859. //            If the anim doesn't loop they won't get handled.
  860.         if ( ( framenum < 1 ) || ( framenum > camera.Num() -1 ) ) {
  861.             gameLocal.Error("Frame command out of range: %d on  anim '%s'. Max %d.", framenum, name.c_str(), camera.Num() -1 );
  862.         }
  863.  
  864.         // Duplicate the frame info
  865.         if ( ii != 0 ) {
  866.             if ( fc.string ) {
  867.                 fc.string = new idStr ( fc.string->c_str() );
  868.             }
  869.             if ( fc.joint ) {
  870.                 fc.joint = new idStr ( fc.joint->c_str() );
  871.             }                
  872.             if ( fc.joint2 ) {
  873.                 fc.joint2 = new idStr ( fc.joint2->c_str() );
  874.             }
  875.             if ( fc.parmList ) {
  876.                 fc.parmList = new idList<idStr>( *fc.parmList );
  877.             }
  878.         }
  879.  
  880.         // frame numbers are 1 based in .def files, but 0 based internally
  881.         framenum--;
  882. // RAVEN END
  883.  
  884.     // allocate space for a new command
  885.     frameCommands.Alloc();
  886.  
  887.     // calculate the index of the new command
  888.     index = frameLookup[ framenum ].firstCommand + frameLookup[ framenum ].num;
  889.  
  890.     // move all commands from our index onward up one to give us space for our new command
  891.     for( i = frameCommands.Num() - 1; i > index; i-- ) {
  892.         frameCommands[ i ] = frameCommands[ i - 1 ];
  893.     }
  894.  
  895.     // fix the indices of any later frames to account for the inserted command
  896.     for( i = framenum + 1; i < frameLookup.Num(); i++ ) {
  897.         frameLookup[ i ].firstCommand++;
  898.     }
  899.  
  900.     // store the new command 
  901.     frameCommands[ index ] = fc;
  902.  
  903.     // increase the number of commands on this frame
  904.     frameLookup[ framenum ].num++;
  905.  
  906. // RAVEN BEGIN
  907. // bdube: loop frame commands
  908.     }
  909. // RAVEN END
  910.  
  911.     // return with no error
  912.     return NULL;
  913. }
  914.  
  915. /*
  916. =====================
  917. rvCameraAnimation::CallFrameCommandSound
  918. =====================
  919. */
  920. void rvCameraAnimation::CallFrameCommandSound ( const frameCommand_t& command, idEntity* ent, const s_channelType channel ) const {
  921.     if ( command.string ) {
  922.         ent->StartSound ( command.string->c_str(), channel, 0, false, NULL );
  923.     } else {
  924.         ent->StartSoundShader( command.soundShader, channel, 0, false, NULL );
  925.     }
  926. }
  927.  
  928. /*
  929. =====================
  930. rvCameraAnimation::CallFrameCommands
  931. =====================
  932. */
  933. void rvCameraAnimation::CallFrameCommands( idEntity *ent, int from, int to ) const {
  934.     int index;
  935.     int end;
  936.     int frame;
  937.     int numframes;
  938.  
  939.     if ( !frameLookup.Num() ) {
  940.         return;
  941.     }
  942.  
  943.     numframes = NumFrames();
  944.  
  945.     frame = from;
  946.     while( frame != to ) {
  947.         frame++;
  948.         if ( frame >= numframes ) {
  949.             frame = 0;
  950.         }
  951.  
  952.         index = frameLookup[ frame ].firstCommand;
  953.         end = index + frameLookup[ frame ].num;
  954.         while( index < end ) {
  955.             const frameCommand_t &command = frameCommands[ index++ ];
  956.  
  957. // RAVEN BEGIN
  958. // bdube: frame command debugging            
  959.             if ( g_showFrameCmds.GetBool() ) {
  960.                 idStr shortName;
  961.                 shortName = name;
  962.                 shortName.StripPath();
  963.                 shortName.StripFileExtension ( );
  964.                 gameLocal.Printf ( "Cameraframecmd: anim=%s frame=%d cmd=%s parm=%s\n",
  965.                              shortName.c_str(),
  966.                              frame + 1,
  967.                              frameCommandInfo[command.type].name,
  968.                              command.string?command.string->c_str():"???" );
  969.             }
  970. // RAVEN END            
  971.  
  972.             switch( command.type ) {
  973.                 case FC_SCRIPTFUNCTION: {
  974.                     gameLocal.CallFrameCommand( ent, command.function );
  975.                     break;
  976.                 }
  977. // RAVEN BEGIN
  978. // bdube: rewrote
  979.                 case FC_SCRIPTFUNCTIONOBJECT: {
  980.                     ent->ProcessEvent ( &EV_CallFunction, command.string->c_str() );
  981.                     break;
  982.                 }
  983. // RAVEN END                
  984.                 case FC_EVENTFUNCTION: {
  985.                     const idEventDef *ev = idEventDef::FindEvent( command.string->c_str() );
  986.                     ent->ProcessEvent( ev );
  987.                     break;
  988.                 }
  989. // RAVEN BEGIN
  990. // abahr:
  991.                 case FC_EVENTFUNCTION_ARGS: {
  992.                     assert( command.event );
  993.                     ent->ProcessEvent( command.event, (int)command.parmList );
  994.                     break;
  995.                 }
  996. // bdube: support indirection and simplify
  997.                 case FC_SOUND:
  998.                 case FC_SOUND_VOICE:
  999.                 case FC_SOUND_VOICE2:
  1000.                 case FC_SOUND_BODY:
  1001.                 case FC_SOUND_BODY2:
  1002.                 case FC_SOUND_BODY3:
  1003.                 case FC_SOUND_WEAPON:
  1004.                 case FC_SOUND_ITEM:
  1005.                 case FC_SOUND_GLOBAL:
  1006.                 case FC_SOUND_CHATTER:
  1007.                     CallFrameCommandSound ( command, ent, (const s_channelType)(command.type - FC_SOUND) );
  1008.                     break;
  1009. // RAVEN END
  1010.  
  1011.                 case FC_FX: {
  1012. // RAVEN BEGIN
  1013. // bdube: use raven effect system
  1014.                     rvClientEffect* cent;
  1015.                     if ( command.string ) {
  1016.                         if ( command.joint ) {
  1017.                             cent = ent->PlayEffect ( command.string->c_str(), ent->GetAnimator()->GetJointHandle ( *command.joint ) );
  1018.                         } else {
  1019.                             cent = gameLocal.PlayEffect ( ent->spawnArgs, command.string->c_str(), ent->GetRenderEntity()->origin, ent->GetRenderEntity()->axis );
  1020.                         }
  1021.                     } else {
  1022.                         if ( command.joint ) {
  1023.                             cent = ent->PlayEffect ( command.effect, ent->GetAnimator()->GetJointHandle ( *command.joint ), vec3_origin, mat3_identity );
  1024.                         } else {
  1025.                             cent = gameLocal.PlayEffect (  command.effect, ent->GetRenderEntity()->origin, ent->GetRenderEntity()->axis );
  1026.                         }
  1027.                     }
  1028.                     // End origin bone specified?
  1029. // RAVEN BEGIN
  1030. // jnewquist: Use accessor for static class type 
  1031.                     if ( cent && command.joint2 && ent->IsType ( idAnimatedEntity::GetClassType() ) ) {
  1032. // RAVEN END
  1033.                         cent->SetEndOrigin ( ent->GetAnimator()->GetJointHandle ( *command.joint2 ) );
  1034.                     }
  1035. // RAVEN END
  1036.                     break;
  1037.                 }
  1038.                 case FC_SKIN:
  1039. //                    ent->SetSkin( command.skin );
  1040.                     break;
  1041.  
  1042.                 case FC_TRIGGER: {
  1043.                     idEntity *target;
  1044.  
  1045.                     target = gameLocal.FindEntity( command.string->c_str() );
  1046.                     if ( target ) {
  1047.                         target->Signal( SIG_TRIGGER );
  1048.                         target->ProcessEvent( &EV_Activate, ent );
  1049.                         target->TriggerGuis();
  1050.                     } else {
  1051.                         gameLocal.Warning( "Framecommand 'trigger' on entity '%s', anim '%s', frame %d: Could not find entity '%s'",
  1052.                             ent->name.c_str(), FullName(), frame + 1, command.string->c_str() );
  1053.                     }
  1054.                     break;
  1055.                 }
  1056.  
  1057.                 case FC_DIRECTDAMAGE: {
  1058.                     ent->ProcessEvent( &AI_DirectDamage, command.string->c_str() );
  1059.                     break;
  1060.                 }
  1061.                 case FC_MUZZLEFLASH: {
  1062.                     break;
  1063.                 }
  1064.                 case FC_FOOTSTEP : {
  1065. //                    ent->ProcessEvent( &EV_Footstep );
  1066.                     break;
  1067.                 }
  1068.                 case FC_LEFTFOOT: {
  1069. //                    ent->ProcessEvent( &EV_FootstepLeft );
  1070.                     break;
  1071.                 }
  1072.                 case FC_RIGHTFOOT: {
  1073. //                    ent->ProcessEvent( &EV_FootstepRight );
  1074.                     break;
  1075.                 }
  1076.                 case FC_ENABLE_EYE_FOCUS: {
  1077.                     ent->ProcessEvent( &AI_EnableEyeFocus );
  1078.                     break;
  1079.                 }
  1080.                 case FC_DISABLE_EYE_FOCUS: {
  1081.                     ent->ProcessEvent( &AI_DisableEyeFocus );
  1082.                     break;
  1083.                 }
  1084.                 case FC_DISABLE_GRAVITY: {
  1085.                     ent->ProcessEvent( &AI_DisableGravity );
  1086.                     break;
  1087.                 }
  1088.                 case FC_ENABLE_GRAVITY: {
  1089.                     ent->ProcessEvent( &AI_EnableGravity );
  1090.                     break;
  1091.                 }
  1092.                 case FC_JUMP: {
  1093.                     ent->ProcessEvent( &AI_JumpFrame );
  1094.                     break;
  1095.                 }
  1096.                 case FC_ENABLE_CLIP: {
  1097.                     ent->ProcessEvent( &AI_EnableClip );
  1098.                     break;
  1099.                 }
  1100.                 case FC_DISABLE_CLIP: {
  1101.                     ent->ProcessEvent( &AI_DisableClip );
  1102.                     break;
  1103.                 }
  1104.                 case FC_ENABLE_WALK_IK: {
  1105. //                    ent->ProcessEvent( &EV_EnableWalkIK );
  1106.                     break;
  1107.                 }
  1108.                 case FC_DISABLE_WALK_IK: {
  1109. //                    ent->ProcessEvent( &EV_DisableWalkIK );
  1110.                     break;
  1111.                 }
  1112.                 case FC_ENABLE_LEG_IK: {
  1113. //                    ent->ProcessEvent( &EV_EnableLegIK, command.index );
  1114.                     break;
  1115.                 }
  1116.                 case FC_DISABLE_LEG_IK: {
  1117. //                    ent->ProcessEvent( &EV_DisableLegIK, command.index );
  1118.                     break;
  1119.                 }
  1120.                 case FC_RECORDDEMO: {
  1121.                     if ( command.string ) {
  1122.                         cmdSystem->BufferCommandText( CMD_EXEC_NOW, va( "recordDemo %s", command.string->c_str() ) );
  1123.                     } else {
  1124.                         cmdSystem->BufferCommandText( CMD_EXEC_NOW, "stoprecording" );
  1125.                     }
  1126.                     break;
  1127.                 }
  1128.                 case FC_AVIGAME: {
  1129.                     if ( command.string ) {
  1130.                         cmdSystem->BufferCommandText( CMD_EXEC_NOW, va( "aviGame %s", command.string->c_str() ) );
  1131.                     } else {
  1132.                         cmdSystem->BufferCommandText( CMD_EXEC_NOW, "aviGame" );
  1133.                     }
  1134.                     break;
  1135.                 }
  1136.  
  1137.                 case FC_AI_ENABLE_PAIN:
  1138. //                    ent->ProcessEvent ( &AI_EnablePain );                
  1139.                     break;
  1140.  
  1141.                 case FC_AI_DISABLE_PAIN:
  1142. //                    ent->ProcessEvent ( &AI_DisablePain );
  1143.                     break;
  1144.  
  1145.                 case FC_AI_ENABLE_DAMAGE:
  1146. //                    ent->ProcessEvent ( &AI_EnableDamage );                
  1147.                     break;
  1148.  
  1149.                 case FC_AI_LOCKENEMYORIGIN:
  1150. //                    ent->ProcessEvent ( &AI_LockEnemyOrigin );
  1151.                     break;
  1152.                     
  1153.                 case FC_AI_ATTACK:                    
  1154. //                    ent->ProcessEvent ( &AI_Attack, command.string->c_str(), command.joint->c_str() );
  1155.                     break;
  1156.  
  1157.                 case FC_AI_DISABLE_DAMAGE:
  1158. //                    ent->ProcessEvent ( &AI_DisableDamage );
  1159.                     break;
  1160.                     
  1161.                 case FC_AI_SPEAK:
  1162. //                    ent->ProcessEvent( &AI_Speak, command.string->c_str() );
  1163.                     break;
  1164.  
  1165.                 case FC_ACT_ATTACH_HIDE:
  1166. /*
  1167.                     if ( ent->IsType(idActor::GetClassType()) )
  1168.                     {
  1169.                         static_cast<idActor*>(ent)->HideAttachment( command.string->c_str() );
  1170.                     }
  1171. */
  1172.                     break;
  1173.  
  1174.                 case FC_ACT_ATTACH_SHOW:
  1175. /*
  1176.                     if ( ent->IsType(idActor::GetClassType()) )
  1177.                     {
  1178.                         static_cast<idActor*>(ent)->ShowAttachment( command.string->c_str() );
  1179.                     }
  1180. */
  1181.                     break;
  1182.  
  1183.                 case FC_AI_ATTACK_MELEE:
  1184. //                    ent->ProcessEvent( &AI_AttackMelee, command.string->c_str() );
  1185.                     break;
  1186.             }
  1187.         }
  1188.     }
  1189. }
  1190.  
  1191.  
  1192.  
  1193.  
  1194.  
  1195.  
  1196.  
  1197.  
  1198.  
  1199. /***********************************************************************
  1200.  
  1201.     idDeclCameraDef
  1202.  
  1203. ***********************************************************************/
  1204.  
  1205. /*
  1206. =====================
  1207. idDeclCameraDef::idDeclCameraDef
  1208. =====================
  1209. */
  1210. idDeclCameraDef::idDeclCameraDef() {
  1211. }
  1212.  
  1213. /*
  1214. =====================
  1215. idDeclCameraDef::~idDeclCameraDef
  1216. =====================
  1217. */
  1218. idDeclCameraDef::~idDeclCameraDef() {
  1219.     FreeData();
  1220. }
  1221.  
  1222. // RAVEN BEGIN
  1223. // jsinger: Added to support serialization/deserialization of binary decls
  1224. #ifdef RV_BINARYDECLS
  1225. /*
  1226. =====================
  1227. idDeclCameraDef::idDeclCameraDef( SerialInputStream &stream )
  1228. =====================
  1229. */
  1230. idDeclCameraDef::idDeclCameraDef( SerialInputStream &stream )
  1231. {
  1232.     // not supported yet
  1233.     assert(false);
  1234. }
  1235.  
  1236. void idDeclCameraDef::Write( SerialOutputStream &stream ) const
  1237. {
  1238.     // not supported yet
  1239.     assert(false);
  1240. }
  1241.  
  1242. void idDeclCameraDef::AddReferences() const
  1243. {
  1244.     // not supported yet
  1245.     assert(false);
  1246. }
  1247. #endif
  1248. // RAVEN END
  1249. /*
  1250. =================
  1251. idDeclCameraDef::Size
  1252. =================
  1253. */
  1254. // RAVEN BEGIN
  1255. // jscott: made more accurate
  1256. size_t idDeclCameraDef::Size( void ) const {
  1257.  
  1258.     size_t    size;
  1259.  
  1260.     size = sizeof( idDeclCameraDef );
  1261.     size += anims.Allocated();
  1262.  
  1263.     return( size );
  1264. }
  1265. // RAVEN END
  1266.  
  1267. /*
  1268. =====================
  1269. idDeclCameraDef::CopyDecl
  1270. =====================
  1271. */
  1272. void idDeclCameraDef::CopyDecl( const idDeclCameraDef *decl ) {
  1273.     int i;
  1274.  
  1275.     FreeData();
  1276.  
  1277.     anims.SetNum( decl->anims.Num() );
  1278.     for( i = 0; i < anims.Num(); i++ ) {
  1279.         anims[ i ] = new rvCameraAnimation( this, decl->anims[ i ] );
  1280.     }
  1281. }
  1282.  
  1283. /*
  1284. =====================
  1285. idDeclCameraDef::FreeData
  1286. =====================
  1287. */
  1288. void idDeclCameraDef::FreeData( void ) {
  1289.     anims.DeleteContents( true );
  1290. }
  1291.  
  1292. /*
  1293. ================
  1294. idDeclCameraDef::DefaultDefinition
  1295. ================
  1296. */
  1297. const char *idDeclCameraDef::DefaultDefinition( void ) const {
  1298.     return "{ }";
  1299. }
  1300.  
  1301.  
  1302.  
  1303. /*
  1304. =====================
  1305. idDeclCameraDef::Touch
  1306. =====================
  1307. */
  1308. void idDeclCameraDef::Touch( void ) const {
  1309. }
  1310.  
  1311. /*
  1312. =====================
  1313. idDeclCameraDef::ParseAnim
  1314. =====================
  1315. */
  1316. bool idDeclCameraDef::ParseAnim( idLexer &src, int numDefaultAnims ) {
  1317.     int                    i;
  1318.     int                    len;
  1319.     rvCameraAnimation    *anim;
  1320.     idStr                alias;
  1321.     idToken                realname;
  1322.     idToken                token;
  1323.     int                    numAnims;
  1324.  
  1325.     numAnims = 0;
  1326.  
  1327.     if( !src.ReadToken( &realname ) ) {
  1328.         src.Warning( "Unexpected end of file" );
  1329.         MakeDefault();
  1330.         return false;
  1331.     }
  1332.     alias = realname;
  1333.  
  1334.     for( i = 0; i < anims.Num(); i++ ) {
  1335.         if ( !idStr::Cmp( anims[ i ]->FullName(), realname ) ) {
  1336.             break;
  1337.         }
  1338.     }
  1339.  
  1340.     if ( ( i < anims.Num() ) && ( i >= numDefaultAnims ) ) {
  1341.         src.Warning( "Duplicate anim '%s'", realname.c_str() );
  1342.         MakeDefault();
  1343.         return false;
  1344.     }
  1345.  
  1346.     if ( i < numDefaultAnims ) {
  1347.         anim = anims[ i ];
  1348.     } else {
  1349.         // create the alias associated with this animation
  1350.         anim = new rvCameraAnimation();
  1351.         anims.Append( anim );
  1352.     }
  1353.  
  1354.     // random anims end with a number.  find the numeric suffix of the animation.
  1355.     len = alias.Length();
  1356.     for( i = len - 1; i > 0; i-- ) {
  1357.         if ( !isdigit( alias[ i ] ) ) {
  1358.             break;
  1359.         }
  1360.     }
  1361.  
  1362.     // check for zero length name, or a purely numeric name
  1363.     if ( i <= 0 ) {
  1364.         src.Warning( "Invalid animation name '%s'", alias.c_str() );
  1365.         MakeDefault();
  1366.         return false;
  1367.     }
  1368.  
  1369.     // remove the numeric suffix
  1370.     alias.CapLength( i + 1 );
  1371.  
  1372.     // parse the anims from the string
  1373.     if( !src.ReadToken( &token ) ) {
  1374.         src.Warning( "Unexpected end of file" );
  1375.         MakeDefault();
  1376.         return false;
  1377.     }
  1378.  
  1379.     anim->SetAnim( this, realname, alias, token );
  1380.  
  1381.     // parse any frame commands or animflags
  1382.     if ( src.CheckTokenString( "{" ) ) {
  1383.         while( 1 ) {
  1384.             if( !src.ReadToken( &token ) ) {
  1385.                 src.Warning( "Unexpected end of file" );
  1386.                 MakeDefault();
  1387.                 return false;
  1388.             }
  1389.             if ( token == "}" ) {
  1390.                 break;
  1391.             } else if ( token == "frame" ) {
  1392.                 // create a frame command
  1393. // RAVEN BEGIN
  1394. // bdube: Support a list of frame numbers
  1395. //                int            framenum;
  1396.                 const char    *err;
  1397.                 idList<int> frameList;
  1398.  
  1399.                 do
  1400.                 {                        
  1401. // RAVEN END                
  1402.                 // make sure we don't have any line breaks while reading the frame command so the error line # will be correct
  1403.                 if ( !src.ReadTokenOnLine( &token ) ) {
  1404.                     src.Warning( "Missing frame # after 'frame'" );
  1405.                     MakeDefault();
  1406.                     return false;
  1407.                 }
  1408.                 if ( token.type == TT_PUNCTUATION && token == "-" ) {
  1409.                     src.Warning( "Invalid frame # after 'frame'" );
  1410.                     MakeDefault();
  1411.                     return false;
  1412.                 } else if ( token.type != TT_NUMBER || token.subtype == TT_FLOAT ) {
  1413.                     src.Error( "expected integer value, found '%s'", token.c_str() );
  1414.                 }
  1415. // RAVEN BEGIN
  1416. // bdube: multiple frames
  1417.                     frameList.Append ( token.GetIntValue() );
  1418.                 
  1419.                 } while ( src.CheckTokenString ( "," ) );
  1420. // RAVEN END                
  1421.  
  1422.                 // put the command on the specified frame of the animation
  1423. // RAVEN BEGIN
  1424. // bdube: Support a list of frame numbers
  1425.                 err = anim->AddFrameCommand( this, frameList, src, NULL );
  1426. // RAVEN END
  1427.                 if ( err ) {
  1428.                     src.Warning( "%s", err );
  1429.                     MakeDefault();
  1430.                     return false;
  1431.                 }
  1432.             } else {
  1433.                 src.Warning( "Unknown command '%s'", token.c_str() );
  1434.                 MakeDefault();
  1435.                 return false;
  1436.             }
  1437.         }
  1438.     }
  1439.  
  1440.     return true;
  1441. }
  1442.  
  1443. /*
  1444. ================
  1445. idDeclCameraDef::Parse
  1446. ================
  1447. */
  1448. bool idDeclCameraDef::Parse( const char *text, const int textLength, bool noCaching ) {
  1449.     idStr                filename;
  1450.     idStr                extension;
  1451.     idLexer                src;
  1452.     idToken                token;
  1453.     idToken                token2;
  1454.     int                    numDefaultAnims;
  1455.     
  1456.     TIME_THIS_SCOPE( __FUNCLINE__);    
  1457.  
  1458.     src.LoadMemory( text, textLength, GetFileName(), GetLineNum() );
  1459.     src.SetFlags( DECL_LEXER_FLAGS );
  1460.     src.SkipUntilString( "{" );
  1461.  
  1462.     numDefaultAnims = 0;
  1463.     while( 1 ) {
  1464.         if ( !src.ReadToken( &token ) ) {
  1465.             break;
  1466.         }
  1467.  
  1468.         if ( !token.Icmp( "}" ) ) {
  1469.             break;
  1470.         }
  1471.         else if ( token == "anim" ) {
  1472.             if ( !ParseAnim( src, numDefaultAnims ) ) {
  1473.                 MakeDefault();
  1474.                 return false;
  1475.             }
  1476.         } else {
  1477.             src.Warning( "unknown token '%s'", token.c_str() );
  1478.             MakeDefault();
  1479.             return false;
  1480.         }
  1481.     }
  1482.  
  1483.     // shrink the anim list down to save space
  1484.     anims.SetGranularity( 1 );
  1485.     anims.SetNum( anims.Num() );
  1486.  
  1487.     return true;
  1488. }
  1489.  
  1490. /*
  1491. =====================
  1492. idDeclCameraDef::Validate
  1493. =====================
  1494. */
  1495. bool idDeclCameraDef::Validate( const char *psText, int iTextLength, idStr &strReportTo ) const {
  1496.     idDeclCameraDef *pSelf = (idDeclCameraDef*) declManager->AllocateDecl( DECL_MODELDEF );
  1497.     bool bOk = pSelf->Parse( psText, iTextLength, false );
  1498.     pSelf->FreeData();
  1499.     delete pSelf->base;
  1500.     delete pSelf;
  1501.  
  1502.     return bOk;
  1503. }
  1504.  
  1505. /*
  1506. =====================
  1507. idDeclCameraDef::HasAnim
  1508. =====================
  1509. */
  1510. bool idDeclCameraDef::HasAnim( const char *name ) const {
  1511.     int    i;
  1512.  
  1513.     // find any animations with same name
  1514.     for( i = 0; i < anims.Num(); i++ ) {
  1515.         if ( !idStr::Cmp( anims[ i ]->Name(), name ) ) {
  1516.             return true;
  1517.         }
  1518.     }
  1519.     
  1520.     return false;
  1521. }
  1522.  
  1523. /*
  1524. =====================
  1525. idDeclCameraDef::NumAnims
  1526. =====================
  1527. */
  1528. int idDeclCameraDef::NumAnims( void ) const {
  1529.     return anims.Num() + 1;
  1530. }
  1531.  
  1532. /*
  1533. =====================
  1534. idDeclCameraDef::GetSpecificAnim
  1535.  
  1536. Gets the exact anim for the name, without randomization.
  1537. =====================
  1538. */
  1539. int idDeclCameraDef::GetSpecificAnim( const char *name ) const {
  1540.     int    i;
  1541.  
  1542.     // find a specific animation
  1543.     for( i = 0; i < anims.Num(); i++ ) {
  1544.         if ( !idStr::Cmp( anims[ i ]->FullName(), name ) ) {
  1545.             return i + 1;
  1546.         }
  1547.     }
  1548.  
  1549.     // didn't find it
  1550.     return 0;
  1551. }
  1552.  
  1553. /*
  1554. =====================
  1555. idDeclCameraDef::GetAnim
  1556. =====================
  1557. */
  1558. int idDeclCameraDef::GetAnim( const char *name ) const {
  1559.     int                i;
  1560.     int                which;
  1561.     const int        MAX_ANIMS = 64;
  1562.     int                animList[ MAX_ANIMS ];
  1563.     int                numAnims;
  1564.     int                len;
  1565.  
  1566.     len = strlen( name );
  1567.     if ( len && idStr::CharIsNumeric( name[ len - 1 ] ) ) {
  1568.         // find a specific animation
  1569.         return GetSpecificAnim( name );
  1570.     }
  1571.  
  1572.     // find all animations with same name
  1573.     numAnims = 0;
  1574.     for( i = 0; i < anims.Num(); i++ ) {
  1575.         if ( !idStr::Cmp( anims[ i ]->Name(), name ) ) {
  1576.             animList[ numAnims++ ] = i;
  1577.             if ( numAnims >= MAX_ANIMS ) {
  1578.                 break;
  1579.             }
  1580.         }
  1581.     }
  1582.  
  1583.     if ( !numAnims ) {
  1584.         return 0;
  1585.     }
  1586.  
  1587.     // get a random anim
  1588.     //FIXME: don't access gameLocal here?
  1589.     which = gameLocal.random.RandomInt( numAnims );
  1590.     return animList[ which ] + 1;
  1591. }
  1592.  
  1593.  
  1594.  
  1595.  
  1596.  
  1597.  
  1598.  
  1599.  
  1600.  
  1601.  
  1602. /*
  1603. ===============================================================================
  1604.  
  1605.   idCameraAnim
  1606.  
  1607. ===============================================================================
  1608. */
  1609. const idEventDef EV_Camera_Start( "start", NULL );
  1610. const idEventDef EV_Camera_Stop( "stop", NULL );
  1611.  
  1612. // RAVEN BEGIN
  1613. // mekberg: wait support
  1614. const idEventDef EV_Camera_IsActive( "isActive", "", 'd' );
  1615. // RAVEN END
  1616.  
  1617. CLASS_DECLARATION( idCamera, idCameraAnim )
  1618.     EVENT( EV_Thread_SetCallback,    idCameraAnim::Event_SetCallback )
  1619.     EVENT( EV_Camera_Stop,            idCameraAnim::Event_Stop )
  1620.     EVENT( EV_Camera_Start,            idCameraAnim::Event_Start )
  1621.     EVENT( EV_Activate,                idCameraAnim::Event_Activate )
  1622.  
  1623.     // RAVEN BEGIN
  1624.     // mekberg: wait support
  1625.     EVENT( EV_IsActive,                idCameraAnim::Event_IsActive )
  1626.     // RAVEN END
  1627. END_CLASS
  1628.  
  1629.  
  1630. /*
  1631. =====================
  1632. idCameraAnim::idCameraAnim
  1633. =====================
  1634. */
  1635. idCameraAnim::idCameraAnim() {
  1636.     threadNum = 0;
  1637.     offset.Zero();
  1638.     cycle = 1;
  1639.     starttime = 0;
  1640.     activator = NULL;
  1641.     lastFrame = -1;
  1642. }
  1643.  
  1644. /*
  1645. =====================
  1646. idCameraAnim::~idCameraAnim
  1647. =====================
  1648. */
  1649. idCameraAnim::~idCameraAnim() {
  1650.     if ( gameLocal.GetCamera() == this ) {
  1651.         gameLocal.SetCamera( NULL );
  1652.     }
  1653. }
  1654.  
  1655. /*
  1656. ===============
  1657. idCameraAnim::Save
  1658. ================
  1659. */
  1660. void idCameraAnim::Save( idSaveGame *savefile ) const {
  1661.     savefile->WriteInt( threadNum );
  1662.     savefile->WriteVec3( offset );
  1663.     savefile->WriteInt( starttime );
  1664.     savefile->WriteInt( cycle );
  1665.     savefile->WriteInt( lastFrame );        // cnicholson: Added unsaved var
  1666.  
  1667.     activator.Save( savefile );
  1668. }
  1669.  
  1670. /*
  1671. ===============
  1672. idCameraAnim::Restore
  1673. ================
  1674. */
  1675. void idCameraAnim::Restore( idRestoreGame *savefile ) {
  1676.     savefile->ReadInt( threadNum );
  1677.     savefile->ReadVec3( offset );
  1678.     savefile->ReadInt( starttime );
  1679.     savefile->ReadInt( cycle );
  1680.     savefile->ReadInt( lastFrame );        // cnicholson: Added unread var
  1681.  
  1682.     activator.Restore( savefile );
  1683.  
  1684.     LoadAnim();
  1685. }
  1686.  
  1687. /*
  1688. =====================
  1689. idCameraAnim::Spawn
  1690. =====================
  1691. */
  1692. void idCameraAnim::Spawn( void ) {
  1693.     if ( spawnArgs.GetVector( "old_origin", "0 0 0", offset ) ) {
  1694.         offset = GetPhysics()->GetOrigin() - offset;
  1695.     } else {
  1696.         offset.Zero();
  1697.     }
  1698.  
  1699.     // always think during cinematics
  1700.     cinematic = true;
  1701.  
  1702.     LoadAnim();
  1703.  
  1704. // RAVEN BEGIN
  1705. // jnewquist: Track texture usage during cinematics for streaming purposes
  1706. #if defined(_CONSOLE) || defined(TEST_MANUAL_STREAMING)
  1707.     idToken token;
  1708.     idStr filename = "cinematics/";
  1709.     filename += gameLocal.mapFileNameStripped;
  1710.     filename += "_";
  1711.     filename += name;
  1712.     filename += ".cincmd";
  1713.     idLexer precache(DECL_LEXER_FLAGS|LEXFL_ONLYSTRINGS);
  1714.     if ( !precache.LoadFile(filename) )
  1715.     {
  1716.         return;
  1717.     }
  1718.     if ( !precache.ReadToken(&token) ) {
  1719.         return;
  1720.     }
  1721.     int imageCount = atoi(token);
  1722.     //common->Printf("imageCount: %d\n", imageCount);
  1723.     imageTable.AssureSize(imageCount);
  1724.     int index = 0;
  1725.     while(precache.ReadToken(&token) && index < imageCount)
  1726.     {
  1727.         imageTable[index++] = strtoul(token, NULL, 16);
  1728.         //common->Printf("%08x\n", imageTable[index-1]);
  1729.     }
  1730.     if ( index < imageCount ) {
  1731.         return;
  1732.     }
  1733.     int cmdCount = atoi(token)*2;
  1734.     //common->Printf("cmdCount %d\n", cmdCount);
  1735.     imageCmds.AssureSize(cmdCount);
  1736.     index = 0;
  1737.     while(precache.ReadToken(&token) && index < cmdCount)
  1738.     {
  1739.         imageCmds[index] = atoi(token);
  1740.         if (precache.ReadToken(&token)) {
  1741.             imageCmds[index+1] = atoi(token);
  1742.         } else {
  1743.             break;
  1744.         }
  1745.         //common->Printf("%d %d\n", imageCmds[index], imageCmds[index+1]);
  1746.         index += 2;
  1747.     }
  1748. #endif
  1749. #ifndef _CONSOLE
  1750.     // touch the cinematic streaming command file during build
  1751.     if ( cvarSystem->GetCVarBool("com_makingBuild") && cvarSystem->GetCVarBool("com_Bundler") )
  1752.     {
  1753.         idFile *file;
  1754.         idStr filename = "cinematics/";
  1755.         filename += gameLocal.mapFileNameStripped;
  1756.         filename += "_";
  1757.         filename += name;
  1758.         filename += ".cincmd";
  1759.         file = fileSystem->OpenFileRead( filename );
  1760.         fileSystem->CloseFile( file );
  1761.     }
  1762. #endif
  1763. // RAVEN END
  1764. }
  1765.  
  1766. /*
  1767. ================
  1768. idCameraAnim::Load
  1769. ================
  1770. */
  1771. void idCameraAnim::LoadAnim( void ) {
  1772.     idLexer        parser( LEXFL_ALLOWPATHNAMES | LEXFL_NOSTRINGESCAPECHARS | LEXFL_NOSTRINGCONCAT );
  1773.     idToken        token;
  1774.     idStr        filename;
  1775.     const char    *key;
  1776.  
  1777.     key = spawnArgs.GetString( "camera" );
  1778.     const idDecl *mapDecl = declManager->FindType( DECL_CAMERADEF, key, false );
  1779.     cameraDef = static_cast<const idDeclCameraDef *>( mapDecl );
  1780.  
  1781.     key = spawnArgs.GetString( "anim" );
  1782.     if ( !key ) {
  1783.         gameLocal.Error( "Missing 'anim' key on '%s'", name.c_str() );
  1784.     }
  1785.  
  1786. }
  1787.  
  1788. /*
  1789. ===============
  1790. idCameraAnim::Start
  1791. ================
  1792. */
  1793. void idCameraAnim::Start( void ) {
  1794.     cycle = spawnArgs.GetInt( "cycle" );
  1795.     if ( !cycle ) {
  1796.         cycle = 1;
  1797.     }
  1798.  
  1799.     if ( g_debugCinematic.GetBool() ) {
  1800.         gameLocal.Printf( "%d: '%s' start\n", gameLocal.framenum, GetName() );
  1801.     }
  1802.  
  1803.     lastFrame = -1;
  1804.     starttime = gameLocal.time;
  1805.     gameLocal.SetCamera( this );
  1806.     BecomeActive( TH_THINK );
  1807.  
  1808. // RAVEN BEGIN
  1809. // jnewquist: Track texture usage during cinematics for streaming purposes
  1810. #ifndef _CONSOLE
  1811.     renderSystem->TrackTextureUsage( idRenderSystem::TEXTURE_TRACK_BEGIN, cameraDef->GetAnim(1)->GetFrameRate(), GetName() );
  1812. #endif
  1813. #if defined(_CONSOLE) || defined(TEST_MANUAL_STREAMING)
  1814.     //common->Printf("Starting %s\n", GetName());
  1815.     renderSystem->BeginManualStreaming( imageTable, imageCmds );
  1816. #endif
  1817. // RAVEN END
  1818.  
  1819.     // if the player has already created the renderview for this frame, have him update it again so that the camera starts this frame
  1820. // RAVEN BEGIN
  1821. // mekberg: make sure render view is valid.
  1822.     if ( gameLocal.GetLocalPlayer( )->GetRenderView( ) && gameLocal.GetLocalPlayer()->GetRenderView()->time == gameLocal.time ) {
  1823. // RAVEN END
  1824.         gameLocal.GetLocalPlayer()->CalculateRenderView();
  1825.     }
  1826. }
  1827.  
  1828. /*
  1829. =====================
  1830. idCameraAnim::Stop
  1831. =====================
  1832. */
  1833. void idCameraAnim::Stop( void ) {
  1834.     if ( gameLocal.GetCamera() == this ) {
  1835.         if ( g_debugCinematic.GetBool() ) {
  1836.             gameLocal.Printf( "%d: '%s' stop\n", gameLocal.framenum, GetName() );
  1837.         }
  1838.  
  1839.         BecomeInactive( TH_THINK );
  1840.         gameLocal.SetCamera( NULL );
  1841.         if ( threadNum ) {
  1842.             idThread::ObjectMoveDone( threadNum, this );
  1843.             threadNum = 0;
  1844.         }
  1845.         ActivateTargets( activator.GetEntity() );
  1846.  
  1847. // RAVEN BEGIN
  1848. // jnewquist: Track texture usage during cinematics for streaming purposes
  1849. #ifndef _CONSOLE
  1850.         renderSystem->TrackTextureUsage( idRenderSystem::TEXTURE_TRACK_END, cameraDef->GetAnim(1)->GetFrameRate() );
  1851. #endif
  1852. #if defined(_CONSOLE) || defined(TEST_MANUAL_STREAMING)
  1853.         //common->Printf("Stopping %s\n", GetName());
  1854.         renderSystem->EndManualStreaming();
  1855. #endif
  1856. // RAVEN END
  1857.     }
  1858. }
  1859.  
  1860. /*
  1861. =====================
  1862. idCameraAnim::Think
  1863. =====================
  1864. */
  1865. void idCameraAnim::Think( void ) {
  1866.     int frame;
  1867.     int frameTime;
  1868.  
  1869.     if ( thinkFlags & TH_THINK ) {
  1870.         // check if we're done in the Think function when the cinematic is being skipped (idCameraAnim::GetViewParms isn't called when skipping cinematics).
  1871. // RAVEN BEGIN
  1872. // abahr: removed '!'
  1873.         if ( gameLocal.skipCinematic ) {
  1874. // RAVEN END
  1875.             return;
  1876.         }
  1877.  
  1878.         if ( cameraDef->GetAnim(1)->NumFrames() < 2 ) {
  1879.             // 1 frame anims never end
  1880.             return;
  1881.         }
  1882.  
  1883.         if ( cameraDef->GetAnim(1)->GetFrameRate() == gameLocal.GetMHz() ) {
  1884.             frameTime    = gameLocal.time - starttime;
  1885.             frame        = frameTime / gameLocal.msec;
  1886.         } else {
  1887.             frameTime    = ( gameLocal.time - starttime ) * cameraDef->GetAnim(1)->GetFrameRate();
  1888.             frame        = frameTime / 1000;
  1889.         }
  1890.         
  1891.         if ( frame > cameraDef->GetAnim(1)->NumFrames() + cameraDef->GetAnim(1)->NumCuts() - 2 ) {
  1892.             if ( cycle > 0 ) {
  1893.                 cycle--;
  1894.             }
  1895.             lastFrame = -1;
  1896.  
  1897.             if ( cycle != 0 ) {
  1898.                 // advance start time so that we loop
  1899.                 starttime += ( ( cameraDef->GetAnim(1)->NumFrames() - cameraDef->GetAnim(1)->NumCuts() ) * 1000 ) / cameraDef->GetAnim(1)->GetFrameRate();
  1900.             } else {
  1901.                 Stop();
  1902.             }
  1903.         }
  1904.     }
  1905. }
  1906.  
  1907. /*
  1908. =====================
  1909. idCameraAnim::GetViewParms
  1910. =====================
  1911. */
  1912. void idCameraAnim::GetViewParms( renderView_t *view ) {
  1913.     int                realFrame;
  1914.     int                frame;
  1915.     int                frameTime;
  1916.     float            lerp;
  1917.     float            invlerp;
  1918.     const cameraFrame_t    *camFrame;
  1919.     int                i;
  1920.     int                cut;
  1921.     idQuat            q1, q2, q3;
  1922.  
  1923.     assert( view );
  1924.     if ( !view ) {
  1925.         return;
  1926.     }
  1927. //RAVEN BEGIN
  1928. //jshepard: safety first
  1929.     if( !cameraDef )    {
  1930.         gameLocal.Warning("Invalid cameraDef in GetViewParms");
  1931.         return;
  1932.     }
  1933. //RAVEN END
  1934.     if ( !cameraDef->GetAnim(1) ) {
  1935.         return;
  1936.     }
  1937.  
  1938.     if ( cameraDef->GetAnim(1)->NumFrames() == 0 ) {
  1939.         // we most likely are in the middle of a restore
  1940.         // FIXME: it would be better to fix it so this doesn't get called during a restore
  1941.         return;
  1942.     }
  1943.  
  1944.     if ( cameraDef->GetAnim(1)->GetFrameRate() == gameLocal.GetMHz() ) {
  1945.         frameTime    = gameLocal.time - starttime;
  1946.         frame        = frameTime / gameLocal.msec;
  1947.         lerp        = 0.0f;
  1948.     } else {
  1949.         frameTime    = ( gameLocal.time - starttime ) * cameraDef->GetAnim(1)->GetFrameRate();
  1950.         frame        = frameTime / 1000;
  1951.         lerp        = ( frameTime % 1000 ) * 0.001f;
  1952.     }
  1953.  
  1954.     // skip any frames where camera cuts occur
  1955.     realFrame = frame;
  1956.     cut = 0;
  1957.     for( i = 0; i < cameraDef->GetAnim(1)->NumCuts(); i++ ) {
  1958.         if ( frame < cameraDef->GetAnim(1)->GetCut( i ) ) {
  1959.             break;
  1960.         }
  1961.         frame++;
  1962.         cut++;
  1963.     }
  1964.     if ( lastFrame != frame ) {
  1965.         cameraDef->GetAnim(1)->CallFrameCommands( this, lastFrame, frame );
  1966.         lastFrame = frame;
  1967.     }
  1968.  
  1969.     if ( g_debugCinematic.GetBool() ) {
  1970.         int prevFrameTime    = ( gameLocal.time - starttime - gameLocal.msec ) * cameraDef->GetAnim(1)->GetFrameRate();
  1971.         int prevFrame        = prevFrameTime / 1000;
  1972.         int prevCut;
  1973.  
  1974.         prevCut = 0;
  1975.         for( i = 0; i < cameraDef->GetAnim(1)->NumCuts(); i++ ) {
  1976.             if ( prevFrame < cameraDef->GetAnim(1)->GetCut( i ) ) {
  1977.                 break;
  1978.             }
  1979.             prevFrame++;
  1980.             prevCut++;
  1981.         }
  1982.  
  1983.         if ( prevCut != cut ) {
  1984.             gameLocal.Printf( "%d: '%s' cut %d\n", gameLocal.framenum, GetName(), cut );
  1985.         }
  1986.     }
  1987.  
  1988.     // clamp to the first frame.  also check if this is a one frame anim.  one frame anims would end immediately,
  1989.     // but since they're mainly used for static cams anyway, just stay on it infinitely.
  1990.     if ( ( frame < 0 ) || ( cameraDef->GetAnim(1)->NumFrames() < 2 ) ) {
  1991.         view->viewaxis = cameraDef->GetAnim(1)->GetAnim( 0 )->q.ToQuat().ToMat3();
  1992.         view->vieworg = cameraDef->GetAnim(1)->GetAnim( 0 )->t + offset;
  1993.         view->fov_x = cameraDef->GetAnim(1)->GetAnim( 0 )->fov;
  1994.     } else if ( frame > cameraDef->GetAnim(1)->NumFrames() - 2 ) {
  1995.         if ( cycle > 0 ) {
  1996.             cycle--;
  1997.         }
  1998.  
  1999.         if ( cycle != 0 ) {
  2000.             // advance start time so that we loop
  2001.             starttime += ( ( cameraDef->GetAnim(1)->NumFrames() - cameraDef->GetAnim(1)->NumCuts() ) * 1000 ) / cameraDef->GetAnim(1)->GetFrameRate();
  2002.             GetViewParms( view );
  2003.             return;
  2004.         }
  2005.  
  2006.         Stop();
  2007.         if ( gameLocal.GetCamera() != NULL ) {
  2008.             // we activated another camera when we stopped, so get it's viewparms instead
  2009.             gameLocal.GetCamera()->GetViewParms( view );
  2010.             return;
  2011.         } else {
  2012.             // just use our last frame
  2013.             camFrame = cameraDef->GetAnim(1)->GetAnim( cameraDef->GetAnim(1)->NumFrames() - 1 );
  2014.             view->viewaxis = camFrame->q.ToQuat().ToMat3();
  2015.             view->vieworg = camFrame->t + offset;
  2016.             view->fov_x = camFrame->fov;
  2017.         }
  2018.     } else if ( lerp == 0.0f ) {
  2019.         camFrame = cameraDef->GetAnim(1)->GetAnim( frame );
  2020.         view->viewaxis = camFrame[ 0 ].q.ToMat3();
  2021.         view->vieworg = camFrame[ 0 ].t + offset;
  2022.         view->fov_x = camFrame[ 0 ].fov;
  2023.     } else {
  2024.         camFrame = cameraDef->GetAnim(1)->GetAnim( frame );
  2025.         invlerp = 1.0f - lerp;
  2026.         q1 = camFrame[ 0 ].q.ToQuat();
  2027.         q2 = camFrame[ 1 ].q.ToQuat();
  2028.         q3.Slerp( q1, q2, lerp );
  2029.         view->viewaxis = q3.ToMat3();
  2030.         view->vieworg = camFrame[ 0 ].t * invlerp + camFrame[ 1 ].t * lerp + offset;
  2031.         view->fov_x = camFrame[ 0 ].fov * invlerp + camFrame[ 1 ].fov * lerp;
  2032.     }
  2033.  
  2034.     gameLocal.CalcFov( view->fov_x, view->fov_x, view->fov_y );
  2035.  
  2036.     // setup the pvs for this frame
  2037.     UpdatePVSAreas( view->vieworg );
  2038.     
  2039. #if 0
  2040.     static int lastFrame = 0;
  2041.     static idVec3 lastFrameVec( 0.0f, 0.0f, 0.0f );
  2042.     if ( gameLocal.time != lastFrame ) {
  2043.         gameRenderWorld->DebugBounds( colorCyan, idBounds( view->vieworg ).Expand( 16.0f ), vec3_origin, gameLocal.msec );
  2044.         gameRenderWorld->DebugLine( colorRed, view->vieworg, view->vieworg + idVec3( 0.0f, 0.0f, 2.0f ), 10000, false );
  2045.         gameRenderWorld->DebugLine( colorCyan, lastFrameVec, view->vieworg, 10000, false );
  2046.         gameRenderWorld->DebugLine( colorYellow, view->vieworg + view->viewaxis[ 0 ] * 64.0f, view->vieworg + view->viewaxis[ 0 ] * 66.0f, 10000, false );
  2047.         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 );
  2048.         lastFrameVec = view->vieworg;
  2049.         lastFrame = gameLocal.time;
  2050.     }
  2051. #endif
  2052.  
  2053.     if ( g_showcamerainfo.GetBool() ) {
  2054.         gameLocal.Printf( "^5Frame: ^7%d/%d\n\n\n", realFrame + 1, cameraDef->GetAnim(1)->NumFrames() - cameraDef->GetAnim(1)->NumCuts() );
  2055.     }
  2056. // jnewquist: Track texture usage during cinematics for streaming purposes
  2057. #ifndef _CONSOLE
  2058.     renderSystem->TrackTextureUsage( idRenderSystem::TEXTURE_TRACK_UPDATE, realFrame );
  2059. #endif
  2060. #if defined(_CONSOLE) || defined(TEST_MANUAL_STREAMING)
  2061.     renderSystem->UpdateManualStreaming( realFrame );
  2062. #endif
  2063. }
  2064. // RAVEN END
  2065.  
  2066. /*
  2067. ===============
  2068. idCameraAnim::Event_Activate
  2069. ================
  2070. */
  2071. void idCameraAnim::Event_Activate( idEntity *_activator ) {
  2072.     activator = _activator;
  2073.     if ( thinkFlags & TH_THINK ) {
  2074.         Stop();
  2075.     } else {
  2076.         Start();
  2077.     }
  2078. }
  2079.  
  2080. /*
  2081. ===============
  2082. idCameraAnim::Event_Start
  2083. ================
  2084. */
  2085. void idCameraAnim::Event_Start( void ) {
  2086.     Start();
  2087. }
  2088.  
  2089. /*
  2090. ===============
  2091. idCameraAnim::Event_Stop
  2092. ================
  2093. */
  2094. void idCameraAnim::Event_Stop( void ) {
  2095.     Stop();
  2096. }
  2097.  
  2098. /*
  2099. ================
  2100. idCameraAnim::Event_SetCallback
  2101. ================
  2102. */
  2103. void idCameraAnim::Event_SetCallback( void ) {
  2104.     if ( ( gameLocal.GetCamera() == this ) && !threadNum ) {
  2105.         threadNum = idThread::CurrentThreadNum();
  2106.         idThread::ReturnInt( true );
  2107.     } else {
  2108.         idThread::ReturnInt( false );
  2109.     }
  2110. }
  2111.  
  2112. // RAVEN BEGIN
  2113. // mekberg: wait support
  2114. /*
  2115. ================
  2116. idCameraAnim::Event_IsActive
  2117. ================
  2118. */
  2119. void idCameraAnim::Event_IsActive( void ) {
  2120.     idThread::ReturnFloat( gameLocal.GetCamera( ) ? 1.0f : 0.0f );
  2121. }
  2122.  
  2123. // RAVEN END
  2124.  
  2125. // RAVEN BEGIN
  2126. // jscott: portal sky support
  2127.  
  2128. /***********************************************************************
  2129.  
  2130.   rvCameraPortalSky
  2131.  
  2132. ***********************************************************************/
  2133.  
  2134. CLASS_DECLARATION( idCamera, rvCameraPortalSky )
  2135. END_CLASS
  2136.  
  2137. /*
  2138. ===============
  2139. rvCameraPortalSky::Save
  2140. ================
  2141. */
  2142. void rvCameraPortalSky::Save( idSaveGame *savefile ) const 
  2143. {
  2144. }
  2145.  
  2146. /*
  2147. ===============
  2148. rvCameraPortalSky::Restore
  2149. ================
  2150. */
  2151. void rvCameraPortalSky::Restore( idRestoreGame *savefile ) 
  2152. {
  2153.     // Run spawn to set default values
  2154.     Spawn();
  2155. }
  2156.  
  2157. /*
  2158. =====================
  2159. rvCameraPortalSky::Spawn
  2160. =====================
  2161. */
  2162. void rvCameraPortalSky::Spawn( void ) 
  2163. {
  2164.     if( gameLocal.GetPortalSky() )
  2165.     {
  2166.         gameLocal.Error( "Only one portal sky camera allowed" );
  2167.     }
  2168.     gameLocal.SetPortalSky( this );
  2169. }
  2170.  
  2171. /*
  2172. =====================
  2173. rvCameraPortalSky::GetViewParms
  2174. =====================
  2175. */
  2176. void rvCameraPortalSky::GetViewParms( renderView_t *view ) 
  2177. {
  2178.     assert( view );
  2179.     if( view ) 
  2180.     {
  2181.         view->vieworg = GetPhysics()->GetOrigin();
  2182.         view->viewID = -1;
  2183.     }
  2184. }
  2185.  
  2186.  
  2187. /***********************************************************************
  2188.  
  2189.   rvCameraPlayback
  2190.  
  2191. ***********************************************************************/
  2192.  
  2193. CLASS_DECLARATION( idCamera, rvCameraPlayback )
  2194. END_CLASS
  2195.  
  2196. /*
  2197. ===============
  2198. rvCameraPlayback::Save
  2199. ================
  2200. */
  2201. void rvCameraPlayback::Save( idSaveGame *savefile ) const 
  2202. {
  2203. }
  2204.  
  2205. /*
  2206. ===============
  2207. rvCameraPlayback::Restore
  2208. ================
  2209. */
  2210. void rvCameraPlayback::Restore( idRestoreGame *savefile ) 
  2211. {
  2212.     // Run spawn to set default values
  2213.     Spawn();
  2214. }
  2215.  
  2216. /*
  2217. =====================
  2218. rvCameraPlayback::Spawn
  2219. =====================
  2220. */
  2221. void rvCameraPlayback::Spawn( void ) 
  2222. {
  2223.     startTime = gameLocal.time;
  2224.     playback = declManager->PlaybackByIndex( g_currentPlayback.GetInteger() );
  2225. }
  2226.  
  2227. /*
  2228. =====================
  2229. rvCameraPlayback::GetViewParms
  2230. =====================
  2231. */
  2232. void rvCameraPlayback::GetViewParms( renderView_t *view ) 
  2233. {
  2234.     rvDeclPlaybackData    pbd;
  2235.  
  2236.     assert( view );
  2237.     if( view ) 
  2238.     {
  2239.         pbd.Init();
  2240.         if( declManager->GetPlaybackData( playback, PBFL_GET_POSITION | PBFL_GET_ANGLES_FROM_VEL, gameLocal.time - startTime, gameLocal.time - startTime, &pbd ) )
  2241.         {
  2242.             startTime = gameLocal.time;
  2243.         }
  2244.  
  2245.         view->vieworg = pbd.GetPosition();
  2246.         view->viewaxis = pbd.GetAngles().ToMat3();
  2247.  
  2248.         // field of view
  2249. // RAVEN BEGIN
  2250. // jshepard: fov as a float for smoove transitions
  2251.         gameLocal.CalcFov ( g_fov.GetFloat(), view->fov_x, view->fov_y );
  2252.  
  2253. // RAVEN END
  2254.     }
  2255. }
  2256.  
  2257. // RAVEN END
  2258.