Quake II RTX doxygen  1.0 dev
entities.c
Go to the documentation of this file.
1 /*
2 Copyright (C) 1997-2001 Id Software, Inc.
3 Copyright (C) 2019, NVIDIA CORPORATION. All rights reserved.
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 2 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 along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19 // cl_ents.c -- entity parsing and management
20 
21 #include "client.h"
22 #include "refresh/models.h"
23 
24 extern qhandle_t cl_mod_powerscreen;
25 extern qhandle_t cl_mod_laser;
26 extern qhandle_t cl_mod_dmspot;
27 extern qhandle_t cl_sfx_footsteps[4];
28 
29 /*
30 =========================================================================
31 
32 FRAME PARSING
33 
34 =========================================================================
35 */
36 
37 static inline qboolean entity_optimized(const entity_state_t *state)
38 {
39  if (cls.serverProtocol != PROTOCOL_VERSION_Q2PRO)
40  return qfalse;
41 
42  if (state->number != cl.frame.clientNum + 1)
43  return qfalse;
44 
45  if (cl.frame.ps.pmove.pm_type >= PM_DEAD)
46  return qfalse;
47 
48  return qtrue;
49 }
50 
51 static inline void
52 entity_update_new(centity_t *ent, const entity_state_t *state, const vec_t *origin)
53 {
54  static int entity_ctr;
55  ent->id = ++entity_ctr;
56  ent->trailcount = 1024; // for diminishing rocket / grenade trails
57 
58  // duplicate the current state so lerping doesn't hurt anything
59  ent->prev = *state;
60 #if USE_FPS
61  ent->prev_frame = state->frame;
62  ent->event_frame = cl.frame.number;
63 #endif
64 
65  if (state->event == EV_PLAYER_TELEPORT ||
66  state->event == EV_OTHER_TELEPORT ||
67  (state->renderfx & (RF_FRAMELERP | RF_BEAM))) {
68  // no lerping if teleported
69  VectorCopy(origin, ent->lerp_origin);
70  return;
71  }
72 
73  // old_origin is valid for new entities,
74  // so use it as starting point for interpolating between
75  VectorCopy(state->old_origin, ent->prev.origin);
76  VectorCopy(state->old_origin, ent->lerp_origin);
77 }
78 
79 static inline void
80 entity_update_old(centity_t *ent, const entity_state_t *state, const vec_t *origin)
81 {
82  int event = state->event;
83 
84 #if USE_FPS
85  // check for new event
86  if (state->event != ent->current.event)
87  ent->event_frame = cl.frame.number; // new
88  else if (cl.frame.number - ent->event_frame >= cl.framediv)
89  ent->event_frame = cl.frame.number; // refreshed
90  else
91  event = 0; // duplicated
92 #endif
93 
94  if (state->modelindex != ent->current.modelindex
95  || state->modelindex2 != ent->current.modelindex2
96  || state->modelindex3 != ent->current.modelindex3
97  || state->modelindex4 != ent->current.modelindex4
98  || event == EV_PLAYER_TELEPORT
99  || event == EV_OTHER_TELEPORT
100  || fabsf(origin[0] - ent->current.origin[0]) > 512
101  || fabsf(origin[1] - ent->current.origin[1]) > 512
102  || fabsf(origin[2] - ent->current.origin[2]) > 512
103  || cl_nolerp->integer == 1) {
104  // some data changes will force no lerping
105  ent->trailcount = 1024; // for diminishing rocket / grenade trails
106 
107  // duplicate the current state so lerping doesn't hurt anything
108  ent->prev = *state;
109 #if USE_FPS
110  ent->prev_frame = state->frame;
111 #endif
112  // no lerping if teleported or morphed
113  VectorCopy(origin, ent->lerp_origin);
114  return;
115  }
116 
117 #if USE_FPS
118  // start alias model animation
119  if (state->frame != ent->current.frame) {
120  ent->prev_frame = ent->current.frame;
121  ent->anim_start = cl.servertime - cl.frametime;
122  Com_DDPrintf("[%d] anim start %d: %d --> %d [%d]\n",
123  ent->anim_start, state->number,
124  ent->prev_frame, state->frame,
125  cl.frame.number);
126  }
127 #endif
128 
129  // shuffle the last state to previous
130  ent->prev = ent->current;
131 }
132 
133 static inline qboolean entity_new(const centity_t *ent)
134 {
135  if (!cl.oldframe.valid)
136  return qtrue; // last received frame was invalid
137 
138  if (ent->serverframe != cl.oldframe.number)
139  return qtrue; // wasn't in last received frame
140 
141  if (cl_nolerp->integer == 2)
142  return qtrue; // developer option, always new
143 
144  if (cl_nolerp->integer == 3)
145  return qfalse; // developer option, lerp from last received frame
146 
147  if (cl.oldframe.number != cl.frame.number - 1)
148  return qtrue; // previous server frame was dropped
149 
150  return qfalse;
151 }
152 
153 static void entity_update(const entity_state_t *state)
154 {
155  centity_t *ent = &cl_entities[state->number];
156  const vec_t *origin;
157  vec3_t origin_v;
158 
159  // if entity is solid, decode mins/maxs and add to the list
160  if (state->solid && state->number != cl.frame.clientNum + 1
161  && cl.numSolidEntities < MAX_PACKET_ENTITIES) {
163  if (state->solid != PACKED_BSP) {
164  // encoded bbox
165  if (cl.esFlags & MSG_ES_LONGSOLID) {
166  MSG_UnpackSolid32(state->solid, ent->mins, ent->maxs);
167  } else {
168  MSG_UnpackSolid16(state->solid, ent->mins, ent->maxs);
169  }
170  }
171  }
172 
173  // work around Q2PRO server bandwidth optimization
174  if (entity_optimized(state)) {
175  VectorScale(cl.frame.ps.pmove.origin, 0.125f, origin_v);
176  origin = origin_v;
177  } else {
178  origin = state->origin;
179  }
180 
181  if (entity_new(ent)) {
182  // wasn't in last update, so initialize some things
183  entity_update_new(ent, state, origin);
184  } else {
185  entity_update_old(ent, state, origin);
186  }
187 
188  ent->serverframe = cl.frame.number;
189  ent->current = *state;
190 
191  // work around Q2PRO server bandwidth optimization
192  if (entity_optimized(state)) {
194  }
195 }
196 
197 // an entity has just been parsed that has an event value
198 static void entity_event(int number)
199 {
200  centity_t *cent = &cl_entities[number];
201 
202  // EF_TELEPORTER acts like an event, but is not cleared each frame
203  if ((cent->current.effects & EF_TELEPORTER) && CL_FRAMESYNC) {
204  CL_TeleporterParticles(cent->current.origin);
205  }
206 
207 #if USE_FPS
208  if (cent->event_frame != cl.frame.number)
209  return;
210 #endif
211 
212  switch (cent->current.event) {
213  case EV_ITEM_RESPAWN:
214  S_StartSound(NULL, number, CHAN_WEAPON, S_RegisterSound("items/respawn1.wav"), 1, ATTN_IDLE, 0);
215  CL_ItemRespawnParticles(cent->current.origin);
216  break;
217  case EV_PLAYER_TELEPORT:
218  S_StartSound(NULL, number, CHAN_WEAPON, S_RegisterSound("misc/tele1.wav"), 1, ATTN_IDLE, 0);
219  CL_TeleportParticles(cent->current.origin);
220  break;
221  case EV_FOOTSTEP:
222  if (cl_footsteps->integer)
223  S_StartSound(NULL, number, CHAN_BODY, cl_sfx_footsteps[rand() & 3], 1, ATTN_NORM, 0);
224  break;
225  case EV_FALLSHORT:
226  S_StartSound(NULL, number, CHAN_AUTO, S_RegisterSound("player/land1.wav"), 1, ATTN_NORM, 0);
227  break;
228  case EV_FALL:
229  S_StartSound(NULL, number, CHAN_AUTO, S_RegisterSound("*fall2.wav"), 1, ATTN_NORM, 0);
230  break;
231  case EV_FALLFAR:
232  S_StartSound(NULL, number, CHAN_AUTO, S_RegisterSound("*fall1.wav"), 1, ATTN_NORM, 0);
233  break;
234  }
235 }
236 
237 static void set_active_state(void)
238 {
239  cls.state = ca_active;
240 
241  cl.serverdelta = Q_align(cl.frame.number, CL_FRAMEDIV);
242  cl.time = cl.servertime = 0; // set time, needed for demos
243 #if USE_FPS
244  cl.keytime = cl.keyservertime = 0;
245  cl.keyframe = cl.frame; // initialize keyframe to make sure it's valid
246 #endif
247 
248  // initialize oldframe so lerping doesn't hurt anything
249  cl.oldframe.valid = qfalse;
250  cl.oldframe.ps = cl.frame.ps;
251 #if USE_FPS
252  cl.oldkeyframe.valid = qfalse;
253  cl.oldkeyframe.ps = cl.keyframe.ps;
254 #endif
255 
256  cl.frameflags = 0;
257 
258  if (cls.netchan) {
259  cl.initialSeq = cls.netchan->outgoing_sequence;
260  }
261 
262  if (cls.demo.playback) {
263  // init some demo things
265  } else {
266  // set initial cl.predicted_origin and cl.predicted_angles
267  VectorScale(cl.frame.ps.pmove.origin, 0.125f, cl.predicted_origin);
268  VectorScale(cl.frame.ps.pmove.velocity, 0.125f, cl.predicted_velocity);
269  if (cl.frame.ps.pmove.pm_type < PM_DEAD &&
270  cls.serverProtocol > PROTOCOL_VERSION_DEFAULT) {
271  // enhanced servers don't send viewangles
273  } else {
274  // just use what server provided
275  VectorCopy(cl.frame.ps.viewangles, cl.predicted_angles);
276  }
277  }
278 
279  SCR_EndLoadingPlaque(); // get rid of loading plaque
280  SCR_LagClear();
281  Con_Close(qfalse); // get rid of connection screen
282 
284 
286 
287  if (!cls.demo.playback) {
288  EXEC_TRIGGER(cl_beginmapcmd);
289  Cmd_ExecTrigger("#cl_enterlevel");
290  }
291 }
292 
293 static void
294 player_update(server_frame_t *oldframe, server_frame_t *frame, int framediv)
295 {
296  player_state_t *ps, *ops;
297  centity_t *ent;
298  int oldnum;
299 
300  // find states to interpolate between
301  ps = &frame->ps;
302  ops = &oldframe->ps;
303 
304  // no lerping if previous frame was dropped or invalid
305  if (!oldframe->valid)
306  goto dup;
307 
308  oldnum = frame->number - framediv;
309  if (oldframe->number != oldnum)
310  goto dup;
311 
312  // no lerping if player entity was teleported (origin check)
313  if (abs(ops->pmove.origin[0] - ps->pmove.origin[0]) > 256 * 8 ||
314  abs(ops->pmove.origin[1] - ps->pmove.origin[1]) > 256 * 8 ||
315  abs(ops->pmove.origin[2] - ps->pmove.origin[2]) > 256 * 8) {
316  goto dup;
317  }
318 
319  // no lerping if player entity was teleported (event check)
320  ent = &cl_entities[frame->clientNum + 1];
321  if (ent->serverframe > oldnum &&
322  ent->serverframe <= frame->number &&
323 #if USE_FPS
324  ent->event_frame > oldnum &&
325  ent->event_frame <= frame->number &&
326 #endif
327  (ent->current.event == EV_PLAYER_TELEPORT
328  || ent->current.event == EV_OTHER_TELEPORT)) {
329  goto dup;
330  }
331 
332  // no lerping if teleport bit was flipped
333  if ((ops->pmove.pm_flags ^ ps->pmove.pm_flags) & PMF_TELEPORT_BIT)
334  goto dup;
335 
336  // no lerping if POV number changed
337  if (oldframe->clientNum != frame->clientNum)
338  goto dup;
339 
340  // developer option
341  if (cl_nolerp->integer == 1)
342  goto dup;
343 
344  return;
345 
346 dup:
347  // duplicate the current state so lerping doesn't hurt anything
348  *ops = *ps;
349 }
350 
351 /*
352 ==================
353 CL_DeltaFrame
354 
355 A valid frame has been parsed.
356 ==================
357 */
358 void CL_DeltaFrame(void)
359 {
360  centity_t *ent;
361  entity_state_t *state;
362  int i, j;
363  int framenum;
364  int prevstate = cls.state;
365 
366  // getting a valid frame message ends the connection process
367  if (cls.state == ca_precached)
369 
370  // set server time
371  framenum = cl.frame.number - cl.serverdelta;
372  cl.servertime = framenum * CL_FRAMETIME;
373 #if USE_FPS
374  cl.keyservertime = (framenum / cl.framediv) * BASE_FRAMETIME;
375 #endif
376 
377  // rebuild the list of solid entities for this frame
378  cl.numSolidEntities = 0;
379 
380  // initialize position of the player's own entity from playerstate.
381  // this is needed in situations when player entity is invisible, but
382  // server sends an effect referencing it's origin (such as MZ_LOGIN, etc)
383  ent = &cl_entities[cl.frame.clientNum + 1];
385 
386  for (i = 0; i < cl.frame.numEntities; i++) {
387  j = (cl.frame.firstEntity + i) & PARSE_ENTITIES_MASK;
388  state = &cl.entityStates[j];
389 
390  // set current and prev
391  entity_update(state);
392 
393  // fire events
394  entity_event(state->number);
395  }
396 
399  }
400 
401  if (prevstate == ca_precached)
402  CL_GTV_Resume();
403  else
405 
406  if (cls.demo.playback) {
407  // this delta has nothing to do with local viewangles,
408  // clear it to avoid interfering with demo freelook hack
409  VectorClear(cl.frame.ps.pmove.delta_angles);
410  }
411 
412  if (cl.oldframe.ps.pmove.pm_type != cl.frame.ps.pmove.pm_type) {
413  IN_Activate();
414  }
415 
417 
418 #if USE_FPS
419  if (CL_FRAMESYNC)
420  player_update(&cl.oldkeyframe, &cl.keyframe, cl.framediv);
421 #endif
422 
424 
426 }
427 
428 #ifdef _DEBUG
429 // for debugging problems when out-of-date entity origin is referenced
430 void CL_CheckEntityPresent(int entnum, const char *what)
431 {
432  centity_t *e;
433 
434  if (entnum == cl.frame.clientNum + 1) {
435  return; // player entity = current
436  }
437 
438  e = &cl_entities[entnum];
439  if (e->serverframe == cl.frame.number) {
440  return; // current
441  }
442 
443  if (e->serverframe) {
444  Com_LPrintf(PRINT_DEVELOPER,
445  "SERVER BUG: %s on entity %d last seen %d frames ago\n",
446  what, entnum, cl.frame.number - e->serverframe);
447  } else {
448  Com_LPrintf(PRINT_DEVELOPER,
449  "SERVER BUG: %s on entity %d never seen before\n",
450  what, entnum);
451  }
452 }
453 #endif
454 
455 
456 /*
457 ==========================================================================
458 
459 INTERPOLATE BETWEEN FRAMES TO GET RENDERING PARMS
460 
461 ==========================================================================
462 */
463 
464 // Use a static entity ID on some things because the renderer relies on eid to match between meshes
465 // on the current and previous frames.
466 #define RESERVED_ENTITIY_GUN 1
467 #define RESERVED_ENTITIY_SHADERBALLS 2
468 #define RESERVED_ENTITIY_COUNT 3
469 
470 static int adjust_shell_fx(int renderfx)
471 {
472  // PMM - at this point, all of the shells have been handled
473  // if we're in the rogue pack, set up the custom mixing, otherwise just
474  // keep going
475  if (!strcmp(fs_game->string, "rogue")) {
476  // all of the solo colors are fine. we need to catch any of the combinations that look bad
477  // (double & half) and turn them into the appropriate color, and make double/quad something special
478  if (renderfx & RF_SHELL_HALF_DAM) {
479  // ditch the half damage shell if any of red, blue, or double are on
480  if (renderfx & (RF_SHELL_RED | RF_SHELL_BLUE | RF_SHELL_DOUBLE))
481  renderfx &= ~RF_SHELL_HALF_DAM;
482  }
483 
484  if (renderfx & RF_SHELL_DOUBLE) {
485  // lose the yellow shell if we have a red, blue, or green shell
486  if (renderfx & (RF_SHELL_RED | RF_SHELL_BLUE | RF_SHELL_GREEN))
487  renderfx &= ~RF_SHELL_DOUBLE;
488  // if we have a red shell, turn it to purple by adding blue
489  if (renderfx & RF_SHELL_RED)
490  renderfx |= RF_SHELL_BLUE;
491  // if we have a blue shell (and not a red shell), turn it to cyan by adding green
492  else if (renderfx & RF_SHELL_BLUE) {
493  // go to green if it's on already, otherwise do cyan (flash green)
494  if (renderfx & RF_SHELL_GREEN)
495  renderfx &= ~RF_SHELL_BLUE;
496  else
497  renderfx |= RF_SHELL_GREEN;
498  }
499  }
500  }
501 
502  return renderfx;
503 }
504 
505 /*
506 ===============
507 CL_AddPacketEntities
508 
509 ===============
510 */
511 static void CL_AddPacketEntities(void)
512 {
513  entity_t ent;
514  entity_state_t *s1;
515  float autorotate;
516  int i;
517  int pnum;
518  centity_t *cent;
519  int autoanim;
520  clientinfo_t *ci;
521  unsigned int effects, renderfx;
522 
523  // bonus items rotate at a fixed rate
524  autorotate = anglemod(cl.time * 0.1f);
525 
526  // brush models can auto animate their frames
527  autoanim = 2 * cl.time / 1000;
528 
529  memset(&ent, 0, sizeof(ent));
530 
531  for (pnum = 0; pnum < cl.frame.numEntities; pnum++) {
532  i = (cl.frame.firstEntity + pnum) & PARSE_ENTITIES_MASK;
533  s1 = &cl.entityStates[i];
534 
535  cent = &cl_entities[s1->number];
536  ent.id = cent->id + RESERVED_ENTITIY_COUNT;
537 
538  effects = s1->effects;
539  renderfx = s1->renderfx;
540 
541  // set frame
542  if (effects & EF_ANIM01)
543  ent.frame = autoanim & 1;
544  else if (effects & EF_ANIM23)
545  ent.frame = 2 + (autoanim & 1);
546  else if (effects & EF_ANIM_ALL)
547  ent.frame = autoanim;
548  else if (effects & EF_ANIM_ALLFAST)
549  ent.frame = cl.time / 100;
550  else
551  ent.frame = s1->frame;
552 
553  // quad and pent can do different things on client
554  if (effects & EF_PENT) {
555  effects &= ~EF_PENT;
556  effects |= EF_COLOR_SHELL;
557  renderfx |= RF_SHELL_RED;
558  }
559 
560  if (effects & EF_QUAD) {
561  effects &= ~EF_QUAD;
562  effects |= EF_COLOR_SHELL;
563  renderfx |= RF_SHELL_BLUE;
564  }
565 
566  if (effects & EF_DOUBLE) {
567  effects &= ~EF_DOUBLE;
568  effects |= EF_COLOR_SHELL;
569  renderfx |= RF_SHELL_DOUBLE;
570  }
571 
572  if (effects & EF_HALF_DAMAGE) {
573  effects &= ~EF_HALF_DAMAGE;
574  effects |= EF_COLOR_SHELL;
575  renderfx |= RF_SHELL_HALF_DAM;
576  }
577 
578  // optionally remove the glowing effect
579  if (cl_noglow->integer)
580  renderfx &= ~RF_GLOW;
581 
582  ent.oldframe = cent->prev.frame;
583  ent.backlerp = 1.0 - cl.lerpfrac;
584 
585  if (renderfx & RF_FRAMELERP) {
586  // step origin discretely, because the frames
587  // do the animation properly
588  VectorCopy(cent->current.origin, ent.origin);
589  VectorCopy(cent->current.old_origin, ent.oldorigin); // FIXME
590  } else if (renderfx & RF_BEAM) {
591  // interpolate start and end points for beams
592  LerpVector(cent->prev.origin, cent->current.origin,
593  cl.lerpfrac, ent.origin);
594  LerpVector(cent->prev.old_origin, cent->current.old_origin,
595  cl.lerpfrac, ent.oldorigin);
596  } else {
597  if (s1->number == cl.frame.clientNum + 1) {
598  // use predicted origin
599  VectorCopy(cl.playerEntityOrigin, ent.origin);
600  VectorCopy(cl.playerEntityOrigin, ent.oldorigin);
601  } else {
602  // interpolate origin
603  LerpVector(cent->prev.origin, cent->current.origin,
604  cl.lerpfrac, ent.origin);
605  VectorCopy(ent.origin, ent.oldorigin);
606  }
607 
608 #if USE_FPS
609  // run alias model animation
610  if (cent->prev_frame != s1->frame) {
611  int delta = cl.time - cent->anim_start;
612  float frac;
613 
614  if (delta > BASE_FRAMETIME) {
615  Com_DDPrintf("[%d] anim end %d: %d --> %d\n",
616  cl.time, s1->number,
617  cent->prev_frame, s1->frame);
618  cent->prev_frame = s1->frame;
619  frac = 1;
620  } else if (delta > 0) {
621  frac = delta * BASE_1_FRAMETIME;
622  Com_DDPrintf("[%d] anim run %d: %d --> %d [%f]\n",
623  cl.time, s1->number,
624  cent->prev_frame, s1->frame,
625  frac);
626  } else {
627  frac = 0;
628  }
629 
630  ent.oldframe = cent->prev_frame;
631  ent.backlerp = 1.0 - frac;
632  }
633 #endif
634  }
635 
636  if ((effects & EF_GIB) && !cl_gibs->integer) {
637  goto skip;
638  }
639 
640  // create a new entity
641 
642  // tweak the color of beams
643  if (renderfx & RF_BEAM) {
644  // the four beam colors are encoded in 32 bits of skinnum (hack)
645  ent.alpha = 0.30;
646  ent.skinnum = (s1->skinnum >> ((rand() % 4) * 8)) & 0xff;
647  ent.model = 0;
648  } else {
649  // set skin
650  if (s1->modelindex == 255) {
651  // use custom player skin
652  ent.skinnum = 0;
653  ci = &cl.clientinfo[s1->skinnum & 0xff];
654  ent.skin = ci->skin;
655  ent.model = ci->model;
656  if (!ent.skin || !ent.model) {
657  ent.skin = cl.baseclientinfo.skin;
658  ent.model = cl.baseclientinfo.model;
659  ci = &cl.baseclientinfo;
660  }
661  if (renderfx & RF_USE_DISGUISE) {
662  char buffer[MAX_QPATH];
663 
664  Q_concat(buffer, sizeof(buffer), "players/", ci->model_name, "/disguise.pcx", NULL);
665  ent.skin = R_RegisterSkin(buffer);
666  }
667  } else {
668  ent.skinnum = s1->skinnum;
669  ent.skin = 0;
670  ent.model = cl.model_draw[s1->modelindex];
671  if (ent.model == cl_mod_laser || ent.model == cl_mod_dmspot)
672  renderfx |= RF_NOSHADOW;
673  }
674  }
675 
676  // only used for black hole model right now, FIXME: do better
677  if ((renderfx & RF_TRANSLUCENT) && !(renderfx & RF_BEAM))
678  ent.alpha = 0.70;
679 
680  // render effects (fullbright, translucent, etc)
681  if ((effects & EF_COLOR_SHELL))
682  ent.flags = 0; // renderfx go on color shell entity
683  else
684  ent.flags = renderfx;
685 
686  // calculate angles
687  if (effects & EF_ROTATE) { // some bonus items auto-rotate
688  ent.angles[0] = 0;
689  ent.angles[1] = autorotate;
690  ent.angles[2] = 0;
691  } else if (effects & EF_SPINNINGLIGHTS) {
692  vec3_t forward;
693  vec3_t start;
694 
695  ent.angles[0] = 0;
696  ent.angles[1] = anglemod(cl.time / 2) + s1->angles[1];
697  ent.angles[2] = 180;
698 
699  AngleVectors(ent.angles, forward, NULL, NULL);
700  VectorMA(ent.origin, 64, forward, start);
701  V_AddLight(start, 100, 1, 0, 0);
702  } else if (s1->number == cl.frame.clientNum + 1) {
703  VectorCopy(cl.playerEntityAngles, ent.angles); // use predicted angles
704  } else { // interpolate angles
705  LerpAngles(cent->prev.angles, cent->current.angles,
706  cl.lerpfrac, ent.angles);
707 
708  // mimic original ref_gl "leaning" bug (uuugly!)
709  if (s1->modelindex == 255 && cl_rollhack->integer) {
710  ent.angles[ROLL] = -ent.angles[ROLL];
711  }
712  }
713 
714  int base_entity_flags = 0;
715 
716  if (s1->number == cl.frame.clientNum + 1) {
717  if (effects & EF_FLAG1)
718  V_AddLight(ent.origin, 225, 1.0, 0.1, 0.1);
719  else if (effects & EF_FLAG2)
720  V_AddLight(ent.origin, 225, 0.1, 0.1, 1.0);
721  else if (effects & EF_TAGTRAIL)
722  V_AddLight(ent.origin, 225, 1.0, 1.0, 0.0);
723  else if (effects & EF_TRACKERTRAIL)
724  V_AddLight(ent.origin, 225, -1.0, -1.0, -1.0);
725 
726  if (!cl.thirdPersonView)
727  {
728  if(vid_rtx->integer)
729  base_entity_flags |= RF_VIEWERMODEL; // only draw from mirrors
730  else
731  goto skip;
732  }
733 
734  // don't tilt the model - looks weird
735  ent.angles[0] = 0.f;
736 
737  // offset the model back a bit to make the view point located in front of the head
738  vec3_t angles = { 0.f, ent.angles[1], 0.f };
739  vec3_t forward;
740  AngleVectors(angles, forward, NULL, NULL);
741 
742  float offset = -15.f;
743  VectorMA(ent.origin, offset, forward, ent.origin);
744  VectorMA(ent.oldorigin, offset, forward, ent.oldorigin);
745  }
746 
747  // if set to invisible, skip
748  if (!s1->modelindex) {
749  goto skip;
750  }
751 
752  if (effects & EF_BFG) {
753  ent.flags |= RF_TRANSLUCENT;
754  ent.alpha = 0.30;
755  }
756 
757  if (effects & EF_PLASMA) {
758  ent.flags |= RF_TRANSLUCENT;
759  ent.alpha = 0.6;
760  }
761 
762  if (effects & EF_SPHERETRANS) {
763  ent.flags |= RF_TRANSLUCENT;
764  if (effects & EF_TRACKERTRAIL)
765  ent.alpha = 0.6;
766  else
767  ent.alpha = 0.3;
768  }
769 
770  ent.flags |= base_entity_flags;
771 
772  // in rtx mode, the base entity has the renderfx for shells
773  if ((effects & EF_COLOR_SHELL) && vid_rtx->integer) {
774  renderfx = adjust_shell_fx(renderfx);
775  ent.flags |= renderfx;
776  }
777 
778  // add to refresh list
779  V_AddEntity(&ent);
780 
781  // add dlights for flares
782  model_t* model;
783  if (ent.model && !(ent.model & 0x80000000) &&
784  (model = MOD_ForHandle(ent.model)))
785  {
786  if (model->model_class == MCLASS_FLARE)
787  {
788  float phase = (float)cl.time * 0.03f + (float)ent.id;
789  float anim = sinf(phase);
790 
791  float offset = anim * 1.5f + 5.f;
792  float brightness = anim * 0.2f + 0.8f;
793 
794  vec3_t origin;
795  VectorCopy(ent.origin, origin);
796  origin[2] += offset;
797 
798  V_AddLightEx(origin, 500.f, 1.6f * brightness, 1.0f * brightness, 0.2f * brightness, 5.f);
799  }
800  }
801 
802  // color shells generate a separate entity for the main model
803  if ((effects & EF_COLOR_SHELL) && !vid_rtx->integer) {
804  renderfx = adjust_shell_fx(renderfx);
805  ent.flags = renderfx | RF_TRANSLUCENT | base_entity_flags;
806  ent.alpha = 0.30;
807  V_AddEntity(&ent);
808  }
809 
810  ent.skin = 0; // never use a custom skin on others
811  ent.skinnum = 0;
812  ent.flags = base_entity_flags;
813  ent.alpha = 0;
814 
815  // duplicate for linked models
816  if (s1->modelindex2) {
817  if (s1->modelindex2 == 255) {
818  // custom weapon
819  ci = &cl.clientinfo[s1->skinnum & 0xff];
820  i = (s1->skinnum >> 8); // 0 is default weapon model
821  if (i < 0 || i > cl.numWeaponModels - 1)
822  i = 0;
823  ent.model = ci->weaponmodel[i];
824  if (!ent.model) {
825  if (i != 0)
826  ent.model = ci->weaponmodel[0];
827  if (!ent.model)
828  ent.model = cl.baseclientinfo.weaponmodel[0];
829  }
830  } else
831  ent.model = cl.model_draw[s1->modelindex2];
832 
833  // PMM - check for the defender sphere shell .. make it translucent
834  if (!Q_strcasecmp(cl.configstrings[CS_MODELS + (s1->modelindex2)], "models/items/shell/tris.md2")) {
835  ent.alpha = 0.32;
836  ent.flags = RF_TRANSLUCENT;
837  }
838 
839  if ((effects & EF_COLOR_SHELL) && vid_rtx->integer) {
840  ent.flags |= renderfx;
841  }
842 
843  V_AddEntity(&ent);
844 
845  //PGM - make sure these get reset.
846  ent.flags = base_entity_flags;
847  ent.alpha = 0;
848  }
849 
850  if (s1->modelindex3) {
851  ent.model = cl.model_draw[s1->modelindex3];
852  V_AddEntity(&ent);
853  }
854 
855  if (s1->modelindex4) {
856  ent.model = cl.model_draw[s1->modelindex4];
857  V_AddEntity(&ent);
858  }
859 
860  if (effects & EF_POWERSCREEN) {
861  ent.model = cl_mod_powerscreen;
862  ent.oldframe = 0;
863  ent.frame = 0;
864  ent.flags |= (RF_TRANSLUCENT | RF_SHELL_GREEN);
865  ent.alpha = 0.30;
866  V_AddEntity(&ent);
867  }
868 
869  // add automatic particle trails
870  if (effects & ~EF_ROTATE) {
871  if (effects & EF_ROCKET) {
872  if (!(cl_disable_particles->integer & NOPART_ROCKET_TRAIL)) {
873  CL_RocketTrail(cent->lerp_origin, ent.origin, cent);
874  }
875  V_AddLight(ent.origin, 200, 0.6f, 0.4f, 0.12f);
876  } else if (effects & EF_BLASTER) {
877  if (effects & EF_TRACKER) {
878  CL_BlasterTrail2(cent->lerp_origin, ent.origin);
879  V_AddLight(ent.origin, 200, 0.1f, 0.4f, 0.12f);
880  } else {
881  CL_BlasterTrail(cent->lerp_origin, ent.origin);
882  V_AddLight(ent.origin, 200, 0.6f, 0.4f, 0.12f);
883  }
884  } else if (effects & EF_HYPERBLASTER) {
885  if (effects & EF_TRACKER)
886  V_AddLight(ent.origin, 200, 0.1f, 0.4f, 0.12f);
887  else
888  V_AddLight(ent.origin, 200, 0.6f, 0.4f, 0.12f);
889  } else if (effects & EF_GIB) {
890  CL_DiminishingTrail(cent->lerp_origin, ent.origin, cent, effects);
891  } else if (effects & EF_GRENADE) {
892  if (!(cl_disable_particles->integer & NOPART_GRENADE_TRAIL)) {
893  CL_DiminishingTrail(cent->lerp_origin, ent.origin, cent, effects);
894  }
895  } else if (effects & EF_FLIES) {
896  CL_FlyEffect(cent, ent.origin);
897  } else if (effects & EF_BFG) {
898  if (effects & EF_ANIM_ALLFAST) {
899  CL_BfgParticles(&ent);
900 #if USE_DLIGHTS
901  i = 100;
902  } else {
903  static const int bfg_lightramp[6] = {300, 400, 600, 300, 150, 75};
904 
905  i = s1->frame; clamp(i, 0, 5);
906  i = bfg_lightramp[i];
907 #endif
908  }
909  const vec3_t nvgreen = { 0.2716f, 0.5795f, 0.04615f };
910  V_AddLightEx(ent.origin, i, nvgreen[0], nvgreen[1], nvgreen[2], 20.f);
911  } else if (effects & EF_TRAP) {
912  ent.origin[2] += 32;
913  CL_TrapParticles(&ent);
914 #if USE_DLIGHTS
915  i = (rand() % 100) + 100;
916  V_AddLight(ent.origin, i, 1, 0.8, 0.1);
917 #endif
918  } else if (effects & EF_FLAG1) {
919  CL_FlagTrail(cent->lerp_origin, ent.origin, 242);
920  V_AddLight(ent.origin, 225, 1, 0.1, 0.1);
921  } else if (effects & EF_FLAG2) {
922  CL_FlagTrail(cent->lerp_origin, ent.origin, 115);
923  V_AddLight(ent.origin, 225, 0.1, 0.1, 1);
924  } else if (effects & EF_TAGTRAIL) {
925  CL_TagTrail(cent->lerp_origin, ent.origin, 220);
926  V_AddLight(ent.origin, 225, 1.0, 1.0, 0.0);
927  } else if (effects & EF_TRACKERTRAIL) {
928  if (effects & EF_TRACKER) {
929 #if USE_DLIGHTS
930  float intensity;
931 
932  intensity = 50 + (500 * (sin(cl.time / 500.0) + 1.0));
933  V_AddLight(ent.origin, intensity, -1.0, -1.0, -1.0);
934 #endif
935  } else {
937  V_AddLight(ent.origin, 155, -1.0, -1.0, -1.0);
938  }
939  } else if (effects & EF_TRACKER) {
940  CL_TrackerTrail(cent->lerp_origin, ent.origin, 0);
941  V_AddLight(ent.origin, 200, -1, -1, -1);
942  } else if (effects & EF_GREENGIB) {
943  CL_DiminishingTrail(cent->lerp_origin, ent.origin, cent, effects);
944  } else if (effects & EF_IONRIPPER) {
945  CL_IonripperTrail(cent->lerp_origin, ent.origin);
946  V_AddLight(ent.origin, 100, 1, 0.5, 0.5);
947  } else if (effects & EF_BLUEHYPERBLASTER) {
948  V_AddLight(ent.origin, 200, 0, 0, 1);
949  } else if (effects & EF_PLASMA) {
950  if (effects & EF_ANIM_ALLFAST) {
951  CL_BlasterTrail(cent->lerp_origin, ent.origin);
952  }
953  V_AddLight(ent.origin, 130, 1, 0.5, 0.5);
954  }
955  }
956 
957 skip:
958  VectorCopy(ent.origin, cent->lerp_origin);
959  }
960 }
961 
962 static int shell_effect_hack(void)
963 {
964  centity_t *ent;
965  int flags = 0;
966 
967  if (cl.frame.clientNum == CLIENTNUM_NONE)
968  return 0;
969 
970  ent = &cl_entities[cl.frame.clientNum + 1];
971  if (ent->serverframe != cl.frame.number)
972  return 0;
973 
974  if (!ent->current.modelindex)
975  return 0;
976 
977  if (ent->current.effects & EF_PENT)
978  flags |= RF_SHELL_RED;
979  if (ent->current.effects & EF_QUAD)
980  flags |= RF_SHELL_BLUE;
981  if (ent->current.effects & EF_DOUBLE)
982  flags |= RF_SHELL_DOUBLE;
983  if (ent->current.effects & EF_HALF_DAMAGE)
984  flags |= RF_SHELL_HALF_DAM;
985 
986  return flags;
987 }
988 
989 /*
990 ==============
991 CL_AddViewWeapon
992 ==============
993 */
994 static void CL_AddViewWeapon(void)
995 {
996  player_state_t *ps, *ops;
997  entity_t gun; // view model
998  int i, shell_flags;
999 
1000  // allow the gun to be completely removed
1001  if (cl_player_model->integer == CL_PLAYER_MODEL_DISABLED) {
1002  return;
1003  }
1004 
1005  if (info_hand->integer == 2) {
1006  return;
1007  }
1008 
1009  // find states to interpolate between
1010  ps = CL_KEYPS;
1011  ops = CL_OLDKEYPS;
1012 
1013  memset(&gun, 0, sizeof(gun));
1014 
1015  if (gun_model) {
1016  gun.model = gun_model; // development tool
1017  } else {
1018  gun.model = cl.model_draw[ps->gunindex];
1019  }
1020  if (!gun.model) {
1021  return;
1022  }
1023 
1024  gun.id = RESERVED_ENTITIY_GUN;
1025 
1026  // set up gun position
1027  for (i = 0; i < 3; i++) {
1028  gun.origin[i] = cl.refdef.vieworg[i] + ops->gunoffset[i] +
1029  CL_KEYLERPFRAC * (ps->gunoffset[i] - ops->gunoffset[i]);
1030  gun.angles[i] = cl.refdef.viewangles[i] + LerpAngle(ops->gunangles[i],
1031  ps->gunangles[i], CL_KEYLERPFRAC);
1032  }
1033 
1034  // adjust for high fov
1035  if (ps->fov > 90) {
1036  vec_t ofs = (90 - ps->fov) * 0.2f;
1037  VectorMA(gun.origin, ofs, cl.v_forward, gun.origin);
1038  }
1039 
1040  // adjust the gun origin so that the gun doesn't intersect with walls
1041  {
1042  vec3_t view_dir, right_dir, up_dir;
1043  vec3_t gun_real_pos, gun_tip;
1044  const float gun_length = 28.f;
1045  const float gun_right = 10.f;
1046  const float gun_up = -5.f;
1047  trace_t trace;
1048  static vec3_t mins = { -4, -4, -4 }, maxs = { 4, 4, 4 };
1049 
1050  AngleVectors(cl.refdef.viewangles, view_dir, right_dir, up_dir);
1051  VectorMA(gun.origin, gun_right, right_dir, gun_real_pos);
1052  VectorMA(gun_real_pos, gun_up, up_dir, gun_real_pos);
1053  VectorMA(gun_real_pos, gun_length, view_dir, gun_tip);
1054 
1055  CM_BoxTrace(&trace, gun_real_pos, gun_tip, mins, maxs, cl.bsp->nodes, MASK_SOLID);
1056 
1057  if (trace.fraction != 1.0f)
1058  {
1059  VectorMA(trace.endpos, -gun_length, view_dir, gun.origin);
1060  VectorMA(gun.origin, -gun_right, right_dir, gun.origin);
1061  VectorMA(gun.origin, -gun_up, up_dir, gun.origin);
1062  }
1063  }
1064 
1065  VectorCopy(gun.origin, gun.oldorigin); // don't lerp at all
1066 
1067  if (gun_frame) {
1068  gun.frame = gun_frame; // development tool
1069  gun.oldframe = gun_frame; // development tool
1070  } else {
1071  gun.frame = ps->gunframe;
1072  if (gun.frame == 0) {
1073  gun.oldframe = 0; // just changed weapons, don't lerp from old
1074  } else {
1075  gun.oldframe = ops->gunframe;
1076  gun.backlerp = 1.0f - CL_KEYLERPFRAC;
1077  }
1078  }
1079 
1080  gun.flags = RF_MINLIGHT | RF_DEPTHHACK | RF_WEAPONMODEL;
1081  if (info_hand->integer == 1) {
1082  gun.flags |= RF_LEFTHAND;
1083  }
1084 
1085  if (cl_gunalpha->value != 1) {
1086  gun.alpha = Cvar_ClampValue(cl_gunalpha, 0.1f, 1.0f);
1087  gun.flags |= RF_TRANSLUCENT;
1088  }
1089 
1090  // add shell effect from player entity
1091  shell_flags = shell_effect_hack();
1092 
1093  // same entity in rtx mode
1094  if (vid_rtx->integer) {
1095  gun.flags |= shell_flags;
1096  }
1097 
1098  model_t* model = MOD_ForHandle(gun.model);
1099  if (model && strstr(model->name, "v_flareg"))
1100  gun.scale = 0.3f;
1101 
1102  V_AddEntity(&gun);
1103 
1104  // separate entity in non-rtx mode
1105  if (shell_flags && !vid_rtx->integer) {
1106  gun.alpha = 0.30f * cl_gunalpha->value;
1107  gun.flags |= shell_flags | RF_TRANSLUCENT;
1108  V_AddEntity(&gun);
1109  }
1110 }
1111 
1112 static void CL_SetupFirstPersonView(void)
1113 {
1114  player_state_t *ps, *ops;
1115  vec3_t kickangles;
1116  float lerp;
1117 
1118  // add kick angles
1119  if (cl_kickangles->integer) {
1120  ps = CL_KEYPS;
1121  ops = CL_OLDKEYPS;
1122 
1123  lerp = CL_KEYLERPFRAC;
1124 
1125  LerpAngles(ops->kick_angles, ps->kick_angles, lerp, kickangles);
1126  VectorAdd(cl.refdef.viewangles, kickangles, cl.refdef.viewangles);
1127  }
1128 
1129  // add the weapon
1130  CL_AddViewWeapon();
1131 
1132  cl.thirdPersonView = qfalse;
1133 }
1134 
1135 /*
1136 ===============
1137 CL_SetupThirdPersionView
1138 ===============
1139 */
1140 static void CL_SetupThirdPersionView(void)
1141 {
1142  vec3_t focus;
1143  float fscale, rscale;
1144  float dist, angle, range;
1145  trace_t trace;
1146  static vec3_t mins = { -4, -4, -4 }, maxs = { 4, 4, 4 };
1147 
1148  // if dead, set a nice view angle
1149  if (cl.frame.ps.stats[STAT_HEALTH] <= 0) {
1150  cl.refdef.viewangles[ROLL] = 0;
1151  cl.refdef.viewangles[PITCH] = 10;
1152  }
1153 
1154  VectorMA(cl.refdef.vieworg, 512, cl.v_forward, focus);
1155 
1156  cl.refdef.vieworg[2] += 8;
1157 
1158  cl.refdef.viewangles[PITCH] *= 0.5f;
1159  AngleVectors(cl.refdef.viewangles, cl.v_forward, cl.v_right, cl.v_up);
1160 
1161  angle = DEG2RAD(cl_thirdperson_angle->value);
1162  range = cl_thirdperson_range->value;
1163  fscale = cos(angle);
1164  rscale = sin(angle);
1165  VectorMA(cl.refdef.vieworg, -range * fscale, cl.v_forward, cl.refdef.vieworg);
1166  VectorMA(cl.refdef.vieworg, -range * rscale, cl.v_right, cl.refdef.vieworg);
1167 
1168  CM_BoxTrace(&trace, cl.playerEntityOrigin, cl.refdef.vieworg,
1169  mins, maxs, cl.bsp->nodes, MASK_SOLID);
1170  if (trace.fraction != 1.0f) {
1171  VectorCopy(trace.endpos, cl.refdef.vieworg);
1172  }
1173 
1174  VectorSubtract(focus, cl.refdef.vieworg, focus);
1175  dist = sqrt(focus[0] * focus[0] + focus[1] * focus[1]);
1176 
1177  cl.refdef.viewangles[PITCH] = -180 / M_PI * atan2(focus[2], dist);
1178  cl.refdef.viewangles[YAW] -= cl_thirdperson_angle->value;
1179 
1180  cl.thirdPersonView = qtrue;
1181 }
1182 
1183 static void CL_FinishViewValues(void)
1184 {
1185  centity_t *ent;
1186 
1188  goto first;
1189 
1190  if (cl.frame.clientNum == CLIENTNUM_NONE)
1191  goto first;
1192 
1193  ent = &cl_entities[cl.frame.clientNum + 1];
1194  if (ent->serverframe != cl.frame.number)
1195  goto first;
1196 
1197  if (!ent->current.modelindex)
1198  goto first;
1199 
1201  return;
1202 
1203 first:
1205 }
1206 
1207 #if USE_SMOOTH_DELTA_ANGLES
1208 static inline float LerpShort(int a2, int a1, float frac)
1209 {
1210  if (a1 - a2 > 32768)
1211  a1 &= 65536;
1212  if (a2 - a1 > 32768)
1213  a1 &= 65536;
1214  return a2 + frac * (a1 - a2);
1215 }
1216 #endif
1217 
1218 static inline float lerp_client_fov(float ofov, float nfov, float lerp)
1219 {
1220  if (cls.demo.playback) {
1221  float fov = info_fov->value;
1222 
1223  if (fov < 1)
1224  fov = 90;
1225  else if (fov > 160)
1226  fov = 160;
1227 
1228  if (info_uf->integer & UF_LOCALFOV)
1229  return fov;
1230 
1231  if (!(info_uf->integer & UF_PLAYERFOV)) {
1232  if (ofov >= 90)
1233  ofov = fov;
1234  if (nfov >= 90)
1235  nfov = fov;
1236  }
1237  }
1238 
1239  return ofov + lerp * (nfov - ofov);
1240 }
1241 
1242 /*
1243 ===============
1244 CL_CalcViewValues
1245 
1246 Sets cl.refdef view values and sound spatialization params.
1247 Usually called from CL_AddEntities, but may be directly called from the main
1248 loop if rendering is disabled but sound is running.
1249 ===============
1250 */
1252 {
1253  player_state_t *ps, *ops;
1254  vec3_t viewoffset;
1255  float lerp;
1256 
1257  if (!cl.frame.valid) {
1258  return;
1259  }
1260 
1261  // find states to interpolate between
1262  ps = &cl.frame.ps;
1263  ops = &cl.oldframe.ps;
1264 
1265  lerp = cl.lerpfrac;
1266 
1267  // calculate the origin
1268  if (!cls.demo.playback && cl_predict->integer && !(ps->pmove.pm_flags & PMF_NO_PREDICTION)) {
1269  // use predicted values
1270  unsigned delta = cls.realtime - cl.predicted_step_time;
1271  float backlerp = lerp - 1.0;
1272 
1273  VectorMA(cl.predicted_origin, backlerp, cl.prediction_error, cl.refdef.vieworg);
1274 
1275  // smooth out stair climbing
1276  if (cl.predicted_step < 127 * 0.125f) {
1277  delta <<= 1; // small steps
1278  }
1279  if (delta < 100) {
1280  cl.refdef.vieworg[2] -= cl.predicted_step * (100 - delta) * 0.01f;
1281  }
1282  } else {
1283  // just use interpolated values
1284  cl.refdef.vieworg[0] = ops->pmove.origin[0] * 0.125f +
1285  lerp * (ps->pmove.origin[0] - ops->pmove.origin[0]) * 0.125f;
1286  cl.refdef.vieworg[1] = ops->pmove.origin[1] * 0.125f +
1287  lerp * (ps->pmove.origin[1] - ops->pmove.origin[1]) * 0.125f;
1288  cl.refdef.vieworg[2] = ops->pmove.origin[2] * 0.125f +
1289  lerp * (ps->pmove.origin[2] - ops->pmove.origin[2]) * 0.125f;
1290  }
1291 
1292  // if not running a demo or on a locked frame, add the local angle movement
1293  if (cls.demo.playback) {
1294  LerpAngles(ops->viewangles, ps->viewangles, lerp, cl.refdef.viewangles);
1295  } else if (ps->pmove.pm_type < PM_DEAD) {
1296  // use predicted values
1297  VectorCopy(cl.predicted_angles, cl.refdef.viewangles);
1298  } else if (ops->pmove.pm_type < PM_DEAD && cls.serverProtocol > PROTOCOL_VERSION_DEFAULT) {
1299  // lerp from predicted angles, since enhanced servers
1300  // do not send viewangles each frame
1301  LerpAngles(cl.predicted_angles, ps->viewangles, lerp, cl.refdef.viewangles);
1302  } else {
1303  // just use interpolated values
1304  LerpAngles(ops->viewangles, ps->viewangles, lerp, cl.refdef.viewangles);
1305  }
1306 
1307 #if USE_SMOOTH_DELTA_ANGLES
1308  cl.delta_angles[0] = LerpShort(ops->pmove.delta_angles[0], ps->pmove.delta_angles[0], lerp);
1309  cl.delta_angles[1] = LerpShort(ops->pmove.delta_angles[1], ps->pmove.delta_angles[1], lerp);
1310  cl.delta_angles[2] = LerpShort(ops->pmove.delta_angles[2], ps->pmove.delta_angles[2], lerp);
1311 #endif
1312 
1313  // don't interpolate blend color
1314  Vector4Copy(ps->blend, cl.refdef.blend);
1315 
1316 #if USE_FPS
1317  ps = &cl.keyframe.ps;
1318  ops = &cl.oldkeyframe.ps;
1319 
1320  lerp = cl.keylerpfrac;
1321 #endif
1322 
1323  // interpolate field of view
1324  cl.fov_x = lerp_client_fov(ops->fov, ps->fov, lerp);
1325  cl.fov_y = V_CalcFov(cl.fov_x, 4, 3);
1326 
1327  LerpVector(ops->viewoffset, ps->viewoffset, lerp, viewoffset);
1328 
1329  AngleVectors(cl.refdef.viewangles, cl.v_forward, cl.v_right, cl.v_up);
1330 
1331  VectorCopy(cl.refdef.vieworg, cl.playerEntityOrigin);
1332  VectorCopy(cl.refdef.viewangles, cl.playerEntityAngles);
1333 
1334  if (cl.playerEntityAngles[PITCH] > 180) {
1335  cl.playerEntityAngles[PITCH] -= 360;
1336  }
1337 
1338  cl.playerEntityAngles[PITCH] = cl.playerEntityAngles[PITCH] / 3;
1339 
1340  VectorAdd(cl.refdef.vieworg, viewoffset, cl.refdef.vieworg);
1341 
1342  VectorCopy(cl.refdef.vieworg, listener_origin);
1343  VectorCopy(cl.v_forward, listener_forward);
1344  VectorCopy(cl.v_right, listener_right);
1345  VectorCopy(cl.v_up, listener_up);
1346 }
1347 
1348 #if CL_RTX_SHADERBALLS
1349 extern qhandle_t cl_dev_shaderballs;
1350 vec3_t cl_dev_shaderballs_pos = { 0 };
1351 
1352 void CL_AddShaderBalls(void)
1353 {
1354  if (cl_dev_shaderballs != -1 && vid_rtx->integer)
1355  {
1356  model_t * model = MOD_ForHandle(cl_dev_shaderballs);
1357 
1358  if (model != NULL && model->meshes != NULL)
1359  {
1360  entity_t entity = { 0 };
1361  entity.model = cl_dev_shaderballs;
1362  VectorCopy(cl_dev_shaderballs_pos, entity.origin);
1363  entity.alpha = 1.0;
1364  entity.id = RESERVED_ENTITIY_SHADERBALLS;
1365  V_AddEntity(&entity);
1366  }
1367  }
1368 }
1369 #endif
1370 
1371 /*
1372 ===============
1373 CL_AddEntities
1374 
1375 Emits all entities, particles, and lights to the refresh
1376 ===============
1377 */
1378 void CL_AddEntities(void)
1379 {
1383  CL_AddTEnts();
1384  CL_AddParticles();
1385 #if USE_DLIGHTS
1386  CL_AddDLights();
1387 #endif
1388 #if USE_LIGHTSTYLES
1389  CL_AddLightStyles();
1390 #endif
1391 #if CL_RTX_SHADERBALLS
1392  CL_AddShaderBalls();
1393 #endif
1395 }
1396 
1397 /*
1398 ===============
1399 CL_GetEntitySoundOrigin
1400 
1401 Called to get the sound spatialization origin
1402 ===============
1403 */
1404 void CL_GetEntitySoundOrigin(int entnum, vec3_t org)
1405 {
1406  centity_t *ent;
1407  mmodel_t *cm;
1408  vec3_t mid;
1409 
1410  if (entnum < 0 || entnum >= MAX_EDICTS) {
1411  Com_Error(ERR_DROP, "%s: bad entnum: %d", __func__, entnum);
1412  }
1413 
1414  if (!entnum || entnum == listener_entnum) {
1415  // should this ever happen?
1416  VectorCopy(listener_origin, org);
1417  return;
1418  }
1419 
1420  // interpolate origin
1421  // FIXME: what should be the sound origin point for RF_BEAM entities?
1422  ent = &cl_entities[entnum];
1423  LerpVector(ent->prev.origin, ent->current.origin, cl.lerpfrac, org);
1424 
1425  // offset the origin for BSP models
1426  if (ent->current.solid == PACKED_BSP) {
1427  cm = cl.model_clip[ent->current.modelindex];
1428  if (cm) {
1429  VectorAvg(cm->mins, cm->maxs, mid);
1430  VectorAdd(org, mid, org);
1431  }
1432  }
1433 }
1434 
CL_AddPacketEntities
static void CL_AddPacketEntities(void)
Definition: entities.c:511
client_state_s::frame
server_frame_t frame
Definition: client.h:212
server_frame_t::valid
qboolean valid
Definition: client.h:129
CL_Tracker_Shell
void CL_Tracker_Shell(vec3_t origin)
Definition: newfx.c:466
client_state_s::bsp
bsp_t * bsp
Definition: client.h:300
adjust_shell_fx
static int adjust_shell_fx(int renderfx)
Definition: entities.c:470
client_state_s::configstrings
char configstrings[MAX_CONFIGSTRINGS][MAX_QPATH]
Definition: client.h:289
CM_BoxTrace
void CM_BoxTrace(trace_t *trace, vec3_t start, vec3_t end, vec3_t mins, vec3_t maxs, mnode_t *headnode, int brushmask)
Definition: cmodel.c:683
CL_GetEntitySoundOrigin
void CL_GetEntitySoundOrigin(int entnum, vec3_t org)
Definition: entities.c:1404
CL_IonripperTrail
void CL_IonripperTrail(vec3_t start, vec3_t end)
Definition: newfx.c:843
CL_FlagTrail
void CL_FlagTrail(vec3_t start, vec3_t end, int color)
Definition: effects.c:1436
client_state_s::entityStates
entity_state_t entityStates[MAX_PARSE_ENTITIES]
Definition: client.h:204
listener_origin
vec3_t listener_origin
Definition: main.c:35
client_state_s::servertime
int servertime
Definition: client.h:214
client_static_s::playback
qhandle_t playback
Definition: client.h:453
shell_effect_hack
static int shell_effect_hack(void)
Definition: entities.c:962
centity_s::prev
entity_state_t prev
Definition: client.h:87
NOPART_ROCKET_TRAIL
#define NOPART_ROCKET_TRAIL
Definition: client.h:498
CL_SetupFirstPersonView
static void CL_SetupFirstPersonView(void)
Definition: entities.c:1112
client_static_s::demo
struct client_static_s::@3 demo
client_state_s::solidEntities
centity_t * solidEntities[MAX_PACKET_ENTITIES]
Definition: client.h:199
cl_kickangles
cvar_t * cl_kickangles
Definition: main.c:36
client_state_s::model_clip
mmodel_t * model_clip[MAX_MODELS]
Definition: client.h:303
centity_s::mins
vec3_t mins
Definition: client.h:89
S_RegisterSound
qhandle_t S_RegisterSound(const char *name)
Definition: main.c:391
CL_BlasterTrail2
void CL_BlasterTrail2(vec3_t start, vec3_t end)
Definition: newfx.c:798
MOD_ForHandle
model_t * MOD_ForHandle(qhandle_t h)
Definition: models.c:430
client_state_s::v_forward
vec3_t v_forward
Definition: client.h:258
entity_update
static void entity_update(const entity_state_t *state)
Definition: entities.c:153
client_state_s::numWeaponModels
int numWeaponModels
Definition: client.h:312
RESERVED_ENTITIY_GUN
#define RESERVED_ENTITIY_GUN
Definition: entities.c:466
CL_CheckPredictionError
void CL_CheckPredictionError(void)
Definition: predict.c:27
listener_up
vec3_t listener_up
Definition: main.c:38
IN_Activate
void IN_Activate(void)
Definition: input.c:117
client_state_s::prediction_error
vec3_t prediction_error
Definition: client.h:196
SCR_SetCrosshairColor
void SCR_SetCrosshairColor(void)
Definition: screen.c:1242
CL_FinishViewValues
static void CL_FinishViewValues(void)
Definition: entities.c:1183
centity_s::id
int id
Definition: client.h:105
CL_KEYLERPFRAC
#define CL_KEYLERPFRAC
Definition: client.h:167
cl_beginmapcmd
cvar_t * cl_beginmapcmd
Definition: main.c:61
Com_PlayerToEntityState
void Com_PlayerToEntityState(const player_state_t *ps, entity_state_t *es)
Definition: utils.c:269
client_state_s::predicted_velocity
vec3_t predicted_velocity
Definition: client.h:195
ca_active
@ ca_active
Definition: client.h:340
Cmd_ExecTrigger
void Cmd_ExecTrigger(const char *string)
Definition: cmd.c:576
client_state_s::thirdPersonView
qboolean thirdPersonView
Definition: client.h:260
client_static_s::state
connstate_t state
Definition: client.h:375
client_state_s::lerpfrac
float lerpfrac
Definition: client.h:246
RESERVED_ENTITIY_SHADERBALLS
#define RESERVED_ENTITIY_SHADERBALLS
Definition: entities.c:467
CL_TagTrail
void CL_TagTrail(vec3_t start, vec3_t end, int color)
Definition: newfx.c:646
cl_disable_particles
cvar_t * cl_disable_particles
Definition: main.c:51
cl_predict
cvar_t * cl_predict
Definition: main.c:28
CL_AddViewWeapon
static void CL_AddViewWeapon(void)
Definition: entities.c:994
CL_TeleporterParticles
void CL_TeleporterParticles(vec3_t org)
Definition: effects.c:1098
client_state_s::v_up
vec3_t v_up
Definition: client.h:258
CL_RocketTrail
void CL_RocketTrail(vec3_t start, vec3_t end, centity_t *old)
Definition: effects.c:1579
CL_CalcViewValues
void CL_CalcViewValues(void)
Definition: entities.c:1251
client_state_s::oldframe
server_frame_t oldframe
Definition: client.h:213
LOC_AddLocationsToScene
void LOC_AddLocationsToScene(void)
Definition: locs.c:177
CL_TrapParticles
void CL_TrapParticles(entity_t *ent)
Definition: newfx.c:897
client_state_s::serverdelta
int serverdelta
Definition: client.h:215
SCR_EndLoadingPlaque
void SCR_EndLoadingPlaque(void)
Definition: screen.c:1456
backlerp
static float backlerp
Definition: mesh.c:26
CL_EmitDemoFrame
void CL_EmitDemoFrame(void)
Definition: demo.c:186
CL_FRAMEDIV
#define CL_FRAMEDIV
Definition: client.h:163
V_AddEntity
void V_AddEntity(entity_t *ent)
Definition: view.c:91
player_update
static void player_update(server_frame_t *oldframe, server_frame_t *frame, int framediv)
Definition: entities.c:294
gun_frame
int gun_frame
Definition: view.c:27
client_state_s::predicted_step
float predicted_step
Definition: client.h:189
CL_PLAYER_MODEL_DISABLED
#define CL_PLAYER_MODEL_DISABLED
Definition: client.h:553
client_static_s::recording
qhandle_t recording
Definition: client.h:454
info_hand
cvar_t * info_hand
Definition: main.c:86
cl_nolerp
cvar_t * cl_nolerp
Definition: main.c:39
CL_FirstDemoFrame
void CL_FirstDemoFrame(void)
Definition: demo.c:876
clientinfo_s::model
qhandle_t model
Definition: client.h:118
ca_precached
@ ca_precached
Definition: client.h:339
client_state_s::refdef
refdef_t refdef
Definition: client.h:253
client_static_s::seeking
qboolean seeking
Definition: client.h:469
Com_Error
void Com_Error(error_type_t type, const char *fmt,...)
Definition: g_main.c:258
client_state_s::frameflags
unsigned frameflags
Definition: client.h:210
client_state_s::playerEntityOrigin
vec3_t playerEntityOrigin
Definition: client.h:263
centity_s::current
entity_state_t current
Definition: client.h:86
client_state_s::predicted_origin
vec3_t predicted_origin
Definition: client.h:193
CL_BfgParticles
void CL_BfgParticles(entity_t *ent)
Definition: effects.c:1847
forward
static vec3_t forward
Definition: p_view.c:27
cl_thirdperson_angle
cvar_t * cl_thirdperson_angle
Definition: main.c:48
cl_player_model
cvar_t * cl_player_model
Definition: main.c:47
Cvar_ClampValue
float Cvar_ClampValue(cvar_t *var, float min, float max)
Definition: cvar.c:571
client_state_s::model_draw
qhandle_t model_draw[MAX_MODELS]
Definition: client.h:302
clientinfo_s::weaponmodel
qhandle_t weaponmodel[MAX_CLIENTWEAPONMODELS]
Definition: client.h:119
client_static_s::serverProtocol
int serverProtocol
Definition: client.h:422
cl_mod_powerscreen
qhandle_t cl_mod_powerscreen
Definition: tent.c:48
SCR_LagClear
void SCR_LagClear(void)
Definition: screen.c:532
clientinfo_s::model_name
char model_name[MAX_QPATH]
Definition: client.h:116
cl_mod_dmspot
qhandle_t cl_mod_dmspot
Definition: tent.c:50
info_uf
cvar_t * info_uf
Definition: main.c:88
cl_gunalpha
cvar_t * cl_gunalpha
Definition: main.c:30
origin
static vec3_t origin
Definition: mesh.c:27
client_state_s::baseclientinfo
clientinfo_t baseclientinfo
Definition: client.h:309
CL_AddTEnts
void CL_AddTEnts(void)
Definition: tent.c:1445
info_fov
cvar_t * info_fov
Definition: main.c:84
AngleVectors
void AngleVectors(vec3_t angles, vec3_t forward, vec3_t right, vec3_t up)
Definition: shared.c:23
client_state_s::time
int time
Definition: client.h:244
client_state_s::esFlags
msgEsFlags_t esFlags
Definition: client.h:207
CL_AddParticles
void CL_AddParticles(void)
Definition: effects.c:1989
fs_game
cvar_t * fs_game
Definition: files.c:202
listener_forward
vec3_t listener_forward
Definition: main.c:36
CL_OLDKEYPS
#define CL_OLDKEYPS
Definition: client.h:166
CL_CheckForPause
void CL_CheckForPause(void)
Definition: main.c:3056
CL_BlasterTrail
void CL_BlasterTrail(vec3_t start, vec3_t end)
Definition: effects.c:1339
Com_LPrintf
void Com_LPrintf(print_type_t type, const char *fmt,...)
Definition: g_main.c:242
Con_Close
void Con_Close(qboolean force)
Definition: console.c:124
V_AddLight
#define V_AddLight(org, intensity, r, g, b)
Definition: client.h:728
CL_DeltaFrame
void CL_DeltaFrame(void)
Definition: entities.c:358
server_frame_t
Definition: client.h:128
client_state_s::clientinfo
clientinfo_t clientinfo[MAX_CLIENTS]
Definition: client.h:308
RESERVED_ENTITIY_COUNT
#define RESERVED_ENTITIY_COUNT
Definition: entities.c:468
set_active_state
static void set_active_state(void)
Definition: entities.c:237
centity_s
Definition: client.h:85
cl
client_state_t cl
Definition: main.c:99
server_frame_t::clientNum
int clientNum
Definition: client.h:138
entity_optimized
static qboolean entity_optimized(const entity_state_t *state)
Definition: entities.c:37
Q_strcasecmp
int Q_strcasecmp(const char *s1, const char *s2)
Definition: shared.c:666
client_state_s::predicted_step_time
unsigned predicted_step_time
Definition: client.h:190
entity_update_old
static void entity_update_old(centity_t *ent, const entity_state_t *state, const vec_t *origin)
Definition: entities.c:80
CL_SetupThirdPersionView
static void CL_SetupThirdPersionView(void)
Definition: entities.c:1140
cls
client_static_t cls
Definition: main.c:98
V_CalcFov
float V_CalcFov(float fov_x, float width, float height)
Definition: view.c:379
lerp_client_fov
static float lerp_client_fov(float ofov, float nfov, float lerp)
Definition: entities.c:1218
V_AddLightEx
#define V_AddLightEx(org, intensity, r, g, b, radius)
Definition: client.h:729
client_state_s::v_right
vec3_t v_right
Definition: client.h:258
server_frame_t::numEntities
int numEntities
Definition: client.h:140
entity_event
static void entity_event(int number)
Definition: entities.c:198
cl_gibs
cvar_t * cl_gibs
Definition: main.c:63
client_state_s::initialSeq
int initialSeq
Definition: client.h:187
client_state_s::fov_x
float fov_x
Definition: client.h:254
cl_noglow
cvar_t * cl_noglow
Definition: main.c:38
CL_TeleportParticles
void CL_TeleportParticles(vec3_t org)
Definition: effects.c:1942
server_frame_t::ps
player_state_t ps
Definition: client.h:137
entity_new
static qboolean entity_new(const centity_t *ent)
Definition: entities.c:133
CL_FRAMETIME
#define CL_FRAMETIME
Definition: client.h:161
centity_s::trailcount
int trailcount
Definition: client.h:93
gun_model
qhandle_t gun_model
Definition: view.c:28
CL_GTV_EmitFrame
void CL_GTV_EmitFrame(void)
Definition: gtv.c:107
CL_FlyEffect
void CL_FlyEffect(centity_t *ent, vec3_t origin)
Definition: effects.c:1815
intensity
cvar_t * intensity
Definition: god_rays.c:38
client.h
CL_GTV_Resume
void CL_GTV_Resume(void)
Definition: gtv.c:256
server_frame_t::number
int number
Definition: client.h:131
CL_ItemRespawnParticles
void CL_ItemRespawnParticles(vec3_t org)
Definition: effects.c:1183
listener_entnum
int listener_entnum
Definition: main.c:39
client_static_s::realtime
unsigned realtime
Definition: client.h:389
CL_KEYPS
#define CL_KEYPS
Definition: client.h:165
CL_UpdateFrameTimes
void CL_UpdateFrameTimes(void)
Definition: main.c:3136
client_state_s::playerEntityAngles
vec3_t playerEntityAngles
Definition: client.h:264
range
int range(edict_t *self, edict_t *other)
Definition: g_ai.c:245
client_state_s::fov_y
float fov_y
Definition: client.h:255
Q_concat
size_t Q_concat(char *dest, size_t size,...)
Definition: shared.c:758
NOPART_GRENADE_TRAIL
#define NOPART_GRENADE_TRAIL
Definition: client.h:496
centity_s::maxs
vec3_t maxs
Definition: client.h:89
vid_rtx
cvar_t * vid_rtx
Definition: refresh.c:30
CL_DiminishingTrail
void CL_DiminishingTrail(vec3_t start, vec3_t end, centity_t *old, int flags)
Definition: effects.c:1484
cl_entities
centity_t cl_entities[MAX_EDICTS]
Definition: main.c:101
CL_PredictAngles
void CL_PredictAngles(void)
Definition: predict.c:168
CL_AddEntities
void CL_AddEntities(void)
Definition: entities.c:1378
cl_footsteps
cvar_t * cl_footsteps
Definition: main.c:26
cl_rollhack
cvar_t * cl_rollhack
Definition: main.c:37
S_StartSound
void S_StartSound(const vec3_t origin, int entnum, int entchannel, qhandle_t hSfx, float vol, float attenuation, float timeofs)
Definition: main.c:824
CL_TrackerTrail
void CL_TrackerTrail(vec3_t start, vec3_t end, int particleColor)
Definition: newfx.c:418
cl_sfx_footsteps
qhandle_t cl_sfx_footsteps[4]
Definition: tent.c:36
cl_mod_laser
qhandle_t cl_mod_laser
Definition: tent.c:49
client_static_s::netchan
netchan_t * netchan
Definition: client.h:421
listener_right
vec3_t listener_right
Definition: main.c:37
centity_s::lerp_origin
vec3_t lerp_origin
Definition: client.h:94
centity_s::serverframe
int serverframe
Definition: client.h:91
server_frame_t::firstEntity
int firstEntity
Definition: client.h:141
client_state_s::numSolidEntities
int numSolidEntities
Definition: client.h:200
CL_FRAMESYNC
#define CL_FRAMESYNC
Definition: client.h:164
clientinfo_s
Definition: client.h:112
entity_update_new
static void entity_update_new(centity_t *ent, const entity_state_t *state, const vec_t *origin)
Definition: entities.c:52
clientinfo_s::skin
qhandle_t skin
Definition: client.h:114
cl_thirdperson_range
cvar_t * cl_thirdperson_range
Definition: main.c:49
client_state_s::predicted_angles
vec3_t predicted_angles
Definition: client.h:194
client_static_s::paused
qboolean paused
Definition: client.h:468
CL_PLAYER_MODEL_THIRD_PERSON
#define CL_PLAYER_MODEL_THIRD_PERSON
Definition: client.h:556