|
|
1.1 root 1: /*
2: Copyright (C) 1996-1997 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: // screen.c -- master for refresh, status bar, console, chat, notify, etc
21:
22: #include "quakedef.h"
23: #include "r_local.h"
24:
25: #include <time.h>
26:
27: /*
28:
29: background clear
30: rendering
31: turtle/net/ram icons
32: sbar
33: centerprint / slow centerprint
34: notify lines
35: intermission / finale overlay
36: loading plaque
37: console
38: menu
39:
40: required background clears
41: required update regions
42:
43:
44: syncronous draw mode or async
45: One off screen buffer, with updates either copied or xblited
46: Need to double buffer?
47:
48:
49: async draw will require the refresh area to be cleared, because it will be
50: xblited, but sync draw can just ignore it.
51:
52: sync
53: draw
54:
55: CenterPrint ()
56: SlowPrint ()
57: Screen_Update ();
58: Con_Printf ();
59:
60: net
61: turn off messages option
62:
63: the refresh is allways rendered, unless the console is full screen
64:
65:
66: console is:
67: notify lines
68: half
69: full
70:
71:
72: */
73:
74:
75: // only the refresh window will be updated unless these variables are flagged
76: int scr_copytop;
77: int scr_copyeverything;
78:
79: float scr_con_current;
80: float scr_conlines; // lines of console to display
81:
82: float oldscreensize, oldfov;
83: float oldsbar;
84: cvar_t scr_viewsize = {"viewsize","100", true};
85: cvar_t scr_fov = {"fov","90"}; // 10 - 170
86: cvar_t scr_conspeed = {"scr_conspeed","300"};
87: cvar_t scr_centertime = {"scr_centertime","2"};
88: cvar_t scr_showram = {"showram","1"};
89: cvar_t scr_showturtle = {"showturtle","0"};
90: cvar_t scr_showpause = {"showpause","1"};
91: cvar_t scr_printspeed = {"scr_printspeed","8"};
92: cvar_t scr_allowsnap = {"scr_allowsnap", "1"};
93:
94: qboolean scr_initialized; // ready to draw
95:
96: qpic_t *scr_ram;
97: qpic_t *scr_net;
98: qpic_t *scr_turtle;
99:
100: int scr_fullupdate;
101:
102: int clearconsole;
103: int clearnotify;
104:
105: int sb_lines;
106:
107: viddef_t vid; // global video state
108:
109: vrect_t *pconupdate;
110: vrect_t scr_vrect;
111:
112: qboolean scr_disabled_for_loading;
113:
114: qboolean scr_skipupdate;
115:
116: qboolean block_drawing;
117:
118: void SCR_ScreenShot_f (void);
119: void SCR_RSShot_f (void);
120:
121: /*
122: ===============================================================================
123:
124: CENTER PRINTING
125:
126: ===============================================================================
127: */
128:
129: char scr_centerstring[1024];
130: float scr_centertime_start; // for slow victory printing
131: float scr_centertime_off;
132: int scr_center_lines;
133: int scr_erase_lines;
134: int scr_erase_center;
135:
136: /*
137: ==============
138: SCR_CenterPrint
139:
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: strncpy (scr_centerstring, str, sizeof(scr_centerstring)-1);
147: scr_centertime_off = scr_centertime.value;
148: scr_centertime_start = cl.time;
149:
150: // count the number of lines for centering
151: scr_center_lines = 1;
152: while (*str)
153: {
154: if (*str == '\n')
155: scr_center_lines++;
156: str++;
157: }
158: }
159:
160: void SCR_EraseCenterString (void)
161: {
162: int y;
163:
164: if (scr_erase_center++ > vid.numpages)
165: {
166: scr_erase_lines = 0;
167: return;
168: }
169:
170: if (scr_center_lines <= 4)
171: y = vid.height*0.35;
172: else
173: y = 48;
174:
175: scr_copytop = 1;
176: Draw_TileClear (0, y, vid.width, min(8*scr_erase_lines, vid.height - y - 1));
177: }
178:
179: void SCR_DrawCenterString (void)
180: {
181: char *start;
182: int l;
183: int j;
184: int x, y;
185: int remaining;
186:
187: // the finale prints the characters one at a time
188: if (cl.intermission)
189: remaining = scr_printspeed.value * (cl.time - scr_centertime_start);
190: else
191: remaining = 9999;
192:
193: scr_erase_center = 0;
194: start = scr_centerstring;
195:
196: if (scr_center_lines <= 4)
197: y = vid.height*0.35;
198: else
199: y = 48;
200:
201: do
202: {
203: // scan the width of the line
204: for (l=0 ; l<40 ; l++)
205: if (start[l] == '\n' || !start[l])
206: break;
207: x = (vid.width - l*8)/2;
208: for (j=0 ; j<l ; j++, x+=8)
209: {
210: Draw_Character (x, y, start[j]);
211: if (!remaining--)
212: return;
213: }
214:
215: y += 8;
216:
217: while (*start && *start != '\n')
218: start++;
219:
220: if (!*start)
221: break;
222: start++; // skip the \n
223: } while (1);
224: }
225:
226: void SCR_CheckDrawCenterString (void)
227: {
228: scr_copytop = 1;
229: if (scr_center_lines > scr_erase_lines)
230: scr_erase_lines = scr_center_lines;
231:
232: scr_centertime_off -= host_frametime;
233:
234: if (scr_centertime_off <= 0 && !cl.intermission)
235: return;
236: if (key_dest != key_game)
237: return;
238:
239: SCR_DrawCenterString ();
240: }
241:
242: //=============================================================================
243:
244: /*
245: ====================
246: CalcFov
247: ====================
248: */
249: float CalcFov (float fov_x, float width, float height)
250: {
251: float a;
252: float x;
253:
254: if (fov_x < 1 || fov_x > 179)
255: Sys_Error ("Bad fov: %f", fov_x);
256:
257: x = width/tan(fov_x/360*M_PI);
258:
259: a = atan (height/x);
260:
261: a = a*360/M_PI;
262:
263: return a;
264: }
265:
266: /*
267: =================
268: SCR_CalcRefdef
269:
270: Must be called whenever vid changes
271: Internal use only
272: =================
273: */
274: static void SCR_CalcRefdef (void)
275: {
276: vrect_t vrect;
277: float size;
278:
279: scr_fullupdate = 0; // force a background redraw
280: vid.recalc_refdef = 0;
281:
282: // force the status bar to redraw
283: Sbar_Changed ();
284:
285: //========================================
286:
287: // bound viewsize
288: if (scr_viewsize.value < 30)
289: Cvar_Set ("viewsize","30");
290: if (scr_viewsize.value > 120)
291: Cvar_Set ("viewsize","120");
292:
293: // bound field of view
294: if (scr_fov.value < 10)
295: Cvar_Set ("fov","10");
296: if (scr_fov.value > 170)
297: Cvar_Set ("fov","170");
298:
299: r_refdef.fov_x = scr_fov.value;
300: r_refdef.fov_y = CalcFov (r_refdef.fov_x, r_refdef.vrect.width, r_refdef.vrect.height);
301:
302: // intermission is always full screen
303: if (cl.intermission)
304: size = 120;
305: else
306: size = scr_viewsize.value;
307:
308: if (size >= 120)
309: sb_lines = 0; // no status bar at all
310: else if (size >= 110)
311: sb_lines = 24; // no inventory
312: else
313: sb_lines = 24+16+8;
314:
315: // these calculations mirror those in R_Init() for r_refdef, but take no
316: // account of water warping
317: vrect.x = 0;
318: vrect.y = 0;
319: vrect.width = vid.width;
320: vrect.height = vid.height;
321:
322: R_SetVrect (&vrect, &scr_vrect, sb_lines);
323:
324: // guard against going from one mode to another that's less than half the
325: // vertical resolution
326: if (scr_con_current > vid.height)
327: scr_con_current = vid.height;
328:
329: // notify the refresh of the change
330: R_ViewChanged (&vrect, sb_lines, vid.aspect);
331: }
332:
333:
334: /*
335: =================
336: SCR_SizeUp_f
337:
338: Keybinding command
339: =================
340: */
341: void SCR_SizeUp_f (void)
342: {
343: if (scr_viewsize.value < 120) {
344: Cvar_SetValue ("viewsize",scr_viewsize.value+10);
345: vid.recalc_refdef = 1;
346: }
347: }
348:
349:
350: /*
351: =================
352: SCR_SizeDown_f
353:
354: Keybinding command
355: =================
356: */
357: void SCR_SizeDown_f (void)
358: {
359: Cvar_SetValue ("viewsize",scr_viewsize.value-10);
360: vid.recalc_refdef = 1;
361: }
362:
363: //============================================================================
364:
365: /*
366: ==================
367: SCR_Init
368: ==================
369: */
370: void SCR_Init (void)
371: {
372: Cvar_RegisterVariable (&scr_fov);
373: Cvar_RegisterVariable (&scr_viewsize);
374: Cvar_RegisterVariable (&scr_conspeed);
375: Cvar_RegisterVariable (&scr_showram);
376: Cvar_RegisterVariable (&scr_showturtle);
377: Cvar_RegisterVariable (&scr_showpause);
378: Cvar_RegisterVariable (&scr_centertime);
379: Cvar_RegisterVariable (&scr_printspeed);
380: Cvar_RegisterVariable (&scr_allowsnap);
381:
382: //
383: // register our commands
384: //
385: Cmd_AddCommand ("screenshot",SCR_ScreenShot_f);
386: Cmd_AddCommand ("snap",SCR_RSShot_f);
387: Cmd_AddCommand ("sizeup",SCR_SizeUp_f);
388: Cmd_AddCommand ("sizedown",SCR_SizeDown_f);
389:
390: scr_ram = W_GetLumpName ("ram");
391: scr_net = W_GetLumpName ("net");
392: scr_turtle = W_GetLumpName ("turtle");
393:
394: scr_initialized = true;
395: }
396:
397:
398:
399: /*
400: ==============
401: SCR_DrawRam
402: ==============
403: */
404: void SCR_DrawRam (void)
405: {
406: if (!scr_showram.value)
407: return;
408:
409: if (!r_cache_thrash)
410: return;
411:
412: Draw_Pic (scr_vrect.x+32, scr_vrect.y, scr_ram);
413: }
414:
415: /*
416: ==============
417: SCR_DrawTurtle
418: ==============
419: */
420: void SCR_DrawTurtle (void)
421: {
422: static int count;
423:
424: if (!scr_showturtle.value)
425: return;
426:
427: if (host_frametime < 0.1)
428: {
429: count = 0;
430: return;
431: }
432:
433: count++;
434: if (count < 3)
435: return;
436:
437: Draw_Pic (scr_vrect.x, scr_vrect.y, scr_turtle);
438: }
439:
440: /*
441: ==============
442: SCR_DrawNet
443: ==============
444: */
445: void SCR_DrawNet (void)
446: {
447: if (cls.netchan.outgoing_sequence - cls.netchan.incoming_acknowledged < UPDATE_BACKUP-1)
448: return;
449: if (cls.demoplayback)
450: return;
451:
452: Draw_Pic (scr_vrect.x+64, scr_vrect.y, scr_net);
453: }
454:
455: void SCR_DrawFPS (void)
456: {
457: extern cvar_t show_fps;
458: static double lastframetime;
459: double t;
460: extern int fps_count;
461: static lastfps;
462: int x, y;
463: char st[80];
464:
465: if (!show_fps.value)
466: return;
467:
468: t = Sys_DoubleTime();
469: if ((t - lastframetime) >= 1.0) {
470: lastfps = fps_count;
471: fps_count = 0;
472: lastframetime = t;
473: }
474:
475: sprintf(st, "%3d FPS", lastfps);
476: x = vid.width - strlen(st) * 8 - 8;
477: y = vid.height - sb_lines - 8;
478: // Draw_TileClear(x, y, strlen(st) * 8, 8);
479: Draw_String(x, y, st);
480: }
481:
482: /*
483: ==============
484: DrawPause
485: ==============
486: */
487: void SCR_DrawPause (void)
488: {
489: qpic_t *pic;
490:
491: if (!scr_showpause.value) // turn off for screenshots
492: return;
493:
494: if (!cl.paused)
495: return;
496:
497: pic = Draw_CachePic ("gfx/pause.lmp");
498: Draw_Pic ( (vid.width - pic->width)/2,
499: (vid.height - 48 - pic->height)/2, pic);
500: }
501:
502:
503: //=============================================================================
504:
505:
506: /*
507: ==================
508: SCR_SetUpToDrawConsole
509: ==================
510: */
511: void SCR_SetUpToDrawConsole (void)
512: {
513: Con_CheckResize ();
514:
515: // decide on the height of the console
516: if (cls.state != ca_active)
517: {
518: scr_conlines = vid.height; // full screen
519: scr_con_current = scr_conlines;
520: }
521: else if (key_dest == key_console)
522: scr_conlines = vid.height/2; // half screen
523: else
524: scr_conlines = 0; // none visible
525:
526: if (scr_conlines < scr_con_current)
527: {
528: scr_con_current -= scr_conspeed.value*host_frametime;
529: if (scr_conlines > scr_con_current)
530: scr_con_current = scr_conlines;
531:
532: }
533: else if (scr_conlines > scr_con_current)
534: {
535: scr_con_current += scr_conspeed.value*host_frametime;
536: if (scr_conlines < scr_con_current)
537: scr_con_current = scr_conlines;
538: }
539:
540: if (clearconsole++ < vid.numpages)
541: {
542: scr_copytop = 1;
543: Draw_TileClear (0,(int)scr_con_current,vid.width, vid.height - (int)scr_con_current);
544: Sbar_Changed ();
545: }
546: else if (clearnotify++ < vid.numpages)
547: {
548: scr_copytop = 1;
549: Draw_TileClear (0,0,vid.width, con_notifylines);
550: }
551: else
552: con_notifylines = 0;
553: }
554:
555: /*
556: ==================
557: SCR_DrawConsole
558: ==================
559: */
560: void SCR_DrawConsole (void)
561: {
562: if (scr_con_current)
563: {
564: scr_copyeverything = 1;
565: Con_DrawConsole (scr_con_current);
566: clearconsole = 0;
567: }
568: else
569: {
570: if (key_dest == key_game || key_dest == key_message)
571: Con_DrawNotify (); // only draw notify in game
572: }
573: }
574:
575:
576: /*
577: ==============================================================================
578:
579: SCREEN SHOTS
580:
581: ==============================================================================
582: */
583:
584:
585: /*
586: ==============
587: WritePCXfile
588: ==============
589: */
590: void WritePCXfile (char *filename, byte *data, int width, int height,
591: int rowbytes, byte *palette, qboolean upload)
592: {
593: int i, j, length;
594: pcx_t *pcx;
595: byte *pack;
596:
597: pcx = Hunk_TempAlloc (width*height*2+1000);
598: if (pcx == NULL)
599: {
600: Con_Printf("SCR_ScreenShot_f: not enough memory\n");
601: return;
602: }
603:
604: pcx->manufacturer = 0x0a; // PCX id
605: pcx->version = 5; // 256 color
606: pcx->encoding = 1; // uncompressed
607: pcx->bits_per_pixel = 8; // 256 color
608: pcx->xmin = 0;
609: pcx->ymin = 0;
610: pcx->xmax = LittleShort((short)(width-1));
611: pcx->ymax = LittleShort((short)(height-1));
612: pcx->hres = LittleShort((short)width);
613: pcx->vres = LittleShort((short)height);
614: Q_memset (pcx->palette,0,sizeof(pcx->palette));
615: pcx->color_planes = 1; // chunky image
616: pcx->bytes_per_line = LittleShort((short)width);
617: pcx->palette_type = LittleShort(2); // not a grey scale
618: Q_memset (pcx->filler,0,sizeof(pcx->filler));
619:
620: // pack the image
621: pack = &pcx->data;
622:
623: for (i=0 ; i<height ; i++)
624: {
625: for (j=0 ; j<width ; j++)
626: {
627: if ( (*data & 0xc0) != 0xc0)
628: *pack++ = *data++;
629: else
630: {
631: *pack++ = 0xc1;
632: *pack++ = *data++;
633: }
634: }
635:
636: data += rowbytes - width;
637: }
638:
639: // write the palette
640: *pack++ = 0x0c; // palette ID byte
641: for (i=0 ; i<768 ; i++)
642: *pack++ = *palette++;
643:
644: // write output file
645: length = pack - (byte *)pcx;
646: if (upload)
647: CL_StartUpload((void *)pcx, length);
648: else
649: COM_WriteFile (filename, pcx, length);
650: }
651:
652:
653:
654: /*
655: ==================
656: SCR_ScreenShot_f
657: ==================
658: */
659: void SCR_ScreenShot_f (void)
660: {
661: int i;
662: char pcxname[80];
663: char checkname[MAX_OSPATH];
664:
665: //
666: // find a file name to save it to
667: //
668: strcpy(pcxname,"quake00.pcx");
669:
670: for (i=0 ; i<=99 ; i++)
671: {
672: pcxname[5] = i/10 + '0';
673: pcxname[6] = i%10 + '0';
674: sprintf (checkname, "%s/%s", com_gamedir, pcxname);
675: if (Sys_FileTime(checkname) == -1)
676: break; // file doesn't exist
677: }
678: if (i==100)
679: {
680: Con_Printf ("SCR_ScreenShot_f: Couldn't create a PCX");
681: return;
682: }
683:
684: //
685: // save the pcx file
686: //
687: D_EnableBackBufferAccess (); // enable direct drawing of console to back
688: // buffer
689:
690: WritePCXfile (pcxname, vid.buffer, vid.width, vid.height, vid.rowbytes,
691: host_basepal, false);
692:
693: D_DisableBackBufferAccess (); // for adapters that can't stay mapped in
694: // for linear writes all the time
695:
696: Con_Printf ("Wrote %s\n", pcxname);
697: }
698:
699: /*
700: Find closest color in the palette for named color
701: */
702: int MipColor(int r, int g, int b)
703: {
704: int i;
705: float dist;
706: int best;
707: float bestdist;
708: int r1, g1, b1;
709: static int lr = -1, lg = -1, lb = -1;
710: static int lastbest;
711:
712: if (r == lr && g == lg && b == lb)
713: return lastbest;
714:
715: bestdist = 256*256*3;
716:
717: for (i = 0; i < 256; i++) {
718: r1 = host_basepal[i*3] - r;
719: g1 = host_basepal[i*3+1] - g;
720: b1 = host_basepal[i*3+2] - b;
721: dist = r1*r1 + g1*g1 + b1*b1;
722: if (dist < bestdist) {
723: bestdist = dist;
724: best = i;
725: }
726: }
727: lr = r; lg = g; lb = b;
728: lastbest = best;
729: return best;
730: }
731:
732: // in draw.c
733: extern byte *draw_chars; // 8*8 graphic characters
734:
735: void SCR_DrawCharToSnap (int num, byte *dest, int width)
736: {
737: int row, col;
738: byte *source;
739: int drawline;
740: int x;
741:
742: row = num>>4;
743: col = num&15;
744: source = draw_chars + (row<<10) + (col<<3);
745:
746: drawline = 8;
747:
748: while (drawline--)
749: {
750: for (x=0 ; x<8 ; x++)
751: if (source[x])
752: dest[x] = source[x];
753: else
754: dest[x] = 98;
755: source += 128;
756: dest += width;
757: }
758:
759: }
760:
761: void SCR_DrawStringToSnap (const char *s, byte *buf, int x, int y, int width)
762: {
763: byte *dest;
764: const unsigned char *p;
765:
766: dest = buf + ((y * width) + x);
767:
768: p = (const unsigned char *)s;
769: while (*p) {
770: SCR_DrawCharToSnap(*p++, dest, width);
771: dest += 8;
772: }
773: }
774:
775:
776: /*
777: ==================
778: SCR_RSShot_f
779: ==================
780: */
781: void SCR_RSShot_f (void)
782: {
783: int i, x, y;
784: unsigned char *src, *dest;
785: char pcxname[80];
786: char checkname[MAX_OSPATH];
787: unsigned char *newbuf, *srcbuf;
788: int srcrowbytes;
789: int w, h;
790: int dx, dy, dex, dey, nx;
791: int r, b, g;
792: int count;
793: float fracw, frach;
794: char st[80];
795: time_t now;
796:
797: if (CL_IsUploading())
798: return; // already one pending
799:
800: if (cls.state < ca_onserver)
801: return; // gotta be connected
802:
803: if (!scr_allowsnap.value) {
804: MSG_WriteByte (&cls.netchan.message, clc_stringcmd);
805: SZ_Print (&cls.netchan.message, "snap\n");
806: Con_Printf("Refusing remote screen shot request.\n");
807: return;
808: }
809:
810: Con_Printf("Remote screen shot requested.\n");
811:
812: #if 0
813: //
814: // find a file name to save it to
815: //
816: strcpy(pcxname,"mquake00.pcx");
817:
818: for (i=0 ; i<=99 ; i++)
819: {
820: pcxname[6] = i/10 + '0';
821: pcxname[7] = i%10 + '0';
822: sprintf (checkname, "%s/%s", com_gamedir, pcxname);
823: if (Sys_FileTime(checkname) == -1)
824: break; // file doesn't exist
825: }
826: if (i==100)
827: {
828: Con_Printf ("SCR_ScreenShot_f: Couldn't create a PCX");
829: return;
830: }
831: #endif
832:
833: //
834: // save the pcx file
835: //
836: D_EnableBackBufferAccess (); // enable direct drawing of console to back
837: // buffer
838:
839: w = (vid.width < RSSHOT_WIDTH) ? vid.width : RSSHOT_WIDTH;
840: h = (vid.height < RSSHOT_HEIGHT) ? vid.height : RSSHOT_HEIGHT;
841:
842: fracw = (float)vid.width / (float)w;
843: frach = (float)vid.height / (float)h;
844:
845: newbuf = malloc(w*h);
846:
847: for (y = 0; y < h; y++) {
848: dest = newbuf + (w * y);
849:
850: for (x = 0; x < w; x++) {
851: r = g = b = 0;
852:
853: dx = x * fracw;
854: dex = (x + 1) * fracw;
855: if (dex == dx) dex++; // at least one
856: dy = y * frach;
857: dey = (y + 1) * frach;
858: if (dey == dy) dey++; // at least one
859:
860: count = 0;
861: for (/* */; dy < dey; dy++) {
862: src = vid.buffer + (vid.rowbytes * dy) + dx;
863: for (nx = dx; nx < dex; nx++) {
864: r += host_basepal[*src * 3];
865: g += host_basepal[*src * 3+1];
866: b += host_basepal[*src * 3+2];
867: src++;
868: count++;
869: }
870: }
871: r /= count;
872: g /= count;
873: b /= count;
874: *dest++ = MipColor(r, g, b);
875: }
876: }
877:
878: time(&now);
879: strcpy(st, ctime(&now));
880: st[strlen(st) - 1] = 0;
881: SCR_DrawStringToSnap (st, newbuf, w - strlen(st)*8, 0, w);
882:
883: strncpy(st, cls.servername, sizeof(st));
884: st[sizeof(st) - 1] = 0;
885: SCR_DrawStringToSnap (st, newbuf, w - strlen(st)*8, 10, w);
886:
887: strncpy(st, name.string, sizeof(st));
888: st[sizeof(st) - 1] = 0;
889: SCR_DrawStringToSnap (st, newbuf, w - strlen(st)*8, 20, w);
890:
891: WritePCXfile (pcxname, newbuf, w, h, w, host_basepal, true);
892:
893: free(newbuf);
894:
895: D_DisableBackBufferAccess (); // for adapters that can't stay mapped in
896: // for linear writes all the time
897:
898: // Con_Printf ("Wrote %s\n", pcxname);
899: Con_Printf ("Sending shot to server...\n");
900: }
901:
902:
903: //=============================================================================
904:
905: char *scr_notifystring;
906: qboolean scr_drawdialog;
907:
908: void SCR_DrawNotifyString (void)
909: {
910: char *start;
911: int l;
912: int j;
913: int x, y;
914:
915: start = scr_notifystring;
916:
917: y = vid.height*0.35;
918:
919: do
920: {
921: // scan the width of the line
922: for (l=0 ; l<40 ; l++)
923: if (start[l] == '\n' || !start[l])
924: break;
925: x = (vid.width - l*8)/2;
926: for (j=0 ; j<l ; j++, x+=8)
927: Draw_Character (x, y, start[j]);
928:
929: y += 8;
930:
931: while (*start && *start != '\n')
932: start++;
933:
934: if (!*start)
935: break;
936: start++; // skip the \n
937: } while (1);
938: }
939:
940: /*
941: ==================
942: SCR_ModalMessage
943:
944: Displays a text string in the center of the screen and waits for a Y or N
945: keypress.
946: ==================
947: */
948: int SCR_ModalMessage (char *text)
949: {
950: scr_notifystring = text;
951:
952: // draw a fresh screen
953: scr_fullupdate = 0;
954: scr_drawdialog = true;
955: SCR_UpdateScreen ();
956: scr_drawdialog = false;
957:
958: S_ClearBuffer (); // so dma doesn't loop current sound
959:
960: do
961: {
962: key_count = -1; // wait for a key down and up
963: Sys_SendKeyEvents ();
964: } while (key_lastpress != 'y' && key_lastpress != 'n' && key_lastpress != K_ESCAPE);
965:
966: scr_fullupdate = 0;
967: SCR_UpdateScreen ();
968:
969: return key_lastpress == 'y';
970: }
971:
972:
973: //=============================================================================
974:
975: /*
976: ===============
977: SCR_BringDownConsole
978:
979: Brings the console down and fades the palettes back to normal
980: ================
981: */
982: void SCR_BringDownConsole (void)
983: {
984: int i;
985:
986: scr_centertime_off = 0;
987:
988: for (i=0 ; i<20 && scr_conlines != scr_con_current ; i++)
989: SCR_UpdateScreen ();
990:
991: cl.cshifts[0].percent = 0; // no area contents palette on next frame
992: VID_SetPalette (host_basepal);
993: }
994:
995:
996: /*
997: ==================
998: SCR_UpdateScreen
999:
1000: This is called every frame, and can also be called explicitly to flush
1001: text to the screen.
1002:
1003: WARNING: be very careful calling this from elsewhere, because the refresh
1004: needs almost the entire 256k of stack space!
1005: ==================
1006: */
1007: void SCR_UpdateScreen (void)
1008: {
1009: static float oldscr_viewsize;
1010: vrect_t vrect;
1011:
1012: if (scr_skipupdate || block_drawing)
1013: return;
1014:
1015: if (scr_disabled_for_loading)
1016: return;
1017:
1018: #ifdef _WIN32
1019: { // don't suck up any cpu if minimized
1020: extern int Minimized;
1021:
1022: if (Minimized)
1023: return;
1024: }
1025: #endif
1026:
1027: scr_copytop = 0;
1028: scr_copyeverything = 0;
1029:
1030: if (!scr_initialized || !con_initialized)
1031: return; // not initialized yet
1032:
1033: if (scr_viewsize.value != oldscr_viewsize)
1034: {
1035: oldscr_viewsize = scr_viewsize.value;
1036: vid.recalc_refdef = 1;
1037: }
1038:
1039: //
1040: // check for vid changes
1041: //
1042: if (oldfov != scr_fov.value)
1043: {
1044: oldfov = scr_fov.value;
1045: vid.recalc_refdef = true;
1046: }
1047:
1048: if (oldscreensize != scr_viewsize.value)
1049: {
1050: oldscreensize = scr_viewsize.value;
1051: vid.recalc_refdef = true;
1052: }
1053:
1054: if (oldsbar != cl_sbar.value)
1055: {
1056: oldsbar = cl_sbar.value;
1057: vid.recalc_refdef = true;
1058: }
1059:
1060: if (vid.recalc_refdef)
1061: {
1062: // something changed, so reorder the screen
1063: SCR_CalcRefdef ();
1064: }
1065:
1066: //
1067: // do 3D refresh drawing, and then update the screen
1068: //
1069: D_EnableBackBufferAccess (); // of all overlay stuff if drawing directly
1070:
1071: if (scr_fullupdate++ < vid.numpages)
1072: { // clear the entire screen
1073: scr_copyeverything = 1;
1074: Draw_TileClear (0,0,vid.width,vid.height);
1075: Sbar_Changed ();
1076: }
1077:
1078: pconupdate = NULL;
1079:
1080:
1081: SCR_SetUpToDrawConsole ();
1082: SCR_EraseCenterString ();
1083:
1084: D_DisableBackBufferAccess (); // for adapters that can't stay mapped in
1085: // for linear writes all the time
1086:
1087: VID_LockBuffer ();
1088: V_RenderView ();
1089: VID_UnlockBuffer ();
1090:
1091: D_EnableBackBufferAccess (); // of all overlay stuff if drawing directly
1092:
1093: if (scr_drawdialog)
1094: {
1095: Sbar_Draw ();
1096: Draw_FadeScreen ();
1097: SCR_DrawNotifyString ();
1098: scr_copyeverything = true;
1099: }
1100: else if (cl.intermission == 1 && key_dest == key_game)
1101: {
1102: Sbar_IntermissionOverlay ();
1103: }
1104: else if (cl.intermission == 2 && key_dest == key_game)
1105: {
1106: Sbar_FinaleOverlay ();
1107: SCR_CheckDrawCenterString ();
1108: }
1109: else
1110: {
1111: SCR_DrawRam ();
1112: SCR_DrawNet ();
1113: SCR_DrawTurtle ();
1114: SCR_DrawPause ();
1115: SCR_DrawFPS ();
1116: SCR_CheckDrawCenterString ();
1117: Sbar_Draw ();
1118: SCR_DrawConsole ();
1119: M_Draw ();
1120: }
1121:
1122:
1123: D_DisableBackBufferAccess (); // for adapters that can't stay mapped in
1124: // for linear writes all the time
1125: if (pconupdate)
1126: {
1127: D_UpdateRects (pconupdate);
1128: }
1129:
1130: V_UpdatePalette ();
1131:
1132: //
1133: // update one of three areas
1134: //
1135: if (scr_copyeverything)
1136: {
1137: vrect.x = 0;
1138: vrect.y = 0;
1139: vrect.width = vid.width;
1140: vrect.height = vid.height;
1141: vrect.pnext = 0;
1142:
1143: VID_Update (&vrect);
1144: }
1145: else if (scr_copytop)
1146: {
1147: vrect.x = 0;
1148: vrect.y = 0;
1149: vrect.width = vid.width;
1150: vrect.height = vid.height - sb_lines;
1151: vrect.pnext = 0;
1152:
1153: VID_Update (&vrect);
1154: }
1155: else
1156: {
1157: vrect.x = scr_vrect.x;
1158: vrect.y = scr_vrect.y;
1159: vrect.width = scr_vrect.width;
1160: vrect.height = scr_vrect.height;
1161: vrect.pnext = 0;
1162:
1163: VID_Update (&vrect);
1164: }
1165: }
1166:
1167: /*
1168: ==================
1169: SCR_UpdateWholeScreen
1170: ==================
1171: */
1172: void SCR_UpdateWholeScreen (void)
1173: {
1174: scr_fullupdate = 0;
1175: SCR_UpdateScreen ();
1176: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.