home *** CD-ROM | disk | FTP | other *** search
/ Magazyn Amiga 14 / MA_Cover_14.iso / source / c / q1source_amy / qw / client / gl_screen.c < prev    next >
Encoding:
C/C++ Source or Header  |  1999-12-21  |  24.3 KB  |  1,189 lines

  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 = {"viewsize","100", true};
  86. cvar_t          scr_fov = {"fov","90"}; // 10 - 170
  87. cvar_t          scr_conspeed = {"scr_conspeed","300"};
  88. cvar_t          scr_centertime = {"scr_centertime","2"};
  89. cvar_t          scr_showram = {"showram","1"};
  90. cvar_t          scr_showturtle = {"showturtle","0"};
  91. cvar_t          scr_showpause = {"showpause","1"};
  92. cvar_t          scr_printspeed = {"scr_printspeed","8"};
  93. cvar_t            scr_allowsnap = {"scr_allowsnap", "1"};
  94. cvar_t            gl_triplebuffer = {"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. */
  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.  
  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.  
  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. */
  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. */
  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 > vid.height - sb_lines)
  326.               r_refdef.vrect.height = vid.height - sb_lines;
  327.     } else if (r_refdef.vrect.height > 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. */
  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. */
  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. */
  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. */
  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. */
  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. */
  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.  
  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 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. */
  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. */
  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. */
  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. */
  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. */  
  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. WritePCXfile 
  678. ============== 
  679. */ 
  680. void WritePCXfile (char *filename, byte *data, int width, int height,
  681.     int rowbytes, byte *palette, qboolean upload) 
  682. {
  683.     int        i, j, length;
  684.     pcx_t    *pcx;
  685.     byte        *pack;
  686.       
  687.     pcx = Hunk_TempAlloc (width*height*2+1000);
  688.     if (pcx == NULL)
  689.     {
  690.         Con_Printf("SCR_ScreenShot_f: not enough memory\n");
  691.         return;
  692.     } 
  693.  
  694.     pcx->manufacturer = 0x0a;    // PCX id
  695.     pcx->version = 5;            // 256 color
  696.      pcx->encoding = 1;        // uncompressed
  697.     pcx->bits_per_pixel = 8;        // 256 color
  698.     pcx->xmin = 0;
  699.     pcx->ymin = 0;
  700.     pcx->xmax = LittleShort((short)(width-1));
  701.     pcx->ymax = LittleShort((short)(height-1));
  702.     pcx->hres = LittleShort((short)width);
  703.     pcx->vres = LittleShort((short)height);
  704.     Q_memset (pcx->palette,0,sizeof(pcx->palette));
  705.     pcx->color_planes = 1;        // chunky image
  706.     pcx->bytes_per_line = LittleShort((short)width);
  707.     pcx->palette_type = LittleShort(2);        // not a grey scale
  708.     Q_memset (pcx->filler,0,sizeof(pcx->filler));
  709.  
  710. // pack the image
  711.     pack = &pcx->data;
  712.  
  713.     data += rowbytes * (height - 1);
  714.  
  715.     for (i=0 ; i<height ; i++)
  716.     {
  717.         for (j=0 ; j<width ; j++)
  718.         {
  719.             if ( (*data & 0xc0) != 0xc0)
  720.                 *pack++ = *data++;
  721.             else
  722.             {
  723.                 *pack++ = 0xc1;
  724.                 *pack++ = *data++;
  725.             }
  726.         }
  727.  
  728.         data += rowbytes - width;
  729.         data -= rowbytes * 2;
  730.     }
  731.             
  732. // write the palette
  733.     *pack++ = 0x0c;    // palette ID byte
  734.     for (i=0 ; i<768 ; i++)
  735.         *pack++ = *palette++;
  736.         
  737. // write output file 
  738.     length = pack - (byte *)pcx;
  739.  
  740.     if (upload)
  741.         CL_StartUpload((void *)pcx, length);
  742.     else
  743.         COM_WriteFile (filename, pcx, length);
  744.  
  745.  
  746.  
  747. /*
  748. Find closest color in the palette for named color
  749. */
  750. int MipColor(int r, int g, int b)
  751. {
  752.     int i;
  753.     float dist;
  754.     int best;
  755.     float bestdist;
  756.     int r1, g1, b1;
  757.     static int lr = -1, lg = -1, lb = -1;
  758.     static int lastbest;
  759.  
  760.     if (r == lr && g == lg && b == lb)
  761.         return lastbest;
  762.  
  763.     bestdist = 256*256*3;
  764.  
  765.     for (i = 0; i < 256; i++) {
  766.         r1 = host_basepal[i*3] - r;
  767.         g1 = host_basepal[i*3+1] - g;
  768.         b1 = host_basepal[i*3+2] - b;
  769.         dist = r1*r1 + g1*g1 + b1*b1;
  770.         if (dist < bestdist) {
  771.             bestdist = dist;
  772.             best = i;
  773.         }
  774.     }
  775.     lr = r; lg = g; lb = b;
  776.     lastbest = best;
  777.     return best;
  778. }
  779.  
  780. // from gl_draw.c
  781. byte        *draw_chars;                // 8*8 graphic characters
  782.  
  783. void SCR_DrawCharToSnap (int num, byte *dest, int width)
  784. {
  785.     int        row, col;
  786.     byte    *source;
  787.     int        drawline;
  788.     int        x;
  789.  
  790.     row = num>>4;
  791.     col = num&15;
  792.     source = draw_chars + (row<<10) + (col<<3);
  793.  
  794.     drawline = 8;
  795.  
  796.     while (drawline--)
  797.     {
  798.         for (x=0 ; x<8 ; x++)
  799.             if (source[x])
  800.                 dest[x] = source[x];
  801.             else
  802.                 dest[x] = 98;
  803.         source += 128;
  804.         dest -= width;
  805.     }
  806.  
  807. }
  808.  
  809. void SCR_DrawStringToSnap (const char *s, byte *buf, int x, int y, int width)
  810. {
  811.     byte *dest;
  812.     const unsigned char *p;
  813.  
  814.     dest = buf + ((y * width) + x);
  815.  
  816.     p = (const unsigned char *)s;
  817.     while (*p) {
  818.         SCR_DrawCharToSnap(*p++, dest, width);
  819.         dest += 8;
  820.     }
  821. }
  822.  
  823.  
  824. /* 
  825. ================== 
  826. SCR_RSShot_f
  827. ================== 
  828. */  
  829. void SCR_RSShot_f (void) 
  830.     int     i, x, y;
  831.     unsigned char        *src, *dest;
  832.     char        pcxname[80]; 
  833.     char        checkname[MAX_OSPATH];
  834.     unsigned char        *newbuf, *srcbuf;
  835.     int srcrowbytes;
  836.     int w, h;
  837.     int dx, dy, dex, dey, nx;
  838.     int r, b, g;
  839.     int count;
  840.     float fracw, frach;
  841.     char st[80];
  842.     time_t now;
  843.  
  844.     if (CL_IsUploading())
  845.         return; // already one pending
  846.  
  847.     if (cls.state < ca_onserver)
  848.         return; // gotta be connected
  849.  
  850.     Con_Printf("Remote screen shot requested.\n");
  851.  
  852. #if 0
  853. // 
  854. // find a file name to save it to 
  855. // 
  856.     strcpy(pcxname,"mquake00.pcx");
  857.         
  858.     for (i=0 ; i<=99 ; i++) 
  859.     { 
  860.         pcxname[6] = i/10 + '0'; 
  861.         pcxname[7] = i%10 + '0'; 
  862.         sprintf (checkname, "%s/%s", com_gamedir, pcxname);
  863.         if (Sys_FileTime(checkname) == -1)
  864.             break;    // file doesn't exist
  865.     } 
  866.     if (i==100) 
  867.     {
  868.         Con_Printf ("SCR_ScreenShot_f: Couldn't create a PCX"); 
  869.         return;
  870.     }
  871. #endif
  872.  
  873. // 
  874. // save the pcx file 
  875. // 
  876.     newbuf = malloc(glheight * glwidth * 3);
  877.  
  878.     glReadPixels (glx, gly, glwidth, glheight, GL_RGB, GL_UNSIGNED_BYTE, newbuf ); 
  879.  
  880.     w = (vid.width < RSSHOT_WIDTH) ? glwidth : RSSHOT_WIDTH;
  881.     h = (vid.height < RSSHOT_HEIGHT) ? glheight : RSSHOT_HEIGHT;
  882.  
  883.     fracw = (float)glwidth / (float)w;
  884.     frach = (float)glheight / (float)h;
  885.  
  886.     for (y = 0; y < h; y++) {
  887.         dest = newbuf + (w*3 * y);
  888.  
  889.         for (x = 0; x < w; x++) {
  890.             r = g = b = 0;
  891.  
  892.             dx = x * fracw;
  893.             dex = (x + 1) * fracw;
  894.             if (dex == dx) dex++; // at least one
  895.             dy = y * frach;
  896.             dey = (y + 1) * frach;
  897.             if (dey == dy) dey++; // at least one
  898.  
  899.             count = 0;
  900.             for (/* */; dy < dey; dy++) {
  901.                 src = newbuf + (glwidth * 3 * dy) + dx * 3;
  902.                 for (nx = dx; nx < dex; nx++) {
  903.                     r += *src++;
  904.                     g += *src++;
  905.                     b += *src++;
  906.                     count++;
  907.                 }
  908.             }
  909.             r /= count;
  910.             g /= count;
  911.             b /= count;
  912.             *dest++ = r;
  913.             *dest++ = b;
  914.             *dest++ = g;
  915.         }
  916.     }
  917.  
  918.     // convert to eight bit
  919.     for (y = 0; y < h; y++) {
  920.         src = newbuf + (w * 3 * y);
  921.         dest = newbuf + (w * y);
  922.  
  923.         for (x = 0; x < w; x++) {
  924.             *dest++ = MipColor(src[0], src[1], src[2]);
  925.             src += 3;
  926.         }
  927.     }
  928.  
  929.     time(&now);
  930.     strcpy(st, ctime(&now));
  931.     st[strlen(st) - 1] = 0;
  932.     SCR_DrawStringToSnap (st, newbuf, w - strlen(st)*8, h - 1, w);
  933.  
  934.     strncpy(st, cls.servername, sizeof(st));
  935.     st[sizeof(st) - 1] = 0;
  936.     SCR_DrawStringToSnap (st, newbuf, w - strlen(st)*8, h - 11, w);
  937.  
  938.     strncpy(st, name.string, sizeof(st));
  939.     st[sizeof(st) - 1] = 0;
  940.     SCR_DrawStringToSnap (st, newbuf, w - strlen(st)*8, h - 21, w);
  941.  
  942.     WritePCXfile (pcxname, newbuf, w, h, w, host_basepal, true);
  943.  
  944.     free(newbuf);
  945.  
  946.     Con_Printf ("Wrote %s\n", pcxname);
  947.  
  948.  
  949.  
  950.  
  951. //=============================================================================
  952.  
  953.  
  954. //=============================================================================
  955.  
  956. char    *scr_notifystring;
  957. qboolean        scr_drawdialog;
  958.  
  959. void SCR_DrawNotifyString (void)
  960. {
  961.     char    *start;
  962.     int             l;
  963.     int             j;
  964.     int             x, y;
  965.  
  966.     start = scr_notifystring;
  967.  
  968.     y = vid.height*0.35;
  969.  
  970.     do      
  971.     {
  972.     // scan the width of the line
  973.         for (l=0 ; l<40 ; l++)
  974.             if (start[l] == '\n' || !start[l])
  975.                 break;
  976.         x = (vid.width - l*8)/2;
  977.         for (j=0 ; j<l ; j++, x+=8)
  978.             Draw_Character (x, y, start[j]);        
  979.             
  980.         y += 8;
  981.  
  982.         while (*start && *start != '\n')
  983.             start++;
  984.  
  985.         if (!*start)
  986.             break;
  987.         start++;                // skip the \n
  988.     } while (1);
  989. }
  990.  
  991. /*
  992. ==================
  993. SCR_ModalMessage
  994.  
  995. Displays a text string in the center of the screen and waits for a Y or N
  996. keypress.  
  997. ==================
  998. */
  999. int SCR_ModalMessage (char *text)
  1000. {
  1001.     scr_notifystring = text;
  1002.  
  1003. // draw a fresh screen
  1004.     scr_fullupdate = 0;
  1005.     scr_drawdialog = true;
  1006.     SCR_UpdateScreen ();
  1007.     scr_drawdialog = false;
  1008.     
  1009.     S_ClearBuffer ();               // so dma doesn't loop current sound
  1010.  
  1011.     do
  1012.     {
  1013.         key_count = -1;         // wait for a key down and up
  1014.         Sys_SendKeyEvents ();
  1015.     } while (key_lastpress != 'y' && key_lastpress != 'n' && key_lastpress != K_ESCAPE);
  1016.  
  1017.     scr_fullupdate = 0;
  1018.     SCR_UpdateScreen ();
  1019.  
  1020.     return key_lastpress == 'y';
  1021. }
  1022.  
  1023.  
  1024. //=============================================================================
  1025.  
  1026. /*
  1027. ===============
  1028. SCR_BringDownConsole
  1029.  
  1030. Brings the console down and fades the palettes back to normal
  1031. ================
  1032. */
  1033. void SCR_BringDownConsole (void)
  1034. {
  1035.     int             i;
  1036.     
  1037.     scr_centertime_off = 0;
  1038.     
  1039.     for (i=0 ; i<20 && scr_conlines != scr_con_current ; i++)
  1040.         SCR_UpdateScreen ();
  1041.  
  1042.     cl.cshifts[0].percent = 0;              // no area contents palette on next frame
  1043.     VID_SetPalette (host_basepal);
  1044. }
  1045.  
  1046. void SCR_TileClear (void)
  1047. {
  1048.     if (r_refdef.vrect.x > 0) {
  1049.         // left
  1050.         Draw_TileClear (0, 0, r_refdef.vrect.x, vid.height - sb_lines);
  1051.         // right
  1052.         Draw_TileClear (r_refdef.vrect.x + r_refdef.vrect.width, 0, 
  1053.             vid.width - r_refdef.vrect.x + r_refdef.vrect.width, 
  1054.             vid.height - sb_lines);
  1055.     }
  1056.     if (r_refdef.vrect.y > 0) {
  1057.         // top
  1058.         Draw_TileClear (r_refdef.vrect.x, 0, 
  1059.             r_refdef.vrect.x + r_refdef.vrect.width, 
  1060.             r_refdef.vrect.y);
  1061.         // bottom
  1062.         Draw_TileClear (r_refdef.vrect.x,
  1063.             r_refdef.vrect.y + r_refdef.vrect.height, 
  1064.             r_refdef.vrect.width, 
  1065.             vid.height - sb_lines - 
  1066.             (r_refdef.vrect.height + r_refdef.vrect.y));
  1067.     }
  1068. }
  1069.  
  1070. float oldsbar = 0;
  1071.  
  1072. /*
  1073. ==================
  1074. SCR_UpdateScreen
  1075.  
  1076. This is called every frame, and can also be called explicitly to flush
  1077. text to the screen.
  1078.  
  1079. WARNING: be very careful calling this from elsewhere, because the refresh
  1080. needs almost the entire 256k of stack space!
  1081. ==================
  1082. */
  1083. void SCR_UpdateScreen (void)
  1084. {
  1085.     if (block_drawing)
  1086.         return;
  1087.  
  1088.     vid.numpages = 2 + gl_triplebuffer.value;
  1089.  
  1090.     scr_copytop = 0;
  1091.     scr_copyeverything = 0;
  1092.  
  1093.     if (scr_disabled_for_loading)
  1094.     {
  1095.         if (realtime - scr_disabled_time > 60)
  1096.         {
  1097.             scr_disabled_for_loading = false;
  1098.             Con_Printf ("load failed.\n");
  1099.         }
  1100.         else
  1101.             return;
  1102.     }
  1103.  
  1104.     if (!scr_initialized || !con_initialized)
  1105.         return;                         // not initialized yet
  1106.  
  1107.  
  1108.     if (oldsbar != cl_sbar.value) {
  1109.         oldsbar = cl_sbar.value;
  1110.         vid.recalc_refdef = true;
  1111.     }
  1112.  
  1113.     GL_BeginRendering (&glx, &gly, &glwidth, &glheight);
  1114.     
  1115.     //
  1116.     // determine size of refresh window
  1117.     //
  1118.     if (oldfov != scr_fov.value)
  1119.     {
  1120.         oldfov = scr_fov.value;
  1121.         vid.recalc_refdef = true;
  1122.     }
  1123.  
  1124.     if (vid.recalc_refdef)
  1125.         SCR_CalcRefdef ();
  1126.  
  1127. //
  1128. // do 3D refresh drawing, and then update the screen
  1129. //
  1130.     SCR_SetUpToDrawConsole ();
  1131.     
  1132.     V_RenderView ();
  1133.  
  1134.     GL_Set2D ();
  1135.  
  1136.     //
  1137.     // draw any areas not covered by the refresh
  1138.     //
  1139.     SCR_TileClear ();
  1140.  
  1141.     if (r_netgraph.value)
  1142.         R_NetGraph ();
  1143.  
  1144.     if (scr_drawdialog)
  1145.     {
  1146.         Sbar_Draw ();
  1147.         Draw_FadeScreen ();
  1148.         SCR_DrawNotifyString ();
  1149.         scr_copyeverything = true;
  1150.     }
  1151.     else if (scr_drawloading)
  1152.     {
  1153.         SCR_DrawLoading ();
  1154.         Sbar_Draw ();
  1155.     }
  1156.     else if (cl.intermission == 1 && key_dest == key_game)
  1157.     {
  1158.         Sbar_IntermissionOverlay ();
  1159.     }
  1160.     else if (cl.intermission == 2 && key_dest == key_game)
  1161.     {
  1162.         Sbar_FinaleOverlay ();
  1163.         SCR_CheckDrawCenterString ();
  1164.     }
  1165.     else
  1166.     {
  1167.         if (crosshair.value)
  1168.             Draw_Crosshair();
  1169.         
  1170.         SCR_DrawRam ();
  1171.         SCR_DrawNet ();
  1172.         SCR_DrawFPS ();
  1173.         SCR_DrawTurtle ();
  1174.         SCR_DrawPause ();
  1175.         SCR_CheckDrawCenterString ();
  1176.         Sbar_Draw ();
  1177.         SCR_DrawConsole ();     
  1178.         M_Draw ();
  1179.     }
  1180.  
  1181.     V_UpdatePalette ();
  1182.  
  1183.     GL_EndRendering ();
  1184. }
  1185.