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 #include "client.h"
23 
24 //=============
25 //
26 // development tools for weapons
27 //
28 int			gun_frame;
29 struct model_s	*gun_model;
30 struct model_s	*clientGun;
31 extern cvar_t	*skin;
32 
33 //=============
34 
35 cvar_t		*crosshair;
36 cvar_t		*crosshair_scale;
37 cvar_t		*gl_transrendersort;
38 cvar_t		*gl_particle_lighting;
39 cvar_t		*gl_particle_min;
40 cvar_t		*gl_particle_max;
41 cvar_t		*cl_testparticles;
42 cvar_t		*cl_testentities;
43 cvar_t		*cl_testlights;
44 cvar_t		*cl_testblend;
45 
46 cvar_t		*cl_stats;
47 
48 cvar_t		*hand;
49 
50 
51 int			r_numdlights;
52 dlight_t	r_dlights[MAX_DLIGHTS];
53 
54 int			r_numentities;
55 entity_t	r_entities[MAX_ENTITIES];
56 
57 int			r_numparticles;
58 particle_t	r_particles[MAX_PARTICLES];
59 
60 lightstyle_t	r_lightstyles[MAX_LIGHTSTYLES];
61 
62 char cl_weaponmodels[MAX_CLIENTWEAPONMODELS][MAX_QPATH];
63 int num_cl_weaponmodels;
64 
65 
66 
67 /*
68 ====================
69 CL_Trace
70 
71 ====================
72 */
73 
CL_Trace(vec3_t start,vec3_t end,float size,int contentmask)74 trace_t CL_Trace (vec3_t start, vec3_t end, float size,  int contentmask)
75 {
76 	vec3_t maxs, mins;
77 
78 	VectorSet(maxs, size, size, size);
79 	VectorSet(mins, -size, -size, -size);
80 
81 	return CM_BoxTrace (start, end, mins, maxs, 0, contentmask);
82 }
83 
84 /*
85 ====================
86 V_ClearScene
87 
88 Specifies the model that will be used as the world
89 ====================
90 */
V_ClearScene(void)91 void V_ClearScene (void)
92 {
93 	r_numdlights = 0;
94 	r_numentities = 0;
95 	r_numparticles = 0;
96 }
97 
98 /*
99 =====================
100 3D Cam Stuff -psychospaz
101 
102 =====================
103 */
104 
105 #define CAM_MAXALPHADIST 0.000111
106 
107 float viewermodelalpha;
108 
AddViewerEntAlpha(entity_t * ent)109 void AddViewerEntAlpha (entity_t *ent)
110 {
111 	if (viewermodelalpha==1 || !cl_3dcam_alpha->value)
112 		return;
113 
114 	ent->alpha *= viewermodelalpha;
115 	if (ent->alpha<.9)
116 		ent->flags |= RF_TRANSLUCENT;
117 }
118 
119 #define ANGLEMAX 90.0
CalcViewerCamTrans(float distance)120 void CalcViewerCamTrans (float distance)
121 {
122 	float alphacalc = cl_3dcam_dist->value;
123 
124 	//no div by 0
125 	if (alphacalc<1)
126 		alphacalc=1;
127 
128 	viewermodelalpha = distance/alphacalc;
129 
130 	if (viewermodelalpha>1)
131 		viewermodelalpha = 1;
132 }
133 
134 /*
135 =====================
136 V_AddEntity
137 
138 =====================
139 */
V_AddEntity(entity_t * ent)140 void V_AddEntity (entity_t *ent)
141 {
142 	if (ent->flags&RF_VIEWERMODEL) //here is our client
143 	{
144 		int i;
145 		vec3_t oldorgdiff;
146 
147 		VectorSubtract(ent->oldorigin, ent->origin, oldorgdiff);
148 
149 		//what was i thinking before!?
150 		for (i=0;i<3;i++)
151 			clientOrg[i] = ent->oldorigin[i] = ent->origin[i] = cl.predicted_origin[i];
152 
153 		VectorAdd(ent->oldorigin, oldorgdiff, ent->oldorigin);
154 
155 		if (hand->value==1) //lefthanded
156 		{
157 			ent->renderfx |= RF_MIRRORMODEL;
158 		}
159 
160 		//saber hack
161 		if (ent->renderfx&RF2_CAMERAMODEL)
162 			ent->flags&=~RF_VIEWERMODEL;
163 
164 		if (cl_3dcam->value && !(cl.attractloop && !(cl.cinematictime > 0 && cls.realtime - cl.cinematictime > 1000)))
165 		{
166 			AddViewerEntAlpha(ent);
167 			ent->flags&=~RF_VIEWERMODEL;
168 			ent->renderfx|=RF2_FORCE_SHADOW|RF2_CAMERAMODEL;
169 		}
170 		else if (ent->renderfx&RF2_CAMERAMODEL)
171 		{
172 			ent->flags &= ~RF_VIEWERMODEL;
173 			ent->renderfx|=RF2_FORCE_SHADOW|RF2_CAMERAMODEL;
174 		}
175 	}
176 
177 	if (r_numentities >= MAX_ENTITIES)
178 		return;
179 	r_entities[r_numentities++] = *ent;
180 }
181 
182 
183 /*
184 =====================
185 V_AddParticle
186 
187 =====================
188 */
V_AddParticle(vec3_t org,vec3_t angle,vec3_t color,float alpha,int alpha_src,int alpha_dst,float size,int image,int flags,decalpolys_t * decal)189 void V_AddParticle (vec3_t org, vec3_t angle, vec3_t color, float alpha, int alpha_src, int alpha_dst, float size, int image, int flags, decalpolys_t *decal)
190 {
191 	int i;
192 	particle_t	*p;
193 
194 	if (r_numparticles >= MAX_PARTICLES)
195 		return;
196 	p = &r_particles[r_numparticles++];
197 
198 	for (i=0;i<3;i++)
199 	{
200 		p->origin[i] = org[i];
201 		p->angle[i] = angle[i];
202 	}
203 	p->red = color[0];
204 	p->green = color[1];
205 	p->blue = color[2];
206 	p->alpha = alpha;
207 	p->image = image;
208 	p->flags = flags;
209 	p->size  = size;
210 	p->decal = decal;
211 
212 	p->blendfunc_src = alpha_src;
213 	p->blendfunc_dst = alpha_dst;
214 }
215 
216 /*
217 =====================
218 V_AddLight
219 
220 =====================
221 */
V_AddLight(vec3_t org,float intensity,float r,float g,float b)222 void V_AddLight (vec3_t org, float intensity, float r, float g, float b)
223 {
224 	dlight_t	*dl;
225 
226 	if (r_numdlights >= MAX_DLIGHTS)
227 		return;
228 	dl = &r_dlights[r_numdlights++];
229 	VectorCopy (org, dl->origin);
230 	VectorCopy (vec3_origin, dl->direction);
231 	dl->intensity = intensity;
232 	dl->color[0] = r;
233 	dl->color[1] = g;
234 	dl->color[2] = b;
235 
236 	dl->spotlight = false;
237 }
238 
239 
240 /*
241 =====================
242 V_AddSpotLight
243 
244 =====================
245 */
V_AddSpotLight(vec3_t org,vec3_t direction,float intensity,float r,float g,float b)246 void V_AddSpotLight (vec3_t org, vec3_t direction, float intensity, float r, float g, float b)
247 {
248 	dlight_t	*dl;
249 
250 	if (r_numdlights >= MAX_DLIGHTS)
251 		return;
252 	dl = &r_dlights[r_numdlights++];
253 	VectorCopy (org, dl->origin);
254 	VectorCopy(direction, dl->direction);
255 	dl->intensity = intensity;
256 	dl->color[0] = r;
257 	dl->color[1] = g;
258 	dl->color[2] = b;
259 
260 	dl->spotlight=true;
261 }
262 
263 
264 /*
265 =====================
266 V_AddLightStyle
267 
268 =====================
269 */
V_AddLightStyle(int style,float r,float g,float b)270 void V_AddLightStyle (int style, float r, float g, float b)
271 {
272 	lightstyle_t	*ls;
273 
274 	if (style < 0 || style > MAX_LIGHTSTYLES)
275 		Com_Error (ERR_DROP, "Bad light style %i", style);
276 	ls = &r_lightstyles[style];
277 
278 	ls->white = r+g+b;
279 	ls->rgb[0] = r;
280 	ls->rgb[1] = g;
281 	ls->rgb[2] = b;
282 }
283 
284 /*
285 ================
286 V_TestParticles
287 
288 If cl_testparticles is set, create 4096 particles in the view
289 ================
290 */
V_TestParticles(void)291 void V_TestParticles (void)
292 {
293 	particle_t	*p;
294 	int			i, j;
295 	float		d, r, u;
296 
297 	r_numparticles = MAX_PARTICLES;
298 	for (i=0 ; i<r_numparticles ; i++)
299 	{
300 		d = i*0.25;
301 		r = 4*((i&7)-3.5);
302 		u = 4*(((i>>3)&7)-3.5);
303 		p = &r_particles[i];
304 
305 		for (j=0 ; j<3 ; j++)
306 			p->origin[j] = cl.refdef.vieworg[j] + cl.v_forward[j]*d +
307 			cl.v_right[j]*r + cl.v_up[j]*u;
308 
309 		p->color = 8;
310 		p->alpha = cl_testparticles->value;
311 	}
312 }
313 
314 /*
315 ================
316 V_TestEntities
317 
318 If cl_testentities is set, create 32 player models
319 ================
320 */
V_TestEntities(void)321 void V_TestEntities (void)
322 {
323 	int			i, j;
324 	float		f, r;
325 	entity_t	*ent;
326 
327 	r_numentities = 32;
328 	memset (r_entities, 0, sizeof(r_entities));
329 
330 	for (i=0 ; i<r_numentities ; i++)
331 	{
332 		ent = &r_entities[i];
333 
334 		r = 64 * ( (i%4) - 1.5 );
335 		f = 64 * (i/4) + 128;
336 
337 		for (j=0 ; j<3 ; j++)
338 			ent->origin[j] = cl.refdef.vieworg[j] + cl.v_forward[j]*f +
339 			cl.v_right[j]*r;
340 
341 		ent->model = cl.baseclientinfo.model;
342 		ent->skin = cl.baseclientinfo.skin;
343 	}
344 }
345 
346 /*
347 ================
348 V_TestLights
349 
350 If cl_testlights is set, create 32 lights models
351 ================
352 */
V_TestLights(void)353 void V_TestLights (void)
354 {
355 	int			i, j;
356 	float		f, r;
357 	dlight_t	*dl;
358 
359 	r_numdlights = 32;
360 	memset (r_dlights, 0, sizeof(r_dlights));
361 
362 	for (i=0 ; i<r_numdlights ; i++)
363 	{
364 		dl = &r_dlights[i];
365 
366 		r = 64 * ( (i%4) - 1.5 );
367 		f = 64 * (i/4) + 128;
368 
369 		for (j=0 ; j<3 ; j++)
370 			dl->origin[j] = cl.refdef.vieworg[j] + cl.v_forward[j]*f +
371 			cl.v_right[j]*r;
372 		dl->color[0] = ((i%6)+1) & 1;
373 		dl->color[1] = (((i%6)+1) & 2)>>1;
374 		dl->color[2] = (((i%6)+1) & 4)>>2;
375 		dl->intensity = 200;
376 		dl->spotlight=true;
377 	}
378 }
379 
380 //===================================================================
381 
382 /*
383 =================
384 CL_PrepRefresh
385 
386 Call before entering a new level, or after changing dlls
387 =================
388 */
389 qboolean needLoadingPlaque (void);
CL_PrepRefresh()390 void CL_PrepRefresh ()
391 {
392 	char		mapname[32];
393 	int			i, max;
394 	char		name[MAX_QPATH];
395 	float		rotate;
396 	vec3_t		axis;
397 	qboolean	newPlaque = needLoadingPlaque();
398 
399 	if (!cl.configstrings[CS_MODELS+1][0])
400 		return;		// no map loaded
401 
402 	if (newPlaque)
403 		SCR_BeginLoadingPlaque();
404 
405 	loadingMessage = true;
406 	Com_sprintf (loadingMessages[0], sizeof(loadingMessages[0]), "^2loading map...");
407 	Com_sprintf (loadingMessages[1], sizeof(loadingMessages[1]), "^2loading models...");
408 	Com_sprintf (loadingMessages[2], sizeof(loadingMessages[2]), "^2loading pics...");
409 	Com_sprintf (loadingMessages[3], sizeof(loadingMessages[3]), "^2loading clients...");
410 	loadingPercent = 0;
411 
412 	SCR_AddDirtyPoint (0, 0);
413 	SCR_AddDirtyPoint (viddef.width-1, viddef.height-1);
414 
415 	// let the render dll load the map
416 	strcpy (mapname, cl.configstrings[CS_MODELS+1] + 5);	// skip "maps/"
417 	mapname[strlen(mapname)-4] = 0;		// cut off ".bsp"
418 
419 	// register models, pics, and skins
420 	Com_Printf ("Map: %s\r", mapname);
421 	SCR_UpdateScreen ();
422 	re.BeginRegistration (mapname);
423 	Com_Printf ("                                     \r");
424 	Com_sprintf (loadingMessages[0], sizeof(loadingMessages[0]), "^i^0loading map...done");
425 	loadingPercent += 20;
426 
427 	// precache status bar pics
428 	Com_Printf ("pics\r");
429 	SCR_UpdateScreen ();
430 	SCR_TouchPics ();
431 	Com_Printf ("                                     \r");
432 
433 	CL_RegisterTEntModels ();
434 
435 	num_cl_weaponmodels = 1;
436 	strcpy(cl_weaponmodels[0], "weapon.md2");
437 
438 	for (i=1, max=0 ; i<MAX_MODELS && cl.configstrings[CS_MODELS+i][0] ; i++)
439 		max++;
440 	for (i=1 ; i<MAX_MODELS && cl.configstrings[CS_MODELS+i][0] ; i++)
441 	{
442 		strcpy (name, cl.configstrings[CS_MODELS+i]);
443 		name[37] = 0;	// never go beyond one line
444 		if (name[0] != '*')
445 		{
446 			Com_Printf ("%s\r", name);
447 
448 			//only make max of 20 chars long
449 			Com_sprintf (loadingMessages[1], sizeof(loadingMessages[1]), "^2loading models...%s",
450 				(strlen(name)>20)? &name[strlen(name)-20]: name);
451 		}
452 
453 		SCR_UpdateScreen ();
454 		Sys_SendKeyEvents ();	// pump message loop
455 		if (name[0] == '#')
456 		{
457 			// special player weapon model
458 			if (num_cl_weaponmodels < MAX_CLIENTWEAPONMODELS)
459 			{
460 				strncpy(cl_weaponmodels[num_cl_weaponmodels], cl.configstrings[CS_MODELS+i]+1,
461 					sizeof(cl_weaponmodels[num_cl_weaponmodels]) - 1);
462 				num_cl_weaponmodels++;
463 			}
464 		}
465 		else
466 		{
467 			cl.model_draw[i] = re.RegisterModel (cl.configstrings[CS_MODELS+i]);
468 			if (name[0] == '*')
469 				cl.model_clip[i] = CM_InlineModel (cl.configstrings[CS_MODELS+i]);
470 			else
471 				cl.model_clip[i] = NULL;
472 		}
473 		if (name[0] != '*')
474 			Com_Printf ("                                     \r");
475 
476 		loadingPercent += 60.0f/(float)max;
477 	}
478 	Com_sprintf (loadingMessages[1], sizeof(loadingMessages[1]), "^i^0loading models...done");
479 
480 	Com_Printf ("images\r", i);
481 	SCR_UpdateScreen ();
482 
483 	for (i=1, max=0 ; i<MAX_IMAGES && cl.configstrings[CS_IMAGES+i][0] ; i++)
484 		max++;
485 	for (i=1 ; i<MAX_IMAGES && cl.configstrings[CS_IMAGES+i][0] ; i++)
486 	{
487 		cl.image_precache[i] = re.RegisterPic (cl.configstrings[CS_IMAGES+i]);
488 		Sys_SendKeyEvents ();	// pump message loop
489 		loadingPercent += 10.0f/(float)max;
490 	}
491 	Com_sprintf (loadingMessages[2], sizeof(loadingMessages[2]), "^i^0loading pics...done");
492 
493 	Com_Printf ("                                     \r");
494 
495 	//refresh the player model/skin info
496 	CL_LoadClientinfo (&cl.baseclientinfo, va("unnamed\\%s\\%s", DEFAULTMODEL, DEFAULTSKIN));
497 
498 	for (i=1, max=0 ; i<MAX_CLIENTS ; i++)
499 		if (cl.configstrings[CS_PLAYERSKINS+i][0])
500 			max++;
501 	for (i=0 ; i<MAX_CLIENTS ; i++)
502 	{
503 		if (!cl.configstrings[CS_PLAYERSKINS+i][0])
504 			continue;
505 
506 		Com_sprintf (loadingMessages[3], sizeof(loadingMessages[3]), "^2loading clients...%i", i);
507 		Com_Printf ("client %i\r", i);
508 		SCR_UpdateScreen ();
509 		Sys_SendKeyEvents ();	// pump message loop
510 		CL_ParseClientinfo (i);
511 		Com_Printf ("                                     \r");
512 		loadingPercent += 10.0f/(float)max;
513 	}
514 	Com_sprintf (loadingMessages[3], sizeof(loadingMessages[3]), "^i^0loading clients...done");
515 
516 	//hack hack hack - psychospaz
517 	loadingPercent = 100;
518 
519 	// set sky textures and speed
520 	Com_Printf ("sky\r", i);
521 	SCR_UpdateScreen ();
522 	rotate = atof (cl.configstrings[CS_SKYROTATE]);
523 	sscanf (cl.configstrings[CS_SKYAXIS], "%f %f %f",
524 		&axis[0], &axis[1], &axis[2]);
525 	re.SetSky (cl.configstrings[CS_SKY], rotate, axis);
526 	Com_Printf ("                                     \r");
527 
528 	// the renderer can now free unneeded stuff
529 	re.EndRegistration ();
530 
531 	// clear any lines of console text
532 	Con_ClearNotify ();
533 
534 	SCR_UpdateScreen ();
535 	cl.refresh_prepped = true;
536 	cl.force_refdef = true;	// make sure we have a valid refdef
537 
538 	// start the cd track
539 	CDAudio_Play (atoi(cl.configstrings[CS_CDTRACK]), true);
540 
541 	loadingMessage = false;
542 
543 	if (newPlaque)
544 		SCR_EndLoadingPlaque();
545 	else
546 		Cvar_Set ("paused", "0");
547 }
548 
549 /*
550 ====================
551 CalcFov
552 ====================
553 */
CalcFov(float fov_x,float width,float height)554 float CalcFov (float fov_x, float width, float height)
555 {
556 	float	a;
557 	float	x;
558 
559 	if (fov_x < 1 || fov_x > 179)
560 		Com_Error (ERR_DROP, "Bad fov: %f", fov_x);
561 
562 	x = width/tan(fov_x/360*M_PI);
563 
564 	a = atan (height/x);
565 
566 	a = a*360/M_PI;
567 
568 	return a;
569 }
570 
571 //============================================================================
572 
573 // gun frame debugging functions
V_Gun_Next_f(void)574 void V_Gun_Next_f (void)
575 {
576 	gun_frame++;
577 	Com_Printf ("frame %i\n", gun_frame);
578 }
579 
V_Gun_Prev_f(void)580 void V_Gun_Prev_f (void)
581 {
582 	gun_frame--;
583 	if (gun_frame < 0)
584 		gun_frame = 0;
585 	Com_Printf ("frame %i\n", gun_frame);
586 }
587 
V_Gun_Model_f(void)588 void V_Gun_Model_f (void)
589 {
590 	char	name[MAX_QPATH];
591 
592 	if (Cmd_Argc() != 2)
593 	{
594 		gun_model = NULL;
595 		return;
596 	}
597 	Com_sprintf (name, sizeof(name), "models/%s/tris.md2", Cmd_Argv(1));
598 	gun_model = re.RegisterModel (name);
599 }
600 
601 //============================================================================
602 
603 
604 /*
605 =================
606 SCR_DrawCrosshair
607 =================
608 */
609 #define DIV640 0.0015625
610 
SCR_DrawCrosshair(void)611 void SCR_DrawCrosshair (void)
612 {
613 	float scale;
614 	int x, y, w, h;
615 
616 	if (!crosshair->value)
617 		return;
618 
619 	if (crosshair->modified)
620 	{
621 		crosshair->modified = false;
622 		SCR_TouchPics ();
623 	}
624 
625 	if (crosshair_scale->modified)
626 	{
627 		crosshair_scale->modified=false;
628 		if (crosshair_scale->value>10)
629 			Cvar_SetValue("crosshair_scale", 10);
630 		else if (crosshair_scale->value<0.25)
631 			Cvar_SetValue("crosshair_scale", 0.25);
632 	}
633 
634 	if (!crosshair_pic[0])
635 		return;
636 
637 	scale = crosshair_scale->value * (viddef.width*DIV640);
638 
639 	w = crosshair_width * scale;
640 	h = crosshair_height * scale;
641 
642 	x = (viddef.width)*0.5;
643 	y = (viddef.height)*0.5;
644 
645 	re.DrawStretchPic (
646 		x-w*0.5, y-h*0.5,
647 		w, h,
648 		crosshair_pic);
649 /*
650 	re.DrawScaledPic (scr_vrect.x + ((scr_vrect.width - crosshair_width)>>1) //width
651 	, scr_vrect.y + ((scr_vrect.height - crosshair_height)>>1)	//height
652 	, scale	//scale
653 	, crosshair_pic); //pic*/
654 }
655 
SCR_DrawIRGoggles(void)656 void SCR_DrawIRGoggles (void)
657 {
658 	re.DrawStretchPic (0, 0, viddef.width, viddef.height, "ir_crosshair");
659 }
660 
SCR_DrawSniperCrosshair(void)661 void SCR_DrawSniperCrosshair (void)
662 {
663 /*	if (modType("dday"))
664 	{
665 		if (!clientGun)
666 			return;
667 		if (cl.refdef.fov_x>=85)
668 			return;
669 
670 		//continue if model is sniper
671 		if ((int)(clientGun)!=(int)(re.RegisterModel("models/weapons/usa/v_m1903/tris.md2")) &&
672 			(int)(clientGun)!=(int)(re.RegisterModel("models/weapons/grm/v_m98ks/tris.md2")) &&
673 			(int)(clientGun)!=(int)(re.RegisterModel("models/weapons/gbr/v_303s/tris.md2")) &&
674 			(int)(clientGun)!=(int)(re.RegisterModel("models/weapons/rus/v_m9130s/tris.md2")))
675 			return;
676 	}
677 	else */if (modType("swq"))
678 	{
679 		if (clientGun)
680 			return;
681 		if (cl.refdef.fov_x>=90)
682 			return;
683 	}
684 	else if (modType("action"))
685 	{
686 		if (clientGun)
687 			return;
688 		if (cl.refdef.fov_x>=85)
689 			return;
690 	}
691 	else return;
692 
693 
694 	re.DrawStretchPic (0, 0, viddef.width, viddef.height, "sniper");
695 }
696 
697 /*
698 ==================
699 V_RenderView
700 
701 ==================
702 */
703 
704 //dirty hack for gloom!!!
705 cvar_t *r_overbrightbits;
706 cvar_t *r_celshading;
707 cvar_t *gl_modulate;
GloomRenderCheck(void)708 void GloomRenderCheck(void)
709 {
710 	if (!r_celshading)
711 		r_celshading = Cvar_Get( "r_celshading", "0", CVAR_ARCHIVE );
712 	if (!gl_modulate)
713 		gl_modulate = Cvar_Get( "gl_modulate", "1", CVAR_ARCHIVE );
714 
715 	if (gl_modulate && gl_modulate->value>1)
716 		Cvar_SetValue( "gl_modulate", 1 );
717 
718 	if (r_celshading && r_celshading->value)
719 		Cvar_SetValue( "r_celshading", 0 );
720 
721 	if (cl_3dcam && cl_3dcam->value)
722 		Cvar_SetValue( "cl_3dcam", 0 );
723 }
724 
V_RenderView(float stereo_separation)725 void V_RenderView( float stereo_separation )
726 {
727 	extern int entitycmpfnc( const entity_t *, const entity_t * );
728 
729 	if (cls.state != ca_active)
730 		return;
731 
732 	if (!cl.refresh_prepped)
733 		return;			// still loading
734 
735 	if (cl_timedemo->value)
736 	{
737 		if (!cl.timedemo_start)
738 			cl.timedemo_start = Sys_Milliseconds ();
739 		cl.timedemo_frames++;
740 	}
741 
742 	// an invalid frame will just use the exact previous refdef
743 	// we can't use the old frame if the video mode has changed, though...
744 	if ( cl.frame.valid && (cl.force_refdef || !cl_paused->value) )
745 	{
746 		cl.force_refdef = false;
747 		V_ClearScene ();
748 
749 		if (cl_testparticles->value)
750 			V_TestParticles ();
751 		if (cl_testentities->value)
752 			V_TestEntities ();
753 		if (cl_testlights->value)
754 			V_TestLights ();
755 		if (cl_testblend->value)
756 		{
757 			cl.refdef.blend[0] = 1;
758 			cl.refdef.blend[1] = 0.5;
759 			cl.refdef.blend[2] = 0.25;
760 			cl.refdef.blend[3] = 0.5;
761 		}
762 
763 		// offset vieworg appropriately if we're doing stereo separation
764 		if ( stereo_separation != 0 )
765 		{
766 			vec3_t tmp;
767 
768 			VectorScale( cl.v_right, stereo_separation, tmp );
769 			VectorAdd( cl.refdef.vieworg, tmp, cl.refdef.vieworg );
770 		}
771 
772 		// never let it sit exactly on a node line, because a water plane can
773 		// dissapear when viewed with the eye exactly on it.
774 		// the server protocol only specifies to 1/8 pixel, so add 1/16 in each axis
775 		cl.refdef.vieworg[0] += 1.0/16;
776 		cl.refdef.vieworg[1] += 1.0/16;
777 		cl.refdef.vieworg[2] += 1.0/16;
778 
779 		// build a refresh entity list and calc cl.sim*
780 		// this also calls CL_CalcViewValues which loads
781 		// v_forward, etc.
782 		CL_AddEntities ();
783 
784 		cl.refdef.x = scr_vrect.x;
785 		cl.refdef.y = scr_vrect.y;
786 		cl.refdef.width = scr_vrect.width;
787 		cl.refdef.height = scr_vrect.height;
788 		cl.refdef.fov_y = CalcFov (cl.refdef.fov_x, cl.refdef.width, cl.refdef.height);
789 		cl.refdef.time = cl.time*0.001;
790 
791 		cl.refdef.areabits = cl.frame.areabits;
792 
793 		if (!cl_add_entities->value)
794 			r_numentities = 0;
795 		if (!cl_add_particles->value)
796 			r_numparticles = 0;
797 		if (!cl_add_lights->value)
798 			r_numdlights = 0;
799 		if (!cl_add_blend->value)
800 		{
801 			VectorClear (cl.refdef.blend);
802 		}
803 
804 		cl.refdef.num_entities = r_numentities;
805 		cl.refdef.entities = r_entities;
806 
807 		cl.refdef.num_particles = r_numparticles;
808 		cl.refdef.particles = r_particles;
809 
810 		cl.refdef.num_dlights = r_numdlights;
811 		cl.refdef.dlights = r_dlights;
812 		cl.refdef.lightstyles = r_lightstyles;
813 
814 		cl.refdef.rdflags = cl.frame.playerstate.rdflags;
815 
816 		// sort entities for better cache locality
817 		if (!gl_transrendersort->value)
818 			qsort( cl.refdef.entities, cl.refdef.num_entities, sizeof( cl.refdef.entities[0] ), (int (*)(const void *, const void *))entitycmpfnc );
819 	}
820 
821 	re.RenderFrame (&cl.refdef);
822 	if (cl_stats->value)
823 		Com_Printf ("ent:%i  lt:%i  part:%i\n", r_numentities, r_numdlights, r_numparticles);
824 	if ( log_stats->value && ( log_stats_file != 0 ) )
825 		fprintf( log_stats_file, "%i,%i,%i,",r_numentities, r_numdlights, r_numparticles);
826 
827 
828 	SCR_AddDirtyPoint (scr_vrect.x, scr_vrect.y);
829 	SCR_AddDirtyPoint (scr_vrect.x+scr_vrect.width-1,
830 		scr_vrect.y+scr_vrect.height-1);
831 
832 	if (!modType("dday")) //dday has no crosshair (FORCED)
833 		SCR_DrawCrosshair ();
834 
835 	SCR_DrawSniperCrosshair();
836 
837 	//hack for gloom
838 	if (modType("gloom"))
839 		GloomRenderCheck();
840 }
841 
842 
843 /*
844 =============
845 V_Viewpos_f
846 =============
847 */
V_Viewpos_f(void)848 void V_Viewpos_f (void)
849 {
850 	Com_Printf ("(%i %i %i) : %i\n", (int)cl.refdef.vieworg[0],
851 		(int)cl.refdef.vieworg[1], (int)cl.refdef.vieworg[2],
852 		(int)cl.refdef.viewangles[YAW]);
853 }
854 
855 /*
856 =============
857 V_Init
858 =============
859 */
V_Init(void)860 void V_Init (void)
861 {
862 	Cmd_AddCommand ("gun_next", V_Gun_Next_f);
863 	Cmd_AddCommand ("gun_prev", V_Gun_Prev_f);
864 	Cmd_AddCommand ("gun_model", V_Gun_Model_f);
865 
866 	Cmd_AddCommand ("viewpos", V_Viewpos_f);
867 
868 	gl_transrendersort = Cvar_Get ("gl_transrendersort", "1", CVAR_ARCHIVE );
869 	gl_particle_lighting = Cvar_Get ("gl_particle_lighting", "0.75", CVAR_ARCHIVE );
870 	gl_particle_min = Cvar_Get ("gl_particle_min", "0", CVAR_ARCHIVE );
871 	gl_particle_max = Cvar_Get ("gl_particle_max", "0", CVAR_ARCHIVE );
872 
873 	hand = Cvar_Get ("hand", "0", CVAR_ARCHIVE);
874 	if (!strcmp("swq",Cvar_Get ("game", "0", CVAR_ARCHIVE)->string)||!strcmp("cotf",Cvar_Get ("game", "0", CVAR_ARCHIVE)->string))
875 		Cvar_SetValue("hand", 0);
876 
877 	crosshair = Cvar_Get ("crosshair", "0", CVAR_ARCHIVE);
878 	crosshair_scale = Cvar_Get ("crosshair_scale", "1", CVAR_ARCHIVE);
879 
880 	cl_testblend = Cvar_Get ("cl_testblend", "0", 0);
881 	cl_testparticles = Cvar_Get ("cl_testparticles", "0", 0);
882 	cl_testentities = Cvar_Get ("cl_testentities", "0", 0);
883 	cl_testlights = Cvar_Get ("cl_testlights", "0", 0);
884 
885 	cl_stats = Cvar_Get ("cl_stats", "0", 0);
886 }
887