5 #include "cl_collision.h"
8 cvar_t scr_viewsize = {CVAR_SAVE, "viewsize","100", "how large the view should be, 110 disables inventory bar, 120 disables status bar"};
9 cvar_t scr_fov = {CVAR_SAVE, "fov","90", "field of vision, 1-170 degrees, default 90, some players use 110-130"}; // 1 - 170
10 cvar_t scr_conspeed = {CVAR_SAVE, "scr_conspeed","900", "speed of console open/close"}; // LordHavoc: quake used 300
11 cvar_t scr_conalpha = {CVAR_SAVE, "scr_conalpha", "1", "opacity of console background"};
12 cvar_t scr_conbrightness = {CVAR_SAVE, "scr_conbrightness", "0.2", "brightness of console background (0 = black, 1 = image)"};
13 cvar_t scr_conforcewhiledisconnected = {CVAR_SAVE, "scr_conforcewhiledisconnected", "1", "forces fullscreen console while disconnected"};
14 cvar_t scr_centertime = {0, "scr_centertime","2", "how long centerprint messages show"};
15 cvar_t scr_showram = {CVAR_SAVE, "showram","1", "show ram icon if low on surface cache memory (not used)"};
16 cvar_t scr_showturtle = {CVAR_SAVE, "showturtle","0", "show turtle icon when framerate is too low (not used)"};
17 cvar_t scr_showpause = {CVAR_SAVE, "showpause","1" "show pause icon when game is paused"};
18 cvar_t scr_showbrand = {0, "showbrand","0", "shows gfx/brand.tga in a corner of the screen (different values select different positions, including centered)"};
19 cvar_t scr_printspeed = {0, "scr_printspeed","8", "speed of intermission printing (episode end texts)"};
20 cvar_t vid_conwidth = {CVAR_SAVE, "vid_conwidth", "640", "virtual width of 2D graphics system"};
21 cvar_t vid_conheight = {CVAR_SAVE, "vid_conheight", "480", "virtual height of 2D graphics system"};
22 cvar_t vid_pixelheight = {CVAR_SAVE, "vid_pixelheight", "1", "adjusts vertical field of vision to account for non-square pixels (1280x1024 on a CRT monitor for example)"};
23 cvar_t scr_screenshot_jpeg = {CVAR_SAVE, "scr_screenshot_jpeg","1", "save jpeg instead of targa"};
24 cvar_t scr_screenshot_jpeg_quality = {CVAR_SAVE, "scr_screenshot_jpeg_quality","0.9", "image quality of saved jpeg"};
25 cvar_t scr_screenshot_gamma = {CVAR_SAVE, "scr_screenshot_gamma","2.2", "gamma correction on saved screenshots and videos, 1.0 saves unmodified images"};
26 // scr_screenshot_name is defined in fs.c
27 cvar_t cl_capturevideo = {0, "cl_capturevideo", "0", "enables saving of video to a file or files (default is .tga files, if scr_screenshot_jpeg is on it saves .jpg files (VERY SLOW), if any rawrgb or rawyv12 are on it saves those formats instead, note that scr_screenshot_gamma affects the brightness of the output)"};
28 cvar_t cl_capturevideo_sound = {0, "cl_capturevideo_sound", "0", "enables saving of sound to a .wav file (warning: this requires exact sync, if your hard drive can't keep up it will abort, if your graphics can't keep up it will save duplicate frames to maintain sound sync)"};
29 cvar_t cl_capturevideo_fps = {0, "cl_capturevideo_fps", "30", "how many frames per second to save (29.97 for NTSC, 30 for typical PC video, 15 can be useful)"};
30 cvar_t cl_capturevideo_rawrgb = {0, "cl_capturevideo_rawrgb", "0", "saves a single .rgb video file containing raw RGB images (you'll need special processing tools to encode this to something more useful)"};
31 cvar_t cl_capturevideo_rawyv12 = {0, "cl_capturevideo_rawyv12", "0", "saves a single .yv12 video file containing raw YV12 (luma plane, then half resolution chroma planes, first chroma blue then chroma red, this is the format used internally by many encoders, some tools can read it directly)"};
32 cvar_t r_textshadow = {0, "r_textshadow", "0" "draws a shadow on all text to improve readability"};
33 cvar_t r_letterbox = {0, "r_letterbox", "0", "reduces vertical height of view to simulate a letterboxed movie effect (can be used by mods for cutscenes)"};
35 int jpeg_supported = false;
37 qboolean scr_initialized; // ready to draw
39 float scr_con_current;
41 extern int con_vislines;
43 void DrawCrosshair(int num);
44 static void SCR_ScreenShot_f (void);
45 static void R_Envmap_f (void);
48 void R_ClearScreen(void);
51 static vec4_t string_colors[] =
54 // LordHavoc: why on earth is cyan before magenta in Quake3?
55 // LordHavoc: note: Doom3 uses white for [0] and [7]
56 {0.0, 0.0, 0.0, 1.0}, // black
57 {1.0, 0.0, 0.0, 1.0}, // red
58 {0.0, 1.0, 0.0, 1.0}, // green
59 {1.0, 1.0, 0.0, 1.0}, // yellow
60 {0.0, 0.0, 1.0, 1.0}, // blue
61 {0.0, 1.0, 1.0, 1.0}, // cyan
62 {1.0, 0.0, 1.0, 1.0}, // magenta
63 {1.0, 1.0, 1.0, 1.0}, // white
64 // [515]'s BX_COLOREDTEXT extension
65 {1.0, 1.0, 1.0, 0.5}, // half transparent
66 {0.5, 0.5, 0.5, 1.0} // half brightness
67 // Black's color table
68 //{1.0, 1.0, 1.0, 1.0},
69 //{1.0, 0.0, 0.0, 1.0},
70 //{0.0, 1.0, 0.0, 1.0},
71 //{0.0, 0.0, 1.0, 1.0},
72 //{1.0, 1.0, 0.0, 1.0},
73 //{0.0, 1.0, 1.0, 1.0},
74 //{1.0, 0.0, 1.0, 1.0},
75 //{0.1, 0.1, 0.1, 1.0}
78 #define STRING_COLORS_COUNT (sizeof(string_colors) / sizeof(vec4_t))
80 // color is read and changed in the end
81 void DrawQ_ColoredString( float x, float y, const char *text, int maxlen, float scalex, float scaley, float basered, float basegreen, float baseblue, float basealpha, int flags, int *outcolor )
86 const char *start, *current;
88 if( !outcolor || *outcolor == -1 ) {
89 colorindex = STRING_COLOR_DEFAULT;
91 colorindex = *outcolor;
93 color = string_colors[colorindex];
96 len = (int)strlen( text );
98 len = min( maxlen, (int) strlen( text ) );
100 start = current = text;
102 // check for color control char
103 if( *current == STRING_COLOR_TAG ) {
110 // display the tag char?
111 if( *current == STRING_COLOR_TAG ) {
112 // only display one of the two
117 } else if( '0' <= *current && *current <= '9' ) {
120 colorindex = colorindex * 10 + (*current - '0');
121 // only read as long as it makes a valid index
122 if( colorindex >= (int)STRING_COLORS_COUNT ) {
123 // undo the last operation
129 } while( len > 0 && '0' <= *current && *current <= '9' );
131 color = string_colors[colorindex];
132 // we jump over the color tag
136 // go on and read normal text in until the next control char
137 while( len > 0 && *current != STRING_COLOR_TAG ) {
142 if( start != current ) {
144 DrawQ_String( x, y, start, current - start, scalex, scaley, basered * color[0], basegreen * color[1], baseblue * color[2], basealpha * color[3], flags );
145 // update x to be at the new start position
146 x += (current - start) * scalex;
147 // set start accordingly
152 // return the last colorindex
154 *outcolor = colorindex;
159 ===============================================================================
163 ===============================================================================
166 char scr_centerstring[MAX_INPUTLINE];
167 float scr_centertime_start; // for slow victory printing
168 float scr_centertime_off;
169 int scr_center_lines;
171 int scr_erase_center;
177 Called for important messages that should stay in the center of the screen
181 void SCR_CenterPrint(char *str)
183 strlcpy (scr_centerstring, str, sizeof (scr_centerstring));
184 scr_centertime_off = scr_centertime.value;
185 scr_centertime_start = cl.time;
187 // count the number of lines for centering
188 scr_center_lines = 1;
198 void SCR_DrawCenterString (void)
206 // the finale prints the characters one at a time
208 remaining = scr_printspeed.value * (cl.time - scr_centertime_start);
212 scr_erase_center = 0;
213 start = scr_centerstring;
218 if (scr_center_lines <= 4)
219 y = vid_conheight.integer*0.35;
226 // scan the width of the line
227 for (l=0 ; l<vid_conwidth.integer/8 ; l++)
228 if (start[l] == '\n' || !start[l])
230 x = (vid_conwidth.integer - l*8)/2;
235 DrawQ_ColoredString(x, y, start, l, 8, 8, 1, 1, 1, 1, 0, &color);
243 while (*start && *start != '\n')
248 start++; // skip the \n
252 void SCR_CheckDrawCenterString (void)
254 if (scr_center_lines > scr_erase_lines)
255 scr_erase_lines = scr_center_lines;
257 scr_centertime_off -= host_frametime;
259 // don't draw if this is a normal stats-screen intermission,
260 // only if it is not an intermission, or a finale intermission
261 if (cl.intermission == 1)
263 if (scr_centertime_off <= 0 && !cl.intermission)
265 if (key_dest != key_game)
268 SCR_DrawCenterString ();
276 void SCR_DrawTurtle (void)
280 if (cls.state != ca_connected)
283 if (!scr_showturtle.integer)
286 if (host_frametime < 0.1)
296 DrawQ_Pic (0, 0, Draw_CachePic("gfx/turtle", false), 0, 0, 1, 1, 1, 1, 0);
304 void SCR_DrawNet (void)
306 if (cls.state != ca_connected)
308 if (realtime - cl.last_received_message < 0.3)
310 if (cls.demoplayback)
313 DrawQ_Pic (64, 0, Draw_CachePic("gfx/net", false), 0, 0, 1, 1, 1, 1, 0);
321 void SCR_DrawPause (void)
325 if (cls.state != ca_connected)
328 if (!scr_showpause.integer) // turn off for screenshots
334 pic = Draw_CachePic ("gfx/pause", true);
335 DrawQ_Pic ((vid_conwidth.integer - pic->width)/2, (vid_conheight.integer - pic->height)/2, pic, 0, 0, 1, 1, 1, 1, 0);
343 void SCR_DrawBrand (void)
348 if (!scr_showbrand.value)
351 pic = Draw_CachePic ("gfx/brand", true);
353 switch ((int)scr_showbrand.value)
355 case 1: // bottom left
357 y = vid_conheight.integer - pic->height;
359 case 2: // bottom centre
360 x = (vid_conwidth.integer - pic->width) / 2;
361 y = vid_conheight.integer - pic->height;
363 case 3: // bottom right
364 x = vid_conwidth.integer - pic->width;
365 y = vid_conheight.integer - pic->height;
367 case 4: // centre right
368 x = vid_conwidth.integer - pic->width;
369 y = (vid_conheight.integer - pic->height) / 2;
372 x = vid_conwidth.integer - pic->width;
375 case 6: // top centre
376 x = (vid_conwidth.integer - pic->width) / 2;
383 case 8: // centre left
385 y = (vid_conheight.integer - pic->height) / 2;
391 DrawQ_Pic (x, y, pic, 0, 0, 1, 1, 1, 1, 0);
399 static void SCR_DrawDownload(void)
405 if (!cls.qw_downloadname[0])
407 dpsnprintf(temp, sizeof(temp), "Downloading %s ... %3i%%\n", cls.qw_downloadname, cls.qw_downloadpercent);
408 len = (int)strlen(temp);
409 x = (vid_conwidth.integer - len*size) / 2;
410 y = vid_conheight.integer - size;
411 DrawQ_Pic(0, y, NULL, vid_conwidth.integer, size, 0, 0, 0, 0.5, 0);
412 DrawQ_String(x, y, temp, len, size, size, 1, 1, 1, 1, 0);
415 //=============================================================================
420 SCR_SetUpToDrawConsole
423 void SCR_SetUpToDrawConsole (void)
425 // lines of console to display
430 if (key_dest == key_game && cls.signon != SIGNONS && scr_conforcewhiledisconnected.integer)
431 key_consoleactive |= KEY_CONSOLEACTIVE_FORCED;
433 key_consoleactive &= ~KEY_CONSOLEACTIVE_FORCED;
435 // decide on the height of the console
436 if (key_consoleactive & KEY_CONSOLEACTIVE_USER)
437 conlines = vid_conheight.integer/2; // half screen
439 conlines = 0; // none visible
441 if (scr_conspeed.value)
443 if (scr_con_current > conlines)
445 scr_con_current -= scr_conspeed.value*host_realframetime;
446 if (scr_con_current < conlines)
447 scr_con_current = conlines;
450 else if (scr_con_current < conlines)
452 scr_con_current += scr_conspeed.value*host_realframetime;
453 if (scr_con_current > conlines)
454 scr_con_current = conlines;
458 scr_con_current = conlines;
466 void SCR_DrawConsole (void)
468 if (key_consoleactive & KEY_CONSOLEACTIVE_FORCED)
471 Con_DrawConsole (vid_conheight.integer);
473 else if (scr_con_current)
474 Con_DrawConsole (scr_con_current);
478 if (key_dest == key_game || key_dest == key_message)
479 Con_DrawNotify (); // only draw notify in game
485 SCR_BeginLoadingPlaque
489 void SCR_BeginLoadingPlaque (void)
491 // save console log up to this point to log_file if it was set by configs
496 SCR_UpdateLoadingScreen();
499 //=============================================================================
501 char r_speeds_string[1024];
502 int speedstringcount, r_timereport_active;
503 double r_timereport_temp = 0, r_timereport_current = 0, r_timereport_start = 0;
505 void R_TimeReport(char *desc)
511 if (r_speeds.integer < 2 || !r_timereport_active || r_showtrispass)
515 r_timereport_temp = r_timereport_current;
516 r_timereport_current = Sys_DoubleTime();
517 t = (int) ((r_timereport_current - r_timereport_temp) * 1000000.0);
519 dpsnprintf(tempbuf, sizeof(tempbuf), "%8i %-11s", t, desc);
520 length = (int)strlen(tempbuf);
521 if (speedstringcount + length > (vid_conwidth.integer / 8))
523 strlcat(r_speeds_string, "\n", sizeof(r_speeds_string));
524 speedstringcount = 0;
526 // skip the space at the beginning if it's the first on the line
527 if (speedstringcount == 0)
529 strlcat(r_speeds_string, tempbuf + 1, sizeof(r_speeds_string));
530 speedstringcount = length - 1;
534 strlcat(r_speeds_string, tempbuf, sizeof(r_speeds_string));
535 speedstringcount += length;
539 void R_TimeReport_Frame(void)
543 if (r_speeds_string[0])
545 if (r_timereport_active)
546 R_TimeReport("total");
548 r_timereport_current = r_timereport_start;
549 if (r_speeds_string[strlen(r_speeds_string)-1] == '\n')
550 r_speeds_string[strlen(r_speeds_string)-1] = 0;
552 for (i = 0;r_speeds_string[i];i++)
553 if (r_speeds_string[i] == '\n')
555 y = vid_conheight.integer - sb_lines - lines * 8;
557 DrawQ_Pic(0, y, NULL, vid_conwidth.integer, lines * 8, 0, 0, 0, 0.5, 0);
558 while (r_speeds_string[i])
561 while (r_speeds_string[i] && r_speeds_string[i] != '\n')
564 DrawQ_String(0, y, r_speeds_string + j, i - j, 8, 8, 1, 1, 1, 1, 0);
565 if (r_speeds_string[i] == '\n')
569 r_speeds_string[0] = 0;
570 r_timereport_active = false;
572 if (r_speeds.integer && cls.signon == SIGNONS && cls.state == ca_connected)
574 speedstringcount = 0;
575 r_speeds_string[0] = 0;
576 r_timereport_active = false;
577 sprintf(r_speeds_string + strlen(r_speeds_string), "org:'%+8.2f %+8.2f %+8.2f' dir:'%+2.3f %+2.3f %+2.3f'\n", r_vieworigin[0], r_vieworigin[1], r_vieworigin[2], r_viewforward[0], r_viewforward[1], r_viewforward[2]);
578 sprintf(r_speeds_string + strlen(r_speeds_string), "%5i entities%6i surfaces%6i triangles%5i leafs%5i portals%6i particles\n", renderstats.entities, renderstats.entities_surfaces, renderstats.entities_triangles, renderstats.world_leafs, renderstats.world_portals, renderstats.particles);
579 sprintf(r_speeds_string + strlen(r_speeds_string), "%4i lights%4i clears%4i scissored%7i light%7i shadow%7i dynamic\n", renderstats.lights, renderstats.lights_clears, renderstats.lights_scissored, renderstats.lights_lighttriangles, renderstats.lights_shadowtriangles, renderstats.lights_dynamicshadowtriangles);
580 if (renderstats.bloom)
581 sprintf(r_speeds_string + strlen(r_speeds_string), "rendered%6i meshes%8i triangles bloompixels%8i copied%8i drawn\n", renderstats.meshes, renderstats.meshes_elements / 3, renderstats.bloom_copypixels, renderstats.bloom_drawpixels);
583 sprintf(r_speeds_string + strlen(r_speeds_string), "rendered%6i meshes%8i triangles\n", renderstats.meshes, renderstats.meshes_elements / 3);
585 memset(&renderstats, 0, sizeof(renderstats));
587 if (r_speeds.integer >= 2)
589 r_timereport_active = true;
590 r_timereport_start = Sys_DoubleTime();
602 void SCR_SizeUp_f (void)
604 Cvar_SetValue ("viewsize",scr_viewsize.value+10);
615 void SCR_SizeDown_f (void)
617 Cvar_SetValue ("viewsize",scr_viewsize.value-10);
620 void CL_Screen_Init(void)
622 Cvar_RegisterVariable (&scr_fov);
623 Cvar_RegisterVariable (&scr_viewsize);
624 Cvar_RegisterVariable (&scr_conspeed);
625 Cvar_RegisterVariable (&scr_conalpha);
626 Cvar_RegisterVariable (&scr_conbrightness);
627 Cvar_RegisterVariable (&scr_conforcewhiledisconnected);
628 Cvar_RegisterVariable (&scr_showram);
629 Cvar_RegisterVariable (&scr_showturtle);
630 Cvar_RegisterVariable (&scr_showpause);
631 Cvar_RegisterVariable (&scr_showbrand);
632 Cvar_RegisterVariable (&scr_centertime);
633 Cvar_RegisterVariable (&scr_printspeed);
634 Cvar_RegisterVariable (&vid_conwidth);
635 Cvar_RegisterVariable (&vid_conheight);
636 Cvar_RegisterVariable (&vid_pixelheight);
637 Cvar_RegisterVariable (&scr_screenshot_jpeg);
638 Cvar_RegisterVariable (&scr_screenshot_jpeg_quality);
639 Cvar_RegisterVariable (&scr_screenshot_gamma);
640 Cvar_RegisterVariable (&cl_capturevideo);
641 Cvar_RegisterVariable (&cl_capturevideo_sound);
642 Cvar_RegisterVariable (&cl_capturevideo_fps);
643 Cvar_RegisterVariable (&cl_capturevideo_rawrgb);
644 Cvar_RegisterVariable (&cl_capturevideo_rawyv12);
645 Cvar_RegisterVariable (&r_textshadow);
646 Cvar_RegisterVariable (&r_letterbox);
648 Cmd_AddCommand ("sizeup",SCR_SizeUp_f, "increase view size (increases viewsize cvar)");
649 Cmd_AddCommand ("sizedown",SCR_SizeDown_f, "decrease view size (decreases viewsize cvar)");
650 Cmd_AddCommand ("screenshot",SCR_ScreenShot_f, "takes a screenshot of the next rendered frame");
651 Cmd_AddCommand ("envmap", R_Envmap_f, "render a cubemap (skybox) of the current scene");
653 scr_initialized = true;
656 void DrawQ_Clear(void)
658 r_refdef.drawqueuesize = 0;
661 static int picelements[6] = {0, 1, 2, 0, 2, 3};
662 void DrawQ_Pic(float x, float y, cachepic_t *pic, float width, float height, float red, float green, float blue, float alpha, int flags)
664 DrawQ_SuperPic(x,y,pic,width,height,0,0,red,green,blue,alpha,1,0,red,green,blue,alpha,0,1,red,green,blue,alpha,1,1,red,green,blue,alpha,flags);
667 void DrawQ_String_Real(float x, float y, const char *string, int maxlen, float scalex, float scaley, float red, float green, float blue, float alpha, int flags)
672 if (alpha < (1.0f / 255.0f))
675 len = (int)strlen(string);
677 for (len = 0;len < maxlen && string[len];len++);
678 for (;len > 0 && string[0] == ' ';string++, x += scalex, len--);
679 for (;len > 0 && string[len - 1] == ' ';len--);
682 if (x >= vid_conwidth.integer || y >= vid_conheight.integer || x < (-scalex * len) || y < (-scaley))
684 size = sizeof(*dq) + ((len + 1 + 3) & ~3);
685 if (r_refdef.drawqueuesize + size > r_refdef.maxdrawqueuesize)
687 red = bound(0, red, 1);
688 green = bound(0, green, 1);
689 blue = bound(0, blue, 1);
690 alpha = bound(0, alpha, 1);
691 dq = (drawqueue_t *)(r_refdef.drawqueue + r_refdef.drawqueuesize);
693 dq->command = DRAWQUEUE_STRING;
695 dq->color = ((unsigned int) (red * 255.0f) << 24) | ((unsigned int) (green * 255.0f) << 16) | ((unsigned int) (blue * 255.0f) << 8) | ((unsigned int) (alpha * 255.0f));
700 out = (char *)(dq + 1);
701 memcpy(out, string, len);
703 r_refdef.drawqueuesize += dq->size;
706 void DrawQ_String(float x, float y, const char *string, int maxlen, float scalex, float scaley, float red, float green, float blue, float alpha, int flags)
708 if (r_textshadow.integer)
709 DrawQ_String_Real(x+scalex*0.25,y+scaley*0.25,string,maxlen,scalex,scaley,0,0,0,alpha*0.8,flags);
711 DrawQ_String_Real(x,y,string,maxlen,scalex,scaley,red,green,blue,alpha,flags);
714 void DrawQ_SuperPic(float x, float y, cachepic_t *pic, float width, float height, float s1, float t1, float r1, float g1, float b1, float a1, float s2, float t2, float r2, float g2, float b2, float a2, float s3, float t3, float r3, float g3, float b3, float a3, float s4, float t4, float r4, float g4, float b4, float a4, int flags)
717 drawqueuemesh_t mesh;
718 memset(&mesh, 0, sizeof(mesh));
724 height = pic->height;
725 mesh.texture = pic->tex;
727 mesh.num_triangles = 2;
728 mesh.num_vertices = 4;
729 mesh.data_element3i = picelements;
730 mesh.data_vertex3f = floats;
731 mesh.data_texcoord2f = floats + 12;
732 mesh.data_color4f = floats + 20;
733 memset(floats, 0, sizeof(floats));
734 mesh.data_vertex3f[0] = mesh.data_vertex3f[9] = x;
735 mesh.data_vertex3f[1] = mesh.data_vertex3f[4] = y;
736 mesh.data_vertex3f[3] = mesh.data_vertex3f[6] = x + width;
737 mesh.data_vertex3f[7] = mesh.data_vertex3f[10] = y + height;
738 mesh.data_texcoord2f[0] = s1;mesh.data_texcoord2f[1] = t1;mesh.data_color4f[ 0] = r1;mesh.data_color4f[ 1] = g1;mesh.data_color4f[ 2] = b1;mesh.data_color4f[ 3] = a1;
739 mesh.data_texcoord2f[2] = s2;mesh.data_texcoord2f[3] = t2;mesh.data_color4f[ 4] = r2;mesh.data_color4f[ 5] = g2;mesh.data_color4f[ 6] = b2;mesh.data_color4f[ 7] = a2;
740 mesh.data_texcoord2f[4] = s4;mesh.data_texcoord2f[5] = t4;mesh.data_color4f[ 8] = r4;mesh.data_color4f[ 9] = g4;mesh.data_color4f[10] = b4;mesh.data_color4f[11] = a4;
741 mesh.data_texcoord2f[6] = s3;mesh.data_texcoord2f[7] = t3;mesh.data_color4f[12] = r3;mesh.data_color4f[13] = g3;mesh.data_color4f[14] = b3;mesh.data_color4f[15] = a3;
742 DrawQ_Mesh (&mesh, flags);
745 void DrawQ_Mesh (drawqueuemesh_t *mesh, int flags)
752 size += sizeof(drawqueuemesh_t);
753 size += sizeof(int[3]) * mesh->num_triangles;
754 size += sizeof(float[3]) * mesh->num_vertices;
755 size += sizeof(float[2]) * mesh->num_vertices;
756 size += sizeof(float[4]) * mesh->num_vertices;
757 if (r_refdef.drawqueuesize + size > r_refdef.maxdrawqueuesize)
759 dq = (drawqueue_t *)(r_refdef.drawqueue + r_refdef.drawqueuesize);
761 dq->command = DRAWQUEUE_MESH;
768 p = (void *)(dq + 1);
769 m = (drawqueuemesh_t *)p;p = (unsigned char*)p + sizeof(drawqueuemesh_t);
770 m->num_triangles = mesh->num_triangles;
771 m->num_vertices = mesh->num_vertices;
772 m->texture = mesh->texture;
773 m->data_element3i = (int *)p;memcpy(m->data_element3i , mesh->data_element3i , m->num_triangles * sizeof(int[3]));p = (unsigned char*)p + m->num_triangles * sizeof(int[3]);
774 m->data_vertex3f = (float *)p;memcpy(m->data_vertex3f , mesh->data_vertex3f , m->num_vertices * sizeof(float[3]));p = (unsigned char*)p + m->num_vertices * sizeof(float[3]);
775 m->data_texcoord2f = (float *)p;memcpy(m->data_texcoord2f, mesh->data_texcoord2f, m->num_vertices * sizeof(float[2]));p = (unsigned char*)p + m->num_vertices * sizeof(float[2]);
776 m->data_color4f = (float *)p;memcpy(m->data_color4f , mesh->data_color4f , m->num_vertices * sizeof(float[4]));p = (unsigned char*)p + m->num_vertices * sizeof(float[4]);
777 r_refdef.drawqueuesize += dq->size;
780 void DrawQ_LineLoop (drawqueuemesh_t *mesh, int flags)
787 size += sizeof(drawqueuemesh_t);
788 size += sizeof(int[3]) * mesh->num_triangles;
789 size += sizeof(float[3]) * mesh->num_vertices;
790 size += sizeof(float[2]) * mesh->num_vertices;
791 size += sizeof(float[4]) * mesh->num_vertices;
792 if (r_refdef.drawqueuesize + size > r_refdef.maxdrawqueuesize)
794 dq = (void *)(r_refdef.drawqueue + r_refdef.drawqueuesize);
796 dq->command = DRAWQUEUE_LINES;
803 p = (void *)(dq + 1);
804 m = p;p = (unsigned char*)p + sizeof(drawqueuemesh_t);
805 m->num_triangles = mesh->num_triangles;
806 m->num_vertices = mesh->num_vertices;
807 m->texture = mesh->texture;
808 m->data_element3i = p;memcpy(m->data_element3i , mesh->data_element3i , m->num_triangles * sizeof(int[3]));p = (unsigned char*)p + m->num_triangles * sizeof(int[3]);
809 m->data_vertex3f = p;memcpy(m->data_vertex3f , mesh->data_vertex3f , m->num_vertices * sizeof(float[3]));p = (unsigned char*)p + m->num_vertices * sizeof(float[3]);
810 m->data_texcoord2f = p;memcpy(m->data_texcoord2f, mesh->data_texcoord2f, m->num_vertices * sizeof(float[2]));p = (unsigned char*)p + m->num_vertices * sizeof(float[2]);
811 m->data_color4f = p;memcpy(m->data_color4f , mesh->data_color4f , m->num_vertices * sizeof(float[4]));p = (unsigned char*)p + m->num_vertices * sizeof(float[4]);
812 r_refdef.drawqueuesize += dq->size;
815 //LordHavoc: FIXME: this is nasty!
816 void DrawQ_LineWidth (float width)
819 static int linewidth = 1;
820 if(width == linewidth)
823 if(r_refdef.drawqueuesize + (int)sizeof(*dq) > r_refdef.maxdrawqueuesize)
825 Con_DPrint("DrawQueue full !\n");
828 dq = (void*) (r_refdef.drawqueue + r_refdef.drawqueuesize);
829 dq->size = sizeof(*dq);
830 dq->command = DRAWQUEUE_LINEWIDTH;
833 r_refdef.drawqueuesize += dq->size;
836 //[515]: this is old, delete
837 void DrawQ_Line (float width, float x1, float y1, float x2, float y2, float r, float g, float b, float alpha, int flags)
841 DrawQ_LineWidth(width);
842 if(r_refdef.drawqueuesize + (int)sizeof(*dq) > r_refdef.maxdrawqueuesize)
844 Con_DPrint("DrawQueue full !\n");
847 dq = (void*) (r_refdef.drawqueue + r_refdef.drawqueuesize);
848 dq->size = sizeof(*dq);
849 dq->command = DRAWQUEUE_LINES;
855 dq->color = ((unsigned int) (r * 255.0f) << 24) | ((unsigned int) (g * 255.0f) << 16) | ((unsigned int) (b * 255.0f) << 8) | ((unsigned int) (alpha * 255.0f));
857 r_refdef.drawqueuesize += dq->size;
860 void DrawQ_SetClipArea(float x, float y, float width, float height)
863 if(r_refdef.drawqueuesize + (int)sizeof(*dq) > r_refdef.maxdrawqueuesize)
865 Con_DPrint("DrawQueue full !\n");
868 dq = (drawqueue_t *) (r_refdef.drawqueue + r_refdef.drawqueuesize);
869 dq->size = sizeof(*dq);
870 dq->command = DRAWQUEUE_SETCLIP;
878 r_refdef.drawqueuesize += dq->size;
881 void DrawQ_ResetClipArea(void)
884 if(r_refdef.drawqueuesize + (int)sizeof(*dq) > r_refdef.maxdrawqueuesize)
886 Con_DPrint("DrawQueue full !\n");
889 dq = (drawqueue_t *) (r_refdef.drawqueue + r_refdef.drawqueuesize);
890 dq->size = sizeof(*dq);
891 dq->command = DRAWQUEUE_RESETCLIP;
899 r_refdef.drawqueuesize += dq->size;
907 void SCR_ScreenShot_f (void)
909 static int shotnumber;
910 static char oldname[MAX_QPATH];
911 char base[MAX_QPATH];
912 char filename[MAX_QPATH];
913 unsigned char *buffer1;
914 unsigned char *buffer2;
915 unsigned char *buffer3;
916 qboolean jpeg = (scr_screenshot_jpeg.integer != 0);
918 sprintf (base, "screenshots/%s", scr_screenshot_name.string);
920 if (strcmp (oldname, scr_screenshot_name.string))
922 sprintf(oldname, "%s", scr_screenshot_name.string);
926 // find a file name to save it to
927 for (;shotnumber < 1000000;shotnumber++)
928 if (!FS_SysFileExists(va("%s/%s%06d.tga", fs_gamedir, base, shotnumber)) && !FS_SysFileExists(va("%s/%s%06d.jpg", fs_gamedir, base, shotnumber)))
930 if (shotnumber >= 1000000)
932 Con_Print("SCR_ScreenShot_f: Couldn't create the image file\n");
936 sprintf(filename, "%s%06d.%s", base, shotnumber, jpeg ? "jpg" : "tga");
938 buffer1 = (unsigned char *)Mem_Alloc(tempmempool, vid.width * vid.height * 3);
939 buffer2 = (unsigned char *)Mem_Alloc(tempmempool, vid.width * vid.height * 3);
940 buffer3 = (unsigned char *)Mem_Alloc(tempmempool, vid.width * vid.height * 3 + 18);
942 if (SCR_ScreenShot (filename, buffer1, buffer2, buffer3, 0, 0, vid.width, vid.height, false, false, false, jpeg, true))
943 Con_Printf("Wrote %s\n", filename);
945 Con_Printf("unable to write %s\n", filename);
954 void SCR_CaptureVideo_BeginVideo(void)
958 unsigned char out[44];
959 if (cls.capturevideo_active)
961 // soundrate is figured out on the first SoundFrame
962 cls.capturevideo_active = true;
963 cls.capturevideo_starttime = Sys_DoubleTime();
964 cls.capturevideo_framerate = bound(1, cl_capturevideo_fps.value, 1000);
965 cls.capturevideo_soundrate = 0;
966 cls.capturevideo_frame = 0;
967 cls.capturevideo_buffer = (unsigned char *)Mem_Alloc(tempmempool, vid.width * vid.height * (3+3+3) + 18);
968 gamma = 1.0/scr_screenshot_gamma.value;
971 for (i = 0;i < 256;i++)
973 unsigned char j = (unsigned char)bound(0, 255*pow(i/255.0, gamma), 255);
974 cls.capturevideo_rgbgammatable[0][i] = j;
975 cls.capturevideo_rgbgammatable[1][i] = j;
976 cls.capturevideo_rgbgammatable[2][i] = j;
980 R = Y + 1.4075 * (Cr - 128);
981 G = Y + -0.3455 * (Cb - 128) + -0.7169 * (Cr - 128);
982 B = Y + 1.7790 * (Cb - 128);
983 Y = R * .299 + G * .587 + B * .114;
984 Cb = R * -.169 + G * -.332 + B * .500 + 128.;
985 Cr = R * .500 + G * -.419 + B * -.0813 + 128.;
987 for (i = 0;i < 256;i++)
989 g = 255*pow(i/255.0, gamma);
990 // Y weights from RGB
991 cls.capturevideo_rgbtoyuvscaletable[0][0][i] = (short)(g * 0.299);
992 cls.capturevideo_rgbtoyuvscaletable[0][1][i] = (short)(g * 0.587);
993 cls.capturevideo_rgbtoyuvscaletable[0][2][i] = (short)(g * 0.114);
994 // Cb weights from RGB
995 cls.capturevideo_rgbtoyuvscaletable[1][0][i] = (short)(g * -0.169);
996 cls.capturevideo_rgbtoyuvscaletable[1][1][i] = (short)(g * -0.332);
997 cls.capturevideo_rgbtoyuvscaletable[1][2][i] = (short)(g * 0.500);
998 // Cr weights from RGB
999 cls.capturevideo_rgbtoyuvscaletable[2][0][i] = (short)(g * 0.500);
1000 cls.capturevideo_rgbtoyuvscaletable[2][1][i] = (short)(g * -0.419);
1001 cls.capturevideo_rgbtoyuvscaletable[2][2][i] = (short)(g * -0.0813);
1002 // range reduction of YCbCr to valid signal range
1003 cls.capturevideo_yuvnormalizetable[0][i] = 16 + i * (236-16) / 256;
1004 cls.capturevideo_yuvnormalizetable[1][i] = 16 + i * (240-16) / 256;
1005 cls.capturevideo_yuvnormalizetable[2][i] = 16 + i * (240-16) / 256;
1008 if (cl_capturevideo_rawrgb.integer)
1010 cls.capturevideo_format = CAPTUREVIDEOFORMAT_RAWRGB;
1011 cls.capturevideo_videofile = FS_Open ("video/dpvideo.rgb", "wb", false, true);
1013 else if (cl_capturevideo_rawyv12.integer)
1015 cls.capturevideo_format = CAPTUREVIDEOFORMAT_RAWYV12;
1016 cls.capturevideo_videofile = FS_Open ("video/dpvideo.yv12", "wb", false, true);
1018 else if (scr_screenshot_jpeg.integer)
1020 cls.capturevideo_format = CAPTUREVIDEOFORMAT_JPEG;
1021 cls.capturevideo_videofile = NULL;
1025 cls.capturevideo_format = CAPTUREVIDEOFORMAT_TARGA;
1026 cls.capturevideo_videofile = NULL;
1029 if (cl_capturevideo_sound.integer)
1031 cls.capturevideo_soundfile = FS_Open ("video/dpvideo.wav", "wb", false, true);
1032 // wave header will be filled out when video ends
1034 FS_Write (cls.capturevideo_soundfile, out, 44);
1037 cls.capturevideo_soundfile = NULL;
1040 void SCR_CaptureVideo_EndVideo(void)
1043 unsigned char out[44];
1044 if (!cls.capturevideo_active)
1046 cls.capturevideo_active = false;
1048 if (cls.capturevideo_videofile)
1050 FS_Close(cls.capturevideo_videofile);
1051 cls.capturevideo_videofile = NULL;
1054 // finish the wave file
1055 if (cls.capturevideo_soundfile)
1057 i = (int)FS_Tell (cls.capturevideo_soundfile);
1058 //"RIFF", (int) unknown (chunk size), "WAVE",
1059 //"fmt ", (int) 16 (chunk size), (short) format 1 (uncompressed PCM), (short) 2 channels, (int) unknown rate, (int) unknown bytes per second, (short) 4 bytes per sample (channels * bytes per channel), (short) 16 bits per channel
1060 //"data", (int) unknown (chunk size)
1061 memcpy (out, "RIFF****WAVEfmt \x10\x00\x00\x00\x01\x00\x02\x00********\x04\x00\x10\0data****", 44);
1062 // the length of the whole RIFF chunk
1064 out[4] = (n) & 0xFF;
1065 out[5] = (n >> 8) & 0xFF;
1066 out[6] = (n >> 16) & 0xFF;
1067 out[7] = (n >> 24) & 0xFF;
1069 n = cls.capturevideo_soundrate;
1070 out[24] = (n) & 0xFF;
1071 out[25] = (n >> 8) & 0xFF;
1072 out[26] = (n >> 16) & 0xFF;
1073 out[27] = (n >> 24) & 0xFF;
1074 // bytes per second (rate * channels * bytes per channel)
1075 n = cls.capturevideo_soundrate * 2 * 2;
1076 out[28] = (n) & 0xFF;
1077 out[29] = (n >> 8) & 0xFF;
1078 out[30] = (n >> 16) & 0xFF;
1079 out[31] = (n >> 24) & 0xFF;
1080 // the length of the data chunk
1082 out[40] = (n) & 0xFF;
1083 out[41] = (n >> 8) & 0xFF;
1084 out[42] = (n >> 16) & 0xFF;
1085 out[43] = (n >> 24) & 0xFF;
1086 FS_Seek (cls.capturevideo_soundfile, 0, SEEK_SET);
1087 FS_Write (cls.capturevideo_soundfile, out, 44);
1088 FS_Close (cls.capturevideo_soundfile);
1089 cls.capturevideo_soundfile = NULL;
1092 if (cls.capturevideo_buffer)
1094 Mem_Free (cls.capturevideo_buffer);
1095 cls.capturevideo_buffer = NULL;
1098 cls.capturevideo_starttime = 0;
1099 cls.capturevideo_framerate = 0;
1100 cls.capturevideo_frame = 0;
1103 qboolean SCR_CaptureVideo_VideoFrame(int newframenum)
1105 int x = 0, y = 0, width = vid.width, height = vid.height;
1106 unsigned char *b, *out;
1108 int outoffset = (width/2)*(height/2);
1109 //return SCR_ScreenShot(filename, cls.capturevideo_buffer, cls.capturevideo_buffer + vid.width * vid.height * 3, cls.capturevideo_buffer + vid.width * vid.height * 6, 0, 0, vid.width, vid.height, false, false, false, jpeg, true);
1110 // speed is critical here, so do saving as directly as possible
1111 switch (cls.capturevideo_format)
1113 case CAPTUREVIDEOFORMAT_RAWYV12:
1114 // FIXME: width/height must be multiple of 2, enforce this?
1115 qglReadPixels (x, y, width, height, GL_RGB, GL_UNSIGNED_BYTE, cls.capturevideo_buffer);
1117 // process one line at a time, and CbCr every other line at 2 pixel intervals
1118 for (y = 0;y < height;y++)
1121 for (b = cls.capturevideo_buffer + (height-1-y)*width*3, out = cls.capturevideo_buffer + width*height*3 + y*width, x = 0;x < width;x++, b += 3, out++)
1122 *out = cls.capturevideo_yuvnormalizetable[0][cls.capturevideo_rgbtoyuvscaletable[0][0][b[0]] + cls.capturevideo_rgbtoyuvscaletable[0][1][b[1]] + cls.capturevideo_rgbtoyuvscaletable[0][2][b[2]]];
1125 // 2x2 Cb and Cr planes
1127 // low quality, no averaging
1128 for (b = cls.capturevideo_buffer + (height-2-y)*width*3, out = cls.capturevideo_buffer + width*height*3 + width*height + (y/2)*(width/2), x = 0;x < width/2;x++, b += 6, out++)
1131 out[0 ] = cls.capturevideo_yuvnormalizetable[2][cls.capturevideo_rgbtoyuvscaletable[2][0][b[0]] + cls.capturevideo_rgbtoyuvscaletable[2][1][b[1]] + cls.capturevideo_rgbtoyuvscaletable[2][2][b[2]] + 128];
1133 out[outoffset] = cls.capturevideo_yuvnormalizetable[1][cls.capturevideo_rgbtoyuvscaletable[1][0][b[0]] + cls.capturevideo_rgbtoyuvscaletable[1][1][b[1]] + cls.capturevideo_rgbtoyuvscaletable[1][2][b[2]] + 128];
1136 // high quality, averaging
1137 int inpitch = width*3;
1138 for (b = cls.capturevideo_buffer + (height-2-y)*width*3, out = cls.capturevideo_buffer + width*height*3 + width*height + (y/2)*(width/2), x = 0;x < width/2;x++, b += 6, out++)
1140 int blockr, blockg, blockb;
1141 blockr = (b[0] + b[3] + b[inpitch+0] + b[inpitch+3]) >> 2;
1142 blockg = (b[1] + b[4] + b[inpitch+1] + b[inpitch+4]) >> 2;
1143 blockb = (b[2] + b[5] + b[inpitch+2] + b[inpitch+5]) >> 2;
1145 out[0 ] = cls.capturevideo_yuvnormalizetable[2][cls.capturevideo_rgbtoyuvscaletable[2][0][blockr] + cls.capturevideo_rgbtoyuvscaletable[2][1][blockg] + cls.capturevideo_rgbtoyuvscaletable[2][2][blockb] + 128];
1147 out[outoffset] = cls.capturevideo_yuvnormalizetable[1][cls.capturevideo_rgbtoyuvscaletable[1][0][blockr] + cls.capturevideo_rgbtoyuvscaletable[1][1][blockg] + cls.capturevideo_rgbtoyuvscaletable[1][2][blockb] + 128];
1152 for (;cls.capturevideo_frame < newframenum;cls.capturevideo_frame++)
1153 if (!FS_Write (cls.capturevideo_videofile, cls.capturevideo_buffer + width*height*3, width*height+(width/2)*(height/2)*2))
1156 case CAPTUREVIDEOFORMAT_RAWRGB:
1157 qglReadPixels (x, y, width, height, GL_RGB, GL_UNSIGNED_BYTE, cls.capturevideo_buffer);
1159 for (;cls.capturevideo_frame < newframenum;cls.capturevideo_frame++)
1160 if (!FS_Write (cls.capturevideo_videofile, cls.capturevideo_buffer, width*height*3))
1163 case CAPTUREVIDEOFORMAT_JPEG:
1164 qglReadPixels (x, y, width, height, GL_RGB, GL_UNSIGNED_BYTE, cls.capturevideo_buffer);
1166 for (;cls.capturevideo_frame < newframenum;cls.capturevideo_frame++)
1168 sprintf(filename, "video/dp%06d.jpg", cls.capturevideo_frame);
1169 if (!JPEG_SaveImage_preflipped (filename, width, height, cls.capturevideo_buffer))
1173 case CAPTUREVIDEOFORMAT_TARGA:
1174 //return Image_WriteTGARGB_preflipped (filename, width, height, cls.capturevideo_buffer, cls.capturevideo_buffer + vid.width * vid.height * 3, );
1175 memset (cls.capturevideo_buffer, 0, 18);
1176 cls.capturevideo_buffer[2] = 2; // uncompressed type
1177 cls.capturevideo_buffer[12] = (width >> 0) & 0xFF;
1178 cls.capturevideo_buffer[13] = (width >> 8) & 0xFF;
1179 cls.capturevideo_buffer[14] = (height >> 0) & 0xFF;
1180 cls.capturevideo_buffer[15] = (height >> 8) & 0xFF;
1181 cls.capturevideo_buffer[16] = 24; // pixel size
1182 qglReadPixels (x, y, width, height, GL_BGR, GL_UNSIGNED_BYTE, cls.capturevideo_buffer + 18);
1184 for (;cls.capturevideo_frame < newframenum;cls.capturevideo_frame++)
1186 sprintf(filename, "video/dp%06d.tga", cls.capturevideo_frame);
1187 if (!FS_WriteFile (filename, cls.capturevideo_buffer, width*height*3 + 18))
1196 void SCR_CaptureVideo_SoundFrame(unsigned char *bufstereo16le, size_t length, int rate)
1198 if (!cls.capturevideo_soundfile)
1200 cls.capturevideo_soundrate = rate;
1201 if (FS_Write (cls.capturevideo_soundfile, bufstereo16le, 4 * length) < (fs_offset_t)(4 * length))
1203 Cvar_SetValueQuick(&cl_capturevideo, 0);
1204 Con_Printf("video sound saving failed on frame %i, out of disk space? stopping video capture.\n", cls.capturevideo_frame);
1205 SCR_CaptureVideo_EndVideo();
1209 void SCR_CaptureVideo(void)
1212 if (cl_capturevideo.integer && r_render.integer)
1214 if (!cls.capturevideo_active)
1215 SCR_CaptureVideo_BeginVideo();
1216 if (cls.capturevideo_framerate != cl_capturevideo_fps.value)
1218 Con_Printf("You can not change the video framerate while recording a video.\n");
1219 Cvar_SetValueQuick(&cl_capturevideo_fps, cls.capturevideo_framerate);
1221 if (cls.capturevideo_soundfile)
1223 // preserve sound sync by duplicating frames when running slow
1224 newframenum = (Sys_DoubleTime() - cls.capturevideo_starttime) * cls.capturevideo_framerate;
1227 newframenum = cls.capturevideo_frame + 1;
1228 // if falling behind more than one second, stop
1229 if (newframenum - cls.capturevideo_frame > (int)ceil(cls.capturevideo_framerate))
1231 Cvar_SetValueQuick(&cl_capturevideo, 0);
1232 Con_Printf("video saving failed on frame %i, your machine is too slow for this capture speed.\n", cls.capturevideo_frame);
1233 SCR_CaptureVideo_EndVideo();
1237 if (!SCR_CaptureVideo_VideoFrame(newframenum))
1239 Cvar_SetValueQuick(&cl_capturevideo, 0);
1240 Con_Printf("video saving failed on frame %i, out of disk space? stopping video capture.\n", cls.capturevideo_frame);
1241 SCR_CaptureVideo_EndVideo();
1244 else if (cls.capturevideo_active)
1245 SCR_CaptureVideo_EndVideo();
1252 Grab six views for environment mapping tests
1259 qboolean flipx, flipy, flipdiagonaly;
1263 {{ 0, 0, 0}, "rt", false, false, false},
1264 {{ 0, 270, 0}, "ft", false, false, false},
1265 {{ 0, 180, 0}, "lf", false, false, false},
1266 {{ 0, 90, 0}, "bk", false, false, false},
1267 {{-90, 180, 0}, "up", true, true, false},
1268 {{ 90, 180, 0}, "dn", true, true, false},
1270 {{ 0, 0, 0}, "px", true, true, true},
1271 {{ 0, 90, 0}, "py", false, true, false},
1272 {{ 0, 180, 0}, "nx", false, false, true},
1273 {{ 0, 270, 0}, "ny", true, false, false},
1274 {{-90, 180, 0}, "pz", false, false, true},
1275 {{ 90, 180, 0}, "nz", false, false, true}
1278 static void R_Envmap_f (void)
1281 char filename[MAX_QPATH], basename[MAX_QPATH];
1282 unsigned char *buffer1;
1283 unsigned char *buffer2;
1284 unsigned char *buffer3;
1286 if (Cmd_Argc() != 3)
1288 Con_Print("envmap <basename> <size>: save out 6 cubic environment map images, usable with loadsky, note that size must one of 128, 256, 512, or 1024 and can't be bigger than your current resolution\n");
1292 strlcpy (basename, Cmd_Argv(1), sizeof (basename));
1293 size = atoi(Cmd_Argv(2));
1294 if (size != 128 && size != 256 && size != 512 && size != 1024)
1296 Con_Print("envmap: size must be one of 128, 256, 512, or 1024\n");
1299 if (size > vid.width || size > vid.height)
1301 Con_Print("envmap: your resolution is not big enough to render that size\n");
1309 r_refdef.width = size;
1310 r_refdef.height = size;
1312 r_refdef.frustum_x = tan(90 * M_PI / 360.0);
1313 r_refdef.frustum_y = tan(90 * M_PI / 360.0);
1315 buffer1 = (unsigned char *)Mem_Alloc(tempmempool, size * size * 3);
1316 buffer2 = (unsigned char *)Mem_Alloc(tempmempool, size * size * 3);
1317 buffer3 = (unsigned char *)Mem_Alloc(tempmempool, size * size * 3 + 18);
1319 for (j = 0;j < 12;j++)
1321 sprintf(filename, "env/%s%s.tga", basename, envmapinfo[j].name);
1322 Matrix4x4_CreateFromQuakeEntity(&r_refdef.viewentitymatrix, r_vieworigin[0], r_vieworigin[1], r_vieworigin[2], envmapinfo[j].angles[0], envmapinfo[j].angles[1], envmapinfo[j].angles[2], 1);
1327 SCR_ScreenShot(filename, buffer1, buffer2, buffer3, 0, vid.height - (r_refdef.y + r_refdef.height), size, size, envmapinfo[j].flipx, envmapinfo[j].flipy, envmapinfo[j].flipdiagonaly, false, false);
1337 //=============================================================================
1339 // LordHavoc: SHOWLMP stuff
1340 #define SHOWLMP_MAXLABELS 256
1341 typedef struct showlmp_s
1351 showlmp_t showlmp[SHOWLMP_MAXLABELS];
1353 void SHOWLMP_decodehide(void)
1357 lmplabel = MSG_ReadString();
1358 for (i = 0;i < SHOWLMP_MAXLABELS;i++)
1359 if (showlmp[i].isactive && strcmp(showlmp[i].label, lmplabel) == 0)
1361 showlmp[i].isactive = false;
1366 void SHOWLMP_decodeshow(void)
1369 char lmplabel[256], picname[256];
1371 strlcpy (lmplabel,MSG_ReadString(), sizeof (lmplabel));
1372 strlcpy (picname, MSG_ReadString(), sizeof (picname));
1373 if (gamemode == GAME_NEHAHRA) // LordHavoc: nasty old legacy junk
1380 x = MSG_ReadShort();
1381 y = MSG_ReadShort();
1384 for (i = 0;i < SHOWLMP_MAXLABELS;i++)
1385 if (showlmp[i].isactive)
1387 if (strcmp(showlmp[i].label, lmplabel) == 0)
1390 break; // drop out to replace it
1393 else if (k < 0) // find first empty one to replace
1396 return; // none found to replace
1397 // change existing one
1398 showlmp[k].isactive = true;
1399 strlcpy (showlmp[k].label, lmplabel, sizeof (showlmp[k].label));
1400 strlcpy (showlmp[k].pic, picname, sizeof (showlmp[k].pic));
1405 void SHOWLMP_drawall(void)
1408 for (i = 0;i < SHOWLMP_MAXLABELS;i++)
1409 if (showlmp[i].isactive)
1410 DrawQ_Pic(showlmp[i].x, showlmp[i].y, Draw_CachePic(showlmp[i].pic, false), 0, 0, 1, 1, 1, 1, 0);
1413 void SHOWLMP_clear(void)
1416 for (i = 0;i < SHOWLMP_MAXLABELS;i++)
1417 showlmp[i].isactive = false;
1420 void CL_SetupScreenSize(void)
1422 float conwidth, conheight;
1424 VID_UpdateGamma(false);
1426 conwidth = bound(320, vid_conwidth.value, 2048);
1427 conheight = bound(200, vid_conheight.value, 1536);
1428 if (vid_conwidth.value != conwidth)
1429 Cvar_SetValue("vid_conwidth", conwidth);
1430 if (vid_conheight.value != conheight)
1431 Cvar_SetValue("vid_conheight", conheight);
1433 vid_conwidth.integer = vid_conwidth.integer;
1434 vid_conheight.integer = vid_conheight.integer;
1436 SCR_SetUpToDrawConsole();
1439 extern void R_Shadow_EditLights_DrawSelectedLightProperties(void);
1440 void CL_UpdateScreen(void)
1442 if (!scr_initialized || !con_initialized || vid_hidden)
1443 return; // not initialized yet
1445 // don't allow cheats in multiplayer
1446 if (!cl.islocalgame && cl.worldmodel)
1448 if (r_fullbright.integer != 0)
1449 Cvar_Set ("r_fullbright", "0");
1450 if (r_ambient.value != 0)
1451 Cvar_Set ("r_ambient", "0");
1455 if (scr_viewsize.value < 30)
1456 Cvar_Set ("viewsize","30");
1457 if (scr_viewsize.value > 120)
1458 Cvar_Set ("viewsize","120");
1460 // bound field of view
1461 if (scr_fov.value < 1)
1462 Cvar_Set ("fov","1");
1463 if (scr_fov.value > 170)
1464 Cvar_Set ("fov","170");
1466 // intermission is always full screen
1467 if (cl.intermission)
1471 if (scr_viewsize.value >= 120)
1472 sb_lines = 0; // no status bar at all
1473 else if (scr_viewsize.value >= 110)
1474 sb_lines = 24; // no inventory
1479 r_refdef.colormask[0] = 1;
1480 r_refdef.colormask[1] = 1;
1481 r_refdef.colormask[2] = 1;
1485 if (r_timereport_active)
1486 R_TimeReport("other");
1488 CL_SetupScreenSize();
1492 if (r_timereport_active)
1493 R_TimeReport("setup");
1495 //FIXME: force menu if nothing else to look at?
1496 //if (key_dest == key_game && cls.signon != SIGNONS && cls.state == ca_disconnected)
1498 if (cls.signon == SIGNONS)
1503 if (!r_letterbox.value)
1506 SCR_CheckDrawCenterString();
1510 if (cls.signon == SIGNONS)
1512 if (r_timereport_active)
1514 R_TimeReport_Frame();
1516 R_Shadow_EditLights_DrawSelectedLightProperties();
1525 if (r_timereport_active)
1526 R_TimeReport("start");
1531 void CL_Screen_NewMap(void)