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