ccamera.cpp 53 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716
  1. /*
  2. ** Command & Conquer Renegade(tm)
  3. ** Copyright 2025 Electronic Arts Inc.
  4. **
  5. ** This program is free software: you can redistribute it and/or modify
  6. ** it under the terms of the GNU General Public License as published by
  7. ** the Free Software Foundation, either version 3 of the License, or
  8. ** (at your option) any later version.
  9. **
  10. ** This program is distributed in the hope that it will be useful,
  11. ** but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. ** GNU General Public License for more details.
  14. **
  15. ** You should have received a copy of the GNU General Public License
  16. ** along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. /***********************************************************************************************
  19. *** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S ***
  20. ***********************************************************************************************
  21. * *
  22. * Project Name : Commando *
  23. * *
  24. * $Archive:: /Commando/Code/Combat/ccamera.cpp $*
  25. * *
  26. * $Author:: Greg_h $*
  27. * *
  28. * $Modtime:: 6/14/02 10:44a $*
  29. * *
  30. * $Revision:: 162 $*
  31. * *
  32. *---------------------------------------------------------------------------------------------*
  33. * Functions: *
  34. * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  35. #include "ccamera.h"
  36. #include "timemgr.h"
  37. #include "physicalgameobj.h"
  38. #include "physcoltest.h"
  39. #include "pscene.h"
  40. #include "combat.h"
  41. #include "input.h"
  42. #include "debug.h"
  43. #include "assets.h"
  44. #include "slist.h"
  45. #include <string.h>
  46. #include "vector3.h"
  47. #include "phys.h"
  48. #include "vehicle.h"
  49. #include "soldier.h"
  50. #include "weapons.h"
  51. #include "gameobjmanager.h"
  52. #include "htree.h"
  53. #include "hanim.h"
  54. #include "hudinfo.h"
  55. #include "listener.h"
  56. #include "wwaudio.h"
  57. #include "soundscene.h"
  58. #include "wwprofile.h"
  59. #include "diaglog.h"
  60. #include "gametype.h"
  61. #include "wwphysids.h"
  62. #include "buildingaggregate.h"
  63. #include "persistfactory.h"
  64. #define MIN_FOV 0.02f
  65. #define MAX_FOV 2.6f
  66. #define CCAMERA_NEARZ 0.26f // near clip plane distance
  67. #define CCAMERA_FARZ 300.0f // far clip plane distance
  68. #define CCAMERA_SHRINK_NEARZ_DIST 0.5f // third person distance below which we start shrinking nearz
  69. #define CCAMERA_MIN_NEARZ 0.2f // how small nearz gets when we're up against a wall
  70. Vector3 FirstPersonOffsetTweak( 0, 0, 0 );
  71. /*
  72. ** Speed at which the camera pushes back out to its default position
  73. ** after a collision. 1.0 = goes all the way in 1 second
  74. */
  75. const float CAMERA_UNWIND_SPEED = 1.0f;
  76. /*
  77. ** Camera Profiles
  78. */
  79. //SList<CCameraProfileClass> ProfileList;
  80. HashTemplateClass<StringClass, CCameraProfileClass*> ProfileHash;
  81. #define CAMERAS_INI_FILENAME "CAMERAS.INI"
  82. #define SECTION_PROFILE_LIST "Profile_List"
  83. #define ENTRY_NAME "Name"
  84. #define ENTRY_FOV "FOV"
  85. #define ENTRY_HEIGHT "Height"
  86. #define ENTRY_VIEWTILT "ViewTilt"
  87. #define ENTRY_TRANSLATIONTILT "TranslationTilt"
  88. #define ENTRY_DISTANCE "Distance"
  89. #define ENTRY_LAG_UP "LagUp"
  90. #define ENTRY_LAG_LEFT "LagLeft"
  91. #define ENTRY_LAG_FORWARD "LagForward"
  92. #define ENTRY_TILTTWEAK "TiltTweak"
  93. /*
  94. **
  95. */
  96. class CCameraProfileClass
  97. {
  98. public:
  99. static void Init( void );
  100. static void Shutdown( void );
  101. void Set_Zoom( float amount );
  102. float Get_Zoom( void );
  103. void Set_Height( float height ) { Height = height; }
  104. float Get_Height( void ) { return Height; }
  105. void Set_Distance( float distance ) { Distance = distance; }
  106. float Get_Distance( void ) { return Distance; }
  107. protected:
  108. CCameraProfileClass( void );
  109. ~CCameraProfileClass( void );
  110. const CCameraProfileClass & operator = ( const CCameraProfileClass & );
  111. void Lerp( const CCameraProfileClass & a, const CCameraProfileClass & b, float lerp );
  112. // StringClass Name;
  113. float FOV; // field of view for the camera
  114. float Height; // height above the origin of "focus" object
  115. float ViewTilt; // default tilt of the camera
  116. float TiltTweak; // default tilt tweak of the camera
  117. float TranslationTilt; // tilt of translation vector for the camera (off of the z axis)
  118. float Distance; // how far back the camera wants to be normally
  119. Vector3 Lag; // the camera lag
  120. static bool _ProfilesInitted;
  121. static CCameraProfileClass * Find( const char * name );
  122. friend CCameraClass;
  123. };
  124. bool CCameraProfileClass::_ProfilesInitted = false;
  125. /*
  126. **
  127. */
  128. CCameraProfileClass::CCameraProfileClass( void ) :
  129. FOV( DEG_TO_RADF( 65.0f ) ),
  130. Height( 1.95f ),
  131. ViewTilt( DEG_TO_RADF(20.0f) ),
  132. TiltTweak( 0.6f ),
  133. TranslationTilt( DEG_TO_RADF( 19.9f ) ),
  134. Distance( 3.1f ),
  135. Lag( 0,0,0 )
  136. {
  137. }
  138. CCameraProfileClass::~CCameraProfileClass( void )
  139. {
  140. }
  141. void CCameraProfileClass::Set_Zoom( float amount )
  142. {
  143. amount = WWMath::Sqrt(amount);
  144. amount = WWMath::Clamp( (1-amount), 0, 1 );
  145. FOV = MIN_FOV + ((0.8f - MIN_FOV) * amount);
  146. }
  147. float CCameraProfileClass::Get_Zoom( void )
  148. {
  149. // TSS - by my reckoning this is the actual zoom factor
  150. return 0.8 / FOV;
  151. }
  152. #define Get_Camera_Profile_Radians( v, e ) \
  153. profile->v = DEG_TO_RADF( camerasINI->Get_Float( section_name, e, RAD_TO_DEGF( profile->v ) ) )
  154. #define Get_Camera_Profile_Float( v, e ) \
  155. profile->v = camerasINI->Get_Float( section_name, e, profile->v )
  156. //#define Get_Camera_Profile_String( v, e ) \
  157. // profile->v = camerasINI->Get_String( section_name, e, profile->v )
  158. void CCameraProfileClass::Init( void )
  159. {
  160. if (_ProfilesInitted) {
  161. CCameraProfileClass::Shutdown();
  162. }
  163. INIClass * camerasINI = Get_INI( CAMERAS_INI_FILENAME );
  164. if (camerasINI != NULL) {
  165. WWASSERT( camerasINI && camerasINI->Section_Count() > 0 );
  166. int count, entry;
  167. count = camerasINI->Entry_Count( SECTION_PROFILE_LIST );
  168. for ( entry = 0; entry < count; entry++ ) {
  169. StringClass section_name(0,true);
  170. camerasINI->Get_String( section_name, SECTION_PROFILE_LIST,
  171. camerasINI->Get_Entry( SECTION_PROFILE_LIST, entry) );
  172. CCameraProfileClass * profile = new CCameraProfileClass();
  173. WWASSERT( profile );
  174. StringClass name(true);
  175. camerasINI->Get_String( name, section_name, ENTRY_NAME, name );
  176. // Get_Camera_Profile_String( name, ENTRY_NAME );
  177. Get_Camera_Profile_Radians( FOV, ENTRY_FOV );
  178. Get_Camera_Profile_Float( Height, ENTRY_HEIGHT );
  179. Get_Camera_Profile_Radians( ViewTilt, ENTRY_VIEWTILT );
  180. Get_Camera_Profile_Float( TiltTweak, ENTRY_TILTTWEAK );
  181. Get_Camera_Profile_Radians( TranslationTilt, ENTRY_TRANSLATIONTILT );
  182. Get_Camera_Profile_Float( Distance, ENTRY_DISTANCE );
  183. Get_Camera_Profile_Float( Lag.Y, ENTRY_LAG_UP );
  184. Get_Camera_Profile_Float( Lag.X, ENTRY_LAG_LEFT );
  185. Get_Camera_Profile_Float( Lag.Z, ENTRY_LAG_FORWARD );
  186. // ProfileList.Add_Tail( profile );
  187. // Convert to lower case
  188. _strlwr(name.Peek_Buffer());
  189. ProfileHash.Insert(name,profile);
  190. }
  191. Release_INI( camerasINI );
  192. } else {
  193. Debug_Say(("CCameraProfileClass::Init - Unable to load %s\n", CAMERAS_INI_FILENAME));
  194. }
  195. _ProfilesInitted = true;
  196. }
  197. void CCameraProfileClass::Shutdown( void )
  198. {
  199. // while( ProfileList.Get_Count() ) {
  200. // delete ProfileList.Remove_Head();
  201. // }
  202. HashTemplateIterator<StringClass,CCameraProfileClass*> ite(ProfileHash);
  203. for (ite.First();!ite.Is_Done();ite.Next()) {
  204. CCameraProfileClass * profile=ite.Peek_Value();
  205. delete profile;
  206. }
  207. ProfileHash.Remove_All();
  208. _ProfilesInitted = false;
  209. }
  210. const CCameraProfileClass & CCameraProfileClass::operator = ( const CCameraProfileClass & src )
  211. {
  212. // Name = src.Name;
  213. FOV = src.FOV;
  214. Height = src.Height;
  215. ViewTilt = src.ViewTilt;
  216. TiltTweak = src.TiltTweak;
  217. TranslationTilt = src.TranslationTilt;
  218. Distance = src.Distance;
  219. Lag = src.Lag;
  220. return *this;
  221. }
  222. float RadianLerp( float a, float b, float lerp )
  223. {
  224. float diff = b - a; // diff should be -180 .. 180
  225. diff = WWMath::Wrap( diff, DEG_TO_RADF( -180 ), DEG_TO_RADF( 180 ) );
  226. // diff += DEG_TO_RAD( 360 ) * WWMath::Sign( -diff ); // Take the long way
  227. return a + diff * lerp;
  228. }
  229. void CCameraProfileClass::Lerp( const CCameraProfileClass & a, const CCameraProfileClass & b, float lerp )
  230. {
  231. *this = a; // Start by taking A
  232. FOV = WWMath::Lerp( a.FOV, b.FOV, lerp );
  233. Height = WWMath::Lerp( a.Height, b.Height, lerp );
  234. ViewTilt = WWMath::Lerp( a.ViewTilt, b.ViewTilt, lerp );
  235. TiltTweak = WWMath::Lerp( a.TiltTweak, b.TiltTweak, lerp );
  236. TranslationTilt= WWMath::Lerp( a.TranslationTilt, b.TranslationTilt, lerp );
  237. Distance = WWMath::Lerp( a.Distance, b.Distance, lerp );
  238. }
  239. CCameraProfileClass * CCameraProfileClass::Find( const char * name )
  240. {
  241. // Compare lower case strings
  242. char tmp[256];
  243. strncpy(tmp,name,sizeof(tmp));
  244. _strlwr(tmp);
  245. StringClass tmp_string(tmp,true);
  246. CCameraProfileClass* profile = ProfileHash.Get(tmp_string);
  247. return profile;
  248. // SLNode<CCameraProfileClass> *node;
  249. // for ( node = ProfileList.Head(); node; node = node->Next()) {
  250. // if ( !stricmp( node->Data()->Name, name ) ) {
  251. // return node->Data();
  252. // }
  253. // }
  254. // return NULL;
  255. }
  256. /*
  257. ** CCameraClass
  258. */
  259. CCameraClass::CCameraClass() :
  260. CameraClass(),
  261. HostModel( NULL ),
  262. AnchorPosition(0,0,0),
  263. IsValid( false ),
  264. Tilt( 0 ),
  265. Heading( 0 ),
  266. DistanceFraction(1.0f),
  267. Enable2DTargeting( false ),
  268. EnableWeaponHelp( false ),
  269. CameraTarget2DOffset( 0.5f, 0.5f ),
  270. LerpTimeTotal( 0.0f ),
  271. LerpTimeRemaining( 0.0f ),
  272. LastAnchorPosition(0,0,0),
  273. LastHeading( 0 ),
  274. CurrentProfile( NULL ),
  275. LastProfile( NULL ),
  276. DefaultProfile( NULL ),
  277. NearClipPlane( CCAMERA_NEARZ ),
  278. FarClipPlane( CCAMERA_FARZ ),
  279. IsStarSniping( false ),
  280. WasStarSniping( false ),
  281. CinematicSnipingEnabled( false ),
  282. CinematicSnipingDesiredZoom( 0 ),
  283. SniperZoom( 0 ),
  284. SniperDistance( 0 ),
  285. SniperListener( NULL ),
  286. SnapShotMode( SNAPSHOT_OFF ),
  287. WeaponHelpTimer( 0 ),
  288. WeaponHelpTargetID( 0 ),
  289. LagPersistTimer( 0 ),
  290. DisableLag( false )
  291. {
  292. Set_Clip_Planes( NearClipPlane, FarClipPlane );
  293. Set_View_Plane( DEG_TO_RAD( 90.0 ) );
  294. SniperListener = new Listener3DClass;
  295. DefaultProfile = CCameraProfileClass::Find( "default" );
  296. DefaultProfileName="default";
  297. Use_Default_Profile();
  298. }
  299. CCameraClass::~CCameraClass(void)
  300. {
  301. Set_Host_Model( NULL );
  302. //
  303. // Remove the sniper listener (if necessary) from the world
  304. //
  305. if ( SniperListener != NULL && WWAudioClass::Get_Instance() != NULL &&
  306. WWAudioClass::Get_Instance()->Get_Sound_Scene() != NULL)
  307. {
  308. if ( WWAudioClass::Get_Instance()->Get_Sound_Scene()->Peek_2nd_Listener() != NULL ) {
  309. WWAudioClass::Get_Instance()->Get_Sound_Scene ()->Set_2nd_Listener( NULL );
  310. }
  311. }
  312. REF_PTR_RELEASE (SniperListener);
  313. }
  314. /*
  315. **
  316. */
  317. void CCameraClass::Init( void )
  318. {
  319. CCameraProfileClass::Init();
  320. }
  321. void CCameraClass::Shutdown( void )
  322. {
  323. CCameraProfileClass::Shutdown();
  324. }
  325. /*
  326. ** Save and Load
  327. */
  328. enum {
  329. XXXCHUNKID_PARENT = 416012036,
  330. CHUNKID_VARIABLES,
  331. MICROCHUNKID_HOST_MODEL = 1,
  332. MICROCHUNKID_ANCHOR_POSITION,
  333. MICROCHUNKID_IS_VALID,
  334. MICROCHUNKID_TILT,
  335. MICROCHUNKID_HEADING,
  336. MICROCHUNKID_DISTANCE_FRACTION,
  337. MICROCHUNKID_ENABLE_2D_TARGETING,
  338. MICROCHUNKID_ENABLE_WEAPON_HELP,
  339. MICROCHUNKID_WEAPON_HELP_TIMER,
  340. MICROCHUNKID_WEAPON_HELP_TARGET_ID,
  341. MICROCHUNKID_STAR_TARGETING_POSITION,
  342. MICROCHUNKID_CAMERA_TARGET_2D_OFFSET,
  343. MICROCHUNKID_LERP_TIME_TOTAL,
  344. MICROCHUNKID_LERP_TIME_REMAINING,
  345. MICROCHUNKID_LAST_ANCHOR_POSITION,
  346. MICROCHUNKID_LAST_HEADING,
  347. MICROCHUNKID_CURRENT_PROFILE,
  348. MICROCHUNKID_LAST_PROFILE,
  349. MICROCHUNKID_DEFAULT_PROFILE,
  350. MICROCHUNKID_NEAR_CLIP_PLANE,
  351. MICROCHUNKID_FAR_CLIP_PLANE,
  352. MICROCHUNKID_IS_STAR_SNIPING,
  353. MICROCHUNKID_WAS_STAR_SNIPING,
  354. MICROCHUNKID_SNIPER_ZOOM,
  355. MICROCHUNKID_SNIPER_DISTANCE,
  356. XXXMICROCHUNKID_IS_SNIPER_LOCKED,
  357. XXXMICROCHUNKID_SNIPER_TARGET_NAME,
  358. XXXMICROCHUNKID_SNIPER_LISTENER,
  359. MICROCHUNKID_SNAP_SHOT_MODE,
  360. MICROCHUNKID_CINEMATIC_SNIPING_ENABLED,
  361. MICROCHUNKID_CINEMATIC_SNIPING_DESIRED_ZOOM,
  362. };
  363. //------------------------------------------------------------------------------------
  364. bool CCameraClass::Save( ChunkSaveClass & csave )
  365. {
  366. csave.Begin_Chunk( CHUNKID_VARIABLES );
  367. WRITE_MICRO_CHUNK( csave, MICROCHUNKID_HOST_MODEL, HostModel );
  368. WRITE_MICRO_CHUNK( csave, MICROCHUNKID_ANCHOR_POSITION, AnchorPosition );
  369. WRITE_MICRO_CHUNK( csave, MICROCHUNKID_IS_VALID, IsValid );
  370. WRITE_MICRO_CHUNK( csave, MICROCHUNKID_TILT, Tilt );
  371. WRITE_MICRO_CHUNK( csave, MICROCHUNKID_HEADING, Heading );
  372. WRITE_MICRO_CHUNK( csave, MICROCHUNKID_DISTANCE_FRACTION, DistanceFraction );
  373. WRITE_MICRO_CHUNK( csave, MICROCHUNKID_ENABLE_2D_TARGETING, Enable2DTargeting );
  374. WRITE_MICRO_CHUNK( csave, MICROCHUNKID_ENABLE_WEAPON_HELP, EnableWeaponHelp );
  375. WRITE_MICRO_CHUNK( csave, MICROCHUNKID_WEAPON_HELP_TIMER, WeaponHelpTimer );
  376. WRITE_MICRO_CHUNK( csave, MICROCHUNKID_WEAPON_HELP_TARGET_ID, WeaponHelpTargetID );
  377. WRITE_MICRO_CHUNK( csave, MICROCHUNKID_STAR_TARGETING_POSITION,StarTargetingPosition );
  378. WRITE_MICRO_CHUNK( csave, MICROCHUNKID_CAMERA_TARGET_2D_OFFSET,CameraTarget2DOffset );
  379. WRITE_MICRO_CHUNK( csave, MICROCHUNKID_LERP_TIME_TOTAL, LerpTimeTotal );
  380. WRITE_MICRO_CHUNK( csave, MICROCHUNKID_LERP_TIME_REMAINING, LerpTimeRemaining );
  381. WRITE_MICRO_CHUNK( csave, MICROCHUNKID_LAST_ANCHOR_POSITION, LastAnchorPosition );
  382. WRITE_MICRO_CHUNK( csave, MICROCHUNKID_LAST_HEADING, LastHeading );
  383. if ( CurrentProfile != NULL ) {
  384. // StringClass name = CurrentProfile->Name;
  385. WRITE_MICRO_CHUNK_WWSTRING( csave, MICROCHUNKID_CURRENT_PROFILE, CurrentProfileName );
  386. }
  387. if ( LastProfile != NULL ) {
  388. // StringClass name = LastProfile->Name;
  389. WRITE_MICRO_CHUNK_WWSTRING( csave, MICROCHUNKID_LAST_PROFILE, LastProfileName );
  390. }
  391. if ( DefaultProfile != NULL ) {
  392. // StringClass name = DefaultProfile->Name;
  393. WRITE_MICRO_CHUNK_WWSTRING( csave, MICROCHUNKID_DEFAULT_PROFILE, DefaultProfileName );
  394. }
  395. // (gth) don't save and load NearClipPlane and FarClipPlane
  396. // WRITE_MICRO_CHUNK( csave, MICROCHUNKID_NEAR_CLIP_PLANE, NearClipPlane );
  397. // WRITE_MICRO_CHUNK( csave, MICROCHUNKID_FAR_CLIP_PLANE, FarClipPlane );
  398. WRITE_MICRO_CHUNK( csave, MICROCHUNKID_IS_STAR_SNIPING, IsStarSniping );
  399. WRITE_MICRO_CHUNK( csave, MICROCHUNKID_WAS_STAR_SNIPING, WasStarSniping );
  400. WRITE_MICRO_CHUNK( csave, MICROCHUNKID_CINEMATIC_SNIPING_ENABLED, CinematicSnipingEnabled );
  401. WRITE_MICRO_CHUNK( csave, MICROCHUNKID_CINEMATIC_SNIPING_DESIRED_ZOOM, CinematicSnipingDesiredZoom );
  402. WRITE_MICRO_CHUNK( csave, MICROCHUNKID_SNIPER_ZOOM, SniperZoom );
  403. WRITE_MICRO_CHUNK( csave, MICROCHUNKID_SNIPER_DISTANCE, SniperDistance );
  404. // WRITE_MICRO_CHUNK( csave, MICROCHUNKID_SNIPER_LISTENER, SniperListener );
  405. WRITE_MICRO_CHUNK( csave, MICROCHUNKID_SNAP_SHOT_MODE, SnapShotMode );
  406. csave.End_Chunk();
  407. return true;
  408. }
  409. //------------------------------------------------------------------------------------
  410. bool CCameraClass::Load( ChunkLoadClass &cload )
  411. {
  412. StringClass current_name;
  413. StringClass last_name;
  414. StringClass default_name;
  415. while (cload.Open_Chunk()) {
  416. switch(cload.Cur_Chunk_ID()) {
  417. case CHUNKID_VARIABLES:
  418. while (cload.Open_Micro_Chunk()) {
  419. switch(cload.Cur_Micro_Chunk_ID()) {
  420. READ_MICRO_CHUNK( cload, MICROCHUNKID_HOST_MODEL, HostModel );
  421. READ_MICRO_CHUNK( cload, MICROCHUNKID_ANCHOR_POSITION, AnchorPosition );
  422. READ_MICRO_CHUNK( cload, MICROCHUNKID_IS_VALID, IsValid );
  423. READ_MICRO_CHUNK( cload, MICROCHUNKID_TILT, Tilt );
  424. READ_MICRO_CHUNK( cload, MICROCHUNKID_HEADING, Heading );
  425. READ_MICRO_CHUNK( cload, MICROCHUNKID_DISTANCE_FRACTION, DistanceFraction );
  426. READ_MICRO_CHUNK( cload, MICROCHUNKID_ENABLE_2D_TARGETING, Enable2DTargeting );
  427. READ_MICRO_CHUNK( cload, MICROCHUNKID_ENABLE_WEAPON_HELP, EnableWeaponHelp );
  428. READ_MICRO_CHUNK( cload, MICROCHUNKID_WEAPON_HELP_TIMER, WeaponHelpTimer );
  429. READ_MICRO_CHUNK( cload, MICROCHUNKID_WEAPON_HELP_TARGET_ID, WeaponHelpTargetID );
  430. READ_MICRO_CHUNK( cload, MICROCHUNKID_STAR_TARGETING_POSITION, StarTargetingPosition );
  431. READ_MICRO_CHUNK( cload, MICROCHUNKID_CAMERA_TARGET_2D_OFFSET, CameraTarget2DOffset );
  432. READ_MICRO_CHUNK( cload, MICROCHUNKID_LERP_TIME_TOTAL, LerpTimeTotal );
  433. READ_MICRO_CHUNK( cload, MICROCHUNKID_LERP_TIME_REMAINING, LerpTimeRemaining );
  434. READ_MICRO_CHUNK( cload, MICROCHUNKID_LAST_ANCHOR_POSITION, LastAnchorPosition );
  435. READ_MICRO_CHUNK( cload, MICROCHUNKID_LAST_HEADING, LastHeading );
  436. READ_MICRO_CHUNK_WWSTRING( cload, MICROCHUNKID_CURRENT_PROFILE,current_name );
  437. READ_MICRO_CHUNK_WWSTRING( cload, MICROCHUNKID_LAST_PROFILE, last_name );
  438. READ_MICRO_CHUNK_WWSTRING( cload, MICROCHUNKID_DEFAULT_PROFILE,default_name );
  439. // (gth) don't save and load NearClipPlane and FarClipPlane
  440. // READ_MICRO_CHUNK( cload, MICROCHUNKID_NEAR_CLIP_PLANE, NearClipPlane );
  441. // READ_MICRO_CHUNK( cload, MICROCHUNKID_FAR_CLIP_PLANE, FarClipPlane );
  442. READ_MICRO_CHUNK( cload, MICROCHUNKID_IS_STAR_SNIPING, IsStarSniping );
  443. READ_MICRO_CHUNK( cload, MICROCHUNKID_WAS_STAR_SNIPING, WasStarSniping );
  444. READ_MICRO_CHUNK( cload, MICROCHUNKID_CINEMATIC_SNIPING_ENABLED, CinematicSnipingEnabled );
  445. READ_MICRO_CHUNK( cload, MICROCHUNKID_CINEMATIC_SNIPING_DESIRED_ZOOM, CinematicSnipingDesiredZoom );
  446. READ_MICRO_CHUNK( cload, MICROCHUNKID_SNIPER_ZOOM, SniperZoom );
  447. READ_MICRO_CHUNK( cload, MICROCHUNKID_SNIPER_DISTANCE, SniperDistance );
  448. // READ_MICRO_CHUNK( cload, MICROCHUNKID_SNIPER_LISTENER, SniperListener );
  449. READ_MICRO_CHUNK( cload, MICROCHUNKID_SNAP_SHOT_MODE, SnapShotMode );
  450. default:
  451. Debug_Say(("Unhandled Micro Chunk:%d File:%s Line:%d\r\n",cload.Cur_Micro_Chunk_ID(),__FILE__,__LINE__));
  452. break;
  453. }
  454. cload.Close_Micro_Chunk();
  455. }
  456. break;
  457. default:
  458. Debug_Say(("Unhandled Chunk:%d File:%s Line:%d\r\n",cload.Cur_Chunk_ID(),__FILE__,__LINE__));
  459. break;
  460. }
  461. cload.Close_Chunk();
  462. }
  463. if ( !current_name.Is_Empty() ) {
  464. CurrentProfile = CCameraProfileClass::Find( current_name );
  465. CurrentProfileName=current_name;
  466. }
  467. if ( !last_name.Is_Empty() ) {
  468. LastProfile = CCameraProfileClass::Find( last_name );
  469. LastProfileName=last_name;
  470. }
  471. if ( !default_name.Is_Empty() ) {
  472. DefaultProfile = CCameraProfileClass::Find( default_name );
  473. DefaultProfileName=default_name;
  474. }
  475. if ( HostModel != NULL ) {
  476. REQUEST_REF_COUNTED_POINTER_REMAP ((RefCountClass **)&HostModel);
  477. }
  478. return true;
  479. }
  480. /*
  481. **
  482. */
  483. void CCameraClass::Set_Host_Model( RenderObjClass * host )
  484. {
  485. DisableLag = true;
  486. static StringClass SavedProfileName;
  487. // If dropping host
  488. if ( HostModel != NULL && host == NULL ) {
  489. if ( SavedProfileName.Is_Empty() ) {
  490. Use_Default_Profile();
  491. } else {
  492. Use_Profile( SavedProfileName ); // Return to saved profile
  493. }
  494. }
  495. // If getting host
  496. if ( HostModel == NULL && host != NULL ) {
  497. SavedProfileName = CurrentProfileName;
  498. Use_Profile( "Cinematic" );
  499. // CurrentProfile->Set_Zoom( 0 );
  500. CurrentProfile->FOV = DEG_TO_RADF( 75.0f );
  501. CinematicSnipingEnabled = false;
  502. }
  503. if ( HostModel ) {
  504. HostModel->Release_Ref();
  505. IsValid = false;
  506. }
  507. HostModel = host;
  508. if ( HostModel ) {
  509. HostModel->Add_Ref();
  510. IsValid = true;
  511. }
  512. // If clearing host, force facing to match the star
  513. if ( host == NULL && COMBAT_STAR != NULL ) {
  514. Force_Heading( COMBAT_STAR->Get_Facing() );
  515. }
  516. // When the camera is controlled, activeate cinematic freeze
  517. GameObjManager::Activate_Cinematic_Freeze( host != NULL );
  518. }
  519. void Convert_World_To_Camera( Matrix3D * tm )
  520. {
  521. tm->Rotate_Y( DEG_TO_RADF(-90.0) );
  522. tm->Rotate_Z( DEG_TO_RADF(-90.0) );
  523. }
  524. void CCameraClass::Use_Host_Model( void )
  525. {
  526. WWASSERT( HostModel );
  527. Matrix3D tm = HostModel->Get_Bone_Transform( "CAMERA" );
  528. Set_Transform( tm );
  529. if ( !CinematicSnipingEnabled ) {
  530. CurrentProfile->FOV = DEG_TO_RADF( 75.0f );
  531. }
  532. Set_View_Plane( CurrentProfile->FOV );
  533. #ifdef ATI_DEMO_HACK
  534. static GameObjReference DemoFocusObject;
  535. /*
  536. ** Focus change key pressed:
  537. */
  538. if (Input::Get_State(INPUT_FUNCTION_PROFILE_RESET)) {
  539. if (DemoFocusObject.Get_Ptr() == NULL) {
  540. /*
  541. ** Count the soldiers in the level (ignoring the human controlled commando)
  542. */
  543. int soldier_count = 0;
  544. SLNode<SmartGameObj> * smart_objnode;
  545. for (smart_objnode = GameObjManager::Get_Smart_Game_Obj_List()->Head(); smart_objnode; smart_objnode = smart_objnode->Next()) {
  546. SmartGameObj * obj = smart_objnode->Data();
  547. if ((obj->As_SoldierGameObj() != NULL) && (obj->Is_Human_Controlled() == false)) {
  548. soldier_count++;
  549. }
  550. }
  551. /*
  552. ** Pick a random soldier to watch
  553. */
  554. int random_soldier = rand() % soldier_count;
  555. soldier_count = 0;
  556. for (smart_objnode = GameObjManager::Get_Smart_Game_Obj_List()->Head(); smart_objnode; smart_objnode = smart_objnode->Next()) {
  557. SmartGameObj * obj = smart_objnode->Data();
  558. if ((obj->As_SoldierGameObj() != NULL) && (obj->Is_Human_Controlled() == false)) {
  559. if (soldier_count == random_soldier) {
  560. DemoFocusObject = obj;
  561. break;
  562. }
  563. soldier_count++;
  564. }
  565. }
  566. } else {
  567. /*
  568. ** Toggle out of demo focus mode
  569. */
  570. DemoFocusObject = NULL;
  571. }
  572. }
  573. /*
  574. ** Position the camera on this soldier
  575. */
  576. if (DemoFocusObject.Get_Ptr() != NULL) {
  577. Vector3 position;
  578. DemoFocusObject.Get_Ptr()->Get_Position(&position);
  579. Matrix3D camera_tm;
  580. camera_tm.Look_At(position + Vector3(2.0f,0.0f,1.75f),position + Vector3(0.0f,0.0f,1.0f),0.0f);
  581. Set_Transform(camera_tm);
  582. }
  583. #endif
  584. }
  585. /*
  586. **
  587. */
  588. void CCameraClass::Set_Anchor_Position( Vector3 pos )
  589. {
  590. AnchorPosition = pos;
  591. // If this is the first anchor point, don't lag the camera
  592. if ( !IsValid ) {
  593. LastAnchorPosition = pos;
  594. IsValid = true;
  595. }
  596. }
  597. /*
  598. **
  599. */
  600. void Ignore_Star_And_Vehicle( void )
  601. {
  602. if (COMBAT_STAR != NULL) {
  603. COMBAT_STAR->Peek_Physical_Object()->Inc_Ignore_Counter();
  604. VehicleGameObj * vehicle = COMBAT_STAR->Get_Profile_Vehicle();
  605. if ( vehicle ) {
  606. vehicle->Peek_Physical_Object()->Inc_Ignore_Counter();
  607. }
  608. }
  609. }
  610. void Unignore_Star_And_Vehicle( void )
  611. {
  612. if (COMBAT_STAR != NULL) {
  613. COMBAT_STAR->Peek_Physical_Object()->Dec_Ignore_Counter();
  614. VehicleGameObj * vehicle = COMBAT_STAR->Get_Profile_Vehicle();
  615. if ( vehicle ) {
  616. vehicle->Peek_Physical_Object()->Dec_Ignore_Counter();
  617. }
  618. }
  619. }
  620. /*
  621. **
  622. */
  623. void CCameraClass::Update()
  624. {
  625. Handle_Input();
  626. WWASSERT( CurrentProfile );
  627. if ( SnapShotMode != SNAPSHOT_OFF ) {
  628. Handle_Snap_Shot_Mode();
  629. return;
  630. }
  631. if ( Is_Using_Host_Model() ) { // if using a host model, update the
  632. Use_Host_Model(); // camera from it
  633. return;
  634. }
  635. Vector3 anchor_position = AnchorPosition;
  636. float camera_heading = Heading;
  637. CCameraProfileClass profile;
  638. bool interpolating = false;
  639. if ( LerpTimeTotal ) {
  640. interpolating = true;
  641. float frame_time = TimeManager::Get_Frame_Seconds();
  642. float lerp = WWMath::Clamp( LerpTimeRemaining / LerpTimeTotal, 0, 1 );
  643. LerpTimeRemaining -= frame_time;
  644. if ( LerpTimeRemaining <= 0 ) {
  645. LerpTimeRemaining = 0.0f;
  646. LerpTimeTotal = 0.0f;
  647. // Set up last, so out Lag code doesn't use the old
  648. LastAnchorPosition = anchor_position;
  649. LastHeading = Heading;
  650. }
  651. profile = *CurrentProfile;
  652. if ( LastProfile ) {
  653. profile.Lerp( *CurrentProfile, *LastProfile, lerp );
  654. }
  655. anchor_position = ::Lerp( anchor_position, LastAnchorPosition, lerp );
  656. camera_heading = RadianLerp( camera_heading, LastHeading, lerp );
  657. } else {
  658. profile = *CurrentProfile;
  659. LastProfile = CurrentProfile;
  660. LastProfileName=CurrentProfileName;
  661. if ( profile.Lag.Length() > 0 ) {
  662. // This is an attempt to not lag when in an elevator
  663. bool lag_ok = false;
  664. if ( COMBAT_STAR == NULL || COMBAT_STAR->Is_Airborne() ) {
  665. lag_ok = true;
  666. LagPersistTimer = 1; // Persist the lag for 1 second
  667. } else {
  668. if ( LagPersistTimer > 0 ) {
  669. lag_ok = true;
  670. LagPersistTimer -= TimeManager::Get_Frame_Seconds();
  671. // Debug_Say(( "Lag Persist\n" ));
  672. }
  673. }
  674. if ( DisableLag ) {
  675. lag_ok = false;
  676. DisableLag = false;
  677. }
  678. if ( lag_ok ) {
  679. // Get position local to the camera
  680. Vector3 local_last;
  681. Vector3 local_current;
  682. Matrix3D tm = Get_Transform();
  683. Matrix3D::Inverse_Transform_Vector( tm, LastAnchorPosition, &local_last );
  684. Matrix3D::Inverse_Transform_Vector( tm, anchor_position, &local_current );
  685. // Lerp // ( left/right, up/down, forward/back )
  686. Vector3 lerp = profile.Lag * WWMath::Clamp( LagPersistTimer, 0, 1); //( 0, 0.5f, 0.2f ); // ( y, z, x )
  687. lerp.X = ::pow( lerp.X, 10 * TimeManager::Get_Frame_Seconds() );
  688. lerp.Y = ::pow( lerp.Y, 10 * TimeManager::Get_Frame_Seconds() );
  689. lerp.Z = ::pow( lerp.Z, 10 * TimeManager::Get_Frame_Seconds() );
  690. lerp = Vector3( 1,1,1 ) - lerp;
  691. local_current.X = local_last.X + ( local_current.X - local_last.X ) * lerp.X;
  692. local_current.Y = local_last.Y + ( local_current.Y - local_last.Y ) * lerp.Y;
  693. local_current.Z = local_last.Z + ( local_current.Z - local_last.Z ) * lerp.Z;
  694. Matrix3D::Transform_Vector( tm, local_current, &anchor_position );
  695. Vector3 diff = anchor_position - LastAnchorPosition;
  696. if ( diff.Length() < 5.0f ) { // Don't lerp over long distances
  697. anchor_position = ::Lerp( anchor_position, LastAnchorPosition, 0.25f );
  698. } else {
  699. LagPersistTimer = 0;
  700. DisableLag = true;
  701. }
  702. }
  703. }
  704. LastAnchorPosition = anchor_position;
  705. LastHeading = Heading;
  706. }
  707. Set_View_Plane( profile.FOV ); // Apply Zoom
  708. // Calculate the Camera Transform
  709. Matrix3D tm(1); // Setup base position
  710. tm.Translate( anchor_position );
  711. tm.Translate( Vector3( 0, 0, profile.Height ) );
  712. Convert_World_To_Camera( &tm ); // Setup orientation
  713. tm.Rotate_Y( camera_heading ); // Apply rotations
  714. tm.Rotate_X( -profile.ViewTilt - Tilt);
  715. // Only do this when the profile has a distance value
  716. if ( profile.Distance != 0 ) {
  717. // Translate along Z so that our near clip plane is behind the head
  718. float nearz,farz;
  719. const float HEAD_RADIUS = 0.2f; // HEAD_RADIUS should be renamed and become part of the profile?
  720. Get_Clip_Planes(nearz,farz);
  721. tm.Translate_Z(nearz + HEAD_RADIUS);
  722. }
  723. Vector3 intermediate_pos = tm.Get_Translation(); // Save base position
  724. Matrix3D intermediate_tm = tm; // Save base transform
  725. // Generate a translation path for the camera which is 'tilt' off of the z-axis
  726. Vector3 camera_move(0,0,profile.Distance);
  727. camera_move.Rotate_X(-profile.TranslationTilt);
  728. camera_move.Rotate_X( -(WWMath::Max( -Tilt * profile.TiltTweak, 0 )) );
  729. tm.Translate(camera_move); // Pull back
  730. Vector3 end_pos = tm.Get_Translation(); // Save the end position
  731. // Sweep the view plane back until it hits something
  732. if ( profile.Distance != 0 ) {
  733. WWPROFILE( "Sweep" );
  734. // (gth) FIXME!
  735. // Sort of a hack here, trying to make the camera not collide with the star
  736. // Really this should make sure we don't collide with whatever the camera is starting inside
  737. Ignore_Star_And_Vehicle();
  738. // Collide the bounding box of the near clip plane
  739. // Have to Set_Transform so that the camera can calculate the box for us
  740. CastResultStruct res;
  741. Set_Transform(intermediate_tm);
  742. Set_Clip_Planes( NearClipPlane,FarClipPlane );
  743. OBBoxClass box = Get_Near_Clip_Bounding_Box();
  744. PhysOBBoxCollisionTestClass boxtest( box,
  745. end_pos - intermediate_pos,
  746. &res,
  747. DEFAULT_COLLISION_GROUP,
  748. COLLISION_TYPE_CAMERA);
  749. PhysicsSceneClass::Get_Instance()->Cast_OBBox(boxtest);
  750. // Solve the problem of the camera when getting out of the car
  751. if ( res.StartBad && interpolating && boxtest.CollidedPhysObj ) {
  752. // ignore what we hit and do it again
  753. PhysClass * hit = boxtest.CollidedPhysObj;
  754. hit->Inc_Ignore_Counter();
  755. res.Reset();
  756. PhysicsSceneClass::Get_Instance()->Cast_OBBox(boxtest);
  757. hit->Dec_Ignore_Counter();
  758. }
  759. // Move the camera to the collision if needed.
  760. if (res.Fraction < DistanceFraction) {
  761. DistanceFraction = res.Fraction; // always pull camera in if a collision occured
  762. }
  763. if (res.Fraction > DistanceFraction) {
  764. float dt = TimeManager::Get_Frame_Seconds();
  765. DistanceFraction += WWMath::Min(res.Fraction-DistanceFraction,CAMERA_UNWIND_SPEED * dt);
  766. }
  767. if (DistanceFraction < 1.0f) {
  768. tm.Set_Translation(intermediate_pos + DistanceFraction * (end_pos - intermediate_pos));
  769. end_pos = tm.Get_Translation();
  770. }
  771. // When Physics_Debug is on, draw the camera collision box in its start point
  772. #ifdef WWDEBUG
  773. PhysicsSceneClass * scene = PhysicsSceneClass::Get_Instance();
  774. if (scene && scene->Is_Debug_Display_Enabled()) {
  775. scene->Add_Debug_OBBox(box,Vector3(1,0,0));
  776. }
  777. #endif
  778. // Now put the star back to his original 'ignore' state
  779. Unignore_Star_And_Vehicle();
  780. } else {
  781. WWPROFILE( "No Sweep" );
  782. // This is a camera which doesn't translate back. Just check its near clip plane for intersection
  783. // with the world and if it does intersect, pull the near clip plane in to its minimum.
  784. Ignore_Star_And_Vehicle();
  785. // Collide the bounding box of the near clip plane
  786. // Have to Set_Transform so that the camera can calculate the box for us
  787. CastResultStruct res;
  788. Set_Transform(tm);
  789. Set_Clip_Planes(NearClipPlane,FarClipPlane);
  790. OBBoxClass box = Get_Near_Clip_Bounding_Box();
  791. Vector3 null_vec(0.0f,0.0f,0.0f);
  792. PhysOBBoxCollisionTestClass boxtest( box,
  793. null_vec,
  794. &res,
  795. DEFAULT_COLLISION_GROUP,
  796. COLLISION_TYPE_CAMERA);
  797. PhysicsSceneClass::Get_Instance()->Cast_OBBox(boxtest);
  798. // Set the near clip plane depending on whether the default near clip plane
  799. // intersected any geometry
  800. if (res.StartBad) {
  801. Set_Clip_Planes(CCAMERA_MIN_NEARZ,FarClipPlane);
  802. } else {
  803. Set_Clip_Planes(NearClipPlane,FarClipPlane);
  804. }
  805. Unignore_Star_And_Vehicle();
  806. }
  807. Set_Transform( tm ); // Set our new transform
  808. // Debug_Say(( "Camera at %1.2f, %1.2f, %1.2f\n", tm.Get_Translation().X, tm.Get_Translation().Y, tm.Get_Translation().Z ));
  809. // First, set the aiming point to where the camera is looking
  810. if ( Determine_Targeting_Position() == false ) {
  811. WWPROFILE( "Help" );
  812. // Then, modify the aiming point for weapon help, if not on a target
  813. Apply_Weapon_Help();
  814. }
  815. // Lastly, pass the aiming point to the star
  816. bool is_star_determining_target = CombatManager::Is_Star_Determining_Target();
  817. if ( COMBAT_STAR && is_star_determining_target ) { // and tell the star what we are looking at...
  818. #if 0
  819. // This didn't work with X key....
  820. // Make sure it is forward in star space
  821. Matrix3D star_tm = COMBAT_STAR->Get_Transform();
  822. Vector3 star_space_pos;
  823. Matrix3D::Inverse_Transform_Vector( star_tm, StarTargetingPosition, &star_space_pos );
  824. if ( star_space_pos.X <= 0 ) {
  825. star_space_pos.X = MAX( star_space_pos.X, 1 );
  826. }
  827. Debug_Say(( "SSP %f %f %f\n", star_space_pos.X, star_space_pos.Y, star_space_pos.Z ));
  828. Matrix3D::Transform_Vector( star_tm, star_space_pos, &StarTargetingPosition );
  829. #endif
  830. COMBAT_STAR->Set_Targeting( StarTargetingPosition );
  831. }
  832. }
  833. /*
  834. ** Determine_Targeting_Position finds the World position and object the player is looking/pointing at
  835. ** The details get stored in HUDInfo
  836. */
  837. bool CCameraClass::Determine_Targeting_Position( void )
  838. {
  839. WWPROFILE( "Determining Targeting" );
  840. bool looking_at_object = false;
  841. Matrix3D tm = Get_Transform();
  842. /*
  843. **
  844. */
  845. SoldierGameObj * star = COMBAT_STAR;
  846. bool is_star_determining_target = CombatManager::Is_Star_Determining_Target();
  847. if ( star && is_star_determining_target ) { // and tell the star what we are looking at...
  848. // Now cast to determine what we are looking/pointing at...
  849. Vector3 cast_start = tm.Get_Translation();
  850. float range = 100;
  851. if ( star && star->Get_Weapon() ) {
  852. range = star->Get_Weapon()->Get_Range();
  853. }
  854. if ( star && star->Get_Vehicle() && star->Get_Vehicle()->Get_Weapon() ) {
  855. range = star->Get_Vehicle()->Get_Weapon()->Get_Range();
  856. }
  857. range += CurrentProfile->Distance;
  858. Vector2 view_plane;
  859. view_plane.X = CameraTarget2DOffset.X;
  860. view_plane.Y = CameraTarget2DOffset.Y;
  861. Vector3 world_pos;
  862. COMBAT_CAMERA->Un_Project( world_pos, view_plane );
  863. Vector3 cast_end = world_pos - cast_start;
  864. cast_end.Normalize();
  865. cast_end *= range;
  866. cast_end += cast_start;
  867. LineSegClass ray;
  868. if ( !Enable2DTargeting ) {
  869. // start the ray in front of the character + 0.5m
  870. float move_forward_dist = DistanceFraction * CurrentProfile->Distance + 0.5f;
  871. cast_start += move_forward_dist * -(tm.Get_Z_Vector());
  872. ray.Set( cast_start, cast_end );
  873. } else {
  874. // for 2D, start at the camera
  875. ray.Set( cast_start, cast_end );
  876. }
  877. // trim off Near Clip from Beginning
  878. float start_fraction = NearClipPlane / ray.Get_Length();
  879. ray.Compute_Point( start_fraction, &cast_start );
  880. ray.Set( cast_start, cast_end );
  881. CastResultStruct result;
  882. PhysRayCollisionTestClass raytest(ray, &result,
  883. BULLET_COLLISION_GROUP, COLLISION_TYPE_PROJECTILE);
  884. WWASSERT(COMBAT_SCENE != NULL);
  885. Ignore_Star_And_Vehicle();
  886. { WWPROFILE( "Cast Ray" );
  887. COMBAT_SCENE->Cast_Ray( raytest );
  888. }
  889. Unignore_Star_And_Vehicle();
  890. // Determine the Camera Target Point and object
  891. ray.Compute_Point( raytest.Result->Fraction, &StarTargetingPosition );
  892. //
  893. // (gth) "hack" to prevent the target point from ever ending up behind the player
  894. // this sometimes happens when looking up at an extreme angle in third person
  895. //
  896. if (COMBAT_STAR != NULL) {
  897. Vector3 player_pos(0,0,0);
  898. if (COMBAT_STAR->Get_Profile_Vehicle() != NULL) {
  899. COMBAT_STAR->Get_Profile_Vehicle()->Get_Position(&player_pos);
  900. } else {
  901. COMBAT_STAR->Get_Position(&player_pos);
  902. }
  903. float player_dx = player_pos.X - cast_start.X;
  904. float player_dy = player_pos.Y - cast_start.Y;
  905. float target_dx = StarTargetingPosition.X - cast_start.X;
  906. float target_dy = StarTargetingPosition.Y - cast_start.Y;
  907. float xy_dist_to_player2 = player_dx * player_dx + player_dy * player_dy;
  908. float xy_dist_to_target2 = target_dx * target_dx + target_dy * target_dy;
  909. if (xy_dist_to_target2 < xy_dist_to_player2) {
  910. // Move the point along the raycast until until
  911. // target is in front of player.
  912. float ray_parameter = 1.1f * WWMath::Sqrt(xy_dist_to_player2) / WWMath::Sqrt(xy_dist_to_target2);
  913. StarTargetingPosition = ray.Get_P0() + ray.Get_Dir() * ray_parameter;
  914. }
  915. }
  916. //Debug_Say(( "Targeting %f %f %f\n", StarTargetingPosition.X, StarTargetingPosition.Y, StarTargetingPosition.Z ));
  917. if ( raytest.CollidedPhysObj != NULL && raytest.CollidedPhysObj->Get_Observer() != NULL ) {
  918. DamageableGameObj * obj = ((CombatPhysObserverClass *)raytest.CollidedPhysObj->Get_Observer())->As_DamageableGameObj();
  919. bool MCT = false;
  920. if ( obj->As_BuildingGameObj() ) {
  921. // Check for MCT collision
  922. if (raytest.CollidedPhysObj->Get_Factory().Chunk_ID() == PHYSICS_CHUNKID_BUILDINGAGGREGATE) {
  923. if (((BuildingAggregateClass *)raytest.CollidedPhysObj)->Is_MCT()) {
  924. MCT = true;
  925. }
  926. }
  927. }
  928. if ( obj->Is_Targetable() == false ) {
  929. obj = NULL;
  930. }
  931. // if stealthed and enemy, it's not targetable
  932. if ( obj && obj->As_SmartGameObj() && obj->As_SmartGameObj()->Is_Stealthed() &&
  933. COMBAT_STAR && obj->Is_Enemy( COMBAT_STAR ) ) {
  934. obj = NULL;
  935. }
  936. looking_at_object = ( obj != NULL );
  937. HUDInfo::Set_Info_Object( obj, MCT ); // Update the HUDInfo Info Object
  938. HUDInfo::Set_Weapon_Target_Object( obj );
  939. }
  940. if ( raytest.CollidedPhysObj ) {
  941. Set_Sniper_Distance( raytest.Result->Fraction * ray.Get_Length() );
  942. } else {
  943. Set_Sniper_Distance( 0 );
  944. }
  945. }
  946. return looking_at_object;
  947. }
  948. /*
  949. ** Apply_Weapon_Help : Use weapon Help to update the StarTargetingPosition );
  950. ** Should only be called if not already on a target object
  951. ** We will only do the search periodically, so we will save the last valid target,
  952. ** and track him until we search again.
  953. */
  954. #define WEAPON_HELP_CHEAT 0
  955. void CCameraClass::Apply_Weapon_Help( void )
  956. {
  957. WWPROFILE( "Weapon Help" );
  958. WeaponHelpTimer -= TimeManager::Get_Frame_Seconds();
  959. if ( WeaponHelpTimer <= 0 ) {
  960. #if WEAPON_HELP_CHEAT
  961. WeaponHelpTimer = 0.01f;
  962. #else
  963. WeaponHelpTimer = 0.5f; // Re-check every 1/2 second
  964. #endif
  965. WeaponHelpTargetID = 0; // Asuume we find nothing
  966. SmartGameObj * star = COMBAT_STAR;
  967. // if ( star && EnableWeaponHelp ) {
  968. #if WEAPON_HELP_CHEAT
  969. if ( star ) {
  970. #else
  971. if ( star && CombatManager::Get_Difficulty_Level() == 0 && IS_MISSION ) { // if on easy difficulty
  972. #endif
  973. // Make sure dot is off
  974. #if WEAPON_HELP_CHEAT
  975. if ( !CombatManager::Is_Hit_Reticle_Enabled() ) {
  976. #else
  977. if ( CombatManager::Is_Hit_Reticle_Enabled() ) {
  978. #endif
  979. CombatManager::Toggle_Hit_Reticle_Enabled();
  980. }
  981. float weapon_range = 100;
  982. if ( star->Get_Weapon() ) {
  983. weapon_range = star->Get_Weapon()->Get_Range();
  984. }
  985. Vector3 star_pos;
  986. star->Get_Position( &star_pos );
  987. SmartGameObj * best_obj = NULL;
  988. #if WEAPON_HELP_CHEAT
  989. float best_distance = 10;
  990. #else
  991. float best_distance = 0.1f;
  992. #endif
  993. // Find a target object near the camera target vector
  994. SLNode<SmartGameObj> * smart_objnode;
  995. for (smart_objnode = GameObjManager::Get_Smart_Game_Obj_List()->Head(); smart_objnode; smart_objnode = smart_objnode->Next()) {
  996. SmartGameObj * obj = smart_objnode->Data();
  997. if ( obj == COMBAT_STAR ) {
  998. continue;
  999. }
  1000. #if WEAPON_HELP_CHEAT
  1001. if ( !obj->Is_Enemy( COMBAT_STAR ) ) {
  1002. continue;
  1003. }
  1004. #endif
  1005. Vector3 pos = obj->Get_Bullseye_Position();
  1006. float range = (pos - star_pos).Length();
  1007. if ( range > weapon_range ) {
  1008. continue;
  1009. }
  1010. Vector3 twoDpos;
  1011. if ( Project( twoDpos, pos ) == CameraClass::INSIDE_FRUSTUM ) {
  1012. twoDpos.X -= CameraTarget2DOffset.X;
  1013. twoDpos.Y -= CameraTarget2DOffset.Y;
  1014. twoDpos.Z = 0;
  1015. float distance = twoDpos.Length();
  1016. if ( distance < best_distance ) {
  1017. // This is the best target so far, cast a Ray and see if it is a possible target
  1018. // We are seeing if the camera can see him, not if the gun can hit him...
  1019. Vector3 cast_start = Get_Transform().Get_Translation();
  1020. Vector3 cast_end = pos;
  1021. LineSegClass ray;
  1022. ray.Set( cast_start, cast_end );
  1023. #if 0
  1024. // trim off Near Clip from Beginning
  1025. float start_fraction = NearClipPlane / ray.Get_Length();
  1026. ray.Compute_Point( start_fraction, &cast_start );
  1027. ray.Set( cast_start, cast_end );
  1028. #endif
  1029. CastResultStruct result;
  1030. PhysRayCollisionTestClass raytest(ray, &result,
  1031. BULLET_COLLISION_GROUP, COLLISION_TYPE_PROJECTILE);
  1032. WWASSERT(COMBAT_SCENE != NULL);
  1033. Ignore_Star_And_Vehicle();
  1034. { WWPROFILE( "Cast Ray" );
  1035. COMBAT_SCENE->Cast_Ray( raytest );
  1036. }
  1037. Unignore_Star_And_Vehicle();
  1038. //Debug_Say(( "Targeting %f %f %f\n", StarTargetingPosition.X, StarTargetingPosition.Y, StarTargetingPosition.Z ));
  1039. if ( raytest.CollidedPhysObj != NULL && raytest.CollidedPhysObj->Get_Observer() != NULL &&
  1040. ((CombatPhysObserverClass *)raytest.CollidedPhysObj->Get_Observer())->As_PhysicalGameObj() ) {
  1041. best_distance = distance;
  1042. best_obj = obj;
  1043. } else {
  1044. // If this is the Info Target, forget him!
  1045. if ( obj == HUDInfo::Get_Info_Object() ) {
  1046. HUDInfo::Set_Info_Object( NULL );
  1047. }
  1048. }
  1049. }
  1050. }
  1051. }
  1052. if ( best_obj != NULL ) {
  1053. // remember this guy
  1054. WeaponHelpTargetID = best_obj->Get_ID();
  1055. StarTargetingPosition = best_obj->Get_Bullseye_Position();
  1056. HUDInfo::Set_Info_Object( best_obj ); // Update HUD Info Object
  1057. }
  1058. }
  1059. } else {
  1060. // If we had a target
  1061. if ( WeaponHelpTargetID != 0 ) {
  1062. SmartGameObj * target = GameObjManager::Find_SmartGameObj( WeaponHelpTargetID );
  1063. // and we still have him
  1064. if ( target != NULL ) {
  1065. // update the targting pos
  1066. StarTargetingPosition = target->Get_Bullseye_Position();
  1067. } else {
  1068. // else, forget about him
  1069. WeaponHelpTargetID = 0;
  1070. }
  1071. }
  1072. }
  1073. }
  1074. void CCameraClass::Use_Profile( const char * name )
  1075. {
  1076. if ( name ) {
  1077. // quick reject if the same
  1078. if ( CurrentProfile && !stricmp( CurrentProfileName, name ) ) {
  1079. return;
  1080. }
  1081. CCameraProfileClass *profile = CCameraProfileClass::Find( name );
  1082. if ( profile ) {
  1083. CurrentProfile = profile;
  1084. CurrentProfileName=name;
  1085. }
  1086. } else {
  1087. CurrentProfile = NULL;
  1088. }
  1089. }
  1090. void CCameraClass::Use_Default_Profile()
  1091. {
  1092. WWASSERT( DefaultProfile );
  1093. CurrentProfile = DefaultProfile;
  1094. CurrentProfileName=DefaultProfileName;
  1095. }
  1096. void CCameraClass::Set_Profile_Height( float height )
  1097. {
  1098. CurrentProfile->Set_Height( height );
  1099. }
  1100. void CCameraClass::Set_Profile_Distance( float distance )
  1101. {
  1102. CurrentProfile->Set_Distance( distance );
  1103. }
  1104. float CCameraClass::Get_Profile_Zoom( void )
  1105. {
  1106. return CurrentProfile->Get_Zoom();
  1107. }
  1108. /*
  1109. **
  1110. */
  1111. void CCameraClass::Handle_Input( void )
  1112. {
  1113. #define TILT_ADJUST (float)DEG_TO_RAD(30.0f)
  1114. #define MAX_TILT (float)DEG_TO_RAD(80.0f)
  1115. #define MIN_TILT (float)DEG_TO_RAD(-30.0f)
  1116. #define DISTANCE_ADJUST 5.0f
  1117. #define MIN_DISTANCE -5.0f
  1118. #define MAX_DISTANCE 200.0f
  1119. #define FOV_ADJUST 1.0f
  1120. #define HEIGHT_ADJUST 0.5f
  1121. #define MIN_HEIGHT -3.0f
  1122. #define MAX_HEIGHT 4.0f
  1123. #define FP_TWEAK_RATE 0.1f;
  1124. float dt = TimeManager::Get_Frame_Real_Seconds();
  1125. // Hold F9 to control the camera
  1126. assert( CurrentProfile != NULL );
  1127. #ifdef WWDEBUG
  1128. if ( CombatManager::Is_First_Person() ) {
  1129. Vector3 tweak(0,0,0);
  1130. tweak.X = ( Input::Get_State( INPUT_FUNCTION_CAMERA_TRANSTILT_INC ) ? 1 : 0 ) +
  1131. ( Input::Get_State( INPUT_FUNCTION_CAMERA_TRANSTILT_DEC ) ? -1 : 0 );
  1132. tweak.Y = ( Input::Get_State( INPUT_FUNCTION_DEBUG_FAR_CLIP_IN ) ? -1 : 0 ) +
  1133. ( Input::Get_State( INPUT_FUNCTION_DEBUG_FAR_CLIP_OUT ) ? 1 : 0 );
  1134. tweak.Z = ( Input::Get_State( INPUT_FUNCTION_CAMERA_DIST_INC ) ? -1 : 0 ) +
  1135. ( Input::Get_State( INPUT_FUNCTION_CAMERA_DIST_DEC ) ? 1 : 0 );
  1136. tweak *= dt * FP_TWEAK_RATE;
  1137. if ( tweak.Length() ) {
  1138. FirstPersonOffsetTweak += tweak;
  1139. Vector3 offset( 0,0,0 );
  1140. if ( COMBAT_STAR != NULL && COMBAT_STAR->Get_Weapon() != NULL ) {
  1141. offset = COMBAT_STAR->Get_Weapon()->Get_First_Person_Model_Offset();
  1142. }
  1143. offset += FirstPersonOffsetTweak;
  1144. Debug_Say(( "First Person Offset ( %1.3f, %1.3f, %1.3f )\n", offset.X, offset.Y, offset.Z ));
  1145. // Debug_Say(( "First Person Tweak ( %1.3f, %1.3f, %1.3f )\n", FirstPersonOffsetTweak.X, FirstPersonOffsetTweak.Y, FirstPersonOffsetTweak.Z ));
  1146. }
  1147. } else {
  1148. float tilt_amount = ( Input::Get_State( INPUT_FUNCTION_CAMERA_TRANSTILT_INC ) ? 1 : 0 ) +
  1149. ( Input::Get_State( INPUT_FUNCTION_CAMERA_TRANSTILT_DEC ) ? -1 : 0 );
  1150. CurrentProfile->TranslationTilt += TILT_ADJUST * tilt_amount * dt;
  1151. CurrentProfile->TranslationTilt = WWMath::Clamp( CurrentProfile->TranslationTilt, MIN_TILT, MAX_TILT );
  1152. float view_tilt_amount = ( Input::Get_State( INPUT_FUNCTION_CAMERA_VIEWTILT_INC ) ? 1 : 0 ) +
  1153. ( Input::Get_State( INPUT_FUNCTION_CAMERA_VIEWTILT_DEC ) ? -1 : 0 );
  1154. CurrentProfile->ViewTilt += TILT_ADJUST * view_tilt_amount * dt;
  1155. CurrentProfile->ViewTilt = WWMath::Clamp( CurrentProfile->ViewTilt, MIN_TILT, MAX_TILT );
  1156. float distance_amount = ( Input::Get_State( INPUT_FUNCTION_CAMERA_DIST_INC ) ? 1 : 0 ) +
  1157. ( Input::Get_State( INPUT_FUNCTION_CAMERA_DIST_DEC ) ? -1 : 0 );
  1158. CurrentProfile->Distance += DISTANCE_ADJUST * distance_amount * dt;
  1159. CurrentProfile->Distance = WWMath::Clamp( CurrentProfile->Distance, MIN_DISTANCE, MAX_DISTANCE );
  1160. float fov_amount = ( Input::Get_State( INPUT_FUNCTION_CAMERA_FOV_INC ) ? 1 : 0 ) +
  1161. ( Input::Get_State( INPUT_FUNCTION_CAMERA_FOV_DEC ) ? -1 : 0 );
  1162. CurrentProfile->FOV += FOV_ADJUST * fov_amount * dt;
  1163. CurrentProfile->FOV = WWMath::Clamp( CurrentProfile->FOV, MIN_FOV, MAX_FOV );
  1164. float height_amount = ( Input::Get_State( INPUT_FUNCTION_CAMERA_HEIGHT_INC ) ? 1 : 0 ) +
  1165. ( Input::Get_State( INPUT_FUNCTION_CAMERA_HEIGHT_DEC ) ? -1 : 0 );
  1166. CurrentProfile->Height += HEIGHT_ADJUST * height_amount * dt;
  1167. CurrentProfile->Height = WWMath::Clamp( CurrentProfile->Height, MIN_HEIGHT, MAX_HEIGHT );
  1168. if ( ( tilt_amount != 0 ) || (view_tilt_amount != 0) || ( distance_amount != 0 ) ||
  1169. ( fov_amount != 0 ) || ( height_amount != 0 ) )
  1170. {
  1171. Debug_Say(( " Dist: %3.1f Height: %3.1f FOV %3.1f TransTilt: %3.1f ViewTilt: %3.1f\n",
  1172. CurrentProfile->Distance,
  1173. CurrentProfile->Height,
  1174. RAD_TO_DEG( CurrentProfile->FOV ),
  1175. RAD_TO_DEG( CurrentProfile->TranslationTilt ),
  1176. RAD_TO_DEG( CurrentProfile->ViewTilt )
  1177. ));
  1178. }
  1179. if ( Input::Get_State( INPUT_FUNCTION_DEBUG_FAR_CLIP_IN ) ||
  1180. Input::Get_State( INPUT_FUNCTION_DEBUG_FAR_CLIP_OUT ) ) {
  1181. float fog_start, fog_stop;
  1182. COMBAT_SCENE->Get_Fog_Range( &fog_start, &fog_stop );
  1183. if ( Input::Get_State( INPUT_FUNCTION_DEBUG_FAR_CLIP_OUT ) ) {
  1184. FarClipPlane *= 1.1f;
  1185. fog_start *= 1.1f;
  1186. } else {
  1187. FarClipPlane /= 1.1f;
  1188. fog_start /= 1.1f;
  1189. }
  1190. COMBAT_SCENE->Set_Fog_Range( fog_start, FarClipPlane );
  1191. Debug_Say(( "FarClipPlane %f\n", FarClipPlane ));
  1192. Set_Clip_Planes( NearClipPlane, FarClipPlane );
  1193. }
  1194. }
  1195. #endif
  1196. if ( CinematicSnipingEnabled ) {
  1197. float zoom_change = CinematicSnipingDesiredZoom - SniperZoom;
  1198. float max = TimeManager::Get_Frame_Seconds();
  1199. zoom_change = WWMath::Clamp( zoom_change, -max, max );
  1200. SniperZoom += zoom_change;
  1201. CurrentProfile->Set_Zoom( SniperZoom );
  1202. }
  1203. #ifdef WWDEBUG
  1204. if ( Input::Get_State( INPUT_FUNCTION_TOGGLE_SNAP_SHOT_MODE ) ) {
  1205. Set_Snap_Shot_Mode( Is_Snap_Shot_Mode() == SNAPSHOT_OFF );
  1206. Debug_Say(( "Snap Shot Mode %s\n", Is_Snap_Shot_Mode() ? "ON" : "OFF" ));
  1207. }
  1208. #endif
  1209. if ( COMBAT_STAR != NULL && COMBAT_STAR->Is_Control_Enabled() == false ) {
  1210. // Don't move camera if control is disabled
  1211. return;
  1212. }
  1213. // if Snipinging Changed, update tilt to match old target
  1214. if ( WasStarSniping != IsStarSniping ) {
  1215. WasStarSniping = IsStarSniping;
  1216. SmartGameObj * star = COMBAT_STAR;
  1217. if ( star ) {
  1218. Vector3 target_pos = star->Get_Targeting_Pos();
  1219. Vector3 camera_pos = AnchorPosition;
  1220. camera_pos.Z += CurrentProfile->Height;
  1221. camera_pos -= target_pos;
  1222. float drop = camera_pos.Z;
  1223. float dist = camera_pos.Length();
  1224. Tilt = WWMath::Asin( drop/dist );
  1225. Tilt -= CurrentProfile->ViewTilt;
  1226. }
  1227. }
  1228. // Sniper Control
  1229. float sniping_scale = 1;
  1230. if ( !Is_Using_Host_Model() && Is_Star_Sniping() ) {
  1231. float amount = Input::Get_Amount( INPUT_FUNCTION_ZOOM_IN ) -
  1232. Input::Get_Amount( INPUT_FUNCTION_ZOOM_OUT );
  1233. SniperZoom += amount * TimeManager::Get_Frame_Seconds();
  1234. SniperZoom = WWMath::Clamp( SniperZoom, 0, 1 );
  1235. // Scale weapon tilt and turn from Zoom
  1236. float sniper_scale = 0.3f;
  1237. float scale = 1 - SniperZoom * (1 - sniper_scale);
  1238. // Debug_Say(( "scale %f\n", scale ));
  1239. sniping_scale = scale * scale;
  1240. // Set Zoom
  1241. CurrentProfile->Set_Zoom( SniperZoom );
  1242. // Update Zooming Sound.....
  1243. }
  1244. // Adjust Tilt
  1245. float tilt_amount = Input::Get_Amount( INPUT_FUNCTION_WEAPON_UP ) -
  1246. Input::Get_Amount( INPUT_FUNCTION_WEAPON_DOWN );
  1247. // Adjust Facing
  1248. float turn_amount = Input::Get_Amount( INPUT_FUNCTION_WEAPON_LEFT ) -
  1249. Input::Get_Amount( INPUT_FUNCTION_WEAPON_RIGHT );
  1250. if ( Input::Get_State( INPUT_FUNCTION_TURN_AROUND ) ) {
  1251. // turn_amount += DEG_TO_RADF( 180.0F ) / dt;
  1252. Heading = Heading + DEG_TO_RADF( 180.0F );
  1253. if ( Heading > DEG_TO_RADF( 360.0F ) ) {
  1254. Heading -= DEG_TO_RADF( 360.0F );
  1255. }
  1256. if ( COMBAT_STAR ) {
  1257. Vector3 pos;
  1258. COMBAT_STAR->Get_Position( &pos );
  1259. DIAG_LOG(( "SPUS", "%1.2f; %1.2f; %1.2f", pos.X, pos.Y, pos.Z ));
  1260. }
  1261. }
  1262. if ( Enable2DTargeting ) {
  1263. // Adjust Targeting Offset
  1264. if ( !( Input::Get_Mouse_2D_Invert() ^ Input::Get_Mouse_Invert() ) ) {
  1265. tilt_amount = -tilt_amount;
  1266. }
  1267. CameraTarget2DOffset.X += -turn_amount * dt;
  1268. CameraTarget2DOffset.Y += -tilt_amount * dt;
  1269. #define _2D_TARGETING_LIMIT 0.85f
  1270. CameraTarget2DOffset.X = WWMath::Clamp( CameraTarget2DOffset.X, -_2D_TARGETING_LIMIT, _2D_TARGETING_LIMIT );
  1271. CameraTarget2DOffset.Y = WWMath::Clamp( CameraTarget2DOffset.Y, -_2D_TARGETING_LIMIT, _2D_TARGETING_LIMIT );
  1272. } else {
  1273. Tilt += -tilt_amount * dt * sniping_scale;
  1274. Heading += turn_amount * dt * sniping_scale;
  1275. CameraTarget2DOffset.X = 0.0f;
  1276. CameraTarget2DOffset.Y = 0.0f;
  1277. }
  1278. // Clamp the tilt to this arbitrary value
  1279. Tilt = WWMath::Clamp( Tilt, DEG_TO_RADF( -80 ), DEG_TO_RADF( 80 ) );
  1280. // if soldier tries to turn, turn the camera
  1281. float soldier_turn = 0;
  1282. if ( COMBAT_STAR != NULL && COMBAT_STAR->Get_Vehicle() == NULL ) {
  1283. // only do this if the soldier is not in a vehicle
  1284. soldier_turn = Input::Get_Amount( INPUT_FUNCTION_TURN_LEFT ) -
  1285. Input::Get_Amount( INPUT_FUNCTION_TURN_RIGHT );
  1286. }
  1287. Heading += soldier_turn * dt * sniping_scale;
  1288. }
  1289. void CCameraClass::Force_Look( const Vector3 & target )
  1290. {
  1291. Vector3 diff = Get_Transform().Get_Translation();
  1292. diff -= target;
  1293. Heading = WWMath::Atan2( -diff.Y, -diff.X );
  1294. float drop = diff.Z;
  1295. float dist = diff.Length();
  1296. Tilt = WWMath::Asin( drop/dist );
  1297. Tilt -= CurrentProfile->ViewTilt;
  1298. }
  1299. void CCameraClass::Set_Lerp_Time( float time )
  1300. {
  1301. LerpTimeTotal = time;
  1302. LerpTimeRemaining = time;
  1303. }
  1304. Vector3 CCameraClass::Get_First_Person_Offset_Tweak( void )
  1305. {
  1306. return FirstPersonOffsetTweak;
  1307. }
  1308. void CCameraClass::Reset_First_Person_Offset_Tweak( void )
  1309. {
  1310. FirstPersonOffsetTweak = Vector3(0,0,0);
  1311. }
  1312. bool CCameraClass::Draw_Sniper( void )
  1313. {
  1314. if ( Is_Using_Host_Model() ) {
  1315. return CinematicSnipingEnabled;
  1316. } else {
  1317. return IsStarSniping;
  1318. }
  1319. }
  1320. void CCameraClass::Cinematic_Sniper_Control( bool enabled, float zoom )
  1321. {
  1322. Debug_Say(( "Camera Sniper Control %d, %f \n", enabled, zoom ));
  1323. CinematicSnipingEnabled = enabled;
  1324. CinematicSnipingDesiredZoom = zoom;
  1325. }
  1326. void CCameraClass::Set_Is_Star_Sniping( bool onoff )
  1327. {
  1328. if (IsStarSniping != onoff) {
  1329. IsStarSniping = onoff;
  1330. //
  1331. // Add or remove the sniper listener from the world
  1332. //
  1333. if ( SniperListener != NULL && WWAudioClass::Get_Instance() != NULL ) {
  1334. if ( WWAudioClass::Get_Instance()->Get_Sound_Scene()->Peek_2nd_Listener() != NULL ) {
  1335. WWAudioClass::Get_Instance()->Get_Sound_Scene()->Set_2nd_Listener( NULL );
  1336. } else {
  1337. WWAudioClass::Get_Instance()->Get_Sound_Scene()->Set_2nd_Listener( SniperListener );
  1338. //
  1339. // Update the listener's position in the world
  1340. //
  1341. Update_Sniper_Listener_Pos();
  1342. }
  1343. }
  1344. if ( COMBAT_STAR ) {
  1345. Vector3 pos;
  1346. COMBAT_STAR->Get_Position( &pos );
  1347. int ammo = 0;
  1348. if ( COMBAT_STAR->Get_Weapon() ) {
  1349. ammo = COMBAT_STAR->Get_Weapon()->Get_Total_Rounds();
  1350. }
  1351. if ( IsStarSniping ) {
  1352. DIAG_LOG(( "SNEN", "%1.2f; %1.2f; %1.2f; %d ", pos.X, pos.Y, pos.Z, ammo ));
  1353. } else {
  1354. DIAG_LOG(( "SNEX", "%1.2f; %1.2f; %1.2f; %d ", pos.X, pos.Y, pos.Z, ammo ));
  1355. }
  1356. }
  1357. }
  1358. return ;
  1359. }
  1360. void CCameraClass::Update_Sniper_Listener_Pos( void )
  1361. {
  1362. if ( SniperListener != NULL ) {
  1363. //
  1364. // Get the camera's transform
  1365. //
  1366. Matrix3D tm = Get_Transform();
  1367. //
  1368. // Calculate what point in world space the sniper is zoomed into
  1369. //
  1370. float dist = ::tan (1.45F + ((1.5672F - 1.45F) * SniperZoom));
  1371. dist = min (dist, SniperDistance);
  1372. Vector3 pos = tm.Get_Translation() - (tm.Get_Z_Vector() * dist);
  1373. //
  1374. // Update the sniper's position
  1375. //
  1376. SniperListener->Set_Transform( Matrix3D( pos ) );
  1377. }
  1378. return ;
  1379. }
  1380. void CCameraClass::Set_Sniper_Distance( float dist )
  1381. {
  1382. //
  1383. // If the distance has changed, update the sniper's listener
  1384. //
  1385. if ( SniperDistance != dist ) {
  1386. SniperDistance = dist;
  1387. Update_Sniper_Listener_Pos();
  1388. }
  1389. return ;
  1390. }
  1391. /*
  1392. **
  1393. */
  1394. void CCameraClass::Handle_Snap_Shot_Mode( void )
  1395. {
  1396. float dt = TimeManager::Get_Frame_Real_Seconds();
  1397. static float tilt = 0;
  1398. static float turn = 0;
  1399. float tilt_amount = Input::Get_Amount( INPUT_FUNCTION_WEAPON_UP ) -
  1400. Input::Get_Amount( INPUT_FUNCTION_WEAPON_DOWN );
  1401. float turn_amount = Input::Get_Amount( INPUT_FUNCTION_WEAPON_LEFT ) -
  1402. Input::Get_Amount( INPUT_FUNCTION_WEAPON_RIGHT );
  1403. if (turn_amount == 0) {
  1404. turn_amount = Input::Get_Amount( INPUT_FUNCTION_TURN_LEFT ) -
  1405. Input::Get_Amount( INPUT_FUNCTION_TURN_RIGHT );
  1406. }
  1407. tilt += tilt_amount * dt;
  1408. turn += turn_amount * dt;
  1409. Matrix3D tm = Get_Transform();
  1410. Vector3 pos = tm.Get_Translation();
  1411. tm.Make_Identity();
  1412. tm.Set_Translation( pos );
  1413. tm.Rotate_Z( turn );
  1414. tm.Rotate_X( tilt );
  1415. float forward = Input::Get_Amount( INPUT_FUNCTION_MOVE_FORWARD ) -
  1416. Input::Get_Amount( INPUT_FUNCTION_MOVE_BACKWARD );
  1417. float left = Input::Get_Amount( INPUT_FUNCTION_MOVE_LEFT ) -
  1418. Input::Get_Amount( INPUT_FUNCTION_MOVE_RIGHT );
  1419. float up = Input::Get_Amount( INPUT_FUNCTION_MOVE_UP ) -
  1420. Input::Get_Amount( INPUT_FUNCTION_MOVE_DOWN );
  1421. SnapShotMode = Input::Get_State( INPUT_FUNCTION_SNAP_SHOT_ADVANCE ) ? SNAPSHOT_PROGRESS : SNAPSHOT_ON;
  1422. dt *= 4;
  1423. tm.Translate( Vector3( -left * dt, up * dt, -forward * dt ) );
  1424. Set_Transform( tm );
  1425. }