gl_screen.c 23 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189
  1. /*
  2. Copyright (C) 1996-1997 Id Software, Inc.
  3. This program is free software; you can redistribute it and/or
  4. modify it under the terms of the GNU General Public License
  5. as published by the Free Software Foundation; either version 2
  6. of the License, or (at your option) any later version.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  10. See the GNU General Public License for more details.
  11. You should have received a copy of the GNU General Public License
  12. along with this program; if not, write to the Free Software
  13. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  14. */
  15. // screen.c -- master for refresh, status bar, console, chat, notify, etc
  16. #include "quakedef.h"
  17. #include <time.h>
  18. /*
  19. background clear
  20. rendering
  21. turtle/net/ram icons
  22. sbar
  23. centerprint / slow centerprint
  24. notify lines
  25. intermission / finale overlay
  26. loading plaque
  27. console
  28. menu
  29. required background clears
  30. required update regions
  31. syncronous draw mode or async
  32. One off screen buffer, with updates either copied or xblited
  33. Need to double buffer?
  34. async draw will require the refresh area to be cleared, because it will be
  35. xblited, but sync draw can just ignore it.
  36. sync
  37. draw
  38. CenterPrint ()
  39. SlowPrint ()
  40. Screen_Update ();
  41. Con_Printf ();
  42. net
  43. turn off messages option
  44. the refresh is allways rendered, unless the console is full screen
  45. console is:
  46. notify lines
  47. half
  48. full
  49. */
  50. int glx, gly, glwidth, glheight;
  51. // only the refresh window will be updated unless these variables are flagged
  52. int scr_copytop;
  53. int scr_copyeverything;
  54. float scr_con_current;
  55. float scr_conlines; // lines of console to display
  56. float oldscreensize, oldfov;
  57. cvar_t scr_viewsize = {"viewsize","100", true};
  58. cvar_t scr_fov = {"fov","90"}; // 10 - 170
  59. cvar_t scr_conspeed = {"scr_conspeed","300"};
  60. cvar_t scr_centertime = {"scr_centertime","2"};
  61. cvar_t scr_showram = {"showram","1"};
  62. cvar_t scr_showturtle = {"showturtle","0"};
  63. cvar_t scr_showpause = {"showpause","1"};
  64. cvar_t scr_printspeed = {"scr_printspeed","8"};
  65. cvar_t scr_allowsnap = {"scr_allowsnap", "1"};
  66. cvar_t gl_triplebuffer = {"gl_triplebuffer", "1", true };
  67. extern cvar_t crosshair;
  68. qboolean scr_initialized; // ready to draw
  69. qpic_t *scr_ram;
  70. qpic_t *scr_net;
  71. qpic_t *scr_turtle;
  72. int scr_fullupdate;
  73. int clearconsole;
  74. int clearnotify;
  75. int sb_lines;
  76. viddef_t vid; // global video state
  77. vrect_t scr_vrect;
  78. qboolean scr_disabled_for_loading;
  79. qboolean scr_drawloading;
  80. float scr_disabled_time;
  81. qboolean block_drawing;
  82. void SCR_ScreenShot_f (void);
  83. void SCR_RSShot_f (void);
  84. /*
  85. ===============================================================================
  86. CENTER PRINTING
  87. ===============================================================================
  88. */
  89. char scr_centerstring[1024];
  90. float scr_centertime_start; // for slow victory printing
  91. float scr_centertime_off;
  92. int scr_center_lines;
  93. int scr_erase_lines;
  94. int scr_erase_center;
  95. /*
  96. ==============
  97. SCR_CenterPrint
  98. Called for important messages that should stay in the center of the screen
  99. for a few moments
  100. ==============
  101. */
  102. void SCR_CenterPrint (char *str)
  103. {
  104. strncpy (scr_centerstring, str, sizeof(scr_centerstring)-1);
  105. scr_centertime_off = scr_centertime.value;
  106. scr_centertime_start = cl.time;
  107. // count the number of lines for centering
  108. scr_center_lines = 1;
  109. while (*str)
  110. {
  111. if (*str == '\n')
  112. scr_center_lines++;
  113. str++;
  114. }
  115. }
  116. void SCR_DrawCenterString (void)
  117. {
  118. char *start;
  119. int l;
  120. int j;
  121. int x, y;
  122. int remaining;
  123. // the finale prints the characters one at a time
  124. if (cl.intermission)
  125. remaining = scr_printspeed.value * (cl.time - scr_centertime_start);
  126. else
  127. remaining = 9999;
  128. scr_erase_center = 0;
  129. start = scr_centerstring;
  130. if (scr_center_lines <= 4)
  131. y = vid.height*0.35;
  132. else
  133. y = 48;
  134. do
  135. {
  136. // scan the width of the line
  137. for (l=0 ; l<40 ; l++)
  138. if (start[l] == '\n' || !start[l])
  139. break;
  140. x = (vid.width - l*8)/2;
  141. for (j=0 ; j<l ; j++, x+=8)
  142. {
  143. Draw_Character (x, y, start[j]);
  144. if (!remaining--)
  145. return;
  146. }
  147. y += 8;
  148. while (*start && *start != '\n')
  149. start++;
  150. if (!*start)
  151. break;
  152. start++; // skip the \n
  153. } while (1);
  154. }
  155. void SCR_CheckDrawCenterString (void)
  156. {
  157. scr_copytop = 1;
  158. if (scr_center_lines > scr_erase_lines)
  159. scr_erase_lines = scr_center_lines;
  160. scr_centertime_off -= host_frametime;
  161. if (scr_centertime_off <= 0 && !cl.intermission)
  162. return;
  163. if (key_dest != key_game)
  164. return;
  165. SCR_DrawCenterString ();
  166. }
  167. //=============================================================================
  168. /*
  169. ====================
  170. CalcFov
  171. ====================
  172. */
  173. float CalcFov (float fov_x, float width, float height)
  174. {
  175. float a;
  176. float x;
  177. if (fov_x < 1 || fov_x > 179)
  178. Sys_Error ("Bad fov: %f", fov_x);
  179. x = width/tan(fov_x/360*M_PI);
  180. a = atan (height/x);
  181. a = a*360/M_PI;
  182. return a;
  183. }
  184. /*
  185. =================
  186. SCR_CalcRefdef
  187. Must be called whenever vid changes
  188. Internal use only
  189. =================
  190. */
  191. static void SCR_CalcRefdef (void)
  192. {
  193. float size;
  194. int h;
  195. qboolean full = false;
  196. scr_fullupdate = 0; // force a background redraw
  197. vid.recalc_refdef = 0;
  198. // force the status bar to redraw
  199. Sbar_Changed ();
  200. //========================================
  201. // bound viewsize
  202. if (scr_viewsize.value < 30)
  203. Cvar_Set ("viewsize","30");
  204. if (scr_viewsize.value > 120)
  205. Cvar_Set ("viewsize","120");
  206. // bound field of view
  207. if (scr_fov.value < 10)
  208. Cvar_Set ("fov","10");
  209. if (scr_fov.value > 170)
  210. Cvar_Set ("fov","170");
  211. // intermission is always full screen
  212. if (cl.intermission)
  213. size = 120;
  214. else
  215. size = scr_viewsize.value;
  216. if (size >= 120)
  217. sb_lines = 0; // no status bar at all
  218. else if (size >= 110)
  219. sb_lines = 24; // no inventory
  220. else
  221. sb_lines = 24+16+8;
  222. if (scr_viewsize.value >= 100.0) {
  223. full = true;
  224. size = 100.0;
  225. } else
  226. size = scr_viewsize.value;
  227. if (cl.intermission)
  228. {
  229. full = true;
  230. size = 100.0;
  231. sb_lines = 0;
  232. }
  233. size /= 100.0;
  234. if (!cl_sbar.value && full)
  235. h = vid.height;
  236. else
  237. h = vid.height - sb_lines;
  238. r_refdef.vrect.width = vid.width * size;
  239. if (r_refdef.vrect.width < 96)
  240. {
  241. size = 96.0 / r_refdef.vrect.width;
  242. r_refdef.vrect.width = 96; // min for icons
  243. }
  244. r_refdef.vrect.height = vid.height * size;
  245. if (cl_sbar.value || !full) {
  246. if (r_refdef.vrect.height > vid.height - sb_lines)
  247. r_refdef.vrect.height = vid.height - sb_lines;
  248. } else if (r_refdef.vrect.height > vid.height)
  249. r_refdef.vrect.height = vid.height;
  250. r_refdef.vrect.x = (vid.width - r_refdef.vrect.width)/2;
  251. if (full)
  252. r_refdef.vrect.y = 0;
  253. else
  254. r_refdef.vrect.y = (h - r_refdef.vrect.height)/2;
  255. r_refdef.fov_x = scr_fov.value;
  256. r_refdef.fov_y = CalcFov (r_refdef.fov_x, r_refdef.vrect.width, r_refdef.vrect.height);
  257. scr_vrect = r_refdef.vrect;
  258. }
  259. /*
  260. =================
  261. SCR_SizeUp_f
  262. Keybinding command
  263. =================
  264. */
  265. void SCR_SizeUp_f (void)
  266. {
  267. Cvar_SetValue ("viewsize",scr_viewsize.value+10);
  268. vid.recalc_refdef = 1;
  269. }
  270. /*
  271. =================
  272. SCR_SizeDown_f
  273. Keybinding command
  274. =================
  275. */
  276. void SCR_SizeDown_f (void)
  277. {
  278. Cvar_SetValue ("viewsize",scr_viewsize.value-10);
  279. vid.recalc_refdef = 1;
  280. }
  281. //============================================================================
  282. /*
  283. ==================
  284. SCR_Init
  285. ==================
  286. */
  287. void SCR_Init (void)
  288. {
  289. Cvar_RegisterVariable (&scr_fov);
  290. Cvar_RegisterVariable (&scr_viewsize);
  291. Cvar_RegisterVariable (&scr_conspeed);
  292. Cvar_RegisterVariable (&scr_showram);
  293. Cvar_RegisterVariable (&scr_showturtle);
  294. Cvar_RegisterVariable (&scr_showpause);
  295. Cvar_RegisterVariable (&scr_centertime);
  296. Cvar_RegisterVariable (&scr_printspeed);
  297. Cvar_RegisterVariable (&scr_allowsnap);
  298. Cvar_RegisterVariable (&gl_triplebuffer);
  299. //
  300. // register our commands
  301. //
  302. Cmd_AddCommand ("screenshot",SCR_ScreenShot_f);
  303. Cmd_AddCommand ("snap",SCR_RSShot_f);
  304. Cmd_AddCommand ("sizeup",SCR_SizeUp_f);
  305. Cmd_AddCommand ("sizedown",SCR_SizeDown_f);
  306. scr_ram = Draw_PicFromWad ("ram");
  307. scr_net = Draw_PicFromWad ("net");
  308. scr_turtle = Draw_PicFromWad ("turtle");
  309. scr_initialized = true;
  310. }
  311. /*
  312. ==============
  313. SCR_DrawRam
  314. ==============
  315. */
  316. void SCR_DrawRam (void)
  317. {
  318. if (!scr_showram.value)
  319. return;
  320. if (!r_cache_thrash)
  321. return;
  322. Draw_Pic (scr_vrect.x+32, scr_vrect.y, scr_ram);
  323. }
  324. /*
  325. ==============
  326. SCR_DrawTurtle
  327. ==============
  328. */
  329. void SCR_DrawTurtle (void)
  330. {
  331. static int count;
  332. if (!scr_showturtle.value)
  333. return;
  334. if (host_frametime < 0.1)
  335. {
  336. count = 0;
  337. return;
  338. }
  339. count++;
  340. if (count < 3)
  341. return;
  342. Draw_Pic (scr_vrect.x, scr_vrect.y, scr_turtle);
  343. }
  344. /*
  345. ==============
  346. SCR_DrawNet
  347. ==============
  348. */
  349. void SCR_DrawNet (void)
  350. {
  351. if (cls.netchan.outgoing_sequence - cls.netchan.incoming_acknowledged < UPDATE_BACKUP-1)
  352. return;
  353. if (cls.demoplayback)
  354. return;
  355. Draw_Pic (scr_vrect.x+64, scr_vrect.y, scr_net);
  356. }
  357. void SCR_DrawFPS (void)
  358. {
  359. extern cvar_t show_fps;
  360. static double lastframetime;
  361. double t;
  362. extern int fps_count;
  363. static lastfps;
  364. int x, y;
  365. char st[80];
  366. if (!show_fps.value)
  367. return;
  368. t = Sys_DoubleTime();
  369. if ((t - lastframetime) >= 1.0) {
  370. lastfps = fps_count;
  371. fps_count = 0;
  372. lastframetime = t;
  373. }
  374. sprintf(st, "%3d FPS", lastfps);
  375. x = vid.width - strlen(st) * 8 - 8;
  376. y = vid.height - sb_lines - 8;
  377. // Draw_TileClear(x, y, strlen(st) * 8, 8);
  378. Draw_String(x, y, st);
  379. }
  380. /*
  381. ==============
  382. DrawPause
  383. ==============
  384. */
  385. void SCR_DrawPause (void)
  386. {
  387. qpic_t *pic;
  388. if (!scr_showpause.value) // turn off for screenshots
  389. return;
  390. if (!cl.paused)
  391. return;
  392. pic = Draw_CachePic ("gfx/pause.lmp");
  393. Draw_Pic ( (vid.width - pic->width)/2,
  394. (vid.height - 48 - pic->height)/2, pic);
  395. }
  396. /*
  397. ==============
  398. SCR_DrawLoading
  399. ==============
  400. */
  401. void SCR_DrawLoading (void)
  402. {
  403. qpic_t *pic;
  404. if (!scr_drawloading)
  405. return;
  406. pic = Draw_CachePic ("gfx/loading.lmp");
  407. Draw_Pic ( (vid.width - pic->width)/2,
  408. (vid.height - 48 - pic->height)/2, pic);
  409. }
  410. //=============================================================================
  411. /*
  412. ==================
  413. SCR_SetUpToDrawConsole
  414. ==================
  415. */
  416. void SCR_SetUpToDrawConsole (void)
  417. {
  418. Con_CheckResize ();
  419. if (scr_drawloading)
  420. return; // never a console with loading plaque
  421. // decide on the height of the console
  422. if (cls.state != ca_active)
  423. {
  424. scr_conlines = vid.height; // full screen
  425. scr_con_current = scr_conlines;
  426. }
  427. else if (key_dest == key_console)
  428. scr_conlines = vid.height/2; // half screen
  429. else
  430. scr_conlines = 0; // none visible
  431. if (scr_conlines < scr_con_current)
  432. {
  433. scr_con_current -= scr_conspeed.value*host_frametime;
  434. if (scr_conlines > scr_con_current)
  435. scr_con_current = scr_conlines;
  436. }
  437. else if (scr_conlines > scr_con_current)
  438. {
  439. scr_con_current += scr_conspeed.value*host_frametime;
  440. if (scr_conlines < scr_con_current)
  441. scr_con_current = scr_conlines;
  442. }
  443. if (clearconsole++ < vid.numpages)
  444. {
  445. Sbar_Changed ();
  446. }
  447. else if (clearnotify++ < vid.numpages)
  448. {
  449. }
  450. else
  451. con_notifylines = 0;
  452. }
  453. /*
  454. ==================
  455. SCR_DrawConsole
  456. ==================
  457. */
  458. void SCR_DrawConsole (void)
  459. {
  460. if (scr_con_current)
  461. {
  462. scr_copyeverything = 1;
  463. Con_DrawConsole (scr_con_current);
  464. clearconsole = 0;
  465. }
  466. else
  467. {
  468. if (key_dest == key_game || key_dest == key_message)
  469. Con_DrawNotify (); // only draw notify in game
  470. }
  471. }
  472. /*
  473. ==============================================================================
  474. SCREEN SHOTS
  475. ==============================================================================
  476. */
  477. typedef struct _TargaHeader {
  478. unsigned char id_length, colormap_type, image_type;
  479. unsigned short colormap_index, colormap_length;
  480. unsigned char colormap_size;
  481. unsigned short x_origin, y_origin, width, height;
  482. unsigned char pixel_size, attributes;
  483. } TargaHeader;
  484. /*
  485. ==================
  486. SCR_ScreenShot_f
  487. ==================
  488. */
  489. void SCR_ScreenShot_f (void)
  490. {
  491. byte *buffer;
  492. char pcxname[80];
  493. char checkname[MAX_OSPATH];
  494. int i, c, temp;
  495. //
  496. // find a file name to save it to
  497. //
  498. strcpy(pcxname,"quake00.tga");
  499. for (i=0 ; i<=99 ; i++)
  500. {
  501. pcxname[5] = i/10 + '0';
  502. pcxname[6] = i%10 + '0';
  503. sprintf (checkname, "%s/%s", com_gamedir, pcxname);
  504. if (Sys_FileTime(checkname) == -1)
  505. break; // file doesn't exist
  506. }
  507. if (i==100)
  508. {
  509. Con_Printf ("SCR_ScreenShot_f: Couldn't create a PCX file\n");
  510. return;
  511. }
  512. buffer = malloc(glwidth*glheight*3 + 18);
  513. memset (buffer, 0, 18);
  514. buffer[2] = 2; // uncompressed type
  515. buffer[12] = glwidth&255;
  516. buffer[13] = glwidth>>8;
  517. buffer[14] = glheight&255;
  518. buffer[15] = glheight>>8;
  519. buffer[16] = 24; // pixel size
  520. glReadPixels (glx, gly, glwidth, glheight, GL_RGB, GL_UNSIGNED_BYTE, buffer+18 );
  521. // swap rgb to bgr
  522. c = 18+glwidth*glheight*3;
  523. for (i=18 ; i<c ; i+=3)
  524. {
  525. temp = buffer[i];
  526. buffer[i] = buffer[i+2];
  527. buffer[i+2] = temp;
  528. }
  529. COM_WriteFile (pcxname, buffer, glwidth*glheight*3 + 18 );
  530. free (buffer);
  531. Con_Printf ("Wrote %s\n", pcxname);
  532. }
  533. /*
  534. ==============
  535. WritePCXfile
  536. ==============
  537. */
  538. void WritePCXfile (char *filename, byte *data, int width, int height,
  539. int rowbytes, byte *palette, qboolean upload)
  540. {
  541. int i, j, length;
  542. pcx_t *pcx;
  543. byte *pack;
  544. pcx = Hunk_TempAlloc (width*height*2+1000);
  545. if (pcx == NULL)
  546. {
  547. Con_Printf("SCR_ScreenShot_f: not enough memory\n");
  548. return;
  549. }
  550. pcx->manufacturer = 0x0a; // PCX id
  551. pcx->version = 5; // 256 color
  552. pcx->encoding = 1; // uncompressed
  553. pcx->bits_per_pixel = 8; // 256 color
  554. pcx->xmin = 0;
  555. pcx->ymin = 0;
  556. pcx->xmax = LittleShort((short)(width-1));
  557. pcx->ymax = LittleShort((short)(height-1));
  558. pcx->hres = LittleShort((short)width);
  559. pcx->vres = LittleShort((short)height);
  560. Q_memset (pcx->palette,0,sizeof(pcx->palette));
  561. pcx->color_planes = 1; // chunky image
  562. pcx->bytes_per_line = LittleShort((short)width);
  563. pcx->palette_type = LittleShort(2); // not a grey scale
  564. Q_memset (pcx->filler,0,sizeof(pcx->filler));
  565. // pack the image
  566. pack = &pcx->data;
  567. data += rowbytes * (height - 1);
  568. for (i=0 ; i<height ; i++)
  569. {
  570. for (j=0 ; j<width ; j++)
  571. {
  572. if ( (*data & 0xc0) != 0xc0)
  573. *pack++ = *data++;
  574. else
  575. {
  576. *pack++ = 0xc1;
  577. *pack++ = *data++;
  578. }
  579. }
  580. data += rowbytes - width;
  581. data -= rowbytes * 2;
  582. }
  583. // write the palette
  584. *pack++ = 0x0c; // palette ID byte
  585. for (i=0 ; i<768 ; i++)
  586. *pack++ = *palette++;
  587. // write output file
  588. length = pack - (byte *)pcx;
  589. if (upload)
  590. CL_StartUpload((void *)pcx, length);
  591. else
  592. COM_WriteFile (filename, pcx, length);
  593. }
  594. /*
  595. Find closest color in the palette for named color
  596. */
  597. int MipColor(int r, int g, int b)
  598. {
  599. int i;
  600. float dist;
  601. int best;
  602. float bestdist;
  603. int r1, g1, b1;
  604. static int lr = -1, lg = -1, lb = -1;
  605. static int lastbest;
  606. if (r == lr && g == lg && b == lb)
  607. return lastbest;
  608. bestdist = 256*256*3;
  609. for (i = 0; i < 256; i++) {
  610. r1 = host_basepal[i*3] - r;
  611. g1 = host_basepal[i*3+1] - g;
  612. b1 = host_basepal[i*3+2] - b;
  613. dist = r1*r1 + g1*g1 + b1*b1;
  614. if (dist < bestdist) {
  615. bestdist = dist;
  616. best = i;
  617. }
  618. }
  619. lr = r; lg = g; lb = b;
  620. lastbest = best;
  621. return best;
  622. }
  623. // from gl_draw.c
  624. byte *draw_chars; // 8*8 graphic characters
  625. void SCR_DrawCharToSnap (int num, byte *dest, int width)
  626. {
  627. int row, col;
  628. byte *source;
  629. int drawline;
  630. int x;
  631. row = num>>4;
  632. col = num&15;
  633. source = draw_chars + (row<<10) + (col<<3);
  634. drawline = 8;
  635. while (drawline--)
  636. {
  637. for (x=0 ; x<8 ; x++)
  638. if (source[x])
  639. dest[x] = source[x];
  640. else
  641. dest[x] = 98;
  642. source += 128;
  643. dest -= width;
  644. }
  645. }
  646. void SCR_DrawStringToSnap (const char *s, byte *buf, int x, int y, int width)
  647. {
  648. byte *dest;
  649. const unsigned char *p;
  650. dest = buf + ((y * width) + x);
  651. p = (const unsigned char *)s;
  652. while (*p) {
  653. SCR_DrawCharToSnap(*p++, dest, width);
  654. dest += 8;
  655. }
  656. }
  657. /*
  658. ==================
  659. SCR_RSShot_f
  660. ==================
  661. */
  662. void SCR_RSShot_f (void)
  663. {
  664. int i, x, y;
  665. unsigned char *src, *dest;
  666. char pcxname[80];
  667. char checkname[MAX_OSPATH];
  668. unsigned char *newbuf, *srcbuf;
  669. int srcrowbytes;
  670. int w, h;
  671. int dx, dy, dex, dey, nx;
  672. int r, b, g;
  673. int count;
  674. float fracw, frach;
  675. char st[80];
  676. time_t now;
  677. if (CL_IsUploading())
  678. return; // already one pending
  679. if (cls.state < ca_onserver)
  680. return; // gotta be connected
  681. Con_Printf("Remote screen shot requested.\n");
  682. #if 0
  683. //
  684. // find a file name to save it to
  685. //
  686. strcpy(pcxname,"mquake00.pcx");
  687. for (i=0 ; i<=99 ; i++)
  688. {
  689. pcxname[6] = i/10 + '0';
  690. pcxname[7] = i%10 + '0';
  691. sprintf (checkname, "%s/%s", com_gamedir, pcxname);
  692. if (Sys_FileTime(checkname) == -1)
  693. break; // file doesn't exist
  694. }
  695. if (i==100)
  696. {
  697. Con_Printf ("SCR_ScreenShot_f: Couldn't create a PCX");
  698. return;
  699. }
  700. #endif
  701. //
  702. // save the pcx file
  703. //
  704. newbuf = malloc(glheight * glwidth * 3);
  705. glReadPixels (glx, gly, glwidth, glheight, GL_RGB, GL_UNSIGNED_BYTE, newbuf );
  706. w = (vid.width < RSSHOT_WIDTH) ? glwidth : RSSHOT_WIDTH;
  707. h = (vid.height < RSSHOT_HEIGHT) ? glheight : RSSHOT_HEIGHT;
  708. fracw = (float)glwidth / (float)w;
  709. frach = (float)glheight / (float)h;
  710. for (y = 0; y < h; y++) {
  711. dest = newbuf + (w*3 * y);
  712. for (x = 0; x < w; x++) {
  713. r = g = b = 0;
  714. dx = x * fracw;
  715. dex = (x + 1) * fracw;
  716. if (dex == dx) dex++; // at least one
  717. dy = y * frach;
  718. dey = (y + 1) * frach;
  719. if (dey == dy) dey++; // at least one
  720. count = 0;
  721. for (/* */; dy < dey; dy++) {
  722. src = newbuf + (glwidth * 3 * dy) + dx * 3;
  723. for (nx = dx; nx < dex; nx++) {
  724. r += *src++;
  725. g += *src++;
  726. b += *src++;
  727. count++;
  728. }
  729. }
  730. r /= count;
  731. g /= count;
  732. b /= count;
  733. *dest++ = r;
  734. *dest++ = b;
  735. *dest++ = g;
  736. }
  737. }
  738. // convert to eight bit
  739. for (y = 0; y < h; y++) {
  740. src = newbuf + (w * 3 * y);
  741. dest = newbuf + (w * y);
  742. for (x = 0; x < w; x++) {
  743. *dest++ = MipColor(src[0], src[1], src[2]);
  744. src += 3;
  745. }
  746. }
  747. time(&now);
  748. strcpy(st, ctime(&now));
  749. st[strlen(st) - 1] = 0;
  750. SCR_DrawStringToSnap (st, newbuf, w - strlen(st)*8, h - 1, w);
  751. strncpy(st, cls.servername, sizeof(st));
  752. st[sizeof(st) - 1] = 0;
  753. SCR_DrawStringToSnap (st, newbuf, w - strlen(st)*8, h - 11, w);
  754. strncpy(st, name.string, sizeof(st));
  755. st[sizeof(st) - 1] = 0;
  756. SCR_DrawStringToSnap (st, newbuf, w - strlen(st)*8, h - 21, w);
  757. WritePCXfile (pcxname, newbuf, w, h, w, host_basepal, true);
  758. free(newbuf);
  759. Con_Printf ("Wrote %s\n", pcxname);
  760. }
  761. //=============================================================================
  762. //=============================================================================
  763. char *scr_notifystring;
  764. qboolean scr_drawdialog;
  765. void SCR_DrawNotifyString (void)
  766. {
  767. char *start;
  768. int l;
  769. int j;
  770. int x, y;
  771. start = scr_notifystring;
  772. y = vid.height*0.35;
  773. do
  774. {
  775. // scan the width of the line
  776. for (l=0 ; l<40 ; l++)
  777. if (start[l] == '\n' || !start[l])
  778. break;
  779. x = (vid.width - l*8)/2;
  780. for (j=0 ; j<l ; j++, x+=8)
  781. Draw_Character (x, y, start[j]);
  782. y += 8;
  783. while (*start && *start != '\n')
  784. start++;
  785. if (!*start)
  786. break;
  787. start++; // skip the \n
  788. } while (1);
  789. }
  790. /*
  791. ==================
  792. SCR_ModalMessage
  793. Displays a text string in the center of the screen and waits for a Y or N
  794. keypress.
  795. ==================
  796. */
  797. int SCR_ModalMessage (char *text)
  798. {
  799. scr_notifystring = text;
  800. // draw a fresh screen
  801. scr_fullupdate = 0;
  802. scr_drawdialog = true;
  803. SCR_UpdateScreen ();
  804. scr_drawdialog = false;
  805. S_ClearBuffer (); // so dma doesn't loop current sound
  806. do
  807. {
  808. key_count = -1; // wait for a key down and up
  809. Sys_SendKeyEvents ();
  810. } while (key_lastpress != 'y' && key_lastpress != 'n' && key_lastpress != K_ESCAPE);
  811. scr_fullupdate = 0;
  812. SCR_UpdateScreen ();
  813. return key_lastpress == 'y';
  814. }
  815. //=============================================================================
  816. /*
  817. ===============
  818. SCR_BringDownConsole
  819. Brings the console down and fades the palettes back to normal
  820. ================
  821. */
  822. void SCR_BringDownConsole (void)
  823. {
  824. int i;
  825. scr_centertime_off = 0;
  826. for (i=0 ; i<20 && scr_conlines != scr_con_current ; i++)
  827. SCR_UpdateScreen ();
  828. cl.cshifts[0].percent = 0; // no area contents palette on next frame
  829. VID_SetPalette (host_basepal);
  830. }
  831. void SCR_TileClear (void)
  832. {
  833. if (r_refdef.vrect.x > 0) {
  834. // left
  835. Draw_TileClear (0, 0, r_refdef.vrect.x, vid.height - sb_lines);
  836. // right
  837. Draw_TileClear (r_refdef.vrect.x + r_refdef.vrect.width, 0,
  838. vid.width - r_refdef.vrect.x + r_refdef.vrect.width,
  839. vid.height - sb_lines);
  840. }
  841. if (r_refdef.vrect.y > 0) {
  842. // top
  843. Draw_TileClear (r_refdef.vrect.x, 0,
  844. r_refdef.vrect.x + r_refdef.vrect.width,
  845. r_refdef.vrect.y);
  846. // bottom
  847. Draw_TileClear (r_refdef.vrect.x,
  848. r_refdef.vrect.y + r_refdef.vrect.height,
  849. r_refdef.vrect.width,
  850. vid.height - sb_lines -
  851. (r_refdef.vrect.height + r_refdef.vrect.y));
  852. }
  853. }
  854. float oldsbar = 0;
  855. /*
  856. ==================
  857. SCR_UpdateScreen
  858. This is called every frame, and can also be called explicitly to flush
  859. text to the screen.
  860. WARNING: be very careful calling this from elsewhere, because the refresh
  861. needs almost the entire 256k of stack space!
  862. ==================
  863. */
  864. void SCR_UpdateScreen (void)
  865. {
  866. if (block_drawing)
  867. return;
  868. vid.numpages = 2 + gl_triplebuffer.value;
  869. scr_copytop = 0;
  870. scr_copyeverything = 0;
  871. if (scr_disabled_for_loading)
  872. {
  873. if (realtime - scr_disabled_time > 60)
  874. {
  875. scr_disabled_for_loading = false;
  876. Con_Printf ("load failed.\n");
  877. }
  878. else
  879. return;
  880. }
  881. if (!scr_initialized || !con_initialized)
  882. return; // not initialized yet
  883. if (oldsbar != cl_sbar.value) {
  884. oldsbar = cl_sbar.value;
  885. vid.recalc_refdef = true;
  886. }
  887. GL_BeginRendering (&glx, &gly, &glwidth, &glheight);
  888. //
  889. // determine size of refresh window
  890. //
  891. if (oldfov != scr_fov.value)
  892. {
  893. oldfov = scr_fov.value;
  894. vid.recalc_refdef = true;
  895. }
  896. if (vid.recalc_refdef)
  897. SCR_CalcRefdef ();
  898. //
  899. // do 3D refresh drawing, and then update the screen
  900. //
  901. SCR_SetUpToDrawConsole ();
  902. V_RenderView ();
  903. GL_Set2D ();
  904. //
  905. // draw any areas not covered by the refresh
  906. //
  907. SCR_TileClear ();
  908. if (r_netgraph.value)
  909. R_NetGraph ();
  910. if (scr_drawdialog)
  911. {
  912. Sbar_Draw ();
  913. Draw_FadeScreen ();
  914. SCR_DrawNotifyString ();
  915. scr_copyeverything = true;
  916. }
  917. else if (scr_drawloading)
  918. {
  919. SCR_DrawLoading ();
  920. Sbar_Draw ();
  921. }
  922. else if (cl.intermission == 1 && key_dest == key_game)
  923. {
  924. Sbar_IntermissionOverlay ();
  925. }
  926. else if (cl.intermission == 2 && key_dest == key_game)
  927. {
  928. Sbar_FinaleOverlay ();
  929. SCR_CheckDrawCenterString ();
  930. }
  931. else
  932. {
  933. if (crosshair.value)
  934. Draw_Crosshair();
  935. SCR_DrawRam ();
  936. SCR_DrawNet ();
  937. SCR_DrawFPS ();
  938. SCR_DrawTurtle ();
  939. SCR_DrawPause ();
  940. SCR_CheckDrawCenterString ();
  941. Sbar_Draw ();
  942. SCR_DrawConsole ();
  943. M_Draw ();
  944. }
  945. V_UpdatePalette ();
  946. GL_EndRendering ();
  947. }