PlayerView.cpp 43 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750
  1. /*
  2. ===========================================================================
  3. Doom 3 BFG Edition GPL Source Code
  4. Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
  5. This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
  6. Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
  7. it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation, either version 3 of the License, or
  9. (at your option) any later version.
  10. Doom 3 BFG Edition Source Code 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. You should have received a copy of the GNU General Public License
  15. along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
  16. In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below.
  17. If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
  18. ===========================================================================
  19. */
  20. #include "../idlib/precompiled.h"
  21. #pragma hdrstop
  22. #include "Game_local.h"
  23. // _D3XP : rename all gameLocal.time to gameLocal.slow.time for merge!
  24. const int IMPULSE_DELAY = 150;
  25. /*
  26. ==============
  27. idPlayerView::idPlayerView
  28. ==============
  29. */
  30. idPlayerView::idPlayerView() {
  31. memset( screenBlobs, 0, sizeof( screenBlobs ) );
  32. memset( &view, 0, sizeof( view ) );
  33. player = NULL;
  34. tunnelMaterial = declManager->FindMaterial( "textures/decals/tunnel" );
  35. armorMaterial = declManager->FindMaterial( "armorViewEffect" );
  36. berserkMaterial = declManager->FindMaterial( "textures/decals/berserk" );
  37. irGogglesMaterial = declManager->FindMaterial( "textures/decals/irblend" );
  38. bloodSprayMaterial = declManager->FindMaterial( "textures/decals/bloodspray" );
  39. bfgMaterial = declManager->FindMaterial( "textures/decals/bfgvision" );
  40. bfgVision = false;
  41. dvFinishTime = 0;
  42. kickFinishTime = 0;
  43. kickAngles.Zero();
  44. lastDamageTime = 0.0f;
  45. fadeTime = 0;
  46. fadeRate = 0.0;
  47. fadeFromColor.Zero();
  48. fadeToColor.Zero();
  49. fadeColor.Zero();
  50. shakeAng.Zero();
  51. fxManager = NULL;
  52. if ( fxManager == NULL ) {
  53. fxManager = new (TAG_ENTITY) FullscreenFXManager;
  54. fxManager->Initialize( this );
  55. }
  56. ClearEffects();
  57. }
  58. /*
  59. ==============
  60. idPlayerView::~idPlayerView
  61. ==============
  62. */
  63. idPlayerView::~idPlayerView() {
  64. delete fxManager;
  65. }
  66. /*
  67. ==============
  68. idPlayerView::Save
  69. ==============
  70. */
  71. void idPlayerView::Save( idSaveGame *savefile ) const {
  72. int i;
  73. const screenBlob_t *blob;
  74. blob = &screenBlobs[ 0 ];
  75. for( i = 0; i < MAX_SCREEN_BLOBS; i++, blob++ ) {
  76. savefile->WriteMaterial( blob->material );
  77. savefile->WriteFloat( blob->x );
  78. savefile->WriteFloat( blob->y );
  79. savefile->WriteFloat( blob->w );
  80. savefile->WriteFloat( blob->h );
  81. savefile->WriteFloat( blob->s1 );
  82. savefile->WriteFloat( blob->t1 );
  83. savefile->WriteFloat( blob->s2 );
  84. savefile->WriteFloat( blob->t2 );
  85. savefile->WriteInt( blob->finishTime );
  86. savefile->WriteInt( blob->startFadeTime );
  87. savefile->WriteFloat( blob->driftAmount );
  88. }
  89. savefile->WriteInt( dvFinishTime );
  90. savefile->WriteInt( kickFinishTime );
  91. savefile->WriteAngles( kickAngles );
  92. savefile->WriteBool( bfgVision );
  93. savefile->WriteMaterial( tunnelMaterial );
  94. savefile->WriteMaterial( armorMaterial );
  95. savefile->WriteMaterial( berserkMaterial );
  96. savefile->WriteMaterial( irGogglesMaterial );
  97. savefile->WriteMaterial( bloodSprayMaterial );
  98. savefile->WriteMaterial( bfgMaterial );
  99. savefile->WriteFloat( lastDamageTime );
  100. savefile->WriteVec4( fadeColor );
  101. savefile->WriteVec4( fadeToColor );
  102. savefile->WriteVec4( fadeFromColor );
  103. savefile->WriteFloat( fadeRate );
  104. savefile->WriteInt( fadeTime );
  105. savefile->WriteAngles( shakeAng );
  106. savefile->WriteObject( player );
  107. savefile->WriteRenderView( view );
  108. if ( fxManager ) {
  109. fxManager->Save( savefile );
  110. }
  111. }
  112. /*
  113. ==============
  114. idPlayerView::Restore
  115. ==============
  116. */
  117. void idPlayerView::Restore( idRestoreGame *savefile ) {
  118. int i;
  119. screenBlob_t *blob;
  120. blob = &screenBlobs[ 0 ];
  121. for( i = 0; i < MAX_SCREEN_BLOBS; i++, blob++ ) {
  122. savefile->ReadMaterial( blob->material );
  123. savefile->ReadFloat( blob->x );
  124. savefile->ReadFloat( blob->y );
  125. savefile->ReadFloat( blob->w );
  126. savefile->ReadFloat( blob->h );
  127. savefile->ReadFloat( blob->s1 );
  128. savefile->ReadFloat( blob->t1 );
  129. savefile->ReadFloat( blob->s2 );
  130. savefile->ReadFloat( blob->t2 );
  131. savefile->ReadInt( blob->finishTime );
  132. savefile->ReadInt( blob->startFadeTime );
  133. savefile->ReadFloat( blob->driftAmount );
  134. }
  135. savefile->ReadInt( dvFinishTime );
  136. savefile->ReadInt( kickFinishTime );
  137. savefile->ReadAngles( kickAngles );
  138. savefile->ReadBool( bfgVision );
  139. savefile->ReadMaterial( tunnelMaterial );
  140. savefile->ReadMaterial( armorMaterial );
  141. savefile->ReadMaterial( berserkMaterial );
  142. savefile->ReadMaterial( irGogglesMaterial );
  143. savefile->ReadMaterial( bloodSprayMaterial );
  144. savefile->ReadMaterial( bfgMaterial );
  145. savefile->ReadFloat( lastDamageTime );
  146. savefile->ReadVec4( fadeColor );
  147. savefile->ReadVec4( fadeToColor );
  148. savefile->ReadVec4( fadeFromColor );
  149. savefile->ReadFloat( fadeRate );
  150. savefile->ReadInt( fadeTime );
  151. savefile->ReadAngles( shakeAng );
  152. savefile->ReadObject( reinterpret_cast<idClass *&>( player ) );
  153. savefile->ReadRenderView( view );
  154. if ( fxManager ) {
  155. fxManager->Restore( savefile );
  156. }
  157. }
  158. /*
  159. ==============
  160. idPlayerView::SetPlayerEntity
  161. ==============
  162. */
  163. void idPlayerView::SetPlayerEntity( idPlayer *playerEnt ) {
  164. player = playerEnt;
  165. }
  166. /*
  167. ==============
  168. idPlayerView::ClearEffects
  169. ==============
  170. */
  171. void idPlayerView::ClearEffects() {
  172. lastDamageTime = MS2SEC( gameLocal.slow.time - 99999 );
  173. dvFinishTime = ( gameLocal.fast.time - 99999 );
  174. kickFinishTime = ( gameLocal.slow.time - 99999 );
  175. for ( int i = 0 ; i < MAX_SCREEN_BLOBS ; i++ ) {
  176. screenBlobs[i].finishTime = gameLocal.fast.time;
  177. }
  178. fadeTime = 0;
  179. bfgVision = false;
  180. }
  181. /*
  182. ==============
  183. idPlayerView::GetScreenBlob
  184. ==============
  185. */
  186. screenBlob_t *idPlayerView::GetScreenBlob() {
  187. screenBlob_t * oldest = &screenBlobs[0];
  188. for ( int i = 1 ; i < MAX_SCREEN_BLOBS ; i++ ) {
  189. if ( screenBlobs[i].finishTime < oldest->finishTime ) {
  190. oldest = &screenBlobs[i];
  191. }
  192. }
  193. return oldest;
  194. }
  195. /*
  196. ==============
  197. idPlayerView::DamageImpulse
  198. LocalKickDir is the direction of force in the player's coordinate system,
  199. which will determine the head kick direction
  200. ==============
  201. */
  202. void idPlayerView::DamageImpulse( idVec3 localKickDir, const idDict *damageDef ) {
  203. //
  204. // double vision effect
  205. //
  206. if ( lastDamageTime > 0.0f && SEC2MS( lastDamageTime ) + IMPULSE_DELAY > gameLocal.slow.time ) {
  207. // keep shotgun from obliterating the view
  208. return;
  209. }
  210. float dvTime = damageDef->GetFloat( "dv_time" );
  211. if ( dvTime ) {
  212. if ( dvFinishTime < gameLocal.fast.time ) {
  213. dvFinishTime = gameLocal.fast.time;
  214. }
  215. dvFinishTime += g_dvTime.GetFloat() * dvTime;
  216. // don't let it add up too much in god mode
  217. if ( dvFinishTime > gameLocal.fast.time + 5000 ) {
  218. dvFinishTime = gameLocal.fast.time + 5000;
  219. }
  220. }
  221. //
  222. // head angle kick
  223. //
  224. float kickTime = damageDef->GetFloat( "kick_time" );
  225. if ( kickTime ) {
  226. kickFinishTime = gameLocal.slow.time + g_kickTime.GetFloat() * kickTime;
  227. // forward / back kick will pitch view
  228. kickAngles[0] = localKickDir[0];
  229. // side kick will yaw view
  230. kickAngles[1] = localKickDir[1]*0.5f;
  231. // up / down kick will pitch view
  232. kickAngles[0] += localKickDir[2];
  233. // roll will come from side
  234. kickAngles[2] = localKickDir[1];
  235. float kickAmplitude = damageDef->GetFloat( "kick_amplitude" );
  236. if ( kickAmplitude ) {
  237. kickAngles *= kickAmplitude;
  238. }
  239. }
  240. //
  241. // screen blob
  242. //
  243. float blobTime = damageDef->GetFloat( "blob_time" );
  244. if ( blobTime ) {
  245. screenBlob_t *blob = GetScreenBlob();
  246. blob->startFadeTime = gameLocal.fast.time;
  247. blob->finishTime = gameLocal.fast.time + blobTime * g_blobTime.GetFloat();
  248. const char *materialName = damageDef->GetString( "mtr_blob" );
  249. blob->material = declManager->FindMaterial( materialName );
  250. blob->x = damageDef->GetFloat( "blob_x" );
  251. blob->x += ( gameLocal.random.RandomInt()&63 ) - 32;
  252. blob->y = damageDef->GetFloat( "blob_y" );
  253. blob->y += ( gameLocal.random.RandomInt()&63 ) - 32;
  254. float scale = ( 256 + ( ( gameLocal.random.RandomInt()&63 ) - 32 ) ) / 256.0f;
  255. blob->w = damageDef->GetFloat( "blob_width" ) * g_blobSize.GetFloat() * scale;
  256. blob->h = damageDef->GetFloat( "blob_height" ) * g_blobSize.GetFloat() * scale;
  257. blob->s1 = 0.0f;
  258. blob->t1 = 0.0f;
  259. blob->s2 = 1.0f;
  260. blob->t2 = 1.0f;
  261. }
  262. //
  263. // save lastDamageTime for tunnel vision accentuation
  264. //
  265. lastDamageTime = MS2SEC( gameLocal.fast.time );
  266. }
  267. /*
  268. ==================
  269. idPlayerView::WeaponFireFeedback
  270. Called when a weapon fires, generates head twitches, etc
  271. ==================
  272. */
  273. void idPlayerView::WeaponFireFeedback( const idDict *weaponDef ) {
  274. int recoilTime = weaponDef->GetInt( "recoilTime" );
  275. // don't shorten a damage kick in progress
  276. if ( recoilTime && kickFinishTime < gameLocal.slow.time ) {
  277. idAngles angles;
  278. weaponDef->GetAngles( "recoilAngles", "5 0 0", angles );
  279. kickAngles = angles;
  280. int finish = gameLocal.slow.time + g_kickTime.GetFloat() * recoilTime;
  281. kickFinishTime = finish;
  282. }
  283. }
  284. /*
  285. ===================
  286. idPlayerView::CalculateShake
  287. ===================
  288. */
  289. void idPlayerView::CalculateShake() {
  290. float shakeVolume = gameSoundWorld->CurrentShakeAmplitude();
  291. //
  292. // shakeVolume should somehow be molded into an angle here
  293. // it should be thought of as being in the range 0.0 -> 1.0, although
  294. // since CurrentShakeAmplitudeForPosition() returns all the shake sounds
  295. // the player can hear, it can go over 1.0 too.
  296. //
  297. shakeAng[0] = gameLocal.random.CRandomFloat() * shakeVolume;
  298. shakeAng[1] = gameLocal.random.CRandomFloat() * shakeVolume;
  299. shakeAng[2] = gameLocal.random.CRandomFloat() * shakeVolume;
  300. }
  301. /*
  302. ===================
  303. idPlayerView::ShakeAxis
  304. ===================
  305. */
  306. idMat3 idPlayerView::ShakeAxis() const {
  307. return shakeAng.ToMat3();
  308. }
  309. /*
  310. ===================
  311. idPlayerView::AngleOffset
  312. kickVector, a world space direction that the attack should
  313. ===================
  314. */
  315. idAngles idPlayerView::AngleOffset() const {
  316. idAngles ang( 0.0f, 0.0f, 0.0f );
  317. if ( gameLocal.slow.time < kickFinishTime ) {
  318. float offset = kickFinishTime - gameLocal.slow.time;
  319. ang = kickAngles * offset * offset * g_kickAmplitude.GetFloat();
  320. for ( int i = 0 ; i < 3 ; i++ ) {
  321. if ( ang[i] > 70.0f ) {
  322. ang[i] = 70.0f;
  323. } else if ( ang[i] < -70.0f ) {
  324. ang[i] = -70.0f;
  325. }
  326. }
  327. }
  328. return ang;
  329. }
  330. /*
  331. ==================
  332. idPlayerView::SingleView
  333. ==================
  334. */
  335. void idPlayerView::SingleView( const renderView_t *view, idMenuHandler_HUD * hudManager ) {
  336. // normal rendering
  337. if ( !view ) {
  338. return;
  339. }
  340. // place the sound origin for the player
  341. gameSoundWorld->PlaceListener( view->vieworg, view->viewaxis, player->entityNumber + 1 );
  342. // if the objective system is up, don't do normal drawing
  343. if ( player->objectiveSystemOpen ) {
  344. if ( player->pdaMenu != NULL ) {
  345. player->pdaMenu->Update();
  346. }
  347. return;
  348. }
  349. // hack the shake in at the very last moment, so it can't cause any consistency problems
  350. renderView_t hackedView = *view;
  351. hackedView.viewaxis = hackedView.viewaxis * ShakeAxis();
  352. if ( gameLocal.portalSkyEnt.GetEntity() && gameLocal.IsPortalSkyAcive() && g_enablePortalSky.GetBool() ) {
  353. renderView_t portalView = hackedView;
  354. portalView.vieworg = gameLocal.portalSkyEnt.GetEntity()->GetPhysics()->GetOrigin();
  355. gameRenderWorld->RenderScene( &portalView );
  356. renderSystem->CaptureRenderToImage( "_currentRender" );
  357. hackedView.forceUpdate = true; // FIX: for smoke particles not drawing when portalSky present
  358. }
  359. // process the frame
  360. fxManager->Process( &hackedView );
  361. if ( !hudManager ) {
  362. return;
  363. }
  364. // draw screen blobs
  365. if ( !pm_thirdPerson.GetBool() && !g_skipViewEffects.GetBool() ) {
  366. if ( !player->spectating ) {
  367. for ( int i = 0 ; i < MAX_SCREEN_BLOBS ; i++ ) {
  368. screenBlob_t *blob = &screenBlobs[i];
  369. if ( blob->finishTime <= gameLocal.fast.time ) {
  370. continue;
  371. }
  372. blob->y += blob->driftAmount;
  373. float fade = (float)( blob->finishTime - gameLocal.fast.time ) / ( blob->finishTime - blob->startFadeTime );
  374. if ( fade > 1.0f ) {
  375. fade = 1.0f;
  376. }
  377. if ( fade ) {
  378. renderSystem->SetColor4( 1.0f, 1.0f, 1.0f, fade );
  379. renderSystem->DrawStretchPic( blob->x, blob->y, blob->w, blob->h,blob->s1, blob->t1, blob->s2, blob->t2, blob->material );
  380. }
  381. }
  382. }
  383. player->DrawHUD( hudManager );
  384. if ( player->spectating ) {
  385. return;
  386. }
  387. // armor impulse feedback
  388. float armorPulse = ( gameLocal.fast.time - player->lastArmorPulse ) / 250.0f;
  389. if ( armorPulse > 0.0f && armorPulse < 1.0f ) {
  390. renderSystem->SetColor4( 1.0f, 1.0f, 1.0f, 1.0f - armorPulse );
  391. renderSystem->DrawStretchPic( 0.0f, 0.0f, SCREEN_WIDTH, SCREEN_HEIGHT, 0.0f, 0.0f, 1.0f, 1.0f, armorMaterial );
  392. }
  393. // tunnel vision
  394. float health = 0.0f;
  395. if ( g_testHealthVision.GetFloat() != 0.0f ) {
  396. health = g_testHealthVision.GetFloat();
  397. } else {
  398. health = player->health;
  399. }
  400. float alpha = health / 100.0f;
  401. if ( alpha < 0.0f ) {
  402. alpha = 0.0f;
  403. }
  404. if ( alpha > 1.0f ) {
  405. alpha = 1.0f;
  406. }
  407. if ( alpha < 1.0f ) {
  408. renderSystem->SetColor4( ( player->health <= 0.0f ) ? MS2SEC( gameLocal.slow.time ) : lastDamageTime, 1.0f, 1.0f, ( player->health <= 0.0f ) ? 0.0f : alpha );
  409. renderSystem->DrawStretchPic( 0.0f, 0.0f, SCREEN_WIDTH, SCREEN_HEIGHT, 0.0f, 0.0f, 1.0f, 1.0f, tunnelMaterial );
  410. }
  411. if ( bfgVision ) {
  412. renderSystem->SetColor4( 1.0f, 1.0f, 1.0f, 1.0f );
  413. renderSystem->DrawStretchPic( 0.0f, 0.0f, SCREEN_WIDTH, SCREEN_HEIGHT, 0.0f, 0.0f, 1.0f, 1.0f, bfgMaterial );
  414. }
  415. }
  416. // test a single material drawn over everything
  417. if ( g_testPostProcess.GetString()[0] ) {
  418. const idMaterial *mtr = declManager->FindMaterial( g_testPostProcess.GetString(), false );
  419. if ( !mtr ) {
  420. common->Printf( "Material not found.\n" );
  421. g_testPostProcess.SetString( "" );
  422. } else {
  423. renderSystem->SetColor4( 1.0f, 1.0f, 1.0f, 1.0f );
  424. renderSystem->DrawStretchPic( 0.0f, 0.0f, SCREEN_WIDTH, SCREEN_HEIGHT, 0.0f, 0.0f, 1.0f, 1.0f, mtr );
  425. }
  426. }
  427. }
  428. /*
  429. =================
  430. idPlayerView::Flash
  431. flashes the player view with the given color
  432. =================
  433. */
  434. void idPlayerView::Flash(idVec4 color, int time ) {
  435. Fade( idVec4( 0.0f, 0.0f, 0.0f, 0.0f ), time);
  436. fadeFromColor = colorWhite;
  437. }
  438. /*
  439. =================
  440. idPlayerView::Fade
  441. used for level transition fades
  442. assumes: color.w is 0 or 1
  443. =================
  444. */
  445. void idPlayerView::Fade( idVec4 color, int time ) {
  446. SetTimeState ts( player->timeGroup );
  447. if ( !fadeTime ) {
  448. fadeFromColor.Set( 0.0f, 0.0f, 0.0f, 1.0f - color[ 3 ] );
  449. } else {
  450. fadeFromColor = fadeColor;
  451. }
  452. fadeToColor = color;
  453. if ( time <= 0 ) {
  454. fadeRate = 0;
  455. time = 0;
  456. fadeColor = fadeToColor;
  457. } else {
  458. fadeRate = 1.0f / ( float )time;
  459. }
  460. if ( gameLocal.realClientTime == 0 && time == 0 ) {
  461. fadeTime = 1;
  462. } else {
  463. fadeTime = gameLocal.realClientTime + time;
  464. }
  465. }
  466. /*
  467. =================
  468. idPlayerView::ScreenFade
  469. =================
  470. */
  471. void idPlayerView::ScreenFade() {
  472. if ( !fadeTime ) {
  473. return;
  474. }
  475. SetTimeState ts( player->timeGroup );
  476. int msec = fadeTime - gameLocal.realClientTime;
  477. if ( msec <= 0 ) {
  478. fadeColor = fadeToColor;
  479. if ( fadeColor[ 3 ] == 0.0f ) {
  480. fadeTime = 0;
  481. }
  482. } else {
  483. float t = ( float )msec * fadeRate;
  484. fadeColor = fadeFromColor * t + fadeToColor * ( 1.0f - t );
  485. }
  486. if ( fadeColor[ 3 ] != 0.0f ) {
  487. renderSystem->SetColor4( fadeColor[ 0 ], fadeColor[ 1 ], fadeColor[ 2 ], fadeColor[ 3 ] );
  488. renderSystem->DrawStretchPic( 0.0f, 0.0f, SCREEN_WIDTH, SCREEN_HEIGHT, 0.0f, 0.0f, 1.0f, 1.0f, declManager->FindMaterial( "_white" ) );
  489. }
  490. }
  491. idCVar stereoRender_interOccularCentimeters( "stereoRender_interOccularCentimeters", "3.0", CVAR_ARCHIVE | CVAR_RENDERER, "Distance between eyes" );
  492. idCVar stereoRender_convergence( "stereoRender_convergence", "6", CVAR_RENDERER, "0 = head mounted display, otherwise world units to convergence plane" );
  493. extern idCVar stereoRender_screenSeparation; // screen units from center to eyes
  494. extern idCVar stereoRender_swapEyes;
  495. // In a head mounted display with separate displays for each eye,
  496. // screen separation will be zero and world separation will be the eye distance.
  497. struct stereoDistances_t {
  498. // Offset to projection matrix, positive one eye, negative the other.
  499. // Total distance is twice this, so 0.05 would give a 10% of screen width
  500. // separation for objects at infinity.
  501. float screenSeparation;
  502. // Game world units from one eye to the centerline.
  503. // Total distance is twice this.
  504. float worldSeparation;
  505. };
  506. float CentimetersToInches( const float cm ) {
  507. return cm / 2.54f;
  508. }
  509. float CentimetersToWorldUnits( const float cm ) {
  510. // In Doom 3, one world unit == one inch
  511. return CentimetersToInches( cm );
  512. }
  513. float CalculateWorldSeparation(
  514. const float screenSeparation,
  515. const float convergenceDistance,
  516. const float fov_x_degrees ) {
  517. const float fovRadians = DEG2RAD( fov_x_degrees );
  518. const float screen = tan( fovRadians * 0.5f ) * fabs( screenSeparation );
  519. const float worldSeparation = screen * convergenceDistance / 0.5f;
  520. return worldSeparation;
  521. }
  522. stereoDistances_t CaclulateStereoDistances(
  523. const float interOcularCentimeters, // distance between two eyes, typically 6.0 - 7.0
  524. const float screenWidthCentimeters, // read from operating system
  525. const float convergenceWorldUnits, // pass 0 for head mounted display mode
  526. const float fov_x_degrees ) { // edge to edge horizontal field of view, typically 60 - 90
  527. stereoDistances_t dists = {};
  528. if ( convergenceWorldUnits == 0.0f ) {
  529. // head mounted display mode
  530. dists.worldSeparation = CentimetersToInches( interOcularCentimeters * 0.5 );
  531. dists.screenSeparation = 0.0f;
  532. return dists;
  533. }
  534. // 3DTV mode
  535. dists.screenSeparation = 0.5f * interOcularCentimeters / screenWidthCentimeters;
  536. dists.worldSeparation = CalculateWorldSeparation( dists.screenSeparation, convergenceWorldUnits, fov_x_degrees );
  537. return dists;
  538. }
  539. float GetScreenSeparationForGuis() {
  540. const stereoDistances_t dists = CaclulateStereoDistances(
  541. stereoRender_interOccularCentimeters.GetFloat(),
  542. renderSystem->GetPhysicalScreenWidthInCentimeters(),
  543. stereoRender_convergence.GetFloat(),
  544. 80.0f /* fov */ );
  545. return dists.screenSeparation;
  546. }
  547. /*
  548. ===================
  549. idPlayerView::EmitStereoEyeView
  550. ===================
  551. */
  552. void idPlayerView::EmitStereoEyeView( const int eye, idMenuHandler_HUD * hudManager ) {
  553. renderView_t * view = player->GetRenderView();
  554. if ( view == NULL ) {
  555. return;
  556. }
  557. renderView_t eyeView = *view;
  558. const stereoDistances_t dists = CaclulateStereoDistances(
  559. stereoRender_interOccularCentimeters.GetFloat(),
  560. renderSystem->GetPhysicalScreenWidthInCentimeters(),
  561. stereoRender_convergence.GetFloat(),
  562. view->fov_x );
  563. eyeView.vieworg += eye * dists.worldSeparation * eyeView.viewaxis[1];
  564. eyeView.viewEyeBuffer = stereoRender_swapEyes.GetBool() ? eye : -eye;
  565. eyeView.stereoScreenSeparation = eye * dists.screenSeparation;
  566. SingleView( &eyeView, hudManager );
  567. }
  568. /*
  569. ===================
  570. IsGameStereoRendered
  571. The crosshair is swapped for a laser sight in stereo rendering
  572. ===================
  573. */
  574. bool IsGameStereoRendered() {
  575. if ( renderSystem->GetStereo3DMode() != STEREO3D_OFF ) {
  576. return true;
  577. }
  578. return false;
  579. }
  580. int EyeForHalfRateFrame( const int frameCount ) {
  581. return ( renderSystem->GetFrameCount() & 1 ) ? -1 : 1;
  582. }
  583. /*
  584. ===================
  585. idPlayerView::RenderPlayerView
  586. ===================
  587. */
  588. void idPlayerView::RenderPlayerView( idMenuHandler_HUD * hudManager ) {
  589. const renderView_t *view = player->GetRenderView();
  590. if ( renderSystem->GetStereo3DMode() != STEREO3D_OFF ) {
  591. // render both eye views each frame on the PC
  592. for ( int eye = 1 ; eye >= -1 ; eye -= 2 ) {
  593. EmitStereoEyeView( eye, hudManager );
  594. }
  595. } else
  596. {
  597. SingleView( view, hudManager );
  598. }
  599. ScreenFade();
  600. }
  601. /*
  602. ===================
  603. idPlayerView::WarpVision
  604. ===================
  605. */
  606. int idPlayerView::AddWarp( idVec3 worldOrigin, float centerx, float centery, float initialRadius, float durationMsec ) {
  607. FullscreenFX_Warp *fx = (FullscreenFX_Warp*)( fxManager->FindFX( "warp" ) );
  608. if ( fx ) {
  609. fx->EnableGrabber( true );
  610. return 1;
  611. }
  612. return 1;
  613. }
  614. void idPlayerView::FreeWarp( int id ) {
  615. FullscreenFX_Warp *fx = (FullscreenFX_Warp*)( fxManager->FindFX( "warp" ) );
  616. if ( fx ) {
  617. fx->EnableGrabber( false );
  618. return;
  619. }
  620. }
  621. /*
  622. ==================
  623. FxFader::FxFader
  624. ==================
  625. */
  626. FxFader::FxFader() {
  627. time = 0;
  628. state = FX_STATE_OFF;
  629. alpha = 0;
  630. msec = 1000;
  631. }
  632. /*
  633. ==================
  634. FxFader::SetTriggerState
  635. ==================
  636. */
  637. bool FxFader::SetTriggerState( bool active ) {
  638. // handle on/off states
  639. if ( active && state == FX_STATE_OFF ) {
  640. state = FX_STATE_RAMPUP;
  641. time = gameLocal.slow.time + msec;
  642. }
  643. else if ( !active && state == FX_STATE_ON ) {
  644. state = FX_STATE_RAMPDOWN;
  645. time = gameLocal.slow.time + msec;
  646. }
  647. // handle rampup/rampdown states
  648. if ( state == FX_STATE_RAMPUP ) {
  649. if ( gameLocal.slow.time >= time ) {
  650. state = FX_STATE_ON;
  651. }
  652. }
  653. else if ( state == FX_STATE_RAMPDOWN ) {
  654. if ( gameLocal.slow.time >= time ) {
  655. state = FX_STATE_OFF;
  656. }
  657. }
  658. // compute alpha
  659. switch ( state ) {
  660. case FX_STATE_ON: alpha = 1; break;
  661. case FX_STATE_OFF: alpha = 0; break;
  662. case FX_STATE_RAMPUP: alpha = 1 - (float)( time - gameLocal.slow.time ) / msec; break;
  663. case FX_STATE_RAMPDOWN: alpha = (float)( time - gameLocal.slow.time ) / msec; break;
  664. }
  665. if ( alpha > 0 ) {
  666. return true;
  667. }
  668. else {
  669. return false;
  670. }
  671. }
  672. /*
  673. ==================
  674. FxFader::Save
  675. ==================
  676. */
  677. void FxFader::Save( idSaveGame *savefile ) {
  678. savefile->WriteInt( time );
  679. savefile->WriteInt( state );
  680. savefile->WriteFloat( alpha );
  681. savefile->WriteInt( msec );
  682. }
  683. /*
  684. ==================
  685. FxFader::Restore
  686. ==================
  687. */
  688. void FxFader::Restore( idRestoreGame *savefile ) {
  689. savefile->ReadInt( time );
  690. savefile->ReadInt( state );
  691. savefile->ReadFloat( alpha );
  692. savefile->ReadInt( msec );
  693. }
  694. /*
  695. ==================
  696. FullscreenFX_Helltime::Save
  697. ==================
  698. */
  699. void FullscreenFX::Save( idSaveGame *savefile ) {
  700. fader.Save( savefile );
  701. }
  702. /*
  703. ==================
  704. FullscreenFX_Helltime::Restore
  705. ==================
  706. */
  707. void FullscreenFX::Restore( idRestoreGame *savefile ) {
  708. fader.Restore( savefile );
  709. }
  710. /*
  711. ==================
  712. FullscreenFX_Helltime::Initialize
  713. ==================
  714. */
  715. void FullscreenFX_Helltime::Initialize() {
  716. initMaterial = declManager->FindMaterial( "textures/d3bfg/bloodorb/init" );
  717. drawMaterial = declManager->FindMaterial( "textures/d3bfg/bloodorb/draw" );
  718. captureMaterials[0] = declManager->FindMaterial( "textures/d3bfg/bloodorb1/capture" );
  719. captureMaterials[1] = declManager->FindMaterial( "textures/d3bfg/bloodorb2/capture" );
  720. captureMaterials[2] = declManager->FindMaterial( "textures/d3bfg/bloodorb3/capture" );
  721. clearAccumBuffer = true;
  722. }
  723. /*
  724. ==================
  725. FullscreenFX_Helltime::DetermineLevel
  726. ==================
  727. */
  728. int FullscreenFX_Helltime::DetermineLevel() {
  729. int testfx = g_testHelltimeFX.GetInteger();
  730. // for testing purposes
  731. if ( testfx >= 0 && testfx < 3 ) {
  732. return testfx;
  733. }
  734. idPlayer * player = fxman->GetPlayer();
  735. if ( player != NULL && player->PowerUpActive( INVULNERABILITY ) ) {
  736. return 2;
  737. }
  738. else if ( player != NULL && player->PowerUpActive( BERSERK ) ) {
  739. return 1;
  740. }
  741. else if ( player != NULL && player->PowerUpActive( HELLTIME ) ) {
  742. return 0;
  743. }
  744. return -1;
  745. }
  746. /*
  747. ==================
  748. FullscreenFX_Helltime::Active
  749. ==================
  750. */
  751. bool FullscreenFX_Helltime::Active() {
  752. if ( gameLocal.inCinematic || common->IsMultiplayer() ) {
  753. return false;
  754. }
  755. if ( DetermineLevel() >= 0 ) {
  756. return true;
  757. }
  758. else {
  759. // latch the clear flag
  760. if ( fader.GetAlpha() == 0 ) {
  761. clearAccumBuffer = true;
  762. }
  763. }
  764. return false;
  765. }
  766. /*
  767. ==================
  768. FullscreenFX_Helltime::AccumPass
  769. ==================
  770. */
  771. void FullscreenFX_Helltime::AccumPass( const renderView_t *view ) {
  772. int level = DetermineLevel();
  773. // for testing
  774. if ( level < 0 || level > 2 ) {
  775. level = 0;
  776. }
  777. renderSystem->SetColor4( 1.0f, 1.0f, 1.0f, 1.0f );
  778. float t0 = 1.0f;
  779. float t1 = 0.0f;
  780. // capture pass
  781. if ( clearAccumBuffer ) {
  782. clearAccumBuffer = false;
  783. renderSystem->DrawStretchPic( 0.0f, 0.0f, SCREEN_WIDTH, SCREEN_HEIGHT, 0.0f, t0, 1.0f, t1, initMaterial );
  784. } else {
  785. renderSystem->DrawStretchPic( 0.0f, 0.0f, SCREEN_WIDTH, SCREEN_HEIGHT, 0.0f, t0, 1.0f, t1, captureMaterials[level] );
  786. }
  787. }
  788. /*
  789. ==================
  790. FullscreenFX_Helltime::HighQuality
  791. ==================
  792. */
  793. void FullscreenFX_Helltime::HighQuality() {
  794. float t0 = 1.0f;
  795. float t1 = 0.0f;
  796. renderSystem->SetColor4( 1.0f, 1.0f, 1.0f, 1.0f );
  797. renderSystem->DrawStretchPic( 0.0f, 0.0f, SCREEN_WIDTH, SCREEN_HEIGHT, 0.0f, t0, 1.0f, t1, drawMaterial );
  798. }
  799. /*
  800. ==================
  801. FullscreenFX_Helltime::Restore
  802. ==================
  803. */
  804. void FullscreenFX_Helltime::Restore( idRestoreGame *savefile ) {
  805. FullscreenFX::Restore( savefile );
  806. // latch the clear flag
  807. clearAccumBuffer = true;
  808. }
  809. /*
  810. ==================
  811. FullscreenFX_Multiplayer::Initialize
  812. ==================
  813. */
  814. void FullscreenFX_Multiplayer::Initialize() {
  815. initMaterial = declManager->FindMaterial( "textures/d3bfg/multiplayer/init" );
  816. captureMaterial = declManager->FindMaterial( "textures/d3bfg/multiplayer/capture" );
  817. drawMaterial = declManager->FindMaterial( "textures/d3bfg/bloodorb/draw" );
  818. clearAccumBuffer = true;
  819. }
  820. /*
  821. ==================
  822. FullscreenFX_Multiplayer::DetermineLevel
  823. ==================
  824. */
  825. int FullscreenFX_Multiplayer::DetermineLevel() {
  826. int testfx = g_testMultiplayerFX.GetInteger();
  827. // for testing purposes
  828. if ( testfx >= 0 && testfx < 3 ) {
  829. return testfx;
  830. }
  831. idPlayer * player = fxman->GetPlayer();
  832. if ( player != NULL && player->PowerUpActive( INVULNERABILITY ) ) {
  833. return 2;
  834. }
  835. //else if ( player->PowerUpActive( HASTE ) ) {
  836. // return 1;
  837. //}
  838. else if ( player != NULL && player->PowerUpActive( BERSERK ) ) {
  839. return 0;
  840. }
  841. return -1;
  842. }
  843. /*
  844. ==================
  845. FullscreenFX_Multiplayer::Active
  846. ==================
  847. */
  848. bool FullscreenFX_Multiplayer::Active() {
  849. if ( !common->IsMultiplayer() && g_testMultiplayerFX.GetInteger() == -1 ) {
  850. return false;
  851. }
  852. if ( DetermineLevel() >= 0 ) {
  853. return true;
  854. } else {
  855. // latch the clear flag
  856. if ( fader.GetAlpha() == 0 ) {
  857. clearAccumBuffer = true;
  858. }
  859. }
  860. return false;
  861. }
  862. /*
  863. ==================
  864. FullscreenFX_Multiplayer::AccumPass
  865. ==================
  866. */
  867. void FullscreenFX_Multiplayer::AccumPass( const renderView_t *view ) {
  868. renderSystem->SetColor4( 1.0f, 1.0f, 1.0f, 1.0f );
  869. float t0 = 1.0f;
  870. float t1 = 0.0f;
  871. // capture pass
  872. if ( clearAccumBuffer ) {
  873. clearAccumBuffer = false;
  874. renderSystem->DrawStretchPic( 0.0f, 0.0f, SCREEN_WIDTH, SCREEN_HEIGHT, 0.0f, t0, 1.0f, t1, initMaterial );
  875. } else {
  876. renderSystem->DrawStretchPic( 0.0f, 0.0f, SCREEN_WIDTH, SCREEN_HEIGHT, 0.0f, t0, 1.0f, t1, captureMaterial );
  877. }
  878. }
  879. /*
  880. ==================
  881. FullscreenFX_Multiplayer::HighQuality
  882. ==================
  883. */
  884. void FullscreenFX_Multiplayer::HighQuality() {
  885. float t0 = 1.0f;
  886. float t1 = 0.0f;
  887. renderSystem->SetColor4( 1.0f, 1.0f, 1.0f, 1.0f );
  888. renderSystem->DrawStretchPic( 0.0f, 0.0f, SCREEN_WIDTH, SCREEN_HEIGHT, 0.0f, t0, 1.0f, t1, drawMaterial );
  889. }
  890. /*
  891. ==================
  892. FullscreenFX_Multiplayer::Restore
  893. ==================
  894. */
  895. void FullscreenFX_Multiplayer::Restore( idRestoreGame *savefile ) {
  896. FullscreenFX::Restore( savefile );
  897. // latch the clear flag
  898. clearAccumBuffer = true;
  899. }
  900. /*
  901. ==================
  902. FullscreenFX_Warp::Initialize
  903. ==================
  904. */
  905. void FullscreenFX_Warp::Initialize() {
  906. material = declManager->FindMaterial( "textures/d3bfg/warp" );
  907. grabberEnabled = false;
  908. startWarpTime = 0;
  909. }
  910. /*
  911. ==================
  912. FullscreenFX_Warp::Active
  913. ==================
  914. */
  915. bool FullscreenFX_Warp::Active() {
  916. if ( grabberEnabled ) {
  917. return true;
  918. }
  919. return false;
  920. }
  921. /*
  922. ==================
  923. FullscreenFX_Warp::Save
  924. ==================
  925. */
  926. void FullscreenFX_Warp::Save( idSaveGame *savefile ) {
  927. FullscreenFX::Save( savefile );
  928. savefile->WriteBool( grabberEnabled );
  929. savefile->WriteInt( startWarpTime );
  930. }
  931. /*
  932. ==================
  933. FullscreenFX_Warp::Restore
  934. ==================
  935. */
  936. void FullscreenFX_Warp::Restore( idRestoreGame *savefile ) {
  937. FullscreenFX::Restore( savefile );
  938. savefile->ReadBool( grabberEnabled );
  939. savefile->ReadInt( startWarpTime );
  940. }
  941. /*
  942. ==================
  943. FullscreenFX_Warp::DrawWarp
  944. ==================
  945. */
  946. void FullscreenFX_Warp::DrawWarp( WarpPolygon_t wp, float interp ) {
  947. idVec4 mid1_uv, mid2_uv;
  948. idVec4 mid1, mid2;
  949. idVec2 drawPts[6];
  950. WarpPolygon_t trans;
  951. trans = wp;
  952. // compute mid points
  953. mid1 = trans.outer1 * ( interp ) + trans.center * ( 1 - interp );
  954. mid2 = trans.outer2 * ( interp ) + trans.center * ( 1 - interp );
  955. mid1_uv = trans.outer1 * ( 0.5 ) + trans.center * ( 1 - 0.5 );
  956. mid2_uv = trans.outer2 * ( 0.5 ) + trans.center * ( 1 - 0.5 );
  957. // draw [outer1, mid2, mid1]
  958. drawPts[0].Set( trans.outer1.x, trans.outer1.y );
  959. drawPts[1].Set( mid2.x, mid2.y );
  960. drawPts[2].Set( mid1.x, mid1.y );
  961. drawPts[3].Set( trans.outer1.z, trans.outer1.w );
  962. drawPts[4].Set( mid2_uv.z, mid2_uv.w );
  963. drawPts[5].Set( mid1_uv.z, mid1_uv.w );
  964. renderSystem->DrawStretchTri( drawPts[0], drawPts[1], drawPts[2], drawPts[3], drawPts[4], drawPts[5], material );
  965. // draw [outer1, outer2, mid2]
  966. drawPts[0].Set( trans.outer1.x, trans.outer1.y );
  967. drawPts[1].Set( trans.outer2.x, trans.outer2.y );
  968. drawPts[2].Set( mid2.x, mid2.y );
  969. drawPts[3].Set( trans.outer1.z, trans.outer1.w );
  970. drawPts[4].Set( trans.outer2.z, trans.outer2.w );
  971. drawPts[5].Set( mid2_uv.z, mid2_uv.w );
  972. renderSystem->DrawStretchTri( drawPts[0], drawPts[1], drawPts[2], drawPts[3], drawPts[4], drawPts[5], material );
  973. // draw [mid1, mid2, center]
  974. drawPts[0].Set( mid1.x, mid1.y );
  975. drawPts[1].Set( mid2.x, mid2.y );
  976. drawPts[2].Set( trans.center.x, trans.center.y );
  977. drawPts[3].Set( mid1_uv.z, mid1_uv.w );
  978. drawPts[4].Set( mid2_uv.z, mid2_uv.w );
  979. drawPts[5].Set( trans.center.z, trans.center.w );
  980. renderSystem->DrawStretchTri( drawPts[0], drawPts[1], drawPts[2], drawPts[3], drawPts[4], drawPts[5], material );
  981. }
  982. /*
  983. ==================
  984. FullscreenFX_Warp::HighQuality
  985. ==================
  986. */
  987. void FullscreenFX_Warp::HighQuality() {
  988. float x1, y1, x2, y2, radius, interp;
  989. idVec2 center;
  990. int STEP = 9;
  991. renderSystem->SetColor4( 1.0f, 1.0f, 1.0f, 1.0f );
  992. interp = ( idMath::Sin( (float)( gameLocal.slow.time - startWarpTime ) / 1000 ) + 1 ) / 2.f;
  993. interp = 0.7 * ( 1 - interp ) + 0.3 * ( interp );
  994. // draw the warps
  995. center.x = 320;
  996. center.y = 240;
  997. radius = 200;
  998. for ( float i = 0; i < 360; i += STEP ) {
  999. // compute the values
  1000. x1 = idMath::Sin( DEG2RAD( i ) );
  1001. y1 = idMath::Cos( DEG2RAD( i ) );
  1002. x2 = idMath::Sin( DEG2RAD( i + STEP ) );
  1003. y2 = idMath::Cos( DEG2RAD( i + STEP ) );
  1004. // add warp polygon
  1005. WarpPolygon_t p;
  1006. p.outer1.x = center.x + x1 * radius;
  1007. p.outer1.y = center.y + y1 * radius;
  1008. p.outer1.z = p.outer1.x / (float)SCREEN_WIDTH;
  1009. p.outer1.w = 1 - ( p.outer1.y / (float)SCREEN_HEIGHT );
  1010. p.outer2.x = center.x + x2 * radius;
  1011. p.outer2.y = center.y + y2 * radius;
  1012. p.outer2.z = p.outer2.x / (float)SCREEN_WIDTH;
  1013. p.outer2.w = 1 - ( p.outer2.y / (float)SCREEN_HEIGHT );
  1014. p.center.x = center.x;
  1015. p.center.y = center.y;
  1016. p.center.z = p.center.x / (float)SCREEN_WIDTH;
  1017. p.center.w = 1 - ( p.center.y / (float)SCREEN_HEIGHT );
  1018. // draw it
  1019. DrawWarp( p, interp );
  1020. }
  1021. }
  1022. /*
  1023. ==================
  1024. FullscreenFX_EnviroSuit::Initialize
  1025. ==================
  1026. */
  1027. void FullscreenFX_EnviroSuit::Initialize() {
  1028. material = declManager->FindMaterial( "textures/d3bfg/enviro_suit" );
  1029. }
  1030. /*
  1031. ==================
  1032. FullscreenFX_EnviroSuit::Active
  1033. ==================
  1034. */
  1035. bool FullscreenFX_EnviroSuit::Active() {
  1036. idPlayer * player = fxman->GetPlayer();
  1037. if ( player != NULL && player->PowerUpActive( ENVIROSUIT ) ) {
  1038. return true;
  1039. }
  1040. return false;
  1041. }
  1042. /*
  1043. ==================
  1044. FullscreenFX_EnviroSuit::HighQuality
  1045. ==================
  1046. */
  1047. void FullscreenFX_EnviroSuit::HighQuality() {
  1048. renderSystem->SetColor4( 1.0f, 1.0f, 1.0f, 1.0f );
  1049. float s0 = 0.0f;
  1050. float t0 = 1.0f;
  1051. float s1 = 1.0f;
  1052. float t1 = 0.0f;
  1053. renderSystem->DrawStretchPic( 0.0f, 0.0f, SCREEN_WIDTH, SCREEN_HEIGHT, s0, t0, s1, t1, material );
  1054. }
  1055. /*
  1056. ==================
  1057. FullscreenFX_DoubleVision::Initialize
  1058. ==================
  1059. */
  1060. void FullscreenFX_DoubleVision::Initialize() {
  1061. material = declManager->FindMaterial( "textures/d3bfg/doubleVision" );
  1062. }
  1063. /*
  1064. ==================
  1065. FullscreenFX_DoubleVision::Active
  1066. ==================
  1067. */
  1068. bool FullscreenFX_DoubleVision::Active() {
  1069. if ( gameLocal.fast.time < fxman->GetPlayerView()->dvFinishTime ) {
  1070. return true;
  1071. }
  1072. return false;
  1073. }
  1074. /*
  1075. ==================
  1076. FullscreenFX_DoubleVision::HighQuality
  1077. ==================
  1078. */
  1079. void FullscreenFX_DoubleVision::HighQuality() {
  1080. int offset = fxman->GetPlayerView()->dvFinishTime - gameLocal.fast.time;
  1081. float scale = offset * g_dvAmplitude.GetFloat();
  1082. // for testing purposes
  1083. if ( !Active() ) {
  1084. static int test = 0;
  1085. if ( test > 312 ) {
  1086. test = 0;
  1087. }
  1088. offset = test++;
  1089. scale = offset * g_dvAmplitude.GetFloat();
  1090. }
  1091. idPlayer * player = fxman->GetPlayer();
  1092. if( player == NULL ) {
  1093. return;
  1094. }
  1095. offset *= 2; // crutch up for higher res
  1096. // set the scale and shift
  1097. if ( scale > 0.5f ) {
  1098. scale = 0.5f;
  1099. }
  1100. float shift = scale * sin( sqrtf( (float)offset ) * g_dvFrequency.GetFloat() );
  1101. shift = fabs( shift );
  1102. // carry red tint if in berserk mode
  1103. idVec4 color( 1.0f, 1.0f, 1.0f, 1.0f );
  1104. if ( gameLocal.fast.time < player->inventory.powerupEndTime[ BERSERK ] ) {
  1105. color.y = 0.0f;
  1106. color.z = 0.0f;
  1107. }
  1108. if ( !common->IsMultiplayer() && gameLocal.fast.time < player->inventory.powerupEndTime[ HELLTIME ] || gameLocal.fast.time < player->inventory.powerupEndTime[ INVULNERABILITY ]) {
  1109. color.y = 0.0f;
  1110. color.z = 0.0f;
  1111. }
  1112. // uv coordinates
  1113. float s0 = shift;
  1114. float t0 = 1.0f;
  1115. float s1 = 1.0f;
  1116. float t1 = 0.0f;
  1117. renderSystem->SetColor4( color.x, color.y, color.z, 1.0f );
  1118. renderSystem->DrawStretchPic( 0.0f, 0.0f, SCREEN_WIDTH, SCREEN_HEIGHT, s0, t0, s1, t1, material );
  1119. renderSystem->SetColor4( color.x, color.y, color.z, 0.5f );
  1120. s0 = 0.0f;
  1121. t0 = 1.0f;
  1122. s1 = ( 1.0-shift );
  1123. t1 = 0.0f;
  1124. renderSystem->DrawStretchPic( 0.0f, 0.0f, SCREEN_WIDTH, SCREEN_HEIGHT, s0, t0, s1, t1, material );
  1125. }
  1126. /*
  1127. ==================
  1128. FullscreenFX_InfluenceVision::Initialize
  1129. ==================
  1130. */
  1131. void FullscreenFX_InfluenceVision::Initialize() {
  1132. }
  1133. /*
  1134. ==================
  1135. FullscreenFX_InfluenceVision::Active
  1136. ==================
  1137. */
  1138. bool FullscreenFX_InfluenceVision::Active() {
  1139. idPlayer * player = fxman->GetPlayer();
  1140. if ( player != NULL && ( player->GetInfluenceMaterial() || player->GetInfluenceEntity() ) ) {
  1141. return true;
  1142. }
  1143. return false;
  1144. }
  1145. /*
  1146. ==================
  1147. FullscreenFX_InfluenceVision::HighQuality
  1148. ==================
  1149. */
  1150. void FullscreenFX_InfluenceVision::HighQuality() {
  1151. float distance = 0.0f;
  1152. float pct = 1.0f;
  1153. idPlayer * player = fxman->GetPlayer();
  1154. if( player == NULL ) {
  1155. return;
  1156. }
  1157. if ( player->GetInfluenceEntity() ) {
  1158. distance = ( player->GetInfluenceEntity()->GetPhysics()->GetOrigin() - player->GetPhysics()->GetOrigin() ).Length();
  1159. if ( player->GetInfluenceRadius() != 0.0f && distance < player->GetInfluenceRadius() ) {
  1160. pct = distance / player->GetInfluenceRadius();
  1161. pct = 1.0f - idMath::ClampFloat( 0.0f, 1.0f, pct );
  1162. }
  1163. }
  1164. if ( player->GetInfluenceMaterial() ) {
  1165. renderSystem->SetColor4( 1.0f, 1.0f, 1.0f, pct );
  1166. renderSystem->DrawStretchPic( 0.0f, 0.0f, SCREEN_WIDTH, SCREEN_HEIGHT, 0.0f, 0.0f, 1.0f, 1.0f, player->GetInfluenceMaterial() );
  1167. } else if ( player->GetInfluenceEntity() == NULL ) {
  1168. return;
  1169. } else {
  1170. // int offset = 25 + sinf( gameLocal.slow.time );
  1171. // DoubleVision( hud, view, pct * offset );
  1172. }
  1173. }
  1174. /*
  1175. ==================
  1176. FullscreenFX_Bloom::Initialize
  1177. ==================
  1178. */
  1179. void FullscreenFX_Bloom::Initialize() {
  1180. drawMaterial = declManager->FindMaterial( "textures/d3bfg/bloom2/draw" );
  1181. initMaterial = declManager->FindMaterial( "textures/d3bfg/bloom2/init" );
  1182. currentIntensity = 0;
  1183. targetIntensity = 0;
  1184. }
  1185. /*
  1186. ==================
  1187. FullscreenFX_Bloom::Active
  1188. ==================
  1189. */
  1190. bool FullscreenFX_Bloom::Active() {
  1191. idPlayer * player = fxman->GetPlayer();
  1192. if ( player != NULL && player->bloomEnabled ) {
  1193. return true;
  1194. }
  1195. return false;
  1196. }
  1197. /*
  1198. ==================
  1199. FullscreenFX_Bloom::HighQuality
  1200. ==================
  1201. */
  1202. void FullscreenFX_Bloom::HighQuality() {
  1203. float shift = 1;
  1204. idPlayer * player = fxman->GetPlayer();
  1205. renderSystem->SetColor4( 1.0f, 1.0f, 1.0f, 1.0f );
  1206. // if intensity value is different, start the blend
  1207. targetIntensity = g_testBloomIntensity.GetFloat();
  1208. if ( player != NULL && player->bloomEnabled ) {
  1209. targetIntensity = player->bloomIntensity;
  1210. }
  1211. float delta = targetIntensity - currentIntensity;
  1212. float step = 0.001f;
  1213. if ( step < fabs( delta ) ) {
  1214. if ( delta < 0 ) {
  1215. step = -step;
  1216. }
  1217. currentIntensity += step;
  1218. }
  1219. // draw the blends
  1220. int num = g_testBloomNumPasses.GetInteger();
  1221. for ( int i = 0; i < num; i++ ) {
  1222. float s1 = 0.0f, t1 = 0.0f, s2 = 1.0f, t2 = 1.0f;
  1223. float alpha;
  1224. // do the center scale
  1225. s1 -= 0.5;
  1226. s1 *= shift;
  1227. s1 += 0.5;
  1228. t1 -= 0.5;
  1229. t1 *= shift;
  1230. t1 += 0.5;
  1231. s2 -= 0.5;
  1232. s2 *= shift;
  1233. s2 += 0.5;
  1234. t2 -= 0.5;
  1235. t2 *= shift;
  1236. t2 += 0.5;
  1237. // draw it
  1238. if ( num == 1 ) {
  1239. alpha = 1;
  1240. } else {
  1241. alpha = 1 - (float)i / ( num - 1 );
  1242. }
  1243. float yScale = 1.0f;
  1244. renderSystem->SetColor4( alpha, alpha, alpha, 1 );
  1245. renderSystem->DrawStretchPic( 0.0f, 0.0f, SCREEN_WIDTH, SCREEN_HEIGHT, s1, t2 * yScale, s2, t1 * yScale, drawMaterial );
  1246. shift += currentIntensity;
  1247. }
  1248. }
  1249. /*
  1250. ==================
  1251. FullscreenFX_Bloom::Save
  1252. ==================
  1253. */
  1254. void FullscreenFX_Bloom::Save( idSaveGame *savefile ) {
  1255. FullscreenFX::Save( savefile );
  1256. savefile->WriteFloat( currentIntensity );
  1257. savefile->WriteFloat( targetIntensity );
  1258. }
  1259. /*
  1260. ==================
  1261. FullscreenFX_Bloom::Restore
  1262. ==================
  1263. */
  1264. void FullscreenFX_Bloom::Restore( idRestoreGame *savefile ) {
  1265. FullscreenFX::Restore( savefile );
  1266. savefile->ReadFloat( currentIntensity );
  1267. savefile->ReadFloat( targetIntensity );
  1268. }
  1269. /*
  1270. ==================
  1271. FullscreenFXManager::FullscreenFXManager
  1272. ==================
  1273. */
  1274. FullscreenFXManager::FullscreenFXManager() {
  1275. playerView = NULL;
  1276. blendBackMaterial = NULL;
  1277. }
  1278. /*
  1279. ==================
  1280. FullscreenFXManager::~FullscreenFXManager
  1281. ==================
  1282. */
  1283. FullscreenFXManager::~FullscreenFXManager() {
  1284. fx.DeleteContents();
  1285. }
  1286. /*
  1287. ==================
  1288. FullscreenFXManager::FindFX
  1289. ==================
  1290. */
  1291. FullscreenFX* FullscreenFXManager::FindFX( idStr name ) {
  1292. for ( int i = 0; i < fx.Num(); i++ ) {
  1293. if ( fx[i]->GetName() == name ) {
  1294. return fx[i];
  1295. }
  1296. }
  1297. return NULL;
  1298. }
  1299. /*
  1300. ==================
  1301. FullscreenFXManager::CreateFX
  1302. ==================
  1303. */
  1304. void FullscreenFXManager::CreateFX( idStr name, idStr fxtype, int fade ) {
  1305. FullscreenFX *pfx = NULL;
  1306. if ( fxtype == "helltime" ) {
  1307. pfx = new (TAG_FX) FullscreenFX_Helltime;
  1308. } else if ( fxtype == "warp" ) {
  1309. pfx = new (TAG_FX) FullscreenFX_Warp;
  1310. } else if ( fxtype == "envirosuit" ) {
  1311. pfx = new (TAG_FX) FullscreenFX_EnviroSuit;
  1312. } else if ( fxtype == "doublevision" ) {
  1313. pfx = new (TAG_FX) FullscreenFX_DoubleVision;
  1314. } else if ( fxtype == "multiplayer" ) {
  1315. pfx = new (TAG_FX) FullscreenFX_Multiplayer;
  1316. } else if ( fxtype == "influencevision" ) {
  1317. pfx = new (TAG_FX) FullscreenFX_InfluenceVision;
  1318. } else if ( fxtype == "bloom" ) {
  1319. pfx = new (TAG_FX) FullscreenFX_Bloom;
  1320. } else {
  1321. assert( 0 );
  1322. }
  1323. if ( pfx ) {
  1324. pfx->Initialize();
  1325. pfx->SetFXManager( this );
  1326. pfx->SetName( name );
  1327. pfx->SetFadeSpeed( fade );
  1328. fx.Append( pfx );
  1329. }
  1330. }
  1331. /*
  1332. ==================
  1333. FullscreenFXManager::Initialize
  1334. ==================
  1335. */
  1336. void FullscreenFXManager::Initialize( idPlayerView *pv ) {
  1337. // set the playerview
  1338. playerView = pv;
  1339. blendBackMaterial = declManager->FindMaterial( "textures/d3bfg/blendBack" );
  1340. // allocate the fx
  1341. CreateFX( "helltime", "helltime", 1000 );
  1342. CreateFX( "warp", "warp", 0 );
  1343. CreateFX( "envirosuit", "envirosuit", 500 );
  1344. CreateFX( "doublevision", "doublevision", 0 );
  1345. CreateFX( "multiplayer", "multiplayer", 1000 );
  1346. CreateFX( "influencevision", "influencevision", 1000 );
  1347. CreateFX( "bloom", "bloom", 0 );
  1348. // pre-cache the texture grab so we dont hitch
  1349. renderSystem->CropRenderSize( 512, 512 );
  1350. renderSystem->CaptureRenderToImage( "_accum" );
  1351. renderSystem->UnCrop();
  1352. renderSystem->CaptureRenderToImage( "_currentRender" );
  1353. }
  1354. /*
  1355. ==================
  1356. FullscreenFXManager::Blendback
  1357. ==================
  1358. */
  1359. void FullscreenFXManager::Blendback( float alpha ) {
  1360. // alpha fade
  1361. if ( alpha < 1.f ) {
  1362. renderSystem->SetColor4( 1.0f, 1.0f, 1.0f, 1.0f - alpha );
  1363. float s0 = 0.0f;
  1364. float t0 = 1.0f;
  1365. float s1 = 1.0f;
  1366. float t1 = 0.0f;
  1367. renderSystem->DrawStretchPic( 0.0f, 0.0f, SCREEN_WIDTH, SCREEN_HEIGHT, s0, t0, s1, t1, blendBackMaterial );
  1368. }
  1369. }
  1370. /*
  1371. ==================
  1372. FullscreenFXManager::Save
  1373. ==================
  1374. */
  1375. void FullscreenFXManager::Save( idSaveGame *savefile ) {
  1376. for ( int i = 0; i < fx.Num(); i++ ) {
  1377. FullscreenFX *pfx = fx[i];
  1378. pfx->Save( savefile );
  1379. }
  1380. }
  1381. /*
  1382. ==================
  1383. FullscreenFXManager::Restore
  1384. ==================
  1385. */
  1386. void FullscreenFXManager::Restore( idRestoreGame *savefile ) {
  1387. for ( int i = 0; i < fx.Num(); i++ ) {
  1388. FullscreenFX *pfx = fx[i];
  1389. pfx->Restore( savefile );
  1390. }
  1391. }
  1392. idCVar player_allowScreenFXInStereo( "player_allowScreenFXInStereo", "1", CVAR_BOOL, "allow full screen fx in stereo mode" );
  1393. /*
  1394. ==================
  1395. FullscreenFXManager::Process
  1396. ==================
  1397. */
  1398. void FullscreenFXManager::Process( const renderView_t *view ) {
  1399. bool allpass = false;
  1400. bool atLeastOneFX = false;
  1401. if ( g_testFullscreenFX.GetInteger() == -2 ) {
  1402. allpass = true;
  1403. }
  1404. // do the first render
  1405. gameRenderWorld->RenderScene( view );
  1406. // we should consider these on a case-by-case basis for stereo rendering
  1407. // double vision could be implemented "for real" by shifting the
  1408. // eye views
  1409. if ( IsGameStereoRendered() && !player_allowScreenFXInStereo.GetBool() ) {
  1410. return;
  1411. }
  1412. // do the process
  1413. for ( int i = 0; i < fx.Num(); i++ ) {
  1414. FullscreenFX *pfx = fx[i];
  1415. bool drawIt = false;
  1416. // determine if we need to draw
  1417. if ( pfx->Active() || g_testFullscreenFX.GetInteger() == i || allpass ) {
  1418. drawIt = pfx->SetTriggerState( true );
  1419. } else {
  1420. drawIt = pfx->SetTriggerState( false );
  1421. }
  1422. // do the actual drawing
  1423. if ( drawIt ) {
  1424. atLeastOneFX = true;
  1425. // we need to dump to _currentRender
  1426. renderSystem->CaptureRenderToImage( "_currentRender" );
  1427. // handle the accum pass if we have one
  1428. if ( pfx->HasAccum() ) {
  1429. // we need to crop the accum pass
  1430. renderSystem->CropRenderSize( 512, 512 );
  1431. pfx->AccumPass( view );
  1432. renderSystem->CaptureRenderToImage( "_accum" );
  1433. renderSystem->UnCrop();
  1434. }
  1435. // do the high quality pass
  1436. pfx->HighQuality();
  1437. // do the blendback
  1438. Blendback( pfx->GetFadeAlpha() );
  1439. }
  1440. }
  1441. }