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