screen.c 22 KB

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