|
|
1.1 root 1: // cl_scrn.c -- master for refresh, status bar, console, chat, notify, etc
2: /*
3: full screen console
4: put up loading plaque
5: blanked background with loading plaque
6: blanked background with menu
7: cinematics
8: full screen image for quit and victory
9: end of unit intermissions
10: */
11: #include "client.h"
12: float scr_con_current; // aproaches scr_conlines at scr_conspeed
13: float scr_conlines; // 0.0 to 1.0 lines of console to display
14: qboolean scr_initialized; // ready to draw
15: int scr_draw_loading;
16: vrect_t scr_vrect; // position of render window on screen
17: cvar_t *scr_viewsize;
18: cvar_t *scr_conspeed;
19: cvar_t *scr_centertime;
20: cvar_t *scr_showturtle;
21: cvar_t *scr_showpause;
22: cvar_t *scr_printspeed;
23: cvar_t *scr_netgraph;
24: cvar_t *scr_timegraph;
25: cvar_t *scr_debuggraph;
26: cvar_t *scr_graphheight;
27: cvar_t *scr_graphscale;
28: cvar_t *scr_graphshift;
29: cvar_t *scr_drawall;
30: typedef struct
31: {
32: int x1, y1, x2, y2;
33: } dirty_t;
34: dirty_t scr_dirty, scr_old_dirty[2];
35:
36: char crosshair_pic[MAX_QPATH];
37: int crosshair_width, crosshair_height;
38: void SCR_TimeRefresh_f (void);
39: void SCR_Loading_f (void);
40: /*
41: ===============================================================================
42: BAR GRAPHS
43: ===============================================================================
44: */
45:
46: /*
47: ==============
48: CL_AddNetgraph
49:
50: A new packet was just parsed
51: ==============
52: */
53: void CL_AddNetgraph (void)
54: {
55: int i;
56: int in;
57: int ping;
58:
59: // if using the debuggraph for something else, don't
60: // add the net lines
61: if (scr_debuggraph->value || scr_timegraph->value)
62: return;
63:
64: for (i=0 ; i<cls.netchan.dropped ; i++)
65: SCR_DebugGraph (30, 0x40);
66:
67: for (i=0 ; i<cl.surpressCount ; i++)
68: SCR_DebugGraph (30, 0xdf);
69:
70: // see what the latency was on this packet
71: in = cls.netchan.incoming_acknowledged & (CMD_BACKUP-1);
72: ping = cls.realtime - cl.cmd_time[in];
73: ping /= 30;
74: if (ping > 30)
75: ping = 30;
76: SCR_DebugGraph (ping, 0xd0);
77: }
78: typedef struct
79: {
80: float value;
81: int color;
82: } graphsamp_t;
83: static int current;
84: static graphsamp_t values[1024];
85: /*
86: ==============
87: SCR_DebugGraph
88: ==============
89: */
90: void SCR_DebugGraph (float value, int color)
91: {
92: values[current&1023].value = value;
93: values[current&1023].color = color;
94: current++;
95: }
96: /*
97: ==============
98: SCR_DrawDebugGraph
99: ==============
100: */
101: void SCR_DrawDebugGraph (void)
102: {
103: int a, x, y, w, i, h;
104: float v;
105: int color;
106: //
107: // draw the graph
108: //
109: w = scr_vrect.width;
110: x = scr_vrect.x;
111: y = scr_vrect.y+scr_vrect.height;
112: re.DrawFill (x, y-scr_graphheight->value,
113: w, scr_graphheight->value, 8);
114: for (a=0 ; a<w ; a++)
115: {
116: i = (current-1-a+1024) & 1023;
117: v = values[i].value;
118: color = values[i].color;
119: v = v*scr_graphscale->value + scr_graphshift->value;
120:
121: if (v < 0)
122: v += scr_graphheight->value * (1+(int)(-v/scr_graphheight->value));
123: h = (int)v % (int)scr_graphheight->value;
124: re.DrawFill (x+w-1-a, y - h, 1, h, color);
125: }
126: }
127: /*
128: ===============================================================================
129: CENTER PRINTING
130: ===============================================================================
131: */
132: char scr_centerstring[1024];
133: float scr_centertime_start; // for slow victory printing
134: float scr_centertime_off;
135: int scr_center_lines;
136: int scr_erase_center;
137: /*
138: ==============
139: SCR_CenterPrint
140: Called for important messages that should stay in the center of the screen
141: for a few moments
142: ==============
143: */
144: void SCR_CenterPrint (char *str)
145: {
146: char *s;
147: char line[64];
148: int i, j, l;
149: strncpy (scr_centerstring, str, sizeof(scr_centerstring)-1);
150: scr_centertime_off = scr_centertime->value;
151: scr_centertime_start = cl.time;
152: // count the number of lines for centering
153: scr_center_lines = 1;
154: s = str;
155: while (*s)
156: {
157: if (*s == '\n')
158: scr_center_lines++;
159: s++;
160: }
161:
162: // echo it to the console
163: Com_Printf("\n\n\35\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\37\n\n");
164:
165: s = str;
166: do
167: {
168: // scan the width of the line
169: for (l=0 ; l<40 ; l++)
170: if (s[l] == '\n' || !s[l])
171: break;
172: for (i=0 ; i<(40-l)/2 ; i++)
173: line[i] = ' ';
174:
175: for (j=0 ; j<l ; j++)
176: {
177: line[i++] = s[j];
178: }
179:
180: line[i] = '\n';
181: line[i+1] = 0;
182:
183: Com_Printf ("%s", line);
184:
185: while (*s && *s != '\n')
186: s++;
187:
188: if (!*s)
189: break;
190: s++; // skip the \n
191: } while (1);
192: Com_Printf("\n\n\35\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\37\n\n");
193: Con_ClearNotify ();
194: }
195: void SCR_DrawCenterString (void)
196: {
197: char *start;
198: int l;
199: int j;
200: int x, y;
201: int remaining;
202: // the finale prints the characters one at a time
203: remaining = 9999;
204: scr_erase_center = 0;
205: start = scr_centerstring;
206: if (scr_center_lines <= 4)
207: y = viddef.height*0.35;
208: else
209: y = 48;
210: do
211: {
212: // scan the width of the line
213: for (l=0 ; l<40 ; l++)
214: if (start[l] == '\n' || !start[l])
215: break;
216: x = (viddef.width - l*8)/2;
217: SCR_AddDirtyPoint (x, y);
218: for (j=0 ; j<l ; j++, x+=8)
219: {
220: re.DrawChar (x, y, start[j]);
221: if (!remaining--)
222: return;
223: }
224: SCR_AddDirtyPoint (x, y+8);
225:
226: y += 8;
227: while (*start && *start != '\n')
228: start++;
229: if (!*start)
230: break;
231: start++; // skip the \n
232: } while (1);
233: }
234: void SCR_CheckDrawCenterString (void)
235: {
236: scr_centertime_off -= cls.frametime;
237:
238: if (scr_centertime_off <= 0)
239: return;
240: SCR_DrawCenterString ();
241: }
242: //=============================================================================
243: /*
244: =================
245: SCR_CalcVrect
246: Sets scr_vrect, the coordinates of the rendered window
247: =================
248: */
249: static void SCR_CalcVrect (void)
250: {
251: int size;
252: // bound viewsize
253: if (scr_viewsize->value < 40)
254: Cvar_Set ("viewsize","40");
255: if (scr_viewsize->value > 100)
256: Cvar_Set ("viewsize","100");
257: size = scr_viewsize->value;
258: scr_vrect.width = viddef.width*size/100;
259: scr_vrect.width &= ~7;
260: scr_vrect.height = viddef.height*size/100;
261: scr_vrect.height &= ~1;
262: scr_vrect.x = (viddef.width - scr_vrect.width)/2;
263: scr_vrect.y = (viddef.height - scr_vrect.height)/2;
264: }
265: /*
266: =================
267: SCR_SizeUp_f
268: Keybinding command
269: =================
270: */
271: void SCR_SizeUp_f (void)
272: {
273: Cvar_SetValue ("viewsize",scr_viewsize->value+10);
274: }
275: /*
276: =================
277: SCR_SizeDown_f
278: Keybinding command
279: =================
280: */
281: void SCR_SizeDown_f (void)
282: {
283: Cvar_SetValue ("viewsize",scr_viewsize->value-10);
284: }
285: /*
286: =================
287: SCR_Sky_f
288: Set a specific sky and rotation speed
289: =================
290: */
291: void SCR_Sky_f (void)
292: {
293: float rotate;
294: vec3_t axis;
295: if (Cmd_Argc() < 2)
296: {
297: Com_Printf ("Usage: sky <basename> <rotate> <axis x y z>\n");
298: return;
299: }
300: if (Cmd_Argc() > 2)
301: rotate = atof(Cmd_Argv(2));
302: else
303: rotate = 0;
304: if (Cmd_Argc() == 6)
305: {
306: axis[0] = atof(Cmd_Argv(3));
307: axis[1] = atof(Cmd_Argv(4));
308: axis[2] = atof(Cmd_Argv(5));
309: }
310: else
311: {
312: axis[0] = 0;
313: axis[1] = 0;
314: axis[2] = 1;
315: }
316: re.SetSky (Cmd_Argv(1), rotate, axis);
317: }
318: //============================================================================
319: /*
320: ==================
321: SCR_Init
322: ==================
323: */
324: void SCR_Init (void)
325: {
326: scr_viewsize = Cvar_Get ("viewsize", "100", CVAR_ARCHIVE);
327: scr_conspeed = Cvar_Get ("scr_conspeed", "3", 0);
328: scr_showturtle = Cvar_Get ("scr_showturtle", "0", 0);
329: scr_showpause = Cvar_Get ("scr_showpause", "1", 0);
330: scr_centertime = Cvar_Get ("scr_centertime", "2.5", 0);
331: scr_printspeed = Cvar_Get ("scr_printspeed", "8", 0);
332: scr_netgraph = Cvar_Get ("netgraph", "0", 0);
333: scr_timegraph = Cvar_Get ("timegraph", "0", 0);
334: scr_debuggraph = Cvar_Get ("debuggraph", "0", 0);
335: scr_graphheight = Cvar_Get ("graphheight", "32", 0);
336: scr_graphscale = Cvar_Get ("graphscale", "1", 0);
337: scr_graphshift = Cvar_Get ("graphshift", "0", 0);
338: scr_drawall = Cvar_Get ("scr_drawall", "0", 0);
339: //
340: // register our commands
341: //
342: Cmd_AddCommand ("timerefresh",SCR_TimeRefresh_f);
343: Cmd_AddCommand ("loading",SCR_Loading_f);
344: Cmd_AddCommand ("sizeup",SCR_SizeUp_f);
345: Cmd_AddCommand ("sizedown",SCR_SizeDown_f);
346: Cmd_AddCommand ("sky",SCR_Sky_f);
347: scr_initialized = true;
348: }
349: /*
350: ==============
351: SCR_DrawNet
352: ==============
353: */
354: void SCR_DrawNet (void)
355: {
356: if (cls.netchan.outgoing_sequence - cls.netchan.incoming_acknowledged
357: < CMD_BACKUP-1)
358: return;
359: re.DrawPic (scr_vrect.x+64, scr_vrect.y, "net");
360: }
361: /*
362: ==============
363: SCR_DrawPause
364: ==============
365: */
366: void SCR_DrawPause (void)
367: {
368: int w, h;
369: if (!scr_showpause->value) // turn off for screenshots
370: return;
371: if (!cl_paused->value)
372: return;
373: re.DrawGetPicSize (&w, &h, "pause");
374: re.DrawPic ((viddef.width-w)/2, viddef.height/2 + 8, "pause");
375: }
376: /*
377: ==============
378: SCR_DrawLoading
379: ==============
380: */
381: void SCR_DrawLoading (void)
382: {
383: int w, h;
384:
385: if (!scr_draw_loading)
386: return;
387: scr_draw_loading = false;
388: re.DrawGetPicSize (&w, &h, "loading");
389: re.DrawPic ((viddef.width-w)/2, (viddef.height-h)/2, "loading");
390: }
391: //=============================================================================
392: /*
393: ==================
394: SCR_RunConsole
395: Scroll it up or down
396: ==================
397: */
398: void SCR_RunConsole (void)
399: {
400: // decide on the height of the console
401: if (cls.key_dest == key_console)
402: scr_conlines = 0.5; // half screen
403: else
404: scr_conlines = 0; // none visible
405:
406: if (scr_conlines < scr_con_current)
407: {
408: scr_con_current -= scr_conspeed->value*cls.frametime;
409: if (scr_conlines > scr_con_current)
410: scr_con_current = scr_conlines;
411: }
412: else if (scr_conlines > scr_con_current)
413: {
414: scr_con_current += scr_conspeed->value*cls.frametime;
415: if (scr_conlines < scr_con_current)
416: scr_con_current = scr_conlines;
417: }
418: }
419: /*
420: ==================
421: SCR_DrawConsole
422: ==================
423: */
424: void SCR_DrawConsole (void)
425: {
426: Con_CheckResize ();
427:
428: if (cls.state == ca_disconnected || cls.state == ca_connecting)
429: { // forced full screen console
430: Con_DrawConsole (1.0);
431: return;
432: }
433: if (cls.state != ca_active || !cl.refresh_prepped)
434: { // connected, but can't render
435: Con_DrawConsole (0.5);
436: re.DrawFill (0, viddef.height/2, viddef.width, viddef.height/2, 0);
437: return;
438: }
439: if (scr_con_current)
440: {
441: Con_DrawConsole (scr_con_current);
442: }
443: else
444: {
445: if (cls.key_dest == key_game || cls.key_dest == key_message)
446: Con_DrawNotify (); // only draw notify in game
447: }
448: }
449: //=============================================================================
450: /*
451: ================
452: SCR_BeginLoadingPlaque
453: ================
454: */
455: void SCR_BeginLoadingPlaque (void)
456: {
457: S_StopAllSounds ();
458: cl.sound_prepped = false; // don't play ambients
459: CDAudio_Stop ();
460: if (cls.disable_screen)
461: return;
462: if (developer->value)
463: return;
464: if (cls.state == ca_disconnected)
465: return; // if at console, don't bring up the plaque
466: if (cls.key_dest == key_console)
467: return;
468: if (cl.cinematictime > 0)
469: scr_draw_loading = 2; // clear to balack first
470: else
471: scr_draw_loading = 1;
472: SCR_UpdateScreen ();
473: cls.disable_screen = Sys_Milliseconds ();
474: cls.disable_servercount = cl.servercount;
475: }
476: /*
477: ================
478: SCR_EndLoadingPlaque
479: ================
480: */
481: void SCR_EndLoadingPlaque (void)
482: {
483: cls.disable_screen = 0;
484: Con_ClearNotify ();
485: }
486: /*
487: ================
488: SCR_Loading_f
489: ================
490: */
491: void SCR_Loading_f (void)
492: {
493: SCR_BeginLoadingPlaque ();
494: }
495: /*
496: ================
497: SCR_TimeRefresh_f
498: ================
499: */
500: int entitycmpfnc( const entity_t *a, const entity_t *b )
501: {
502: /*
503: ** all other models are sorted by model then skin
504: */
505: if ( a->model == b->model )
506: {
507: return ( ( int ) a->skin - ( int ) b->skin );
508: }
509: else
510: {
511: return ( ( int ) a->model - ( int ) b->model );
512: }
513: }
514:
515: void SCR_TimeRefresh_f (void)
516: {
517: int i;
518: int start, stop;
519: float time;
520:
521: if ( cls.state != ca_active )
522: return;
523: start = Sys_Milliseconds ();
524: if (Cmd_Argc() == 2)
525: { // run without page flipping
526: re.BeginFrame( 0 );
527: for (i=0 ; i<128 ; i++)
528: {
529: cl.refdef.viewangles[1] = i/128.0*360.0;
530: re.RenderFrame (&cl.refdef);
531: }
532: re.EndFrame();
533: }
534: else
535: {
536: for (i=0 ; i<128 ; i++)
537: {
538: cl.refdef.viewangles[1] = i/128.0*360.0;
539: re.BeginFrame( 0 );
540: re.RenderFrame (&cl.refdef);
541: re.EndFrame();
542: }
543: }
544: stop = Sys_Milliseconds ();
545: time = (stop-start)/1000.0;
546: Com_Printf ("%f seconds (%f fps)\n", time, 128/time);
547: }
548: /*
549: =================
550: SCR_AddDirtyPoint
551: =================
552: */
553: void SCR_AddDirtyPoint (int x, int y)
554: {
555: if (x < scr_dirty.x1)
556: scr_dirty.x1 = x;
557: if (x > scr_dirty.x2)
558: scr_dirty.x2 = x;
559: if (y < scr_dirty.y1)
560: scr_dirty.y1 = y;
561: if (y > scr_dirty.y2)
562: scr_dirty.y2 = y;
563: }
564: void SCR_DirtyScreen (void)
565: {
566: SCR_AddDirtyPoint (0, 0);
567: SCR_AddDirtyPoint (viddef.width-1, viddef.height-1);
568: }
569: /*
570: ==============
571: SCR_TileClear
572: Clear any parts of the tiled background that were drawn on last frame
573: ==============
574: */
575: void SCR_TileClear (void)
576: {
577: int i;
578: int top, bottom, left, right;
579: dirty_t clear;
580:
581: if (scr_drawall->value)
582: SCR_DirtyScreen (); // for power vr or broken page flippers...
583: if (scr_con_current == 1.0)
584: return; // full screen console
585: if (scr_viewsize->value == 100)
586: return; // full screen rendering
587: if (cl.cinematictime > 0)
588: return; // full screen cinematic
589: // erase rect will be the union of the past three frames
590: // so tripple buffering works properly
591: clear = scr_dirty;
592: for (i=0 ; i<2 ; i++)
593: {
594: if (scr_old_dirty[i].x1 < clear.x1)
595: clear.x1 = scr_old_dirty[i].x1;
596: if (scr_old_dirty[i].x2 > clear.x2)
597: clear.x2 = scr_old_dirty[i].x2;
598: if (scr_old_dirty[i].y1 < clear.y1)
599: clear.y1 = scr_old_dirty[i].y1;
600: if (scr_old_dirty[i].y2 > clear.y2)
601: clear.y2 = scr_old_dirty[i].y2;
602: }
603: scr_old_dirty[1] = scr_old_dirty[0];
604: scr_old_dirty[0] = scr_dirty;
605: scr_dirty.x1 = 9999;
606: scr_dirty.x2 = -9999;
607: scr_dirty.y1 = 9999;
608: scr_dirty.y2 = -9999;
609: // don't bother with anything convered by the console)
610: top = scr_con_current*viddef.height;
611: if (top >= clear.y1)
612: clear.y1 = top;
613: if (clear.y2 <= clear.y1)
614: return; // nothing disturbed
615: top = scr_vrect.y;
616: bottom = top + scr_vrect.height-1;
617: left = scr_vrect.x;
618: right = left + scr_vrect.width-1;
619: if (clear.y1 < top)
620: { // clear above view screen
621: i = clear.y2 < top-1 ? clear.y2 : top-1;
622: re.DrawTileClear (clear.x1 , clear.y1,
623: clear.x2 - clear.x1 + 1, i - clear.y1+1, "backtile");
624: clear.y1 = top;
625: }
626: if (clear.y2 > bottom)
627: { // clear below view screen
628: i = clear.y1 > bottom+1 ? clear.y1 : bottom+1;
629: re.DrawTileClear (clear.x1, i,
630: clear.x2-clear.x1+1, clear.y2-i+1, "backtile");
631: clear.y2 = bottom;
632: }
633: if (clear.x1 < left)
634: { // clear left of view screen
635: i = clear.x2 < left-1 ? clear.x2 : left-1;
636: re.DrawTileClear (clear.x1, clear.y1,
637: i-clear.x1+1, clear.y2 - clear.y1 + 1, "backtile");
638: clear.x1 = left;
639: }
640: if (clear.x2 > right)
641: { // clear left of view screen
642: i = clear.x1 > right+1 ? clear.x1 : right+1;
643: re.DrawTileClear (i, clear.y1,
644: clear.x2-i+1, clear.y2 - clear.y1 + 1, "backtile");
645: clear.x2 = right;
646: }
647: }
648: //===============================================================
649: #define STAT_MINUS 10 // num frame for '-' stats digit
650: char *sb_nums[2][11] =
651: {
652: {"num_0", "num_1", "num_2", "num_3", "num_4", "num_5",
653: "num_6", "num_7", "num_8", "num_9", "num_minus"},
654: {"anum_0", "anum_1", "anum_2", "anum_3", "anum_4", "anum_5",
655: "anum_6", "anum_7", "anum_8", "anum_9", "anum_minus"}
656: };
657: #define ICON_WIDTH 24
658: #define ICON_HEIGHT 24
659: #define CHAR_WIDTH 16
660: #define ICON_SPACE 8
661: /*
662: ================
663: SizeHUDString
664: Allow embedded \n in the string
665: ================
666: */
667: void SizeHUDString (char *string, int *w, int *h)
668: {
669: int lines, width, current;
670: lines = 1;
671: width = 0;
672: current = 0;
673: while (*string)
674: {
675: if (*string == '\n')
676: {
677: lines++;
678: current = 0;
679: }
680: else
681: {
682: current++;
683: if (current > width)
684: width = current;
685: }
686: string++;
687: }
688: *w = width * 8;
689: *h = lines * 8;
690: }
691: void DrawHUDString (char *string, int x, int y, int centerwidth, int xor)
692: {
693: int margin;
694: char line[1024];
695: int width;
696: int i;
697: margin = x;
698: while (*string)
699: {
700: // scan out one line of text from the string
701: width = 0;
702: while (*string && *string != '\n')
703: line[width++] = *string++;
704: line[width] = 0;
705: if (centerwidth)
706: x = margin + (centerwidth - width*8)/2;
707: else
708: x = margin;
709: for (i=0 ; i<width ; i++)
710: {
711: re.DrawChar (x, y, line[i]^xor);
712: x += 8;
713: }
714: if (*string)
715: {
716: string++; // skip the \n
717: x = margin;
718: y += 8;
719: }
720: }
721: }
722: /*
723: ==============
724: SCR_DrawField
725: ==============
726: */
727: void SCR_DrawField (int x, int y, int color, int width, int value)
728: {
729: char num[16], *ptr;
730: int l;
731: int frame;
732: if (width < 1)
733: return;
734: // draw number string
735: if (width > 5)
736: width = 5;
737: SCR_AddDirtyPoint (x, y);
738: SCR_AddDirtyPoint (x+width*CHAR_WIDTH+2, y+23);
739:
740: Com_sprintf (num, sizeof(num), "%i", value);
741: l = strlen(num);
742: if (l > width)
743: l = width;
744: x += 2 + CHAR_WIDTH*(width - l);
745: ptr = num;
746: while (*ptr && l)
747: {
748: if (*ptr == '-')
749: frame = STAT_MINUS;
750: else
751: frame = *ptr -'0';
752: re.DrawPic (x,y,sb_nums[color][frame]);
753: x += CHAR_WIDTH;
754: ptr++;
755: l--;
756: }
757: }
758: /*
759: ===============
760: SCR_TouchPics
761: Allows rendering code to cache all needed sbar graphics
762: ===============
763: */
764: void SCR_TouchPics (void)
765: {
766: int i, j;
767: for (i=0 ; i<2 ; i++)
768: for (j=0 ; j<11 ; j++)
769: re.RegisterPic (sb_nums[i][j]);
770:
771: if (crosshair->value)
772: {
773: if (crosshair->value > 3 || crosshair->value < 0)
774: crosshair->value = 3;
775:
776: Com_sprintf (crosshair_pic, sizeof(crosshair_pic), "ch%i", (int)(crosshair->value));
777: re.DrawGetPicSize (&crosshair_width, &crosshair_height, crosshair_pic);
778: if (!crosshair_width)
779: crosshair_pic[0] = 0;
780: }
781: }
782: /*
783: ================
784: SCR_ExecuteLayoutString
785: ================
786: */
787: void SCR_ExecuteLayoutString (char *s)
788: {
789: int x, y;
790: int value;
791: char *token;
792: int width;
793: int index;
794: clientinfo_t *ci;
795: if (cls.state != ca_active || !cl.refresh_prepped)
796: return;
797: if (!s[0])
798: return;
799: x = 0;
800: y = 0;
801: width = 3;
802: while (s)
803: {
804: token = COM_Parse (&s);
805: if (!strcmp(token, "xl"))
806: {
807: token = COM_Parse (&s);
808: x = atoi(token);
809: continue;
810: }
811: if (!strcmp(token, "xr"))
812: {
813: token = COM_Parse (&s);
814: x = viddef.width + atoi(token);
815: continue;
816: }
817: if (!strcmp(token, "xv"))
818: {
819: token = COM_Parse (&s);
820: x = viddef.width/2 - 160 + atoi(token);
821: continue;
822: }
823: if (!strcmp(token, "yt"))
824: {
825: token = COM_Parse (&s);
826: y = atoi(token);
827: continue;
828: }
829: if (!strcmp(token, "yb"))
830: {
831: token = COM_Parse (&s);
832: y = viddef.height + atoi(token);
833: continue;
834: }
835: if (!strcmp(token, "yv"))
836: {
837: token = COM_Parse (&s);
838: y = viddef.height/2 - 120 + atoi(token);
839: continue;
840: }
841: if (!strcmp(token, "pic"))
842: { // draw a pic from a stat number
843: token = COM_Parse (&s);
844: value = cl.frame.playerstate.stats[atoi(token)];
845: if (value >= MAX_IMAGES)
846: Com_Error (ERR_DROP, "Pic >= MAX_IMAGES");
847: if (cl.configstrings[CS_IMAGES+value])
848: {
849: SCR_AddDirtyPoint (x, y);
850: SCR_AddDirtyPoint (x+23, y+23);
851: re.DrawPic (x, y, cl.configstrings[CS_IMAGES+value]);
852: }
853: continue;
854: }
855:
856: if (!strcmp(token, "client"))
857: { // draw a deathmatch client block
858: int score, ping, time;
859:
860: token = COM_Parse (&s);
861: x = viddef.width/2 - 160 + atoi(token);
862: token = COM_Parse (&s);
863: y = viddef.height/2 - 120 + atoi(token);
864: SCR_AddDirtyPoint (x, y);
865: SCR_AddDirtyPoint (x+159, y+31);
866:
867: token = COM_Parse (&s);
868: value = atoi(token);
869: if (value >= MAX_CLIENTS || value < 0)
870: Com_Error (ERR_DROP, "client >= MAX_CLIENTS");
871: ci = &cl.clientinfo[value];
872:
873: token = COM_Parse (&s);
874: score = atoi(token);
875:
876: token = COM_Parse (&s);
877: ping = atoi(token);
878:
879: token = COM_Parse (&s);
880: time = atoi(token);
881:
882: DrawAltString (x+32, y, ci->name);
883: DrawString (x+32, y+8, "Score: ");
884: DrawAltString (x+32+7*8, y+8, va("%i", score));
885: DrawString (x+32, y+16, va("Ping: %i", ping));
886: DrawString (x+32, y+24, va("Time: %i", time));
887:
888: if (!ci->icon)
889: ci = &cl.baseclientinfo;
890: re.DrawPic (x, y, ci->iconname);
891: continue;
892: }
893:
894: if (!strcmp(token, "ctf"))
895: { // draw a ctf client block
896: int score, ping;
897: char block[80];
898:
899: token = COM_Parse (&s);
900: x = viddef.width/2 - 160 + atoi(token);
901: token = COM_Parse (&s);
902: y = viddef.height/2 - 120 + atoi(token);
903: SCR_AddDirtyPoint (x, y);
904: SCR_AddDirtyPoint (x+159, y+31);
905:
906: token = COM_Parse (&s);
907: value = atoi(token);
908: if (value >= MAX_CLIENTS || value < 0)
909: Com_Error (ERR_DROP, "client >= MAX_CLIENTS");
910: ci = &cl.clientinfo[value];
911:
912: token = COM_Parse (&s);
913: score = atoi(token);
914:
915: token = COM_Parse (&s);
916: ping = atoi(token);
917: if (ping > 999)
918: ping = 999;
919:
920: sprintf(block, "%3d %3d %-12.12s", score, ping, ci->name);
921:
922: if (value == cl.playernum)
923: DrawAltString (x, y, block);
924: else
925: DrawString (x, y, block);
926: continue;
927: }
928:
929: if (!strcmp(token, "picn"))
930: { // draw a pic from a name
931: token = COM_Parse (&s);
932: SCR_AddDirtyPoint (x, y);
933: SCR_AddDirtyPoint (x+23, y+23);
934: re.DrawPic (x, y, token);
935: continue;
936: }
937: if (!strcmp(token, "num"))
938: { // draw a number
939: token = COM_Parse (&s);
940: width = atoi(token);
941: token = COM_Parse (&s);
942: value = cl.frame.playerstate.stats[atoi(token)];
943: SCR_DrawField (x, y, 0, width, value);
944: continue;
945: }
946:
947: if (!strcmp(token, "hnum"))
948: { // health number
949: int color;
950:
951: width = 3;
952: value = cl.frame.playerstate.stats[STAT_HEALTH];
953: if (value > 25)
954: color = 0; // green
955: else if (value > 0)
956: color = (cl.frame.serverframe>>2) & 1; // flash
957: else
958: color = 1;
959:
960: if (cl.frame.playerstate.stats[STAT_FLASHES] & 1)
961: re.DrawPic (x, y, "field_3");
962:
963: SCR_DrawField (x, y, color, width, value);
964: continue;
965: }
966:
967: if (!strcmp(token, "anum"))
968: { // ammo number
969: int color;
970:
971: width = 3;
972: value = cl.frame.playerstate.stats[STAT_AMMO];
973: if (value > 5)
974: color = 0; // green
975: else if (value >= 0)
976: color = (cl.frame.serverframe>>2) & 1; // flash
977: else
978: continue; // negative number = don't show
979:
980: if (cl.frame.playerstate.stats[STAT_FLASHES] & 4)
981: re.DrawPic (x, y, "field_3");
982:
983: SCR_DrawField (x, y, color, width, value);
984: continue;
985: }
986:
987: if (!strcmp(token, "rnum"))
988: { // armor number
989: int color;
990:
991: width = 3;
992: value = cl.frame.playerstate.stats[STAT_ARMOR];
993: if (value < 1)
994: continue;
995:
996: color = 0; // green
997:
998: if (cl.frame.playerstate.stats[STAT_FLASHES] & 2)
999: re.DrawPic (x, y, "field_3");
1000:
1001: SCR_DrawField (x, y, color, width, value);
1002: continue;
1003: }
1004:
1005:
1006: if (!strcmp(token, "stat_string"))
1007: {
1008: token = COM_Parse (&s);
1009: index = atoi(token);
1010: if (index < 0 || index >= MAX_CONFIGSTRINGS)
1011: Com_Error (ERR_DROP, "Bad stat_string index");
1012: index = cl.frame.playerstate.stats[index];
1013: if (index < 0 || index >= MAX_CONFIGSTRINGS)
1014: Com_Error (ERR_DROP, "Bad stat_string index");
1015: DrawString (x, y, cl.configstrings[index]);
1016: continue;
1017: }
1018: if (!strcmp(token, "cstring"))
1019: {
1020: token = COM_Parse (&s);
1021: DrawHUDString (token, x, y, 320, 0);
1022: continue;
1023: }
1024: if (!strcmp(token, "string"))
1025: {
1026: token = COM_Parse (&s);
1027: DrawString (x, y, token);
1028: continue;
1029: }
1030:
1031: if (!strcmp(token, "cstring2"))
1032: {
1033: token = COM_Parse (&s);
1034: DrawHUDString (token, x, y, 320,0x80);
1035: continue;
1036: }
1037:
1038: if (!strcmp(token, "string2"))
1039: {
1040: token = COM_Parse (&s);
1041: DrawAltString (x, y, token);
1042: continue;
1043: }
1044: if (!strcmp(token, "if"))
1045: { // draw a number
1046: token = COM_Parse (&s);
1047: value = cl.frame.playerstate.stats[atoi(token)];
1048: if (!value)
1049: { // skip to endif
1050: while (s && strcmp(token, "endif") )
1051: {
1052: token = COM_Parse (&s);
1053: }
1054: }
1055: continue;
1056: }
1057: }
1058: }
1059: /*
1060: ================
1061: SCR_DrawStats
1062: The status bar is a small layout program that
1063: is based on the stats array
1064: ================
1065: */
1066: void SCR_DrawStats (void)
1067: {
1068: SCR_ExecuteLayoutString (cl.configstrings[CS_STATUSBAR]);
1069: }
1070: /*
1071: ================
1072: SCR_DrawLayout
1073: ================
1074: */
1075: #define STAT_LAYOUTS 13
1076: void SCR_DrawLayout (void)
1077: {
1078: if (!cl.frame.playerstate.stats[STAT_LAYOUTS])
1079: return;
1080: SCR_ExecuteLayoutString (cl.layout);
1081: }
1082: //=======================================================
1083: /*
1084: ==================
1085: SCR_UpdateScreen
1086: This is called every frame, and can also be called explicitly to flush
1087: text to the screen.
1088: ==================
1089: */
1090: void SCR_UpdateScreen (void)
1091: {
1092: int numframes;
1093: int i;
1094: float separation[2] = { 0, 0 };
1095:
1096: // if the screen is disabled (loading plaque is up, or vid mode changing)
1097: // do nothing at all
1098: if (cls.disable_screen)
1099: {
1100: if (Sys_Milliseconds() - cls.disable_screen > 120000)
1101: {
1102: cls.disable_screen = 0;
1103: Com_Printf ("Loading plaque timed out.\n");
1104: }
1105: return;
1106: }
1107:
1108: if (!scr_initialized || !con.initialized)
1109: return; // not initialized yet
1110:
1111: /*
1112: ** range check cl_camera_separation so we don't inadvertently fry someone's
1113: ** brain
1114: */
1115: if ( cl_stereo_separation->value > 1.0 )
1116: Cvar_SetValue( "cl_stereo_separation", 1.0 );
1117: else if ( cl_stereo_separation->value < 0 )
1118: Cvar_SetValue( "cl_stereo_separation", 0.0 );
1119:
1120: if ( cl_stereo->value )
1121: {
1122: numframes = 2;
1123: separation[0] = -cl_stereo_separation->value / 2;
1124: separation[1] = cl_stereo_separation->value / 2;
1125: }
1126: else
1127: {
1128: separation[0] = 0;
1129: separation[1] = 0;
1130: numframes = 1;
1131: }
1132: for ( i = 0; i < numframes; i++ )
1133: {
1134: re.BeginFrame( separation[i] );
1135: if (scr_draw_loading == 2)
1136: { // loading plaque over black screen
1137: int w, h;
1138: re.CinematicSetPalette(NULL);
1139: scr_draw_loading = false;
1140: re.DrawGetPicSize (&w, &h, "loading");
1141: re.DrawPic ((viddef.width-w)/2, (viddef.height-h)/2, "loading");
1142: // re.EndFrame();
1143: // return;
1144: }
1145: // if a cinematic is supposed to be running, handle menus
1146: // and console specially
1147: else if (cl.cinematictime > 0)
1148: {
1149: if (cls.key_dest == key_menu)
1150: {
1151: if (cl.cinematicpalette_active)
1152: {
1153: re.CinematicSetPalette(NULL);
1154: cl.cinematicpalette_active = false;
1155: }
1156: M_Draw ();
1157: // re.EndFrame();
1158: // return;
1159: }
1160: else if (cls.key_dest == key_console)
1161: {
1162: if (cl.cinematicpalette_active)
1163: {
1164: re.CinematicSetPalette(NULL);
1165: cl.cinematicpalette_active = false;
1166: }
1167: SCR_DrawConsole ();
1168: // re.EndFrame();
1169: // return;
1170: }
1171: else
1172: {
1173: SCR_DrawCinematic();
1174: // re.EndFrame();
1175: // return;
1176: }
1177: }
1178: else
1179: {
1180: // make sure the game palette is active
1181: if (cl.cinematicpalette_active)
1182: {
1183: re.CinematicSetPalette(NULL);
1184: cl.cinematicpalette_active = false;
1185: }
1186: // do 3D refresh drawing, and then update the screen
1187: SCR_CalcVrect ();
1188: // clear any dirty part of the background
1189: SCR_TileClear ();
1190: V_RenderView ( separation[i] );
1191: SCR_DrawStats ();
1192: if (cl.frame.playerstate.stats[STAT_LAYOUTS] & 1)
1193: SCR_DrawLayout ();
1194: if (cl.frame.playerstate.stats[STAT_LAYOUTS] & 2)
1195: CL_DrawInventory ();
1196:
1197: SCR_DrawNet ();
1198: SCR_CheckDrawCenterString ();
1199: if (scr_timegraph->value)
1200: SCR_DebugGraph (cls.frametime*300, 0);
1201: if (scr_debuggraph->value || scr_timegraph->value || scr_netgraph->value)
1202: SCR_DrawDebugGraph ();
1203: SCR_DrawPause ();
1204: SCR_DrawConsole ();
1205: M_Draw ();
1206: SCR_DrawLoading ();
1207: }
1208: }
1209: re.EndFrame();
1210: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.