Quake-2

Quake 2 GPL Source Release
Log | Files | Refs

cl_view.c (12877B)


      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 
     31 //=============
     32 
     33 cvar_t		*crosshair;
     34 cvar_t		*cl_testparticles;
     35 cvar_t		*cl_testentities;
     36 cvar_t		*cl_testlights;
     37 cvar_t		*cl_testblend;
     38 
     39 cvar_t		*cl_stats;
     40 
     41 
     42 int			r_numdlights;
     43 dlight_t	r_dlights[MAX_DLIGHTS];
     44 
     45 int			r_numentities;
     46 entity_t	r_entities[MAX_ENTITIES];
     47 
     48 int			r_numparticles;
     49 particle_t	r_particles[MAX_PARTICLES];
     50 
     51 lightstyle_t	r_lightstyles[MAX_LIGHTSTYLES];
     52 
     53 char cl_weaponmodels[MAX_CLIENTWEAPONMODELS][MAX_QPATH];
     54 int num_cl_weaponmodels;
     55 
     56 /*
     57 ====================
     58 V_ClearScene
     59 
     60 Specifies the model that will be used as the world
     61 ====================
     62 */
     63 void V_ClearScene (void)
     64 {
     65 	r_numdlights = 0;
     66 	r_numentities = 0;
     67 	r_numparticles = 0;
     68 }
     69 
     70 
     71 /*
     72 =====================
     73 V_AddEntity
     74 
     75 =====================
     76 */
     77 void V_AddEntity (entity_t *ent)
     78 {
     79 	if (r_numentities >= MAX_ENTITIES)
     80 		return;
     81 	r_entities[r_numentities++] = *ent;
     82 }
     83 
     84 
     85 /*
     86 =====================
     87 V_AddParticle
     88 
     89 =====================
     90 */
     91 void V_AddParticle (vec3_t org, int color, float alpha)
     92 {
     93 	particle_t	*p;
     94 
     95 	if (r_numparticles >= MAX_PARTICLES)
     96 		return;
     97 	p = &r_particles[r_numparticles++];
     98 	VectorCopy (org, p->origin);
     99 	p->color = color;
    100 	p->alpha = alpha;
    101 }
    102 
    103 /*
    104 =====================
    105 V_AddLight
    106 
    107 =====================
    108 */
    109 void V_AddLight (vec3_t org, float intensity, float r, float g, float b)
    110 {
    111 	dlight_t	*dl;
    112 
    113 	if (r_numdlights >= MAX_DLIGHTS)
    114 		return;
    115 	dl = &r_dlights[r_numdlights++];
    116 	VectorCopy (org, dl->origin);
    117 	dl->intensity = intensity;
    118 	dl->color[0] = r;
    119 	dl->color[1] = g;
    120 	dl->color[2] = b;
    121 }
    122 
    123 
    124 /*
    125 =====================
    126 V_AddLightStyle
    127 
    128 =====================
    129 */
    130 void V_AddLightStyle (int style, float r, float g, float b)
    131 {
    132 	lightstyle_t	*ls;
    133 
    134 	if (style < 0 || style > MAX_LIGHTSTYLES)
    135 		Com_Error (ERR_DROP, "Bad light style %i", style);
    136 	ls = &r_lightstyles[style];
    137 
    138 	ls->white = r+g+b;
    139 	ls->rgb[0] = r;
    140 	ls->rgb[1] = g;
    141 	ls->rgb[2] = b;
    142 }
    143 
    144 /*
    145 ================
    146 V_TestParticles
    147 
    148 If cl_testparticles is set, create 4096 particles in the view
    149 ================
    150 */
    151 void V_TestParticles (void)
    152 {
    153 	particle_t	*p;
    154 	int			i, j;
    155 	float		d, r, u;
    156 
    157 	r_numparticles = MAX_PARTICLES;
    158 	for (i=0 ; i<r_numparticles ; i++)
    159 	{
    160 		d = i*0.25;
    161 		r = 4*((i&7)-3.5);
    162 		u = 4*(((i>>3)&7)-3.5);
    163 		p = &r_particles[i];
    164 
    165 		for (j=0 ; j<3 ; j++)
    166 			p->origin[j] = cl.refdef.vieworg[j] + cl.v_forward[j]*d +
    167 			cl.v_right[j]*r + cl.v_up[j]*u;
    168 
    169 		p->color = 8;
    170 		p->alpha = cl_testparticles->value;
    171 	}
    172 }
    173 
    174 /*
    175 ================
    176 V_TestEntities
    177 
    178 If cl_testentities is set, create 32 player models
    179 ================
    180 */
    181 void V_TestEntities (void)
    182 {
    183 	int			i, j;
    184 	float		f, r;
    185 	entity_t	*ent;
    186 
    187 	r_numentities = 32;
    188 	memset (r_entities, 0, sizeof(r_entities));
    189 
    190 	for (i=0 ; i<r_numentities ; i++)
    191 	{
    192 		ent = &r_entities[i];
    193 
    194 		r = 64 * ( (i%4) - 1.5 );
    195 		f = 64 * (i/4) + 128;
    196 
    197 		for (j=0 ; j<3 ; j++)
    198 			ent->origin[j] = cl.refdef.vieworg[j] + cl.v_forward[j]*f +
    199 			cl.v_right[j]*r;
    200 
    201 		ent->model = cl.baseclientinfo.model;
    202 		ent->skin = cl.baseclientinfo.skin;
    203 	}
    204 }
    205 
    206 /*
    207 ================
    208 V_TestLights
    209 
    210 If cl_testlights is set, create 32 lights models
    211 ================
    212 */
    213 void V_TestLights (void)
    214 {
    215 	int			i, j;
    216 	float		f, r;
    217 	dlight_t	*dl;
    218 
    219 	r_numdlights = 32;
    220 	memset (r_dlights, 0, sizeof(r_dlights));
    221 
    222 	for (i=0 ; i<r_numdlights ; i++)
    223 	{
    224 		dl = &r_dlights[i];
    225 
    226 		r = 64 * ( (i%4) - 1.5 );
    227 		f = 64 * (i/4) + 128;
    228 
    229 		for (j=0 ; j<3 ; j++)
    230 			dl->origin[j] = cl.refdef.vieworg[j] + cl.v_forward[j]*f +
    231 			cl.v_right[j]*r;
    232 		dl->color[0] = ((i%6)+1) & 1;
    233 		dl->color[1] = (((i%6)+1) & 2)>>1;
    234 		dl->color[2] = (((i%6)+1) & 4)>>2;
    235 		dl->intensity = 200;
    236 	}
    237 }
    238 
    239 //===================================================================
    240 
    241 /*
    242 =================
    243 CL_PrepRefresh
    244 
    245 Call before entering a new level, or after changing dlls
    246 =================
    247 */
    248 void CL_PrepRefresh (void)
    249 {
    250 	char		mapname[32];
    251 	int			i;
    252 	char		name[MAX_QPATH];
    253 	float		rotate;
    254 	vec3_t		axis;
    255 
    256 	if (!cl.configstrings[CS_MODELS+1][0])
    257 		return;		// no map loaded
    258 
    259 	SCR_AddDirtyPoint (0, 0);
    260 	SCR_AddDirtyPoint (viddef.width-1, viddef.height-1);
    261 
    262 	// let the render dll load the map
    263 	strcpy (mapname, cl.configstrings[CS_MODELS+1] + 5);	// skip "maps/"
    264 	mapname[strlen(mapname)-4] = 0;		// cut off ".bsp"
    265 
    266 	// register models, pics, and skins
    267 	Com_Printf ("Map: %s\r", mapname); 
    268 	SCR_UpdateScreen ();
    269 	re.BeginRegistration (mapname);
    270 	Com_Printf ("                                     \r");
    271 
    272 	// precache status bar pics
    273 	Com_Printf ("pics\r"); 
    274 	SCR_UpdateScreen ();
    275 	SCR_TouchPics ();
    276 	Com_Printf ("                                     \r");
    277 
    278 	CL_RegisterTEntModels ();
    279 
    280 	num_cl_weaponmodels = 1;
    281 	strcpy(cl_weaponmodels[0], "weapon.md2");
    282 
    283 	for (i=1 ; i<MAX_MODELS && cl.configstrings[CS_MODELS+i][0] ; i++)
    284 	{
    285 		strcpy (name, cl.configstrings[CS_MODELS+i]);
    286 		name[37] = 0;	// never go beyond one line
    287 		if (name[0] != '*')
    288 			Com_Printf ("%s\r", name); 
    289 		SCR_UpdateScreen ();
    290 		Sys_SendKeyEvents ();	// pump message loop
    291 		if (name[0] == '#')
    292 		{
    293 			// special player weapon model
    294 			if (num_cl_weaponmodels < MAX_CLIENTWEAPONMODELS)
    295 			{
    296 				strncpy(cl_weaponmodels[num_cl_weaponmodels], cl.configstrings[CS_MODELS+i]+1,
    297 					sizeof(cl_weaponmodels[num_cl_weaponmodels]) - 1);
    298 				num_cl_weaponmodels++;
    299 			}
    300 		} 
    301 		else
    302 		{
    303 			cl.model_draw[i] = re.RegisterModel (cl.configstrings[CS_MODELS+i]);
    304 			if (name[0] == '*')
    305 				cl.model_clip[i] = CM_InlineModel (cl.configstrings[CS_MODELS+i]);
    306 			else
    307 				cl.model_clip[i] = NULL;
    308 		}
    309 		if (name[0] != '*')
    310 			Com_Printf ("                                     \r");
    311 	}
    312 
    313 	Com_Printf ("images\r", i); 
    314 	SCR_UpdateScreen ();
    315 	for (i=1 ; i<MAX_IMAGES && cl.configstrings[CS_IMAGES+i][0] ; i++)
    316 	{
    317 		cl.image_precache[i] = re.RegisterPic (cl.configstrings[CS_IMAGES+i]);
    318 		Sys_SendKeyEvents ();	// pump message loop
    319 	}
    320 	
    321 	Com_Printf ("                                     \r");
    322 	for (i=0 ; i<MAX_CLIENTS ; i++)
    323 	{
    324 		if (!cl.configstrings[CS_PLAYERSKINS+i][0])
    325 			continue;
    326 		Com_Printf ("client %i\r", i); 
    327 		SCR_UpdateScreen ();
    328 		Sys_SendKeyEvents ();	// pump message loop
    329 		CL_ParseClientinfo (i);
    330 		Com_Printf ("                                     \r");
    331 	}
    332 
    333 	CL_LoadClientinfo (&cl.baseclientinfo, "unnamed\\male/grunt");
    334 
    335 	// set sky textures and speed
    336 	Com_Printf ("sky\r", i); 
    337 	SCR_UpdateScreen ();
    338 	rotate = atof (cl.configstrings[CS_SKYROTATE]);
    339 	sscanf (cl.configstrings[CS_SKYAXIS], "%f %f %f", 
    340 		&axis[0], &axis[1], &axis[2]);
    341 	re.SetSky (cl.configstrings[CS_SKY], rotate, axis);
    342 	Com_Printf ("                                     \r");
    343 
    344 	// the renderer can now free unneeded stuff
    345 	re.EndRegistration ();
    346 
    347 	// clear any lines of console text
    348 	Con_ClearNotify ();
    349 
    350 	SCR_UpdateScreen ();
    351 	cl.refresh_prepped = true;
    352 	cl.force_refdef = true;	// make sure we have a valid refdef
    353 
    354 	// start the cd track
    355 	CDAudio_Play (atoi(cl.configstrings[CS_CDTRACK]), true);
    356 }
    357 
    358 /*
    359 ====================
    360 CalcFov
    361 ====================
    362 */
    363 float CalcFov (float fov_x, float width, float height)
    364 {
    365 	float	a;
    366 	float	x;
    367 
    368 	if (fov_x < 1 || fov_x > 179)
    369 		Com_Error (ERR_DROP, "Bad fov: %f", fov_x);
    370 
    371 	x = width/tan(fov_x/360*M_PI);
    372 
    373 	a = atan (height/x);
    374 
    375 	a = a*360/M_PI;
    376 
    377 	return a;
    378 }
    379 
    380 //============================================================================
    381 
    382 // gun frame debugging functions
    383 void V_Gun_Next_f (void)
    384 {
    385 	gun_frame++;
    386 	Com_Printf ("frame %i\n", gun_frame);
    387 }
    388 
    389 void V_Gun_Prev_f (void)
    390 {
    391 	gun_frame--;
    392 	if (gun_frame < 0)
    393 		gun_frame = 0;
    394 	Com_Printf ("frame %i\n", gun_frame);
    395 }
    396 
    397 void V_Gun_Model_f (void)
    398 {
    399 	char	name[MAX_QPATH];
    400 
    401 	if (Cmd_Argc() != 2)
    402 	{
    403 		gun_model = NULL;
    404 		return;
    405 	}
    406 	Com_sprintf (name, sizeof(name), "models/%s/tris.md2", Cmd_Argv(1));
    407 	gun_model = re.RegisterModel (name);
    408 }
    409 
    410 //============================================================================
    411 
    412 
    413 /*
    414 =================
    415 SCR_DrawCrosshair
    416 =================
    417 */
    418 void SCR_DrawCrosshair (void)
    419 {
    420 	if (!crosshair->value)
    421 		return;
    422 
    423 	if (crosshair->modified)
    424 	{
    425 		crosshair->modified = false;
    426 		SCR_TouchPics ();
    427 	}
    428 
    429 	if (!crosshair_pic[0])
    430 		return;
    431 
    432 	re.DrawPic (scr_vrect.x + ((scr_vrect.width - crosshair_width)>>1)
    433 	, scr_vrect.y + ((scr_vrect.height - crosshair_height)>>1), crosshair_pic);
    434 }
    435 
    436 /*
    437 ==================
    438 V_RenderView
    439 
    440 ==================
    441 */
    442 void V_RenderView( float stereo_separation )
    443 {
    444 	extern int entitycmpfnc( const entity_t *, const entity_t * );
    445 
    446 	if (cls.state != ca_active)
    447 		return;
    448 
    449 	if (!cl.refresh_prepped)
    450 		return;			// still loading
    451 
    452 	if (cl_timedemo->value)
    453 	{
    454 		if (!cl.timedemo_start)
    455 			cl.timedemo_start = Sys_Milliseconds ();
    456 		cl.timedemo_frames++;
    457 	}
    458 
    459 	// an invalid frame will just use the exact previous refdef
    460 	// we can't use the old frame if the video mode has changed, though...
    461 	if ( cl.frame.valid && (cl.force_refdef || !cl_paused->value) )
    462 	{
    463 		cl.force_refdef = false;
    464 
    465 		V_ClearScene ();
    466 
    467 		// build a refresh entity list and calc cl.sim*
    468 		// this also calls CL_CalcViewValues which loads
    469 		// v_forward, etc.
    470 		CL_AddEntities ();
    471 
    472 		if (cl_testparticles->value)
    473 			V_TestParticles ();
    474 		if (cl_testentities->value)
    475 			V_TestEntities ();
    476 		if (cl_testlights->value)
    477 			V_TestLights ();
    478 		if (cl_testblend->value)
    479 		{
    480 			cl.refdef.blend[0] = 1;
    481 			cl.refdef.blend[1] = 0.5;
    482 			cl.refdef.blend[2] = 0.25;
    483 			cl.refdef.blend[3] = 0.5;
    484 		}
    485 
    486 		// offset vieworg appropriately if we're doing stereo separation
    487 		if ( stereo_separation != 0 )
    488 		{
    489 			vec3_t tmp;
    490 
    491 			VectorScale( cl.v_right, stereo_separation, tmp );
    492 			VectorAdd( cl.refdef.vieworg, tmp, cl.refdef.vieworg );
    493 		}
    494 
    495 		// never let it sit exactly on a node line, because a water plane can
    496 		// dissapear when viewed with the eye exactly on it.
    497 		// the server protocol only specifies to 1/8 pixel, so add 1/16 in each axis
    498 		cl.refdef.vieworg[0] += 1.0/16;
    499 		cl.refdef.vieworg[1] += 1.0/16;
    500 		cl.refdef.vieworg[2] += 1.0/16;
    501 
    502 		cl.refdef.x = scr_vrect.x;
    503 		cl.refdef.y = scr_vrect.y;
    504 		cl.refdef.width = scr_vrect.width;
    505 		cl.refdef.height = scr_vrect.height;
    506 		cl.refdef.fov_y = CalcFov (cl.refdef.fov_x, cl.refdef.width, cl.refdef.height);
    507 		cl.refdef.time = cl.time*0.001;
    508 
    509 		cl.refdef.areabits = cl.frame.areabits;
    510 
    511 		if (!cl_add_entities->value)
    512 			r_numentities = 0;
    513 		if (!cl_add_particles->value)
    514 			r_numparticles = 0;
    515 		if (!cl_add_lights->value)
    516 			r_numdlights = 0;
    517 		if (!cl_add_blend->value)
    518 		{
    519 			VectorClear (cl.refdef.blend);
    520 		}
    521 
    522 		cl.refdef.num_entities = r_numentities;
    523 		cl.refdef.entities = r_entities;
    524 		cl.refdef.num_particles = r_numparticles;
    525 		cl.refdef.particles = r_particles;
    526 		cl.refdef.num_dlights = r_numdlights;
    527 		cl.refdef.dlights = r_dlights;
    528 		cl.refdef.lightstyles = r_lightstyles;
    529 
    530 		cl.refdef.rdflags = cl.frame.playerstate.rdflags;
    531 
    532 		// sort entities for better cache locality
    533         qsort( cl.refdef.entities, cl.refdef.num_entities, sizeof( cl.refdef.entities[0] ), (int (*)(const void *, const void *))entitycmpfnc );
    534 	}
    535 
    536 	re.RenderFrame (&cl.refdef);
    537 	if (cl_stats->value)
    538 		Com_Printf ("ent:%i  lt:%i  part:%i\n", r_numentities, r_numdlights, r_numparticles);
    539 	if ( log_stats->value && ( log_stats_file != 0 ) )
    540 		fprintf( log_stats_file, "%i,%i,%i,",r_numentities, r_numdlights, r_numparticles);
    541 
    542 
    543 	SCR_AddDirtyPoint (scr_vrect.x, scr_vrect.y);
    544 	SCR_AddDirtyPoint (scr_vrect.x+scr_vrect.width-1,
    545 		scr_vrect.y+scr_vrect.height-1);
    546 
    547 	SCR_DrawCrosshair ();
    548 }
    549 
    550 
    551 /*
    552 =============
    553 V_Viewpos_f
    554 =============
    555 */
    556 void V_Viewpos_f (void)
    557 {
    558 	Com_Printf ("(%i %i %i) : %i\n", (int)cl.refdef.vieworg[0],
    559 		(int)cl.refdef.vieworg[1], (int)cl.refdef.vieworg[2], 
    560 		(int)cl.refdef.viewangles[YAW]);
    561 }
    562 
    563 /*
    564 =============
    565 V_Init
    566 =============
    567 */
    568 void V_Init (void)
    569 {
    570 	Cmd_AddCommand ("gun_next", V_Gun_Next_f);
    571 	Cmd_AddCommand ("gun_prev", V_Gun_Prev_f);
    572 	Cmd_AddCommand ("gun_model", V_Gun_Model_f);
    573 
    574 	Cmd_AddCommand ("viewpos", V_Viewpos_f);
    575 
    576 	crosshair = Cvar_Get ("crosshair", "0", CVAR_ARCHIVE);
    577 
    578 	cl_testblend = Cvar_Get ("cl_testblend", "0", 0);
    579 	cl_testparticles = Cvar_Get ("cl_testparticles", "0", 0);
    580 	cl_testentities = Cvar_Get ("cl_testentities", "0", 0);
    581 	cl_testlights = Cvar_Get ("cl_testlights", "0", 0);
    582 
    583 	cl_stats = Cvar_Get ("cl_stats", "0", 0);
    584 }