view.c 22 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073
  1. /*
  2. Copyright (C) 1996-1997 Id Software, Inc.
  3. This program is free software; you can redistribute it and/or
  4. modify it under the terms of the GNU General Public License
  5. as published by the Free Software Foundation; either version 2
  6. of the License, or (at your option) any later version.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  10. See the GNU General Public License for more details.
  11. You should have received a copy of the GNU General Public License
  12. along with this program; if not, write to the Free Software
  13. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  14. */
  15. // view.c -- player eye positioning
  16. #include "quakedef.h"
  17. #include "r_local.h"
  18. /*
  19. The view is allowed to move slightly from it's true position for bobbing,
  20. but if it exceeds 8 pixels linear distance (spherical, not box), the list of
  21. entities sent from the server may not include everything in the pvs, especially
  22. when crossing a water boudnary.
  23. */
  24. cvar_t lcd_x = {"lcd_x", "0"}; // FIXME: make this work sometime...
  25. cvar_t cl_rollspeed = {"cl_rollspeed", "200"};
  26. cvar_t cl_rollangle = {"cl_rollangle", "2.0"};
  27. cvar_t cl_bob = {"cl_bob","0.02", false};
  28. cvar_t cl_bobcycle = {"cl_bobcycle","0.6", false};
  29. cvar_t cl_bobup = {"cl_bobup","0.5", false};
  30. cvar_t v_kicktime = {"v_kicktime", "0.5", false};
  31. cvar_t v_kickroll = {"v_kickroll", "0.6", false};
  32. cvar_t v_kickpitch = {"v_kickpitch", "0.6", false};
  33. cvar_t v_iyaw_cycle = {"v_iyaw_cycle", "2", false};
  34. cvar_t v_iroll_cycle = {"v_iroll_cycle", "0.5", false};
  35. cvar_t v_ipitch_cycle = {"v_ipitch_cycle", "1", false};
  36. cvar_t v_iyaw_level = {"v_iyaw_level", "0.3", false};
  37. cvar_t v_iroll_level = {"v_iroll_level", "0.1", false};
  38. cvar_t v_ipitch_level = {"v_ipitch_level", "0.3", false};
  39. cvar_t v_idlescale = {"v_idlescale", "0", false};
  40. cvar_t crosshair = {"crosshair", "0", true};
  41. cvar_t crosshaircolor = {"crosshaircolor", "79", true};
  42. cvar_t cl_crossx = {"cl_crossx", "0", true};
  43. cvar_t cl_crossy = {"cl_crossy", "0", true};
  44. #ifdef GLQUAKE
  45. cvar_t gl_cshiftpercent = {"gl_cshiftpercent", "100", false};
  46. #endif
  47. cvar_t v_contentblend = {"v_contentblend", "1", false};
  48. float v_dmg_time, v_dmg_roll, v_dmg_pitch;
  49. extern int in_forward, in_forward2, in_back;
  50. frame_t *view_frame;
  51. player_state_t *view_message;
  52. /*
  53. ===============
  54. V_CalcRoll
  55. ===============
  56. */
  57. float V_CalcRoll (vec3_t angles, vec3_t velocity)
  58. {
  59. vec3_t forward, right, up;
  60. float sign;
  61. float side;
  62. float value;
  63. AngleVectors (angles, forward, right, up);
  64. side = DotProduct (velocity, right);
  65. sign = side < 0 ? -1 : 1;
  66. side = fabs(side);
  67. value = cl_rollangle.value;
  68. if (side < cl_rollspeed.value)
  69. side = side * value / cl_rollspeed.value;
  70. else
  71. side = value;
  72. return side*sign;
  73. }
  74. /*
  75. ===============
  76. V_CalcBob
  77. ===============
  78. */
  79. float V_CalcBob (void)
  80. {
  81. static double bobtime;
  82. static float bob;
  83. float cycle;
  84. if (cl.spectator)
  85. return 0;
  86. if (onground == -1)
  87. return bob; // just use old value
  88. bobtime += host_frametime;
  89. cycle = bobtime - (int)(bobtime/cl_bobcycle.value)*cl_bobcycle.value;
  90. cycle /= cl_bobcycle.value;
  91. if (cycle < cl_bobup.value)
  92. cycle = M_PI * cycle / cl_bobup.value;
  93. else
  94. cycle = M_PI + M_PI*(cycle-cl_bobup.value)/(1.0 - cl_bobup.value);
  95. // bob is proportional to simulated velocity in the xy plane
  96. // (don't count Z, or jumping messes it up)
  97. bob = sqrt(cl.simvel[0]*cl.simvel[0] + cl.simvel[1]*cl.simvel[1]) * cl_bob.value;
  98. bob = bob*0.3 + bob*0.7*sin(cycle);
  99. if (bob > 4)
  100. bob = 4;
  101. else if (bob < -7)
  102. bob = -7;
  103. return bob;
  104. }
  105. //=============================================================================
  106. cvar_t v_centermove = {"v_centermove", "0.15", false};
  107. cvar_t v_centerspeed = {"v_centerspeed","500"};
  108. void V_StartPitchDrift (void)
  109. {
  110. #if 1
  111. if (cl.laststop == cl.time)
  112. {
  113. return; // something else is keeping it from drifting
  114. }
  115. #endif
  116. if (cl.nodrift || !cl.pitchvel)
  117. {
  118. cl.pitchvel = v_centerspeed.value;
  119. cl.nodrift = false;
  120. cl.driftmove = 0;
  121. }
  122. }
  123. void V_StopPitchDrift (void)
  124. {
  125. cl.laststop = cl.time;
  126. cl.nodrift = true;
  127. cl.pitchvel = 0;
  128. }
  129. /*
  130. ===============
  131. V_DriftPitch
  132. Moves the client pitch angle towards cl.idealpitch sent by the server.
  133. If the user is adjusting pitch manually, either with lookup/lookdown,
  134. mlook and mouse, or klook and keyboard, pitch drifting is constantly stopped.
  135. Drifting is enabled when the center view key is hit, mlook is released and
  136. lookspring is non 0, or when
  137. ===============
  138. */
  139. void V_DriftPitch (void)
  140. {
  141. float delta, move;
  142. if (view_message->onground == -1 || cls.demoplayback )
  143. {
  144. cl.driftmove = 0;
  145. cl.pitchvel = 0;
  146. return;
  147. }
  148. // don't count small mouse motion
  149. if (cl.nodrift)
  150. {
  151. if ( fabs(cl.frames[(cls.netchan.outgoing_sequence-1)&UPDATE_MASK].cmd.forwardmove) < 200)
  152. cl.driftmove = 0;
  153. else
  154. cl.driftmove += host_frametime;
  155. if ( cl.driftmove > v_centermove.value)
  156. {
  157. V_StartPitchDrift ();
  158. }
  159. return;
  160. }
  161. delta = 0 - cl.viewangles[PITCH];
  162. if (!delta)
  163. {
  164. cl.pitchvel = 0;
  165. return;
  166. }
  167. move = host_frametime * cl.pitchvel;
  168. cl.pitchvel += host_frametime * v_centerspeed.value;
  169. //Con_Printf ("move: %f (%f)\n", move, host_frametime);
  170. if (delta > 0)
  171. {
  172. if (move > delta)
  173. {
  174. cl.pitchvel = 0;
  175. move = delta;
  176. }
  177. cl.viewangles[PITCH] += move;
  178. }
  179. else if (delta < 0)
  180. {
  181. if (move > -delta)
  182. {
  183. cl.pitchvel = 0;
  184. move = -delta;
  185. }
  186. cl.viewangles[PITCH] -= move;
  187. }
  188. }
  189. /*
  190. ==============================================================================
  191. PALETTE FLASHES
  192. ==============================================================================
  193. */
  194. cshift_t cshift_empty = { {130,80,50}, 0 };
  195. cshift_t cshift_water = { {130,80,50}, 128 };
  196. cshift_t cshift_slime = { {0,25,5}, 150 };
  197. cshift_t cshift_lava = { {255,80,0}, 150 };
  198. cvar_t v_gamma = {"gamma", "1", true};
  199. byte gammatable[256]; // palette is sent through this
  200. #ifdef GLQUAKE
  201. byte ramps[3][256];
  202. float v_blend[4]; // rgba 0.0 - 1.0
  203. #endif // GLQUAKE
  204. void BuildGammaTable (float g)
  205. {
  206. int i, inf;
  207. if (g == 1.0)
  208. {
  209. for (i=0 ; i<256 ; i++)
  210. gammatable[i] = i;
  211. return;
  212. }
  213. for (i=0 ; i<256 ; i++)
  214. {
  215. inf = 255 * pow ( (i+0.5)/255.5 , g ) + 0.5;
  216. if (inf < 0)
  217. inf = 0;
  218. if (inf > 255)
  219. inf = 255;
  220. gammatable[i] = inf;
  221. }
  222. }
  223. /*
  224. =================
  225. V_CheckGamma
  226. =================
  227. */
  228. qboolean V_CheckGamma (void)
  229. {
  230. static float oldgammavalue;
  231. if (v_gamma.value == oldgammavalue)
  232. return false;
  233. oldgammavalue = v_gamma.value;
  234. BuildGammaTable (v_gamma.value);
  235. vid.recalc_refdef = 1; // force a surface cache flush
  236. return true;
  237. }
  238. /*
  239. ===============
  240. V_ParseDamage
  241. ===============
  242. */
  243. void V_ParseDamage (void)
  244. {
  245. int armor, blood;
  246. vec3_t from;
  247. int i;
  248. vec3_t forward, right, up;
  249. float side;
  250. float count;
  251. armor = MSG_ReadByte ();
  252. blood = MSG_ReadByte ();
  253. for (i=0 ; i<3 ; i++)
  254. from[i] = MSG_ReadCoord ();
  255. count = blood*0.5 + armor*0.5;
  256. if (count < 10)
  257. count = 10;
  258. cl.faceanimtime = cl.time + 0.2; // but sbar face into pain frame
  259. cl.cshifts[CSHIFT_DAMAGE].percent += 3*count;
  260. if (cl.cshifts[CSHIFT_DAMAGE].percent < 0)
  261. cl.cshifts[CSHIFT_DAMAGE].percent = 0;
  262. if (cl.cshifts[CSHIFT_DAMAGE].percent > 150)
  263. cl.cshifts[CSHIFT_DAMAGE].percent = 150;
  264. if (armor > blood)
  265. {
  266. cl.cshifts[CSHIFT_DAMAGE].destcolor[0] = 200;
  267. cl.cshifts[CSHIFT_DAMAGE].destcolor[1] = 100;
  268. cl.cshifts[CSHIFT_DAMAGE].destcolor[2] = 100;
  269. }
  270. else if (armor)
  271. {
  272. cl.cshifts[CSHIFT_DAMAGE].destcolor[0] = 220;
  273. cl.cshifts[CSHIFT_DAMAGE].destcolor[1] = 50;
  274. cl.cshifts[CSHIFT_DAMAGE].destcolor[2] = 50;
  275. }
  276. else
  277. {
  278. cl.cshifts[CSHIFT_DAMAGE].destcolor[0] = 255;
  279. cl.cshifts[CSHIFT_DAMAGE].destcolor[1] = 0;
  280. cl.cshifts[CSHIFT_DAMAGE].destcolor[2] = 0;
  281. }
  282. //
  283. // calculate view angle kicks
  284. //
  285. VectorSubtract (from, cl.simorg, from);
  286. VectorNormalize (from);
  287. AngleVectors (cl.simangles, forward, right, up);
  288. side = DotProduct (from, right);
  289. v_dmg_roll = count*side*v_kickroll.value;
  290. side = DotProduct (from, forward);
  291. v_dmg_pitch = count*side*v_kickpitch.value;
  292. v_dmg_time = v_kicktime.value;
  293. }
  294. /*
  295. ==================
  296. V_cshift_f
  297. ==================
  298. */
  299. void V_cshift_f (void)
  300. {
  301. cshift_empty.destcolor[0] = atoi(Cmd_Argv(1));
  302. cshift_empty.destcolor[1] = atoi(Cmd_Argv(2));
  303. cshift_empty.destcolor[2] = atoi(Cmd_Argv(3));
  304. cshift_empty.percent = atoi(Cmd_Argv(4));
  305. }
  306. /*
  307. ==================
  308. V_BonusFlash_f
  309. When you run over an item, the server sends this command
  310. ==================
  311. */
  312. void V_BonusFlash_f (void)
  313. {
  314. cl.cshifts[CSHIFT_BONUS].destcolor[0] = 215;
  315. cl.cshifts[CSHIFT_BONUS].destcolor[1] = 186;
  316. cl.cshifts[CSHIFT_BONUS].destcolor[2] = 69;
  317. cl.cshifts[CSHIFT_BONUS].percent = 50;
  318. }
  319. /*
  320. =============
  321. V_SetContentsColor
  322. Underwater, lava, etc each has a color shift
  323. =============
  324. */
  325. void V_SetContentsColor (int contents)
  326. {
  327. if (!v_contentblend.value) {
  328. cl.cshifts[CSHIFT_CONTENTS] = cshift_empty;
  329. return;
  330. }
  331. switch (contents)
  332. {
  333. case CONTENTS_EMPTY:
  334. cl.cshifts[CSHIFT_CONTENTS] = cshift_empty;
  335. break;
  336. case CONTENTS_LAVA:
  337. cl.cshifts[CSHIFT_CONTENTS] = cshift_lava;
  338. break;
  339. case CONTENTS_SOLID:
  340. case CONTENTS_SLIME:
  341. cl.cshifts[CSHIFT_CONTENTS] = cshift_slime;
  342. break;
  343. default:
  344. cl.cshifts[CSHIFT_CONTENTS] = cshift_water;
  345. }
  346. }
  347. /*
  348. =============
  349. V_CalcPowerupCshift
  350. =============
  351. */
  352. void V_CalcPowerupCshift (void)
  353. {
  354. if (cl.stats[STAT_ITEMS] & IT_QUAD)
  355. {
  356. cl.cshifts[CSHIFT_POWERUP].destcolor[0] = 0;
  357. cl.cshifts[CSHIFT_POWERUP].destcolor[1] = 0;
  358. cl.cshifts[CSHIFT_POWERUP].destcolor[2] = 255;
  359. cl.cshifts[CSHIFT_POWERUP].percent = 30;
  360. }
  361. else if (cl.stats[STAT_ITEMS] & IT_SUIT)
  362. {
  363. cl.cshifts[CSHIFT_POWERUP].destcolor[0] = 0;
  364. cl.cshifts[CSHIFT_POWERUP].destcolor[1] = 255;
  365. cl.cshifts[CSHIFT_POWERUP].destcolor[2] = 0;
  366. cl.cshifts[CSHIFT_POWERUP].percent = 20;
  367. }
  368. else if (cl.stats[STAT_ITEMS] & IT_INVISIBILITY)
  369. {
  370. cl.cshifts[CSHIFT_POWERUP].destcolor[0] = 100;
  371. cl.cshifts[CSHIFT_POWERUP].destcolor[1] = 100;
  372. cl.cshifts[CSHIFT_POWERUP].destcolor[2] = 100;
  373. cl.cshifts[CSHIFT_POWERUP].percent = 100;
  374. }
  375. else if (cl.stats[STAT_ITEMS] & IT_INVULNERABILITY)
  376. {
  377. cl.cshifts[CSHIFT_POWERUP].destcolor[0] = 255;
  378. cl.cshifts[CSHIFT_POWERUP].destcolor[1] = 255;
  379. cl.cshifts[CSHIFT_POWERUP].destcolor[2] = 0;
  380. cl.cshifts[CSHIFT_POWERUP].percent = 30;
  381. }
  382. else
  383. cl.cshifts[CSHIFT_POWERUP].percent = 0;
  384. }
  385. /*
  386. =============
  387. V_CalcBlend
  388. =============
  389. */
  390. #ifdef GLQUAKE
  391. void V_CalcBlend (void)
  392. {
  393. float r, g, b, a, a2;
  394. int j;
  395. r = 0;
  396. g = 0;
  397. b = 0;
  398. a = 0;
  399. for (j=0 ; j<NUM_CSHIFTS ; j++)
  400. {
  401. if (!gl_cshiftpercent.value)
  402. continue;
  403. a2 = ((cl.cshifts[j].percent * gl_cshiftpercent.value) / 100.0) / 255.0;
  404. // a2 = (cl.cshifts[j].percent/2)/255.0;
  405. if (!a2)
  406. continue;
  407. a = a + a2*(1-a);
  408. //Con_Printf ("j:%i a:%f\n", j, a);
  409. a2 = a2/a;
  410. r = r*(1-a2) + cl.cshifts[j].destcolor[0]*a2;
  411. g = g*(1-a2) + cl.cshifts[j].destcolor[1]*a2;
  412. b = b*(1-a2) + cl.cshifts[j].destcolor[2]*a2;
  413. }
  414. v_blend[0] = r/255.0;
  415. v_blend[1] = g/255.0;
  416. v_blend[2] = b/255.0;
  417. v_blend[3] = a;
  418. if (v_blend[3] > 1)
  419. v_blend[3] = 1;
  420. if (v_blend[3] < 0)
  421. v_blend[3] = 0;
  422. }
  423. #endif
  424. /*
  425. =============
  426. V_UpdatePalette
  427. =============
  428. */
  429. #ifdef GLQUAKE
  430. void V_UpdatePalette (void)
  431. {
  432. int i, j;
  433. qboolean new;
  434. byte *basepal, *newpal;
  435. byte pal[768];
  436. float r,g,b,a;
  437. int ir, ig, ib;
  438. qboolean force;
  439. V_CalcPowerupCshift ();
  440. new = false;
  441. for (i=0 ; i<NUM_CSHIFTS ; i++)
  442. {
  443. if (cl.cshifts[i].percent != cl.prev_cshifts[i].percent)
  444. {
  445. new = true;
  446. cl.prev_cshifts[i].percent = cl.cshifts[i].percent;
  447. }
  448. for (j=0 ; j<3 ; j++)
  449. if (cl.cshifts[i].destcolor[j] != cl.prev_cshifts[i].destcolor[j])
  450. {
  451. new = true;
  452. cl.prev_cshifts[i].destcolor[j] = cl.cshifts[i].destcolor[j];
  453. }
  454. }
  455. // drop the damage value
  456. cl.cshifts[CSHIFT_DAMAGE].percent -= host_frametime*150;
  457. if (cl.cshifts[CSHIFT_DAMAGE].percent <= 0)
  458. cl.cshifts[CSHIFT_DAMAGE].percent = 0;
  459. // drop the bonus value
  460. cl.cshifts[CSHIFT_BONUS].percent -= host_frametime*100;
  461. if (cl.cshifts[CSHIFT_BONUS].percent <= 0)
  462. cl.cshifts[CSHIFT_BONUS].percent = 0;
  463. force = V_CheckGamma ();
  464. if (!new && !force)
  465. return;
  466. V_CalcBlend ();
  467. //Con_Printf("b: %4.2f %4.2f %4.2f %4.6f\n", v_blend[0], v_blend[1], v_blend[2], v_blend[3]);
  468. a = v_blend[3];
  469. r = 255*v_blend[0]*a;
  470. g = 255*v_blend[1]*a;
  471. b = 255*v_blend[2]*a;
  472. a = 1-a;
  473. for (i=0 ; i<256 ; i++)
  474. {
  475. ir = i*a + r;
  476. ig = i*a + g;
  477. ib = i*a + b;
  478. if (ir > 255)
  479. ir = 255;
  480. if (ig > 255)
  481. ig = 255;
  482. if (ib > 255)
  483. ib = 255;
  484. ramps[0][i] = gammatable[ir];
  485. ramps[1][i] = gammatable[ig];
  486. ramps[2][i] = gammatable[ib];
  487. }
  488. basepal = host_basepal;
  489. newpal = pal;
  490. for (i=0 ; i<256 ; i++)
  491. {
  492. ir = basepal[0];
  493. ig = basepal[1];
  494. ib = basepal[2];
  495. basepal += 3;
  496. newpal[0] = ramps[0][ir];
  497. newpal[1] = ramps[1][ig];
  498. newpal[2] = ramps[2][ib];
  499. newpal += 3;
  500. }
  501. VID_ShiftPalette (pal);
  502. }
  503. #else // !GLQUAKE
  504. /*
  505. =============
  506. V_UpdatePalette
  507. =============
  508. */
  509. void V_UpdatePalette (void)
  510. {
  511. int i, j;
  512. qboolean new;
  513. byte *basepal, *newpal;
  514. byte pal[768];
  515. int r,g,b;
  516. qboolean force;
  517. V_CalcPowerupCshift ();
  518. new = false;
  519. for (i=0 ; i<NUM_CSHIFTS ; i++)
  520. {
  521. if (cl.cshifts[i].percent != cl.prev_cshifts[i].percent)
  522. {
  523. new = true;
  524. cl.prev_cshifts[i].percent = cl.cshifts[i].percent;
  525. }
  526. for (j=0 ; j<3 ; j++)
  527. if (cl.cshifts[i].destcolor[j] != cl.prev_cshifts[i].destcolor[j])
  528. {
  529. new = true;
  530. cl.prev_cshifts[i].destcolor[j] = cl.cshifts[i].destcolor[j];
  531. }
  532. }
  533. // drop the damage value
  534. cl.cshifts[CSHIFT_DAMAGE].percent -= host_frametime*150;
  535. if (cl.cshifts[CSHIFT_DAMAGE].percent <= 0)
  536. cl.cshifts[CSHIFT_DAMAGE].percent = 0;
  537. // drop the bonus value
  538. cl.cshifts[CSHIFT_BONUS].percent -= host_frametime*100;
  539. if (cl.cshifts[CSHIFT_BONUS].percent <= 0)
  540. cl.cshifts[CSHIFT_BONUS].percent = 0;
  541. force = V_CheckGamma ();
  542. if (!new && !force)
  543. return;
  544. basepal = host_basepal;
  545. newpal = pal;
  546. for (i=0 ; i<256 ; i++)
  547. {
  548. r = basepal[0];
  549. g = basepal[1];
  550. b = basepal[2];
  551. basepal += 3;
  552. for (j=0 ; j<NUM_CSHIFTS ; j++)
  553. {
  554. r += (cl.cshifts[j].percent*(cl.cshifts[j].destcolor[0]-r))>>8;
  555. g += (cl.cshifts[j].percent*(cl.cshifts[j].destcolor[1]-g))>>8;
  556. b += (cl.cshifts[j].percent*(cl.cshifts[j].destcolor[2]-b))>>8;
  557. }
  558. newpal[0] = gammatable[r];
  559. newpal[1] = gammatable[g];
  560. newpal[2] = gammatable[b];
  561. newpal += 3;
  562. }
  563. VID_ShiftPalette (pal);
  564. }
  565. #endif // !GLQUAKE
  566. /*
  567. ==============================================================================
  568. VIEW RENDERING
  569. ==============================================================================
  570. */
  571. float angledelta (float a)
  572. {
  573. a = anglemod(a);
  574. if (a > 180)
  575. a -= 360;
  576. return a;
  577. }
  578. /*
  579. ==================
  580. CalcGunAngle
  581. ==================
  582. */
  583. void CalcGunAngle (void)
  584. {
  585. float yaw, pitch, move;
  586. static float oldyaw = 0;
  587. static float oldpitch = 0;
  588. yaw = r_refdef.viewangles[YAW];
  589. pitch = -r_refdef.viewangles[PITCH];
  590. yaw = angledelta(yaw - r_refdef.viewangles[YAW]) * 0.4;
  591. if (yaw > 10)
  592. yaw = 10;
  593. if (yaw < -10)
  594. yaw = -10;
  595. pitch = angledelta(-pitch - r_refdef.viewangles[PITCH]) * 0.4;
  596. if (pitch > 10)
  597. pitch = 10;
  598. if (pitch < -10)
  599. pitch = -10;
  600. move = host_frametime*20;
  601. if (yaw > oldyaw)
  602. {
  603. if (oldyaw + move < yaw)
  604. yaw = oldyaw + move;
  605. }
  606. else
  607. {
  608. if (oldyaw - move > yaw)
  609. yaw = oldyaw - move;
  610. }
  611. if (pitch > oldpitch)
  612. {
  613. if (oldpitch + move < pitch)
  614. pitch = oldpitch + move;
  615. }
  616. else
  617. {
  618. if (oldpitch - move > pitch)
  619. pitch = oldpitch - move;
  620. }
  621. oldyaw = yaw;
  622. oldpitch = pitch;
  623. cl.viewent.angles[YAW] = r_refdef.viewangles[YAW] + yaw;
  624. cl.viewent.angles[PITCH] = - (r_refdef.viewangles[PITCH] + pitch);
  625. }
  626. /*
  627. ==============
  628. V_BoundOffsets
  629. ==============
  630. */
  631. void V_BoundOffsets (void)
  632. {
  633. // absolutely bound refresh reletive to entity clipping hull
  634. // so the view can never be inside a solid wall
  635. if (r_refdef.vieworg[0] < cl.simorg[0] - 14)
  636. r_refdef.vieworg[0] = cl.simorg[0] - 14;
  637. else if (r_refdef.vieworg[0] > cl.simorg[0] + 14)
  638. r_refdef.vieworg[0] = cl.simorg[0] + 14;
  639. if (r_refdef.vieworg[1] < cl.simorg[1] - 14)
  640. r_refdef.vieworg[1] = cl.simorg[1] - 14;
  641. else if (r_refdef.vieworg[1] > cl.simorg[1] + 14)
  642. r_refdef.vieworg[1] = cl.simorg[1] + 14;
  643. if (r_refdef.vieworg[2] < cl.simorg[2] - 22)
  644. r_refdef.vieworg[2] = cl.simorg[2] - 22;
  645. else if (r_refdef.vieworg[2] > cl.simorg[2] + 30)
  646. r_refdef.vieworg[2] = cl.simorg[2] + 30;
  647. }
  648. /*
  649. ==============
  650. V_AddIdle
  651. Idle swaying
  652. ==============
  653. */
  654. void V_AddIdle (void)
  655. {
  656. r_refdef.viewangles[ROLL] += v_idlescale.value * sin(cl.time*v_iroll_cycle.value) * v_iroll_level.value;
  657. r_refdef.viewangles[PITCH] += v_idlescale.value * sin(cl.time*v_ipitch_cycle.value) * v_ipitch_level.value;
  658. r_refdef.viewangles[YAW] += v_idlescale.value * sin(cl.time*v_iyaw_cycle.value) * v_iyaw_level.value;
  659. cl.viewent.angles[ROLL] -= v_idlescale.value * sin(cl.time*v_iroll_cycle.value) * v_iroll_level.value;
  660. cl.viewent.angles[PITCH] -= v_idlescale.value * sin(cl.time*v_ipitch_cycle.value) * v_ipitch_level.value;
  661. cl.viewent.angles[YAW] -= v_idlescale.value * sin(cl.time*v_iyaw_cycle.value) * v_iyaw_level.value;
  662. }
  663. /*
  664. ==============
  665. V_CalcViewRoll
  666. Roll is induced by movement and damage
  667. ==============
  668. */
  669. void V_CalcViewRoll (void)
  670. {
  671. float side;
  672. side = V_CalcRoll (cl.simangles, cl.simvel);
  673. r_refdef.viewangles[ROLL] += side;
  674. if (v_dmg_time > 0)
  675. {
  676. r_refdef.viewangles[ROLL] += v_dmg_time/v_kicktime.value*v_dmg_roll;
  677. r_refdef.viewangles[PITCH] += v_dmg_time/v_kicktime.value*v_dmg_pitch;
  678. v_dmg_time -= host_frametime;
  679. }
  680. }
  681. /*
  682. ==================
  683. V_CalcIntermissionRefdef
  684. ==================
  685. */
  686. void V_CalcIntermissionRefdef (void)
  687. {
  688. entity_t *view;
  689. float old;
  690. // view is the weapon model
  691. view = &cl.viewent;
  692. VectorCopy (cl.simorg, r_refdef.vieworg);
  693. VectorCopy (cl.simangles, r_refdef.viewangles);
  694. view->model = NULL;
  695. // allways idle in intermission
  696. old = v_idlescale.value;
  697. v_idlescale.value = 1;
  698. V_AddIdle ();
  699. v_idlescale.value = old;
  700. }
  701. /*
  702. ==================
  703. V_CalcRefdef
  704. ==================
  705. */
  706. void V_CalcRefdef (void)
  707. {
  708. entity_t *view;
  709. int i;
  710. vec3_t forward, right, up;
  711. float bob;
  712. static float oldz = 0;
  713. V_DriftPitch ();
  714. // view is the weapon model (only visible from inside body)
  715. view = &cl.viewent;
  716. bob = V_CalcBob ();
  717. // refresh position from simulated origin
  718. VectorCopy (cl.simorg, r_refdef.vieworg);
  719. r_refdef.vieworg[2] += bob;
  720. // never let it sit exactly on a node line, because a water plane can
  721. // dissapear when viewed with the eye exactly on it.
  722. // the server protocol only specifies to 1/8 pixel, so add 1/16 in each axis
  723. r_refdef.vieworg[0] += 1.0/16;
  724. r_refdef.vieworg[1] += 1.0/16;
  725. r_refdef.vieworg[2] += 1.0/16;
  726. VectorCopy (cl.simangles, r_refdef.viewangles);
  727. V_CalcViewRoll ();
  728. V_AddIdle ();
  729. if (view_message->flags & PF_GIB)
  730. r_refdef.vieworg[2] += 8; // gib view height
  731. else if (view_message->flags & PF_DEAD)
  732. r_refdef.vieworg[2] -= 16; // corpse view height
  733. else
  734. r_refdef.vieworg[2] += 22; // view height
  735. if (view_message->flags & PF_DEAD) // PF_GIB will also set PF_DEAD
  736. r_refdef.viewangles[ROLL] = 80; // dead view angle
  737. // offsets
  738. AngleVectors (cl.simangles, forward, right, up);
  739. // set up gun position
  740. VectorCopy (cl.simangles, view->angles);
  741. CalcGunAngle ();
  742. VectorCopy (cl.simorg, view->origin);
  743. view->origin[2] += 22;
  744. for (i=0 ; i<3 ; i++)
  745. {
  746. view->origin[i] += forward[i]*bob*0.4;
  747. // view->origin[i] += right[i]*bob*0.4;
  748. // view->origin[i] += up[i]*bob*0.8;
  749. }
  750. view->origin[2] += bob;
  751. // fudge position around to keep amount of weapon visible
  752. // roughly equal with different FOV
  753. if (scr_viewsize.value == 110)
  754. view->origin[2] += 1;
  755. else if (scr_viewsize.value == 100)
  756. view->origin[2] += 2;
  757. else if (scr_viewsize.value == 90)
  758. view->origin[2] += 1;
  759. else if (scr_viewsize.value == 80)
  760. view->origin[2] += 0.5;
  761. if (view_message->flags & (PF_GIB|PF_DEAD) )
  762. view->model = NULL;
  763. else
  764. view->model = cl.model_precache[cl.stats[STAT_WEAPON]];
  765. view->frame = view_message->weaponframe;
  766. view->colormap = vid.colormap;
  767. // set up the refresh position
  768. r_refdef.viewangles[PITCH] += cl.punchangle;
  769. // smooth out stair step ups
  770. if ( (view_message->onground != -1) && (cl.simorg[2] - oldz > 0) )
  771. {
  772. float steptime;
  773. steptime = host_frametime;
  774. oldz += steptime * 80;
  775. if (oldz > cl.simorg[2])
  776. oldz = cl.simorg[2];
  777. if (cl.simorg[2] - oldz > 12)
  778. oldz = cl.simorg[2] - 12;
  779. r_refdef.vieworg[2] += oldz - cl.simorg[2];
  780. view->origin[2] += oldz - cl.simorg[2];
  781. }
  782. else
  783. oldz = cl.simorg[2];
  784. }
  785. /*
  786. =============
  787. DropPunchAngle
  788. =============
  789. */
  790. void DropPunchAngle (void)
  791. {
  792. cl.punchangle -= 10*host_frametime;
  793. if (cl.punchangle < 0)
  794. cl.punchangle = 0;
  795. }
  796. /*
  797. ==================
  798. V_RenderView
  799. The player's clipping box goes from (-16 -16 -24) to (16 16 32) from
  800. the entity origin, so any view position inside that will be valid
  801. ==================
  802. */
  803. extern vrect_t scr_vrect;
  804. void V_RenderView (void)
  805. {
  806. // if (cl.simangles[ROLL])
  807. // Sys_Error ("cl.simangles[ROLL]"); // DEBUG
  808. cl.simangles[ROLL] = 0; // FIXME @@@
  809. if (cls.state != ca_active)
  810. return;
  811. view_frame = &cl.frames[cls.netchan.incoming_sequence & UPDATE_MASK];
  812. view_message = &view_frame->playerstate[cl.playernum];
  813. DropPunchAngle ();
  814. if (cl.intermission)
  815. { // intermission / finale rendering
  816. V_CalcIntermissionRefdef ();
  817. }
  818. else
  819. {
  820. V_CalcRefdef ();
  821. }
  822. R_PushDlights ();
  823. R_RenderView ();
  824. #ifndef GLQUAKE
  825. if (crosshair.value)
  826. Draw_Crosshair();
  827. #endif
  828. }
  829. //============================================================================
  830. /*
  831. =============
  832. V_Init
  833. =============
  834. */
  835. void V_Init (void)
  836. {
  837. Cmd_AddCommand ("v_cshift", V_cshift_f);
  838. Cmd_AddCommand ("bf", V_BonusFlash_f);
  839. Cmd_AddCommand ("centerview", V_StartPitchDrift);
  840. Cvar_RegisterVariable (&v_centermove);
  841. Cvar_RegisterVariable (&v_centerspeed);
  842. Cvar_RegisterVariable (&v_iyaw_cycle);
  843. Cvar_RegisterVariable (&v_iroll_cycle);
  844. Cvar_RegisterVariable (&v_ipitch_cycle);
  845. Cvar_RegisterVariable (&v_iyaw_level);
  846. Cvar_RegisterVariable (&v_iroll_level);
  847. Cvar_RegisterVariable (&v_ipitch_level);
  848. Cvar_RegisterVariable (&v_contentblend);
  849. Cvar_RegisterVariable (&v_idlescale);
  850. Cvar_RegisterVariable (&crosshaircolor);
  851. Cvar_RegisterVariable (&crosshair);
  852. Cvar_RegisterVariable (&cl_crossx);
  853. Cvar_RegisterVariable (&cl_crossy);
  854. #ifdef GLQUAKE
  855. Cvar_RegisterVariable (&gl_cshiftpercent);
  856. #endif
  857. Cvar_RegisterVariable (&cl_rollspeed);
  858. Cvar_RegisterVariable (&cl_rollangle);
  859. Cvar_RegisterVariable (&cl_bob);
  860. Cvar_RegisterVariable (&cl_bobcycle);
  861. Cvar_RegisterVariable (&cl_bobup);
  862. Cvar_RegisterVariable (&v_kicktime);
  863. Cvar_RegisterVariable (&v_kickroll);
  864. Cvar_RegisterVariable (&v_kickpitch);
  865. BuildGammaTable (1.0); // no gamma yet
  866. Cvar_RegisterVariable (&v_gamma);
  867. }