Quake II RTX doxygen  1.0 dev
view.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_view.c -- player rendering positioning
20 
21 #include "client.h"
22 
23 //=============
24 //
25 // development tools for weapons
26 //
28 qhandle_t gun_model;
29 
30 //=============
31 
32 static cvar_t *cl_add_particles;
33 #if USE_DLIGHTS
34 static cvar_t *cl_add_lights;
35 static cvar_t *cl_show_lights;
36 #endif
37 static cvar_t *cl_add_entities;
38 static cvar_t *cl_add_blend;
39 
40 #ifdef _DEBUG
41 static cvar_t *cl_testparticles;
42 static cvar_t *cl_testentities;
43 #if USE_DLIGHTS
44 static cvar_t *cl_testlights;
45 #endif
46 static cvar_t *cl_testblend;
47 
48 static cvar_t *cl_stats;
49 #endif
50 
51 static cvar_t *cl_adjustfov;
52 
53 #if USE_DLIGHTS
54 int r_numdlights;
55 dlight_t r_dlights[MAX_DLIGHTS];
56 #endif
57 
59 entity_t r_entities[MAX_ENTITIES];
60 
62 particle_t r_particles[MAX_PARTICLES];
63 
64 #if USE_LIGHTSTYLES
65 lightstyle_t r_lightstyles[MAX_LIGHTSTYLES];
66 #endif
67 
68 /*
69 ====================
70 V_ClearScene
71 
72 Specifies the model that will be used as the world
73 ====================
74 */
75 static void V_ClearScene(void)
76 {
77 #if USE_DLIGHTS
78  r_numdlights = 0;
79 #endif
80  r_numentities = 0;
81  r_numparticles = 0;
82 }
83 
84 
85 /*
86 =====================
87 V_AddEntity
88 
89 =====================
90 */
91 void V_AddEntity(entity_t *ent)
92 {
93  if (r_numentities >= MAX_ENTITIES)
94  return;
95 
96  r_entities[r_numentities++] = *ent;
97 }
98 
99 
100 /*
101 =====================
102 V_AddParticle
103 
104 =====================
105 */
106 void V_AddParticle(particle_t *p)
107 {
108  if (r_numparticles >= MAX_PARTICLES)
109  return;
110  r_particles[r_numparticles++] = *p;
111 }
112 
113 #if USE_DLIGHTS
114 /*
115 =====================
116 V_AddLight
117 
118 =====================
119 */
120 void V_AddLightEx(vec3_t org, float intensity, float r, float g, float b, float radius)
121 {
122  dlight_t *dl;
123 
124  if (r_numdlights >= MAX_DLIGHTS)
125  return;
126  dl = &r_dlights[r_numdlights++];
127  VectorCopy(org, dl->origin);
128  dl->intensity = intensity;
129  dl->color[0] = r;
130  dl->color[1] = g;
131  dl->color[2] = b;
132  dl->radius = radius;
133 
134  if (cl_show_lights->integer && r_numparticles < MAX_PARTICLES)
135  {
136  particle_t* part = &r_particles[r_numparticles++];
137 
138  VectorCopy(dl->origin, part->origin);
139  part->radius = radius;
140  part->brightness = max(r, max(g, b));
141  part->color = -1;
142  part->rgba.u8[0] = (uint8_t)max(0.f, min(255.f, r / part->brightness * 255.f));
143  part->rgba.u8[1] = (uint8_t)max(0.f, min(255.f, g / part->brightness * 255.f));
144  part->rgba.u8[2] = (uint8_t)max(0.f, min(255.f, b / part->brightness * 255.f));
145  part->rgba.u8[3] = 255;
146  part->alpha = 1.f;
147  }
148 }
149 
150 void V_AddLight(vec3_t org, float intensity, float r, float g, float b)
151 {
152  V_AddLightEx(org, intensity, r, g, b, 10.f);
153 }
154 #endif
155 
156 #if USE_LIGHTSTYLES
157 /*
158 =====================
159 V_AddLightStyle
160 
161 =====================
162 */
163 void V_AddLightStyle(int style, vec4_t value)
164 {
165  lightstyle_t *ls;
166 
167  if (style < 0 || style >= MAX_LIGHTSTYLES)
168  Com_Error(ERR_DROP, "Bad light style %i", style);
169  ls = &r_lightstyles[style];
170 
171  //ls->white = r+g+b;
172  ls->rgb[0] = value[0];
173  ls->rgb[1] = value[1];
174  ls->rgb[2] = value[2];
175  ls->white = value[3];
176 }
177 #endif
178 
179 #ifdef _DEBUG
180 
181 /*
182 ================
183 V_TestParticles
184 
185 If cl_testparticles is set, create 4096 particles in the view
186 ================
187 */
188 static void V_TestParticles(void)
189 {
190  particle_t *p;
191  int i, j;
192  float d, r, u;
193 
194  r_numparticles = MAX_PARTICLES;
195  for (i = 0; i < r_numparticles; i++) {
196  d = i * 0.25;
197  r = 4 * ((i & 7) - 3.5);
198  u = 4 * (((i >> 3) & 7) - 3.5);
199  p = &r_particles[i];
200 
201  for (j = 0; j < 3; j++)
202  p->origin[j] = cl.refdef.vieworg[j] + cl.v_forward[j] * d +
203  cl.v_right[j] * r + cl.v_up[j] * u;
204 
205  p->color = 8;
206  p->alpha = cl_testparticles->value;
207  }
208 }
209 
210 /*
211 ================
212 V_TestEntities
213 
214 If cl_testentities is set, create 32 player models
215 ================
216 */
217 static void V_TestEntities(void)
218 {
219  int i, j;
220  float f, r;
221  entity_t *ent;
222 
223  r_numentities = 32;
224  memset(r_entities, 0, sizeof(r_entities));
225 
226  for (i = 0; i < r_numentities; i++) {
227  ent = &r_entities[i];
228 
229  r = 64 * ((i % 4) - 1.5);
230  f = 64 * (i / 4) + 128;
231 
232  for (j = 0; j < 3; j++)
233  ent->origin[j] = cl.refdef.vieworg[j] + cl.v_forward[j] * f +
234  cl.v_right[j] * r;
235 
236  ent->model = cl.baseclientinfo.model;
237  ent->skin = cl.baseclientinfo.skin;
238  }
239 }
240 
241 #if USE_DLIGHTS
242 /*
243 ================
244 V_TestLights
245 
246 If cl_testlights is set, create 32 lights models
247 ================
248 */
249 static void V_TestLights(void)
250 {
251  int i, j;
252  float f, r;
253  dlight_t *dl;
254 
255  if (cl_testlights->integer != 1) {
256  dl = &r_dlights[0];
257  r_numdlights = 1;
258 
259  VectorMA(cl.refdef.vieworg, 256, cl.v_forward, dl->origin);
260  if (cl_testlights->integer == -1)
261  VectorSet(dl->color, -1, -1, -1);
262  else
263  VectorSet(dl->color, 1, 1, 1);
264  dl->intensity = 256;
265  return;
266  }
267 
268  r_numdlights = 32;
269  memset(r_dlights, 0, sizeof(r_dlights));
270 
271  for (i = 0; i < r_numdlights; i++) {
272  dl = &r_dlights[i];
273 
274  r = 64 * ((i % 4) - 1.5);
275  f = 64 * (i / 4) + 128;
276 
277  for (j = 0; j < 3; j++)
278  dl->origin[j] = cl.refdef.vieworg[j] + cl.v_forward[j] * f +
279  cl.v_right[j] * r;
280  dl->color[0] = ((i % 6) + 1) & 1;
281  dl->color[1] = (((i % 6) + 1) & 2) >> 1;
282  dl->color[2] = (((i % 6) + 1) & 4) >> 2;
283  dl->intensity = 200;
284  }
285 }
286 #endif
287 
288 #endif
289 
290 //===================================================================
291 
293 {
294  if (cls.state < ca_connected) {
295  return;
296  }
297  if (cls.serverProtocol < PROTOCOL_VERSION_R1Q2) {
298  return;
299  }
300 
301  MSG_WriteByte(clc_setting);
302  MSG_WriteShort(CLS_NOBLEND);
303  MSG_WriteShort(!cl_add_blend->integer);
304  MSG_FlushTo(&cls.netchan->message);
305 }
306 
307 //============================================================================
308 
309 // gun frame debugging functions
310 static void V_Gun_Next_f(void)
311 {
312  gun_frame++;
313  Com_Printf("frame %i\n", gun_frame);
314 }
315 
316 static void V_Gun_Prev_f(void)
317 {
318  gun_frame--;
319  if (gun_frame < 0)
320  gun_frame = 0;
321  Com_Printf("frame %i\n", gun_frame);
322 }
323 
324 static void V_Gun_Model_f(void)
325 {
326  char name[MAX_QPATH];
327 
328  if (Cmd_Argc() != 2) {
329  gun_model = 0;
330  return;
331  }
332  Q_concat(name, sizeof(name), "models/", Cmd_Argv(1), "/tris.md2", NULL);
333  gun_model = R_RegisterModel(name);
334 }
335 
336 //============================================================================
337 
338 static int entitycmpfnc(const void *_a, const void *_b)
339 {
340  const entity_t *a = (const entity_t *)_a;
341  const entity_t *b = (const entity_t *)_b;
342 
343  // all other models are sorted by model then skin
344  if (a->model == b->model)
345  return a->skin - b->skin;
346  else
347  return a->model - b->model;
348 }
349 
350 static void V_SetLightLevel(void)
351 {
352  vec3_t shadelight;
353 
354  // save off light value for server to look at (BIG HACK!)
355  R_LightPoint(cl.refdef.vieworg, shadelight);
356 
357  // pick the greatest component, which should be the same
358  // as the mono value returned by software
359  if (shadelight[0] > shadelight[1]) {
360  if (shadelight[0] > shadelight[2]) {
361  cl.lightlevel = 150.0f * shadelight[0];
362  } else {
363  cl.lightlevel = 150.0f * shadelight[2];
364  }
365  } else {
366  if (shadelight[1] > shadelight[2]) {
367  cl.lightlevel = 150.0f * shadelight[1];
368  } else {
369  cl.lightlevel = 150.0f * shadelight[2];
370  }
371  }
372 }
373 
374 /*
375 ====================
376 V_CalcFov
377 ====================
378 */
379 float V_CalcFov(float fov_x, float width, float height)
380 {
381  float a;
382  float x;
383 
384  if (fov_x < 1 || fov_x > 179)
385  Com_Error(ERR_DROP, "%s: bad fov: %f", __func__, fov_x);
386 
387  x = width / tan(fov_x / 360 * M_PI);
388 
389  a = atan(height / x);
390  a = a * 360 / M_PI;
391 
392  return a;
393 }
394 
395 
396 /*
397 ==================
398 V_RenderView
399 
400 ==================
401 */
402 void V_RenderView(void)
403 {
404  // an invalid frame will just use the exact previous refdef
405  // we can't use the old frame if the video mode has changed, though...
406  if (cl.frame.valid) {
407  V_ClearScene();
408 
409  // build a refresh entity list and calc cl.sim*
410  // this also calls CL_CalcViewValues which loads
411  // v_forward, etc.
412  CL_AddEntities();
413 
414 #ifdef _DEBUG
415  if (cl_testparticles->integer)
416  V_TestParticles();
417  if (cl_testentities->integer)
418  V_TestEntities();
419 #if USE_DLIGHTS
420  if (cl_testlights->integer)
421  V_TestLights();
422 #endif
423  if (cl_testblend->integer) {
424  cl.refdef.blend[0] = 1;
425  cl.refdef.blend[1] = 0.5;
426  cl.refdef.blend[2] = 0.25;
427  cl.refdef.blend[3] = 0.5;
428  }
429 #endif
430 
431  // never let it sit exactly on a node line, because a water plane can
432  // dissapear when viewed with the eye exactly on it.
433  // the server protocol only specifies to 1/8 pixel, so add 1/16 in each axis
434  cl.refdef.vieworg[0] += 1.0 / 16;
435  cl.refdef.vieworg[1] += 1.0 / 16;
436  cl.refdef.vieworg[2] += 1.0 / 16;
437 
438  cl.refdef.x = scr_vrect.x;
439  cl.refdef.y = scr_vrect.y;
440  cl.refdef.width = scr_vrect.width;
441  cl.refdef.height = scr_vrect.height;
442 
443  // adjust for non-4/3 screens
444  if (cl_adjustfov->integer) {
445  cl.refdef.fov_y = cl.fov_y;
446  cl.refdef.fov_x = V_CalcFov(cl.refdef.fov_y, cl.refdef.height, cl.refdef.width);
447  } else {
448  cl.refdef.fov_x = cl.fov_x;
449  cl.refdef.fov_y = V_CalcFov(cl.refdef.fov_x, cl.refdef.width, cl.refdef.height);
450  }
451 
452  cl.refdef.time = cl.time * 0.001;
453 
454  if (cl.frame.areabytes) {
455  cl.refdef.areabits = cl.frame.areabits;
456  } else {
457  cl.refdef.areabits = NULL;
458  }
459 
460  if (!cl_add_entities->integer)
461  r_numentities = 0;
462  if (!cl_add_particles->integer)
463  r_numparticles = 0;
464 #if USE_DLIGHTS
465  if (!cl_add_lights->integer)
466  r_numdlights = 0;
467 #endif
468  if (!cl_add_blend->integer)
469  Vector4Clear(cl.refdef.blend);
470 
471  cl.refdef.num_entities = r_numentities;
472  cl.refdef.entities = r_entities;
473  cl.refdef.num_particles = r_numparticles;
474  cl.refdef.particles = r_particles;
475 #if USE_DLIGHTS
476  cl.refdef.num_dlights = r_numdlights;
477  cl.refdef.dlights = r_dlights;
478 #endif
479 #if USE_LIGHTSTYLES
480  cl.refdef.lightstyles = r_lightstyles;
481 #endif
482 
483  cl.refdef.rdflags = cl.frame.ps.rdflags;
484 
485  // sort entities for better cache locality
486  qsort(cl.refdef.entities, cl.refdef.num_entities, sizeof(cl.refdef.entities[0]), entitycmpfnc);
487  }
488 
490 #ifdef _DEBUG
491  if (cl_stats->integer)
492 #if USE_DLIGHTS
493  Com_Printf("ent:%i lt:%i part:%i\n", r_numentities, r_numdlights, r_numparticles);
494 #else
495  Com_Printf("ent:%i part:%i\n", r_numentities, r_numparticles);
496 #endif
497 #endif
498 
499  V_SetLightLevel();
500 }
501 
502 
503 /*
504 =============
505 V_Viewpos_f
506 =============
507 */
508 static void V_Viewpos_f(void)
509 {
510  Com_Printf("(%i %i %i) : %i\n", (int)cl.refdef.vieworg[0],
511  (int)cl.refdef.vieworg[1], (int)cl.refdef.vieworg[2],
512  (int)cl.refdef.viewangles[YAW]);
513 }
514 
515 static const cmdreg_t v_cmds[] = {
516  { "gun_next", V_Gun_Next_f },
517  { "gun_prev", V_Gun_Prev_f },
518  { "gun_model", V_Gun_Model_f },
519  { "viewpos", V_Viewpos_f },
520  { NULL }
521 };
522 
523 static void cl_add_blend_changed(cvar_t *self)
524 {
526 }
527 
528 /*
529 =============
530 V_Init
531 =============
532 */
533 void V_Init(void)
534 {
536 
537 #ifdef _DEBUG
538  cl_testblend = Cvar_Get("cl_testblend", "0", 0);
539  cl_testparticles = Cvar_Get("cl_testparticles", "0", 0);
540  cl_testentities = Cvar_Get("cl_testentities", "0", 0);
541 #if USE_DLIGHTS
542  cl_testlights = Cvar_Get("cl_testlights", "0", CVAR_CHEAT);
543 #endif
544 
545  cl_stats = Cvar_Get("cl_stats", "0", 0);
546 #endif
547 
548 #if USE_DLIGHTS
549  cl_add_lights = Cvar_Get("cl_lights", "1", 0);
550  cl_show_lights = Cvar_Get("cl_show_lights", "0", 0);
551 #endif
552  cl_add_particles = Cvar_Get("cl_particles", "1", 0);
553  cl_add_entities = Cvar_Get("cl_entities", "1", 0);
554  cl_add_blend = Cvar_Get("cl_blend", "1", 0);
556 
557  cl_adjustfov = Cvar_Get("cl_adjustfov", "1", 0);
558 }
559 
560 void V_Shutdown(void)
561 {
563 }
564 
565 
566 
client_state_s::frame
server_frame_t frame
Definition: client.h:212
server_frame_t::valid
qboolean valid
Definition: client.h:129
cl_add_particles
static cvar_t * cl_add_particles
Definition: view.c:32
r_numentities
int r_numentities
Definition: view.c:58
height
static int height
Definition: physical_sky.c:39
V_RenderView
void V_RenderView(void)
Definition: view.c:402
client_state_s::v_forward
vec3_t v_forward
Definition: client.h:258
r_entities
entity_t r_entities[MAX_ENTITIES]
Definition: view.c:59
Cvar_Get
cvar_t * Cvar_Get(const char *var_name, const char *var_value, int flags)
Definition: cvar.c:257
R_LightPoint
void(* R_LightPoint)(vec3_t origin, vec3_t light)
Definition: refresh.c:409
V_SetLightLevel
static void V_SetLightLevel(void)
Definition: view.c:350
cl_add_entities
static cvar_t * cl_add_entities
Definition: view.c:37
client_static_s::state
connstate_t state
Definition: client.h:375
ca_connected
@ ca_connected
Definition: client.h:337
V_Gun_Next_f
static void V_Gun_Next_f(void)
Definition: view.c:310
entitycmpfnc
static int entitycmpfnc(const void *_a, const void *_b)
Definition: view.c:338
client_state_s::v_up
vec3_t v_up
Definition: client.h:258
V_AddParticle
void V_AddParticle(particle_t *p)
Definition: view.c:106
MSG_WriteByte
void MSG_WriteByte(int c)
Definition: msg.c:107
Cmd_Deregister
void Cmd_Deregister(const cmdreg_t *reg)
Definition: cmd.c:1580
cl_add_blend
static cvar_t * cl_add_blend
Definition: view.c:38
gun_frame
int gun_frame
Definition: view.c:27
Cmd_Argv
char * Cmd_Argv(int arg)
Definition: cmd.c:899
Cmd_Argc
int Cmd_Argc(void)
Definition: cmd.c:889
server_frame_t::areabytes
int areabytes
Definition: client.h:135
width
static int width
Definition: physical_sky.c:38
r_particles
particle_t r_particles[MAX_PARTICLES]
Definition: view.c:62
clientinfo_s::model
qhandle_t model
Definition: client.h:118
client_state_s::refdef
refdef_t refdef
Definition: client.h:253
Com_Error
void Com_Error(error_type_t type, const char *fmt,...)
Definition: g_main.c:258
R_RegisterModel
qhandle_t R_RegisterModel(const char *name)
Definition: models.c:305
V_Viewpos_f
static void V_Viewpos_f(void)
Definition: view.c:508
V_ClearScene
static void V_ClearScene(void)
Definition: view.c:75
r_numparticles
int r_numparticles
Definition: view.c:61
V_Init
void V_Init(void)
Definition: view.c:533
CL_UpdateBlendSetting
void CL_UpdateBlendSetting(void)
Definition: view.c:292
client_static_s::serverProtocol
int serverProtocol
Definition: client.h:422
server_frame_t::areabits
byte areabits[MAX_MAP_AREA_BYTES]
Definition: client.h:134
V_Gun_Model_f
static void V_Gun_Model_f(void)
Definition: view.c:324
Cmd_Register
void Cmd_Register(const cmdreg_t *reg)
Definition: cmd.c:1572
client_state_s::baseclientinfo
clientinfo_t baseclientinfo
Definition: client.h:309
client_state_s::time
int time
Definition: client.h:244
v_cmds
static const cmdreg_t v_cmds[]
Definition: view.c:515
client_state_s::lightlevel
int lightlevel
Definition: client.h:256
cl_add_blend_changed
static void cl_add_blend_changed(cvar_t *self)
Definition: view.c:523
V_AddLight
#define V_AddLight(org, intensity, r, g, b)
Definition: client.h:728
MSG_WriteShort
void MSG_WriteShort(int c)
Definition: msg.c:125
V_Shutdown
void V_Shutdown(void)
Definition: view.c:560
V_Gun_Prev_f
static void V_Gun_Prev_f(void)
Definition: view.c:316
cl
client_state_t cl
Definition: main.c:99
CL_AddEntities
void CL_AddEntities(void)
Definition: entities.c:1378
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
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
client_state_s::fov_x
float fov_x
Definition: client.h:254
gun_model
qhandle_t gun_model
Definition: view.c:28
server_frame_t::ps
player_state_t ps
Definition: client.h:137
R_RenderFrame
void(* R_RenderFrame)(refdef_t *fd)
Definition: refresh.c:408
intensity
cvar_t * intensity
Definition: god_rays.c:38
client.h
shadelight
static const vec_t * shadelight
Definition: mesh.c:35
scr_vrect
vrect_t scr_vrect
Definition: screen.c:105
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
cl_adjustfov
static cvar_t * cl_adjustfov
Definition: view.c:51
client_static_s::netchan
netchan_t * netchan
Definition: client.h:421
V_AddEntity
void V_AddEntity(entity_t *ent)
Definition: view.c:91
clientinfo_s::skin
qhandle_t skin
Definition: client.h:114