cl_scrn.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548
  1. /*
  2. ===========================================================================
  3. Copyright (C) 1999-2005 Id Software, Inc.
  4. This file is part of Quake III Arena source code.
  5. Quake III Arena source code is free software; you can redistribute it
  6. and/or modify it under the terms of the GNU General Public License as
  7. published by the Free Software Foundation; either version 2 of the License,
  8. or (at your option) any later version.
  9. Quake III Arena source code is distributed in the hope that it will be
  10. useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with Foobar; if not, write to the Free Software
  15. Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
  16. ===========================================================================
  17. */
  18. // cl_scrn.c -- master for refresh, status bar, console, chat, notify, etc
  19. #include "client.h"
  20. qboolean scr_initialized; // ready to draw
  21. cvar_t *cl_timegraph;
  22. cvar_t *cl_debuggraph;
  23. cvar_t *cl_graphheight;
  24. cvar_t *cl_graphscale;
  25. cvar_t *cl_graphshift;
  26. /*
  27. ================
  28. SCR_DrawNamedPic
  29. Coordinates are 640*480 virtual values
  30. =================
  31. */
  32. void SCR_DrawNamedPic( float x, float y, float width, float height, const char *picname ) {
  33. qhandle_t hShader;
  34. assert( width != 0 );
  35. hShader = re.RegisterShader( picname );
  36. SCR_AdjustFrom640( &x, &y, &width, &height );
  37. re.DrawStretchPic( x, y, width, height, 0, 0, 1, 1, hShader );
  38. }
  39. /*
  40. ================
  41. SCR_AdjustFrom640
  42. Adjusted for resolution and screen aspect ratio
  43. ================
  44. */
  45. void SCR_AdjustFrom640( float *x, float *y, float *w, float *h ) {
  46. float xscale;
  47. float yscale;
  48. #if 0
  49. // adjust for wide screens
  50. if ( cls.glconfig.vidWidth * 480 > cls.glconfig.vidHeight * 640 ) {
  51. *x += 0.5 * ( cls.glconfig.vidWidth - ( cls.glconfig.vidHeight * 640 / 480 ) );
  52. }
  53. #endif
  54. // scale for screen sizes
  55. xscale = cls.glconfig.vidWidth / 640.0;
  56. yscale = cls.glconfig.vidHeight / 480.0;
  57. if ( x ) {
  58. *x *= xscale;
  59. }
  60. if ( y ) {
  61. *y *= yscale;
  62. }
  63. if ( w ) {
  64. *w *= xscale;
  65. }
  66. if ( h ) {
  67. *h *= yscale;
  68. }
  69. }
  70. /*
  71. ================
  72. SCR_FillRect
  73. Coordinates are 640*480 virtual values
  74. =================
  75. */
  76. void SCR_FillRect( float x, float y, float width, float height, const float *color ) {
  77. re.SetColor( color );
  78. SCR_AdjustFrom640( &x, &y, &width, &height );
  79. re.DrawStretchPic( x, y, width, height, 0, 0, 0, 0, cls.whiteShader );
  80. re.SetColor( NULL );
  81. }
  82. /*
  83. ================
  84. SCR_DrawPic
  85. Coordinates are 640*480 virtual values
  86. =================
  87. */
  88. void SCR_DrawPic( float x, float y, float width, float height, qhandle_t hShader ) {
  89. SCR_AdjustFrom640( &x, &y, &width, &height );
  90. re.DrawStretchPic( x, y, width, height, 0, 0, 1, 1, hShader );
  91. }
  92. /*
  93. ** SCR_DrawChar
  94. ** chars are drawn at 640*480 virtual screen size
  95. */
  96. static void SCR_DrawChar( int x, int y, float size, int ch ) {
  97. int row, col;
  98. float frow, fcol;
  99. float ax, ay, aw, ah;
  100. ch &= 255;
  101. if ( ch == ' ' ) {
  102. return;
  103. }
  104. if ( y < -size ) {
  105. return;
  106. }
  107. ax = x;
  108. ay = y;
  109. aw = size;
  110. ah = size;
  111. SCR_AdjustFrom640( &ax, &ay, &aw, &ah );
  112. row = ch>>4;
  113. col = ch&15;
  114. frow = row*0.0625;
  115. fcol = col*0.0625;
  116. size = 0.0625;
  117. re.DrawStretchPic( ax, ay, aw, ah,
  118. fcol, frow,
  119. fcol + size, frow + size,
  120. cls.charSetShader );
  121. }
  122. /*
  123. ** SCR_DrawSmallChar
  124. ** small chars are drawn at native screen resolution
  125. */
  126. void SCR_DrawSmallChar( int x, int y, int ch ) {
  127. int row, col;
  128. float frow, fcol;
  129. float size;
  130. ch &= 255;
  131. if ( ch == ' ' ) {
  132. return;
  133. }
  134. if ( y < -SMALLCHAR_HEIGHT ) {
  135. return;
  136. }
  137. row = ch>>4;
  138. col = ch&15;
  139. frow = row*0.0625;
  140. fcol = col*0.0625;
  141. size = 0.0625;
  142. re.DrawStretchPic( x, y, SMALLCHAR_WIDTH, SMALLCHAR_HEIGHT,
  143. fcol, frow,
  144. fcol + size, frow + size,
  145. cls.charSetShader );
  146. }
  147. /*
  148. ==================
  149. SCR_DrawBigString[Color]
  150. Draws a multi-colored string with a drop shadow, optionally forcing
  151. to a fixed color.
  152. Coordinates are at 640 by 480 virtual resolution
  153. ==================
  154. */
  155. void SCR_DrawStringExt( int x, int y, float size, const char *string, float *setColor, qboolean forceColor ) {
  156. vec4_t color;
  157. const char *s;
  158. int xx;
  159. // draw the drop shadow
  160. color[0] = color[1] = color[2] = 0;
  161. color[3] = setColor[3];
  162. re.SetColor( color );
  163. s = string;
  164. xx = x;
  165. while ( *s ) {
  166. if ( Q_IsColorString( s ) ) {
  167. s += 2;
  168. continue;
  169. }
  170. SCR_DrawChar( xx+2, y+2, size, *s );
  171. xx += size;
  172. s++;
  173. }
  174. // draw the colored text
  175. s = string;
  176. xx = x;
  177. re.SetColor( setColor );
  178. while ( *s ) {
  179. if ( Q_IsColorString( s ) ) {
  180. if ( !forceColor ) {
  181. Com_Memcpy( color, g_color_table[ColorIndex(*(s+1))], sizeof( color ) );
  182. color[3] = setColor[3];
  183. re.SetColor( color );
  184. }
  185. s += 2;
  186. continue;
  187. }
  188. SCR_DrawChar( xx, y, size, *s );
  189. xx += size;
  190. s++;
  191. }
  192. re.SetColor( NULL );
  193. }
  194. void SCR_DrawBigString( int x, int y, const char *s, float alpha ) {
  195. float color[4];
  196. color[0] = color[1] = color[2] = 1.0;
  197. color[3] = alpha;
  198. SCR_DrawStringExt( x, y, BIGCHAR_WIDTH, s, color, qfalse );
  199. }
  200. void SCR_DrawBigStringColor( int x, int y, const char *s, vec4_t color ) {
  201. SCR_DrawStringExt( x, y, BIGCHAR_WIDTH, s, color, qtrue );
  202. }
  203. /*
  204. ==================
  205. SCR_DrawSmallString[Color]
  206. Draws a multi-colored string with a drop shadow, optionally forcing
  207. to a fixed color.
  208. Coordinates are at 640 by 480 virtual resolution
  209. ==================
  210. */
  211. void SCR_DrawSmallStringExt( int x, int y, const char *string, float *setColor, qboolean forceColor ) {
  212. vec4_t color;
  213. const char *s;
  214. int xx;
  215. // draw the colored text
  216. s = string;
  217. xx = x;
  218. re.SetColor( setColor );
  219. while ( *s ) {
  220. if ( Q_IsColorString( s ) ) {
  221. if ( !forceColor ) {
  222. Com_Memcpy( color, g_color_table[ColorIndex(*(s+1))], sizeof( color ) );
  223. color[3] = setColor[3];
  224. re.SetColor( color );
  225. }
  226. s += 2;
  227. continue;
  228. }
  229. SCR_DrawSmallChar( xx, y, *s );
  230. xx += SMALLCHAR_WIDTH;
  231. s++;
  232. }
  233. re.SetColor( NULL );
  234. }
  235. /*
  236. ** SCR_Strlen -- skips color escape codes
  237. */
  238. static int SCR_Strlen( const char *str ) {
  239. const char *s = str;
  240. int count = 0;
  241. while ( *s ) {
  242. if ( Q_IsColorString( s ) ) {
  243. s += 2;
  244. } else {
  245. count++;
  246. s++;
  247. }
  248. }
  249. return count;
  250. }
  251. /*
  252. ** SCR_GetBigStringWidth
  253. */
  254. int SCR_GetBigStringWidth( const char *str ) {
  255. return SCR_Strlen( str ) * 16;
  256. }
  257. //===============================================================================
  258. /*
  259. =================
  260. SCR_DrawDemoRecording
  261. =================
  262. */
  263. void SCR_DrawDemoRecording( void ) {
  264. char string[1024];
  265. int pos;
  266. if ( !clc.demorecording ) {
  267. return;
  268. }
  269. if ( clc.spDemoRecording ) {
  270. return;
  271. }
  272. pos = FS_FTell( clc.demofile );
  273. sprintf( string, "RECORDING %s: %ik", clc.demoName, pos / 1024 );
  274. SCR_DrawStringExt( 320 - strlen( string ) * 4, 20, 8, string, g_color_table[7], qtrue );
  275. }
  276. /*
  277. ===============================================================================
  278. DEBUG GRAPH
  279. ===============================================================================
  280. */
  281. typedef struct
  282. {
  283. float value;
  284. int color;
  285. } graphsamp_t;
  286. static int current;
  287. static graphsamp_t values[1024];
  288. /*
  289. ==============
  290. SCR_DebugGraph
  291. ==============
  292. */
  293. void SCR_DebugGraph (float value, int color)
  294. {
  295. values[current&1023].value = value;
  296. values[current&1023].color = color;
  297. current++;
  298. }
  299. /*
  300. ==============
  301. SCR_DrawDebugGraph
  302. ==============
  303. */
  304. void SCR_DrawDebugGraph (void)
  305. {
  306. int a, x, y, w, i, h;
  307. float v;
  308. int color;
  309. //
  310. // draw the graph
  311. //
  312. w = cls.glconfig.vidWidth;
  313. x = 0;
  314. y = cls.glconfig.vidHeight;
  315. re.SetColor( g_color_table[0] );
  316. re.DrawStretchPic(x, y - cl_graphheight->integer,
  317. w, cl_graphheight->integer, 0, 0, 0, 0, cls.whiteShader );
  318. re.SetColor( NULL );
  319. for (a=0 ; a<w ; a++)
  320. {
  321. i = (current-1-a+1024) & 1023;
  322. v = values[i].value;
  323. color = values[i].color;
  324. v = v * cl_graphscale->integer + cl_graphshift->integer;
  325. if (v < 0)
  326. v += cl_graphheight->integer * (1+(int)(-v / cl_graphheight->integer));
  327. h = (int)v % cl_graphheight->integer;
  328. re.DrawStretchPic( x+w-1-a, y - h, 1, h, 0, 0, 0, 0, cls.whiteShader );
  329. }
  330. }
  331. //=============================================================================
  332. /*
  333. ==================
  334. SCR_Init
  335. ==================
  336. */
  337. void SCR_Init( void ) {
  338. cl_timegraph = Cvar_Get ("timegraph", "0", CVAR_CHEAT);
  339. cl_debuggraph = Cvar_Get ("debuggraph", "0", CVAR_CHEAT);
  340. cl_graphheight = Cvar_Get ("graphheight", "32", CVAR_CHEAT);
  341. cl_graphscale = Cvar_Get ("graphscale", "1", CVAR_CHEAT);
  342. cl_graphshift = Cvar_Get ("graphshift", "0", CVAR_CHEAT);
  343. scr_initialized = qtrue;
  344. }
  345. //=======================================================
  346. /*
  347. ==================
  348. SCR_DrawScreenField
  349. This will be called twice if rendering in stereo mode
  350. ==================
  351. */
  352. void SCR_DrawScreenField( stereoFrame_t stereoFrame ) {
  353. re.BeginFrame( stereoFrame );
  354. // wide aspect ratio screens need to have the sides cleared
  355. // unless they are displaying game renderings
  356. if ( cls.state != CA_ACTIVE ) {
  357. if ( cls.glconfig.vidWidth * 480 > cls.glconfig.vidHeight * 640 ) {
  358. re.SetColor( g_color_table[0] );
  359. re.DrawStretchPic( 0, 0, cls.glconfig.vidWidth, cls.glconfig.vidHeight, 0, 0, 0, 0, cls.whiteShader );
  360. re.SetColor( NULL );
  361. }
  362. }
  363. if ( !uivm ) {
  364. Com_DPrintf("draw screen without UI loaded\n");
  365. return;
  366. }
  367. // if the menu is going to cover the entire screen, we
  368. // don't need to render anything under it
  369. if ( !VM_Call( uivm, UI_IS_FULLSCREEN )) {
  370. switch( cls.state ) {
  371. default:
  372. Com_Error( ERR_FATAL, "SCR_DrawScreenField: bad cls.state" );
  373. break;
  374. case CA_CINEMATIC:
  375. SCR_DrawCinematic();
  376. break;
  377. case CA_DISCONNECTED:
  378. // force menu up
  379. S_StopAllSounds();
  380. VM_Call( uivm, UI_SET_ACTIVE_MENU, UIMENU_MAIN );
  381. break;
  382. case CA_CONNECTING:
  383. case CA_CHALLENGING:
  384. case CA_CONNECTED:
  385. // connecting clients will only show the connection dialog
  386. // refresh to update the time
  387. VM_Call( uivm, UI_REFRESH, cls.realtime );
  388. VM_Call( uivm, UI_DRAW_CONNECT_SCREEN, qfalse );
  389. break;
  390. case CA_LOADING:
  391. case CA_PRIMED:
  392. // draw the game information screen and loading progress
  393. CL_CGameRendering( stereoFrame );
  394. // also draw the connection information, so it doesn't
  395. // flash away too briefly on local or lan games
  396. // refresh to update the time
  397. VM_Call( uivm, UI_REFRESH, cls.realtime );
  398. VM_Call( uivm, UI_DRAW_CONNECT_SCREEN, qtrue );
  399. break;
  400. case CA_ACTIVE:
  401. CL_CGameRendering( stereoFrame );
  402. SCR_DrawDemoRecording();
  403. break;
  404. }
  405. }
  406. // the menu draws next
  407. if ( cls.keyCatchers & KEYCATCH_UI && uivm ) {
  408. VM_Call( uivm, UI_REFRESH, cls.realtime );
  409. }
  410. // console draws next
  411. Con_DrawConsole ();
  412. // debug graph can be drawn on top of anything
  413. if ( cl_debuggraph->integer || cl_timegraph->integer || cl_debugMove->integer ) {
  414. SCR_DrawDebugGraph ();
  415. }
  416. }
  417. /*
  418. ==================
  419. SCR_UpdateScreen
  420. This is called every frame, and can also be called explicitly to flush
  421. text to the screen.
  422. ==================
  423. */
  424. void SCR_UpdateScreen( void ) {
  425. static int recursive;
  426. if ( !scr_initialized ) {
  427. return; // not initialized yet
  428. }
  429. if ( ++recursive > 2 ) {
  430. Com_Error( ERR_FATAL, "SCR_UpdateScreen: recursively called" );
  431. }
  432. recursive = 1;
  433. // if running in stereo, we need to draw the frame twice
  434. if ( cls.glconfig.stereoEnabled ) {
  435. SCR_DrawScreenField( STEREO_LEFT );
  436. SCR_DrawScreenField( STEREO_RIGHT );
  437. } else {
  438. SCR_DrawScreenField( STEREO_CENTER );
  439. }
  440. if ( com_speeds->integer ) {
  441. re.EndFrame( &time_frontend, &time_backend );
  442. } else {
  443. re.EndFrame( NULL, NULL );
  444. }
  445. recursive = 0;
  446. }