1 /*
2 Copyright (C) 1997-2001 Id Software, Inc.
3
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13 See the GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19 */
20 // cl_view.c -- player rendering positioning
21
22 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #endif
25
26 #include "client.h"
27
28 //=============
29 //
30 // development tools for weapons
31 //
32 int gun_frame;
33 struct model_s *gun_model;
34 //=============
35
36 int r_numgrasses;
37 grass_t r_grasses[MAX_GRASSES];
38
39 int r_numbeams;
40 beam_t r_beams[MAX_BEAMS];
41
42 extern cvar_t *cl_showPlayerNames;
43 extern cvar_t *name;
44 extern char map_music[260];
45 extern cvar_t *background_music;
46 extern qboolean IsVisible(vec3_t org1,vec3_t org2);
47 extern void R_VCFreeFrame(void);
48
49 cvar_t *crosshair;
50 cvar_t *cl_testparticles;
51 cvar_t *cl_testentities;
52 cvar_t *cl_testlights;
53 cvar_t *cl_testblend;
54
55 cvar_t *cl_stats;
56
57 qboolean need_free_vbo;
58
59 int r_numdlights;
60 dlight_t r_dlights[MAX_DLIGHTS];
61
62 int r_numentities;
63 entity_t r_entities[MAX_ENTITIES];
64
65 int r_numviewentities;
66 entity_t r_viewentities[MAX_ENTITIES];
67
68 int r_numparticles;
69 particle_t *r_particles[MAX_PARTICLES];
70
71 lightstyle_t r_lightstyles[MAX_LIGHTSTYLES];
72
73 char cl_weaponmodels[MAX_CLIENTWEAPONMODELS][MAX_QPATH];
74 int num_cl_weaponmodels;
75
76 /*
77 ====================
78 V_ClearScene
79
80 Specifies the model that will be used as the world
81 ====================
82 */
V_ClearScene(void)83 void V_ClearScene (void)
84 {
85 r_numdlights = 0;
86 r_numentities = 0;
87 r_numviewentities = 0;
88 r_numparticles = 0;
89 }
90
91
92 /*
93 =====================
94 V_AddEntity
95
96 =====================
97 */
V_AddEntity(entity_t * ent)98 void V_AddEntity (entity_t *ent)
99 {
100 if (r_numentities >= MAX_ENTITIES)
101 return;
102 r_entities[r_numentities++] = *ent;
103 }
104
105 /*
106 =====================
107 V_AddViewEntity
108
109 =====================
110 */
V_AddViewEntity(entity_t * ent)111 void V_AddViewEntity (entity_t *ent)
112 {
113 if (r_numviewentities >= MAX_ENTITIES)
114 return;
115 r_viewentities[r_numviewentities++] = *ent;
116 }
117
118
119 /*
120 =====================
121 V_AddParticle
122
123 =====================
124 */
V_AddParticle(particle_t * p)125 void V_AddParticle (particle_t *p)
126 {
127
128 if (r_numparticles >= MAX_PARTICLES)
129 return;
130 r_particles[r_numparticles++] = p;
131 }
132
133 /*
134 =====================
135 V_AddLight
136
137 =====================
138 */
139 extern cvar_t *gl_dynamic;
V_AddLight(vec3_t org,float intensity,float r,float g,float b)140 void V_AddLight (vec3_t org, float intensity, float r, float g, float b)
141 {
142 dlight_t *dl;
143
144 if (gl_dynamic->integer == 0)
145 return;
146 if (r_numdlights >= MAX_DLIGHTS)
147 return;
148 dl = &r_dlights[r_numdlights++];
149 VectorCopy (org, dl->origin);
150 dl->intensity = intensity;
151 dl->color[0] = r;
152 dl->color[1] = g;
153 dl->color[2] = b;
154 }
155
156 /*
157 =====================
158 V_AddLightStyle
159
160 =====================
161 */
V_AddLightStyle(int style,float r,float g,float b)162 void V_AddLightStyle (int style, float r, float g, float b)
163 {
164 lightstyle_t *ls;
165
166 if (style < 0 || style > MAX_LIGHTSTYLES)
167 Com_Error (ERR_DROP, "Bad light style %i", style);
168 ls = &r_lightstyles[style];
169
170 ls->white = r+g+b;
171 ls->rgb[0] = r;
172 ls->rgb[1] = g;
173 ls->rgb[2] = b;
174 }
175
176 /*
177 ================
178 V_TestParticles
179
180 If cl_testparticles is set, create 4096 particles in the view
181 ================
182 */
183 void CL_LogoutEffect (vec3_t org, int type);
V_TestParticles(void)184 void V_TestParticles (void)
185 {
186 vec3_t org;
187
188 VectorMA (cl.refdef.vieworg, 128, cl.v_forward, org);
189 CL_LogoutEffect (org, MZ_LOGOUT);
190 }
191
192 /*
193 ================
194 V_TestEntities
195
196 If cl_testentities is set, create 32 player models
197 ================
198 */
V_TestEntities(void)199 void V_TestEntities (void)
200 {
201 int i, j;
202 float f, r;
203 entity_t *ent;
204
205 r_numentities = 32;
206 memset (r_entities, 0, sizeof(r_entities));
207
208 for (i=0 ; i<r_numentities ; i++)
209 {
210 ent = &r_entities[i];
211
212 r = 64 * ( (i%4) - 1.5 );
213 f = 64 * (i/4) + 128;
214
215 for (j=0 ; j<3 ; j++)
216 ent->origin[j] = cl.refdef.vieworg[j] + cl.v_forward[j]*f +
217 cl.v_right[j]*r;
218
219 ent->model = cl.baseclientinfo.model;
220 ent->skin = cl.baseclientinfo.skin;
221 }
222 }
223
224 /*
225 ================
226 V_TestLights
227
228 If cl_testlights is set, create 32 lights models
229 ================
230 */
V_TestLights(void)231 void V_TestLights (void)
232 {
233 int i, j;
234 float f, r;
235 dlight_t *dl;
236
237 r_numdlights = 32;
238 memset (r_dlights, 0, sizeof(r_dlights));
239
240 for (i=0 ; i<r_numdlights ; i++)
241 {
242 dl = &r_dlights[i];
243
244 r = 64 * ( (i%4) - 1.5 );
245 f = 64 * (i/4) + 128;
246
247 for (j=0 ; j<3 ; j++)
248 dl->origin[j] = cl.refdef.vieworg[j] + cl.v_forward[j]*f +
249 cl.v_right[j]*r;
250 dl->color[0] = ((i%6)+1) & 1;
251 dl->color[1] = (((i%6)+1) & 2)>>1;
252 dl->color[2] = (((i%6)+1) & 4)>>2;
253 dl->intensity = 200;
254 }
255 }
256
257 //===================================================================
258
259 /*
260 =================
261 CL_PrepRefresh
262
263 Call before entering a new level, or after changing dlls
264 =================
265 */
266 qboolean needLoadingPlaque (void);
267 extern int seconds, minutes;
CL_PrepRefresh(void)268 void CL_PrepRefresh ( void )
269 {
270 char mapname[32];
271 int i, max;
272 char name[MAX_QPATH];
273 float rotate;
274 vec3_t axis;
275 qboolean newPlaque = needLoadingPlaque();
276
277 loadingPercent = 0;
278 rocketlauncher = 0;
279 rocketlauncher_drawn = 0;
280 smartgun = 0;
281 smartgun_drawn = 0;
282 disruptor = 0;
283 disruptor_drawn = 0;
284 flamethrower = 0;
285 flamethrower_drawn = 0;
286 beamgun = 0;
287 beamgun_drawn = 0;
288 chaingun = 0;
289 chaingun_drawn = 0;
290 vaporizer = 0;
291 vaporizer_drawn = 0;
292 quad = 0;
293 quad_drawn = 0;
294 haste = 0;
295 haste_drawn = 0;
296 sproing = 0;
297 sproing_drawn = 0;
298 inv = 0;
299 inv_drawn = 0;
300 adren = 0;
301 adren_drawn = 0;
302
303 numitemicons = 0;
304
305 //reset clock
306 seconds = minutes = 0;
307
308 if (!cl.configstrings[CS_MODELS+1][0])
309 return; // no map loaded
310
311 if (newPlaque)
312 SCR_BeginLoadingPlaque();
313
314 loadingMessage = true;
315 memset( loadingMessages , 0 , sizeof( loadingMessages ) );
316 Com_sprintf (loadingMessages[0][0], CL_LOADMSG_LENGTH, "Loading map...");
317 Com_sprintf (loadingMessages[1][0], CL_LOADMSG_LENGTH, "Loading models...");
318 Com_sprintf (loadingMessages[2][0], CL_LOADMSG_LENGTH, "Loading pics...");
319 Com_sprintf (loadingMessages[3][0], CL_LOADMSG_LENGTH, "Loading clients...");
320
321 // let the render dll load the map
322 strcpy (mapname, cl.configstrings[CS_MODELS+1] + 5); // skip "maps/"
323 mapname[strlen(mapname)-4] = 0; // cut off ".bsp"
324
325 // register models, pics, and skins
326
327 //this was moved here, to prevent having a pic loaded over and over again, which was
328 //totally killing performance after a dozen or so maps.
329 // 2010-10 modified on suspicion of affecting possible compiler bug. see R_RegisterPic()
330 map_pic_loaded = false;
331 if ( R_RegisterPic( va("/levelshots/%s.pcx", mapname)) != NULL )
332 {
333 map_pic_loaded = true;
334 }
335
336 Com_Printf ("Map: %s\r", mapname);
337 Com_sprintf( loadingMessages[0][1] , CL_LOADMSG_LENGTH , "^3in progress" );
338 SCR_UpdateScreen ();
339 R_BeginRegistration (mapname);
340 Com_Printf (" \r");
341 Com_sprintf (loadingMessages[0][1], CL_LOADMSG_LENGTH, "^2done");
342 loadingPercent += 20;
343
344 // precache status bar pics
345 Com_Printf ("pics\r");
346 SCR_UpdateScreen ();
347 SCR_TouchPics ();
348 Com_Printf (" \r");
349
350 num_cl_weaponmodels = 1;
351 strcpy(cl_weaponmodels[0], "weapon.md2");
352
353 for (i=1, max=0 ; i<MAX_MODELS && cl.configstrings[CS_MODELS+i][0] ; i++)
354 max++;
355
356 for (i=1 ; i<MAX_MODELS && cl.configstrings[CS_MODELS+i][0] ; i++)
357 {
358 strcpy (name, cl.configstrings[CS_MODELS+i]);
359 // name[37] = 0; 2010-10 archaic line length truncates log lines
360
361 if (name[0] != '*')
362 {
363 Com_Printf ("%s\r", name);
364
365 //only make max of 20 chars long
366 Com_sprintf( loadingMessages[1][1] , CL_LOADMSG_LENGTH , "^1%s" , name );
367
368 //check for types
369 if(!strcmp(name, "models/weapons/g_rocket/tris.md2"))
370 rocketlauncher = 1;
371 if(!strcmp(name, "models/weapons/g_glaunch/tris.md2"))
372 rocketlauncher = 1;
373 if(!strcmp(name, "models/weapons/g_shotg2/tris.md2"))
374 chaingun = 1;
375 if(!strcmp(name, "models/weapons/g_shotg/tris.md2"))
376 smartgun = 1;
377 if(!strcmp(name, "models/weapons/g_rail/tris.md2"))
378 beamgun = 1;
379 if(!strcmp(name, "models/weapons/g_hyperb/tris.md2"))
380 disruptor = 1;
381 if(!strcmp(name, "models/weapons/g_chain/tris.md2"))
382 flamethrower = 1;
383 if(!strcmp(name, "models/weapons/g_machn/tris.md2"))
384 vaporizer = 1;
385 if(!strcmp(name, "models/weapons/g_bfg/tris.md2"))
386 vaporizer = 1;
387 if(!strcmp(name, "models/items/quaddama/tris.md2"))
388 quad = 1;
389 if(!strcmp(name, "models/items/haste/tris.md2"))
390 haste = 1;
391 if(!strcmp(name, "models/items/sproing/tris.md2"))
392 sproing = 1;
393 if(!strcmp(name, "models/items/adrenaline/tris.md2"))
394 adren = 1;
395 if(!strcmp(name, "models/items/invulner/tris.md2"))
396 inv = 1;
397 }
398
399 SCR_UpdateScreen ();
400
401 Sys_SendKeyEvents (); // pump message loop
402 if (name[0] == '#')
403 {
404 // special player weapon model
405 if (num_cl_weaponmodels < MAX_CLIENTWEAPONMODELS)
406 {
407 strncpy(cl_weaponmodels[num_cl_weaponmodels], cl.configstrings[CS_MODELS+i]+1,
408 sizeof(cl_weaponmodels[num_cl_weaponmodels]) - 1);
409 num_cl_weaponmodels++;
410
411 }
412 }
413 else
414 {
415 cl.model_draw[i] = R_RegisterModel (cl.configstrings[CS_MODELS+i]);
416 if (name[0] == '*')
417 cl.model_clip[i] = CM_InlineModel (cl.configstrings[CS_MODELS+i]);
418 else
419 cl.model_clip[i] = NULL;
420 }
421 if (name[0] != '*')
422 Com_Printf (" \r");
423
424 loadingPercent += 60.0f/(float)max;
425 }
426
427 Com_sprintf (loadingMessages[1][1], CL_LOADMSG_LENGTH, "^3precaching");
428
429 SCR_UpdateScreen ();
430
431 R_RegisterBasePlayerModels();
432 if(cl_precachecustom->value)
433 R_RegisterCustomPlayerModels();
434
435 Com_sprintf (loadingMessages[1][1], CL_LOADMSG_LENGTH, "^2done");
436
437 Com_Printf ("images\r", i);
438 SCR_UpdateScreen ();
439
440 for (i=1, max=0 ; i<MAX_IMAGES && cl.configstrings[CS_IMAGES+i][0] ; i++)
441 max++;
442
443 for (i=1 ; i<MAX_IMAGES && cl.configstrings[CS_IMAGES+i][0] ; i++)
444 {
445 cl.image_precache[i] = R_RegisterPic (cl.configstrings[CS_IMAGES+i]);
446 Sys_SendKeyEvents (); // pump message loop
447 loadingPercent += 10.0f/(float)max;
448 }
449 Com_sprintf (loadingMessages[2][1], CL_LOADMSG_LENGTH, "^2done");
450
451 Com_Printf (" \r");
452
453 //refresh the player model/skin info
454 CL_LoadClientinfo (&cl.baseclientinfo, va("unnamed\\%s\\%s", DEFAULTMODEL, DEFAULTSKIN));
455
456 for (i=1, max=0 ; i<MAX_CLIENTS ; i++)
457 if (cl.configstrings[CS_PLAYERSKINS+i][0])
458 max++;
459
460 for (i=0 ; i<MAX_CLIENTS ; i++)
461 {
462 if (!cl.configstrings[CS_PLAYERSKINS+i][0])
463 continue;
464
465 Com_sprintf (loadingMessages[3][1], CL_LOADMSG_LENGTH, "^3%i" , i);
466 Com_Printf ("client %i\r", i);
467 SCR_UpdateScreen ();
468 Sys_SendKeyEvents (); // pump message loop
469
470 CL_ParseClientinfo (i);
471 Com_Printf (" \r");
472 loadingPercent += 10.0f/(float)max;
473 }
474 Com_sprintf (loadingMessages[3][1], CL_LOADMSG_LENGTH, "^2done");
475
476 //hack hack hack - psychospaz
477 loadingPercent = 100;
478
479 // set sky textures and speed
480 Com_Printf ("sky\r", i);
481 SCR_UpdateScreen ();
482 rotate = atof (cl.configstrings[CS_SKYROTATE]);
483 sscanf( cl.configstrings[CS_SKYAXIS], "%f %f %f",
484 &axis[0], &axis[1], &axis[2]);
485 R_SetSky( cl.configstrings[CS_SKY], rotate, axis );
486 Com_Printf (" \r");
487
488 // the renderer can now free unneeded stuff
489 R_EndRegistration ();
490
491 // clear any lines of console text
492 CON_ClearNotify( );
493
494 SCR_UpdateScreen ();
495 cl.refresh_prepped = true;
496 cl.force_refdef = true; // make sure we have a valid refdef
497
498 // start background music
499 background_music = Cvar_Get ("background_music", "1", CVAR_ARCHIVE);
500 S_StartMapMusic();
501
502 //loadingMessage = false;
503 rocketlauncher = 0;
504 rocketlauncher_drawn = 0;
505 smartgun = 0;
506 smartgun_drawn = 0;
507 disruptor = 0;
508 disruptor_drawn = 0;
509 flamethrower = 0;
510 flamethrower_drawn = 0;
511 beamgun = 0;
512 beamgun_drawn = 0;
513 chaingun = 0;
514 chaingun_drawn = 0;
515 vaporizer = 0;
516 vaporizer_drawn = 0;
517 quad = 0;
518 quad_drawn = 0;
519 haste = 0;
520 haste_drawn = 0;
521 sproing = 0;
522 sproing_drawn = 0;
523 inv = 0;
524 inv_drawn = 0;
525 adren = 0;
526 adren_drawn = 0;
527 numitemicons = 0;
528
529 if (newPlaque)
530 SCR_EndLoadingPlaque();
531 else
532 Cvar_Set ("paused", "0");
533 }
534
535 /*
536 ====================
537 CalcFov
538 ====================
539 */
CalcFov(float fov_x,float width,float height)540 float CalcFov (float fov_x, float width, float height)
541 {
542 float a;
543 float x;
544
545 if (fov_x < 1 || fov_x > 179)
546 Com_Error (ERR_DROP, "Bad fov: %f", fov_x);
547
548 x = width/tanf(fov_x/360*M_PI);
549 a = atan (height/x);
550 a = a*360/M_PI;
551
552 return a;
553 }
554
555 /*
556 =================
557 SCR_DrawCrosshair
558 =================
559 */
560 extern cvar_t *hand;
SCR_DrawCrosshair(refdef_t * fd)561 void SCR_DrawCrosshair (refdef_t *fd)
562 {
563 int x, y, crosshairposition;
564
565 if (!strcmp(crosshair->string, "none"))
566 return;
567
568 if (crosshair->modified)
569 {
570 crosshair->modified = false;
571 SCR_TouchPics ();
572 }
573
574 if (!crosshair_pic[0])
575 return;
576
577 x = fd->x + ((fd->width - crosshair_width)>>1);
578 y = fd->y + ((fd->height - crosshair_height)>>1);
579
580 // get rid of the old crosshair adjustment built into the texture
581 x -= 4;
582 y -= 4;
583
584 // add a new crosshair adjustment offset
585 crosshairposition = cl.frame.playerstate.stats[STAT_FLAGS] & STAT_FLAGS_CROSSHAIRPOSITION;
586 if (crosshairposition != STAT_FLAGS_CROSSHAIRCENTER)
587 {
588 double x_offs, y_offs;
589 switch (crosshairposition)
590 {
591 default: // other crosshair positions reserved for future use
592 case STAT_FLAGS_CROSSHAIRPOS1: // use the original default
593 x_offs = y_offs = 4.0;
594 break;
595 case STAT_FLAGS_CROSSHAIRPOS2:
596 x_offs = 2.0;
597 y_offs = 3.0;
598 break;
599 }
600 y_offs *= (double)fd->height/480.0;
601 x_offs *= (double)fd->width/640.0;
602 if (y_offs-(int)y_offs >= 0.5)
603 y_offs = (int)y_offs + 1;
604 if (x_offs-(int)x_offs >= 0.5)
605 x_offs = (int)x_offs + 1;
606 if (hand->integer == 1)
607 x_offs = -x_offs;
608 else if (hand->integer == 2)
609 x_offs = 0;
610 x += x_offs;
611 y += y_offs;
612 }
613
614 Draw_Pic (x, y, crosshair_pic);
615 }
616
InFront(vec3_t target)617 qboolean InFront (vec3_t target)
618 {
619 vec3_t vec;
620 float dot;
621 vec3_t forward;
622
623 AngleVectors (cl.refdef.viewangles, forward, NULL, NULL);
624 VectorSubtract (target, cl.refdef.vieworg, vec);
625 VectorNormalize (vec);
626 dot = DotProduct (vec, forward);
627
628 if (dot > 0.3)
629 return true;
630 return false;
631 }
632 //==============
633 //SCR_DrawPlayerNamesCenter
634 // shows player names at center of screen
635 //==============
SCR_DrawPlayerNamesCenter(void)636 void SCR_DrawPlayerNamesCenter( void )
637 {
638 static vec3_t mins = { -8, -8, -8 };
639 static vec3_t maxs = { 8, 8, 8 };
640 FNT_font_t font;
641 struct FNT_window_s box;
642 int i;
643 centity_t * cent;
644 float dist, mindist;
645 trace_t trace;
646 vec3_t vecdist;
647 vec3_t temp;
648 vec3_t axis[3];
649 int closest;
650
651 if( !cl_showPlayerNames->integer )
652 return;
653
654 mindist = 1000;
655 closest = 0;
656
657 for( i = 0; i < MAX_CLIENTS; i++ )
658 {
659 cent = cl_entities + i + 1;
660
661 if( !cent->current.modelindex )
662 continue;
663
664 if(!strcmp(cl.clientinfo[i].name, name->string))
665 continue;
666
667 trace = CL_Trace ( cl.refdef.vieworg, mins, maxs, cent->current.origin, -1, MASK_PLAYERSOLID, true, NULL);
668 if (trace.fraction != 1.0)
669 continue;
670
671 VectorSubtract(cent->current.origin, cl.refdef.vieworg, vecdist);
672 dist = VectorLength(vecdist);
673
674 if (dist >= 1000)
675 continue;
676
677 if(dist < mindist && (strlen(cl.clientinfo[i].name) > 1) && InFront(cent->current.origin) ) {
678 mindist = dist;
679 closest = i;
680 }
681
682 VectorSubtract (cent->current.origin, cl.refdef.vieworg, temp);
683 VectorNormalize (temp);
684
685 AngleVectors(cl.refdef.viewangles, axis[0], axis[1], axis[2]);
686
687 if (DotProduct (temp, axis[0]) < 0)
688 continue;
689 }
690
691 if (!closest) {
692 return;
693 }
694
695 font = FNT_AutoGet( CL_gameFont );
696 box.x = (int)( ( cl.refdef.width - 200 ) / 2 );
697 box.y = (int)( cl.refdef.height / 1.8 );
698 box.width = 400;
699 box.height = 0;
700 FNT_BoundedPrint( font , cl.clientinfo[closest].name , FNT_CMODE_QUAKE_SRS ,
701 FNT_ALIGN_CENTER , &box , FNT_colors[ 2 ] );
702
703 }
704
705 //==============
706 //SCR_DrawPlayerNames
707 // shows player names at their feets.
708 //==============
709 extern void R_TransformVectorToScreen( refdef_t *rd, vec3_t in, vec2_t out );
SCR_DrawPlayerNames(void)710 void SCR_DrawPlayerNames( void )
711 {
712 // static vec4_t whiteTransparent = { 1.0f, 1.0f, 1.0f, 0.5f };
713 FNT_font_t font;
714 int i;
715 centity_t * cent;
716 float dist;
717 trace_t trace;
718 vec2_t screen_pos;
719 vec3_t vecdist;
720 vec3_t temp;
721 vec3_t axis[3];
722 static vec3_t mins = { -4, -4, -4 };
723 static vec3_t maxs = { 4, 4, 4 };
724
725 font = FNT_AutoGet( CL_gameFont );
726 for( i = 0; i < MAX_CLIENTS; i++ )
727 {
728 struct FNT_window_s box;
729
730 cent = cl_entities + i + 1;
731
732 if( !cent->current.modelindex )
733 continue;
734
735 if(!strcmp(cl.clientinfo[i].name, name->string))
736 continue;
737
738 trace = CL_Trace ( cl.refdef.vieworg, mins, maxs, cent->current.origin, -1, MASK_PLAYERSOLID, true, NULL);
739 if (trace.fraction != 1.0)
740 continue;
741
742 VectorSubtract(cent->current.origin, cl.refdef.vieworg, vecdist);
743 dist = VectorLength(vecdist);
744
745 if (dist >= 1000 || !InFront(cent->current.origin))
746 continue;
747
748 VectorSubtract (cent->current.origin, cl.refdef.vieworg, temp);
749 VectorNormalize (temp);
750
751 AngleVectors(cl.refdef.viewangles, axis[0], axis[1], axis[2]);
752
753 if (DotProduct (temp, axis[0]) < 0)
754 continue;
755
756 R_TransformVectorToScreen(&cl.refdef, cent->current.origin, screen_pos);
757 box.x = (int)screen_pos[0];
758 box.y = cl.refdef.height-(int)screen_pos[1]-cl.refdef.height/6;
759 box.width = box.height = 0;
760 FNT_BoundedPrint( font , cl.clientinfo[i].name , FNT_CMODE_QUAKE_SRS ,
761 FNT_ALIGN_LEFT , &box , FNT_colors[ 2 ] );
762
763 }
764 }
765
SCR_DrawBases(void)766 void SCR_DrawBases (void)
767 {
768 FNT_font_t font;
769 int i;
770 entity_t * ent;
771 vec2_t screen_pos;
772
773 font = FNT_AutoGet( CL_gameFont );
774 for (i=0 ; i<cl.refdef.num_entities; i++)
775 {
776 struct FNT_window_s box;
777 const char * str;
778
779 ent = &r_entities[i];
780 if(!ent->team)
781 continue;
782 if (!InFront(ent->origin))
783 continue;
784
785 R_TransformVectorToScreen(&cl.refdef, ent->origin, screen_pos);
786 box.x = (int)screen_pos[0];
787 box.y = cl.refdef.height-(int)screen_pos[1]-cl.refdef.height/6;
788 box.width = box.height = 0;
789
790 if(ent->team == 2)
791 str = "^4Blue Flag";
792 else if(ent->team == 1)
793 str = "^1Red Flag";
794 else
795 str = "Flag";
796 FNT_BoundedPrint( font , str , FNT_CMODE_QUAKE_SRS , FNT_ALIGN_LEFT , &box , FNT_colors[ 2 ] );
797 }
798 }
799
800 /*
801 ==================
802 V_RenderView
803
804 ==================
805 */
806 extern cvar_t *scr_netgraph;
807 extern cvar_t *scr_timegraph;
808 extern cvar_t *scr_debuggraph;
809 extern cvar_t *scr_graphheight;
V_RenderView(float stereo_separation)810 void V_RenderView( float stereo_separation )
811 {
812 extern int entitycmpfnc( const entity_t *, const entity_t * );
813
814 if (cls.state != ca_active)
815 return;
816
817 if (!cl.refresh_prepped)
818 return; // still loading
819
820 if ( cl_timedemo && cl_timedemo->integer )
821 {
822 if ( cl.timedemo_start > 0 )
823 { /* frame counter increment for timedemo benchmark */
824 cl.timedemo_frames++;
825 }
826 else
827 { /* time demo start trigger */
828 cl.timedemo_start = Sys_Milliseconds ();
829 cl.timedemo_frames = 0;
830 }
831 }
832
833 // an invalid frame will just use the exact previous refdef
834 // we can't use the old frame if the video mode has changed, though...
835 if ( cl.frame.valid && (cl.force_refdef || !cl_paused->value) )
836 {
837 cl.force_refdef = false;
838
839 // build a refresh entity list and calc cl.sim*
840 // this also calls CL_CalcViewValues which loads
841 // v_forward, etc.
842 CL_AddEntities ();
843
844 if (cl_testparticles->value)
845 V_TestParticles ();
846 if (cl_testentities->value)
847 V_TestEntities ();
848 if (cl_testlights->value)
849 V_TestLights ();
850 if (cl_testblend->value)
851 {
852 cl.refdef.blend[0] = 1;
853 cl.refdef.blend[1] = 0.5;
854 cl.refdef.blend[2] = 0.25;
855 cl.refdef.blend[3] = 0.5;
856 }
857
858 // offset vieworg appropriately if we're doing stereo separation
859 if ( stereo_separation != 0 )
860 {
861 vec3_t tmp;
862
863 VectorScale( cl.v_right, stereo_separation, tmp );
864 VectorAdd( cl.refdef.vieworg, tmp, cl.refdef.vieworg );
865 }
866
867 // never let it sit exactly on a node line, because a water plane can
868 // dissapear when viewed with the eye exactly on it.
869 // the server protocol only specifies to 1/8 pixel, so add 1/16 in each axis
870 cl.refdef.vieworg[0] += 1.0/16;
871 cl.refdef.vieworg[1] += 1.0/16;
872 cl.refdef.vieworg[2] += 1.0/16;
873
874 cl.refdef.x = scr_vrect.x;
875 cl.refdef.y = scr_vrect.y;
876 cl.refdef.width = scr_vrect.width;
877 cl.refdef.height = scr_vrect.height;
878
879 if (scr_debuggraph->integer || scr_timegraph->integer || scr_netgraph->integer)
880 cl.refdef.height -= scr_graphheight->integer;
881
882 cl.refdef.fov_y = CalcFov (cl.refdef.fov_x, cl.refdef.width, cl.refdef.height);
883 cl.refdef.time = cl.time*0.001;
884
885 cl.refdef.areabits = cl.frame.areabits;
886
887 if (!cl_add_entities->value) {
888 r_numentities = 0;
889 r_numviewentities = 0;
890 }
891 if (!cl_add_particles->value)
892 r_numparticles = 0;
893 if (!cl_add_lights->value)
894 r_numdlights = 0;
895 if (!cl_add_blend->value)
896 {
897 Vector4Clear (cl.refdef.blend);
898 }
899
900 cl.refdef.num_entities = r_numentities;
901 cl.refdef.entities = r_entities;
902 cl.refdef.num_viewentities = r_numviewentities;
903 cl.refdef.viewentities = r_viewentities;
904 cl.refdef.num_particles = r_numparticles;
905 cl.refdef.particles = r_particles;
906 cl.refdef.num_dlights = r_numdlights;
907 cl.refdef.dlights = r_dlights;
908 cl.refdef.lightstyles = r_lightstyles;
909 cl.refdef.num_grasses = r_numgrasses;
910 cl.refdef.grasses = r_grasses;
911 cl.refdef.num_beams = r_numbeams;
912 cl.refdef.beams = r_beams;
913
914 cl.refdef.rdflags = cl.frame.playerstate.rdflags;
915
916 // sort entities for better cache locality
917 qsort( cl.refdef.entities, cl.refdef.num_entities, sizeof( cl.refdef.entities[0] ), (int (*)(const void *, const void *))entitycmpfnc );
918
919 V_ClearScene ();
920 }
921
922 cl.refdef.rdflags |= RDF_BLOOM; //BLOOMS
923
924 R_VCFreeFrame();
925 need_free_vbo = false;
926
927 R_RenderFrame (&cl.refdef);
928 if (cl_stats->value)
929 Com_Printf ("ent:%i lt:%i part:%i\n", r_numentities, r_numdlights, r_numparticles);
930 if ( log_stats->value && ( log_stats_file != 0 ) )
931 fprintf( log_stats_file, "%i,%i,%i,",r_numentities, r_numdlights, r_numparticles);
932
933
934 SCR_DrawCrosshair (&cl.refdef);
935
936 if(cl_showPlayerNames->integer) {
937 if(cl_showPlayerNames->integer == 2)
938 SCR_DrawPlayerNames();
939 else
940 SCR_DrawPlayerNamesCenter();
941
942 SCR_DrawBases();
943 }
944
945 }
946
947 /**
948 * @brief Console output of position and orientation
949 *
950 * Target of 'viewpos' command. Modified 2011-02. Added pitch.
951 * Helps with repeatable positioning for timerefresh command
952 * and other performance testing.
953 */
V_Viewpos_f(void)954 void V_Viewpos_f (void)
955 {
956 Com_Printf ("x:%#1.0f y:%#1.0f z:%#1.0f yaw:%#1.0f pitch:%#1.0f\n",
957 cl.refdef.vieworg[0], cl.refdef.vieworg[1], cl.refdef.vieworg[2],
958 cl.refdef.viewangles[YAW], cl.refdef.viewangles[PITCH] );
959 }
960
961 /*
962 =============
963 V_Init
964 =============
965 */
V_Init(void)966 void V_Init (void)
967 {
968 Cmd_AddCommand ("viewpos", V_Viewpos_f);
969
970 crosshair = Cvar_Get ("crosshair", "0", CVAR_ARCHIVE);
971
972 cl_testblend = Cvar_Get ("cl_testblend", "0", 0);
973 cl_testparticles = Cvar_Get ("cl_testparticles", "0", 0);
974 cl_testentities = Cvar_Get ("cl_testentities", "0", 0);
975 cl_testlights = Cvar_Get ("cl_testlights", "0", 0);
976
977 cl_stats = Cvar_Get ("cl_stats", "0", 0);
978 }
979