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 */
SCR_CenterPrint(char * str)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
SCR_EraseCenterString(void)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
SCR_DrawCenterString(void)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
SCR_CheckDrawCenterString(void)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 */
CalcFov(float fov_x,float width,float height)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 */
SCR_CalcRefdef(void)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 */
SCR_SizeUp_f(void)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 */
SCR_SizeDown_f(void)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 */
SCR_Init(void)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 */
SCR_DrawRam(void)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 */
SCR_DrawTurtle(void)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 */
SCR_DrawNet(void)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
SCR_DrawFPS(void)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 */
SCR_DrawPause(void)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 */
SCR_SetUpToDrawConsole(void)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 */
SCR_DrawConsole(void)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 */
WritePCXfile(char * filename,byte * data,int width,int height,int rowbytes,byte * palette,qboolean upload)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 */
SCR_ScreenShot_f(void)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 */
MipColor(int r,int g,int b)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
SCR_DrawCharToSnap(int num,byte * dest,int width)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
SCR_DrawStringToSnap(const char * s,byte * buf,int x,int y,int width)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 */
SCR_RSShot_f(void)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
SCR_DrawNotifyString(void)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 */
SCR_ModalMessage(char * text)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 */
SCR_BringDownConsole(void)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 */
SCR_UpdateScreen(void)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 */
SCR_UpdateWholeScreen(void)1172 void SCR_UpdateWholeScreen (void)
1173 {
1174 scr_fullupdate = 0;
1175 SCR_UpdateScreen ();
1176 }
1177