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