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)
493 SCR_UpdateLoadingScreen();
496 //=============================================================================
498 char r_speeds_string[1024];
499 int speedstringcount, r_timereport_active;
500 double r_timereport_temp = 0, r_timereport_current = 0, r_timereport_start = 0;
502 void R_TimeReport(char *desc)
508 if (r_speeds.integer < 2 || !r_timereport_active || r_showtrispass)
512 r_timereport_temp = r_timereport_current;
513 r_timereport_current = Sys_DoubleTime();
514 t = (int) ((r_timereport_current - r_timereport_temp) * 1000000.0);
516 dpsnprintf(tempbuf, sizeof(tempbuf), "%8i %s", t, desc);
517 length = (int)strlen(tempbuf);
519 tempbuf[length++] = ' ';
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 j = (int)strlen(r_speeds_string);
550 if (r_timereport_active && j > 0)
552 if (r_speeds_string[j-1] == '\n')
553 r_speeds_string[j-1] = 0;
555 for (i = 0;r_speeds_string[i];i++)
556 if (r_speeds_string[i] == '\n')
558 y = vid_conheight.integer - sb_lines - lines * 8;
560 DrawQ_Pic(0, y, NULL, vid_conwidth.integer, lines * 8, 0, 0, 0, 0.5, 0);
561 while (r_speeds_string[i])
564 while (r_speeds_string[i] && r_speeds_string[i] != '\n')
567 DrawQ_String(0, y, r_speeds_string + j, i - j, 8, 8, 1, 1, 1, 1, 0);
568 if (r_speeds_string[i] == '\n')
573 r_speeds_string[0] = 0;
574 r_timereport_active = false;
576 if (r_speeds.integer && cls.signon == SIGNONS && cls.state == ca_connected)
578 speedstringcount = 0;
579 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]);
580 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);
581 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);
582 if (renderstats.bloom)
583 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);
585 sprintf(r_speeds_string + strlen(r_speeds_string), "rendered%6i meshes%8i triangles\n", renderstats.meshes, renderstats.meshes_elements / 3);
587 memset(&renderstats, 0, sizeof(renderstats));
589 if (r_speeds.integer >= 2)
591 r_timereport_active = true;
592 r_timereport_start = Sys_DoubleTime();
604 void SCR_SizeUp_f (void)
606 Cvar_SetValue ("viewsize",scr_viewsize.value+10);
617 void SCR_SizeDown_f (void)
619 Cvar_SetValue ("viewsize",scr_viewsize.value-10);
622 void CL_Screen_Init(void)
624 Cvar_RegisterVariable (&scr_fov);
625 Cvar_RegisterVariable (&scr_viewsize);
626 Cvar_RegisterVariable (&scr_conspeed);
627 Cvar_RegisterVariable (&scr_conalpha);
628 Cvar_RegisterVariable (&scr_conbrightness);
629 Cvar_RegisterVariable (&scr_conforcewhiledisconnected);
630 Cvar_RegisterVariable (&scr_showram);
631 Cvar_RegisterVariable (&scr_showturtle);
632 Cvar_RegisterVariable (&scr_showpause);
633 Cvar_RegisterVariable (&scr_showbrand);
634 Cvar_RegisterVariable (&scr_centertime);
635 Cvar_RegisterVariable (&scr_printspeed);
636 Cvar_RegisterVariable (&vid_conwidth);
637 Cvar_RegisterVariable (&vid_conheight);
638 Cvar_RegisterVariable (&vid_pixelheight);
639 Cvar_RegisterVariable (&scr_screenshot_jpeg);
640 Cvar_RegisterVariable (&scr_screenshot_jpeg_quality);
641 Cvar_RegisterVariable (&scr_screenshot_gamma);
642 Cvar_RegisterVariable (&cl_capturevideo);
643 Cvar_RegisterVariable (&cl_capturevideo_sound);
644 Cvar_RegisterVariable (&cl_capturevideo_fps);
645 Cvar_RegisterVariable (&cl_capturevideo_rawrgb);
646 Cvar_RegisterVariable (&cl_capturevideo_rawyv12);
647 Cvar_RegisterVariable (&r_textshadow);
648 Cvar_RegisterVariable (&r_letterbox);
650 Cmd_AddCommand ("sizeup",SCR_SizeUp_f, "increase view size (increases viewsize cvar)");
651 Cmd_AddCommand ("sizedown",SCR_SizeDown_f, "decrease view size (decreases viewsize cvar)");
652 Cmd_AddCommand ("screenshot",SCR_ScreenShot_f, "takes a screenshot of the next rendered frame");
653 Cmd_AddCommand ("envmap", R_Envmap_f, "render a cubemap (skybox) of the current scene");
655 scr_initialized = true;
658 void DrawQ_Clear(void)
660 r_refdef.drawqueuesize = 0;
663 static int picelements[6] = {0, 1, 2, 0, 2, 3};
664 void DrawQ_Pic(float x, float y, cachepic_t *pic, float width, float height, float red, float green, float blue, float alpha, int flags)
666 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);
669 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)
674 if (alpha < (1.0f / 255.0f))
677 len = (int)strlen(string);
679 for (len = 0;len < maxlen && string[len];len++);
680 for (;len > 0 && string[0] == ' ';string++, x += scalex, len--);
681 for (;len > 0 && string[len - 1] == ' ';len--);
684 if (x >= vid_conwidth.integer || y >= vid_conheight.integer || x < (-scalex * len) || y < (-scaley))
686 size = sizeof(*dq) + ((len + 1 + 3) & ~3);
687 if (r_refdef.drawqueuesize + size > r_refdef.maxdrawqueuesize)
689 red = bound(0, red, 1);
690 green = bound(0, green, 1);
691 blue = bound(0, blue, 1);
692 alpha = bound(0, alpha, 1);
693 dq = (drawqueue_t *)(r_refdef.drawqueue + r_refdef.drawqueuesize);
695 dq->command = DRAWQUEUE_STRING;
697 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));
702 out = (char *)(dq + 1);
703 memcpy(out, string, len);
705 r_refdef.drawqueuesize += dq->size;
708 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)
710 if (r_textshadow.integer)
711 DrawQ_String_Real(x+scalex*0.25,y+scaley*0.25,string,maxlen,scalex,scaley,0,0,0,alpha*0.8,flags);
713 DrawQ_String_Real(x,y,string,maxlen,scalex,scaley,red,green,blue,alpha,flags);
716 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)
719 drawqueuemesh_t mesh;
720 memset(&mesh, 0, sizeof(mesh));
726 height = pic->height;
727 mesh.texture = pic->tex;
729 mesh.num_triangles = 2;
730 mesh.num_vertices = 4;
731 mesh.data_element3i = picelements;
732 mesh.data_vertex3f = floats;
733 mesh.data_texcoord2f = floats + 12;
734 mesh.data_color4f = floats + 20;
735 memset(floats, 0, sizeof(floats));
736 mesh.data_vertex3f[0] = mesh.data_vertex3f[9] = x;
737 mesh.data_vertex3f[1] = mesh.data_vertex3f[4] = y;
738 mesh.data_vertex3f[3] = mesh.data_vertex3f[6] = x + width;
739 mesh.data_vertex3f[7] = mesh.data_vertex3f[10] = y + height;
740 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;
741 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;
742 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;
743 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;
744 DrawQ_Mesh (&mesh, flags);
747 void DrawQ_Mesh (drawqueuemesh_t *mesh, int flags)
754 size += sizeof(drawqueuemesh_t);
755 size += sizeof(int[3]) * mesh->num_triangles;
756 size += sizeof(float[3]) * mesh->num_vertices;
757 size += sizeof(float[2]) * mesh->num_vertices;
758 size += sizeof(float[4]) * mesh->num_vertices;
759 if (r_refdef.drawqueuesize + size > r_refdef.maxdrawqueuesize)
761 dq = (drawqueue_t *)(r_refdef.drawqueue + r_refdef.drawqueuesize);
763 dq->command = DRAWQUEUE_MESH;
770 p = (void *)(dq + 1);
771 m = (drawqueuemesh_t *)p;p = (unsigned char*)p + sizeof(drawqueuemesh_t);
772 m->num_triangles = mesh->num_triangles;
773 m->num_vertices = mesh->num_vertices;
774 m->texture = mesh->texture;
775 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]);
776 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]);
777 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]);
778 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]);
779 r_refdef.drawqueuesize += dq->size;
782 void DrawQ_LineLoop (drawqueuemesh_t *mesh, int flags)
789 size += sizeof(drawqueuemesh_t);
790 size += sizeof(int[3]) * mesh->num_triangles;
791 size += sizeof(float[3]) * mesh->num_vertices;
792 size += sizeof(float[2]) * mesh->num_vertices;
793 size += sizeof(float[4]) * mesh->num_vertices;
794 if (r_refdef.drawqueuesize + size > r_refdef.maxdrawqueuesize)
796 dq = (void *)(r_refdef.drawqueue + r_refdef.drawqueuesize);
798 dq->command = DRAWQUEUE_LINES;
805 p = (void *)(dq + 1);
806 m = p;p = (unsigned char*)p + sizeof(drawqueuemesh_t);
807 m->num_triangles = mesh->num_triangles;
808 m->num_vertices = mesh->num_vertices;
809 m->texture = mesh->texture;
810 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]);
811 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]);
812 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]);
813 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]);
814 r_refdef.drawqueuesize += dq->size;
817 //LordHavoc: FIXME: this is nasty!
818 void DrawQ_LineWidth (float width)
821 static int linewidth = 1;
822 if(width == linewidth)
825 if(r_refdef.drawqueuesize + (int)sizeof(*dq) > r_refdef.maxdrawqueuesize)
827 Con_DPrint("DrawQueue full !\n");
830 dq = (void*) (r_refdef.drawqueue + r_refdef.drawqueuesize);
831 dq->size = sizeof(*dq);
832 dq->command = DRAWQUEUE_LINEWIDTH;
835 r_refdef.drawqueuesize += dq->size;
838 //[515]: this is old, delete
839 void DrawQ_Line (float width, float x1, float y1, float x2, float y2, float r, float g, float b, float alpha, int flags)
843 DrawQ_LineWidth(width);
844 if(r_refdef.drawqueuesize + (int)sizeof(*dq) > r_refdef.maxdrawqueuesize)
846 Con_DPrint("DrawQueue full !\n");
849 dq = (void*) (r_refdef.drawqueue + r_refdef.drawqueuesize);
850 dq->size = sizeof(*dq);
851 dq->command = DRAWQUEUE_LINES;
857 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));
859 r_refdef.drawqueuesize += dq->size;
862 void DrawQ_SetClipArea(float x, float y, float width, float height)
865 if(r_refdef.drawqueuesize + (int)sizeof(*dq) > r_refdef.maxdrawqueuesize)
867 Con_DPrint("DrawQueue full !\n");
870 dq = (drawqueue_t *) (r_refdef.drawqueue + r_refdef.drawqueuesize);
871 dq->size = sizeof(*dq);
872 dq->command = DRAWQUEUE_SETCLIP;
880 r_refdef.drawqueuesize += dq->size;
883 void DrawQ_ResetClipArea(void)
886 if(r_refdef.drawqueuesize + (int)sizeof(*dq) > r_refdef.maxdrawqueuesize)
888 Con_DPrint("DrawQueue full !\n");
891 dq = (drawqueue_t *) (r_refdef.drawqueue + r_refdef.drawqueuesize);
892 dq->size = sizeof(*dq);
893 dq->command = DRAWQUEUE_RESETCLIP;
901 r_refdef.drawqueuesize += dq->size;
909 void SCR_ScreenShot_f (void)
911 static int shotnumber;
912 static char oldname[MAX_QPATH];
913 char base[MAX_QPATH];
914 char filename[MAX_QPATH];
915 unsigned char *buffer1;
916 unsigned char *buffer2;
917 unsigned char *buffer3;
918 qboolean jpeg = (scr_screenshot_jpeg.integer != 0);
920 sprintf (base, "screenshots/%s", scr_screenshot_name.string);
922 if (strcmp (oldname, scr_screenshot_name.string))
924 sprintf(oldname, "%s", scr_screenshot_name.string);
928 // find a file name to save it to
929 for (;shotnumber < 1000000;shotnumber++)
930 if (!FS_SysFileExists(va("%s/%s%06d.tga", fs_gamedir, base, shotnumber)) && !FS_SysFileExists(va("%s/%s%06d.jpg", fs_gamedir, base, shotnumber)))
932 if (shotnumber >= 1000000)
934 Con_Print("SCR_ScreenShot_f: Couldn't create the image file\n");
938 sprintf(filename, "%s%06d.%s", base, shotnumber, jpeg ? "jpg" : "tga");
940 buffer1 = (unsigned char *)Mem_Alloc(tempmempool, vid.width * vid.height * 3);
941 buffer2 = (unsigned char *)Mem_Alloc(tempmempool, vid.width * vid.height * 3);
942 buffer3 = (unsigned char *)Mem_Alloc(tempmempool, vid.width * vid.height * 3 + 18);
944 if (SCR_ScreenShot (filename, buffer1, buffer2, buffer3, 0, 0, vid.width, vid.height, false, false, false, jpeg, true))
945 Con_Printf("Wrote %s\n", filename);
947 Con_Printf("unable to write %s\n", filename);
956 typedef enum capturevideoformat_e
958 CAPTUREVIDEOFORMAT_TARGA,
959 CAPTUREVIDEOFORMAT_JPEG,
960 CAPTUREVIDEOFORMAT_RAWRGB,
961 CAPTUREVIDEOFORMAT_RAWYV12
963 capturevideoformat_t;
965 qboolean cl_capturevideo_active = false;
966 capturevideoformat_t cl_capturevideo_format;
967 static double cl_capturevideo_starttime = 0;
968 double cl_capturevideo_framerate = 0;
969 static int cl_capturevideo_soundrate = 0;
970 static int cl_capturevideo_frame = 0;
971 static unsigned char *cl_capturevideo_buffer = NULL;
972 static qfile_t *cl_capturevideo_videofile = NULL;
973 qfile_t *cl_capturevideo_soundfile = NULL;
974 static short cl_capturevideo_rgbtoyuvscaletable[3][3][256];
975 static unsigned char cl_capturevideo_yuvnormalizetable[3][256];
976 //static unsigned char cl_capturevideo_rgbgammatable[3][256];
978 void SCR_CaptureVideo_BeginVideo(void)
982 unsigned char out[44];
983 if (cl_capturevideo_active)
985 // soundrate is figured out on the first SoundFrame
986 cl_capturevideo_active = true;
987 cl_capturevideo_starttime = Sys_DoubleTime();
988 cl_capturevideo_framerate = bound(1, cl_capturevideo_fps.value, 1000);
989 cl_capturevideo_soundrate = 0;
990 cl_capturevideo_frame = 0;
991 cl_capturevideo_buffer = (unsigned char *)Mem_Alloc(tempmempool, vid.width * vid.height * (3+3+3) + 18);
992 gamma = 1.0/scr_screenshot_gamma.value;
995 for (i = 0;i < 256;i++)
997 unsigned char j = (unsigned char)bound(0, 255*pow(i/255.0, gamma), 255);
998 cl_capturevideo_rgbgammatable[0][i] = j;
999 cl_capturevideo_rgbgammatable[1][i] = j;
1000 cl_capturevideo_rgbgammatable[2][i] = j;
1004 R = Y + 1.4075 * (Cr - 128);
1005 G = Y + -0.3455 * (Cb - 128) + -0.7169 * (Cr - 128);
1006 B = Y + 1.7790 * (Cb - 128);
1007 Y = R * .299 + G * .587 + B * .114;
1008 Cb = R * -.169 + G * -.332 + B * .500 + 128.;
1009 Cr = R * .500 + G * -.419 + B * -.0813 + 128.;
1011 for (i = 0;i < 256;i++)
1013 g = 255*pow(i/255.0, gamma);
1014 // Y weights from RGB
1015 cl_capturevideo_rgbtoyuvscaletable[0][0][i] = (short)(g * 0.299);
1016 cl_capturevideo_rgbtoyuvscaletable[0][1][i] = (short)(g * 0.587);
1017 cl_capturevideo_rgbtoyuvscaletable[0][2][i] = (short)(g * 0.114);
1018 // Cb weights from RGB
1019 cl_capturevideo_rgbtoyuvscaletable[1][0][i] = (short)(g * -0.169);
1020 cl_capturevideo_rgbtoyuvscaletable[1][1][i] = (short)(g * -0.332);
1021 cl_capturevideo_rgbtoyuvscaletable[1][2][i] = (short)(g * 0.500);
1022 // Cr weights from RGB
1023 cl_capturevideo_rgbtoyuvscaletable[2][0][i] = (short)(g * 0.500);
1024 cl_capturevideo_rgbtoyuvscaletable[2][1][i] = (short)(g * -0.419);
1025 cl_capturevideo_rgbtoyuvscaletable[2][2][i] = (short)(g * -0.0813);
1026 // range reduction of YCbCr to valid signal range
1027 cl_capturevideo_yuvnormalizetable[0][i] = 16 + i * (236-16) / 256;
1028 cl_capturevideo_yuvnormalizetable[1][i] = 16 + i * (240-16) / 256;
1029 cl_capturevideo_yuvnormalizetable[2][i] = 16 + i * (240-16) / 256;
1032 if (cl_capturevideo_rawrgb.integer)
1034 cl_capturevideo_format = CAPTUREVIDEOFORMAT_RAWRGB;
1035 cl_capturevideo_videofile = FS_Open ("video/dpvideo.rgb", "wb", false, true);
1037 else if (cl_capturevideo_rawyv12.integer)
1039 cl_capturevideo_format = CAPTUREVIDEOFORMAT_RAWYV12;
1040 cl_capturevideo_videofile = FS_Open ("video/dpvideo.yv12", "wb", false, true);
1042 else if (scr_screenshot_jpeg.integer)
1044 cl_capturevideo_format = CAPTUREVIDEOFORMAT_JPEG;
1045 cl_capturevideo_videofile = NULL;
1049 cl_capturevideo_format = CAPTUREVIDEOFORMAT_TARGA;
1050 cl_capturevideo_videofile = NULL;
1053 if (cl_capturevideo_sound.integer)
1055 cl_capturevideo_soundfile = FS_Open ("video/dpvideo.wav", "wb", false, true);
1056 // wave header will be filled out when video ends
1058 FS_Write (cl_capturevideo_soundfile, out, 44);
1061 cl_capturevideo_soundfile = NULL;
1064 void SCR_CaptureVideo_EndVideo(void)
1067 unsigned char out[44];
1068 if (!cl_capturevideo_active)
1070 cl_capturevideo_active = false;
1072 if (cl_capturevideo_videofile)
1074 FS_Close(cl_capturevideo_videofile);
1075 cl_capturevideo_videofile = NULL;
1078 // finish the wave file
1079 if (cl_capturevideo_soundfile)
1081 i = (int)FS_Tell (cl_capturevideo_soundfile);
1082 //"RIFF", (int) unknown (chunk size), "WAVE",
1083 //"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
1084 //"data", (int) unknown (chunk size)
1085 memcpy (out, "RIFF****WAVEfmt \x10\x00\x00\x00\x01\x00\x02\x00********\x04\x00\x10\0data****", 44);
1086 // the length of the whole RIFF chunk
1088 out[4] = (n) & 0xFF;
1089 out[5] = (n >> 8) & 0xFF;
1090 out[6] = (n >> 16) & 0xFF;
1091 out[7] = (n >> 24) & 0xFF;
1093 n = cl_capturevideo_soundrate;
1094 out[24] = (n) & 0xFF;
1095 out[25] = (n >> 8) & 0xFF;
1096 out[26] = (n >> 16) & 0xFF;
1097 out[27] = (n >> 24) & 0xFF;
1098 // bytes per second (rate * channels * bytes per channel)
1099 n = cl_capturevideo_soundrate * 2 * 2;
1100 out[28] = (n) & 0xFF;
1101 out[29] = (n >> 8) & 0xFF;
1102 out[30] = (n >> 16) & 0xFF;
1103 out[31] = (n >> 24) & 0xFF;
1104 // the length of the data chunk
1106 out[40] = (n) & 0xFF;
1107 out[41] = (n >> 8) & 0xFF;
1108 out[42] = (n >> 16) & 0xFF;
1109 out[43] = (n >> 24) & 0xFF;
1110 FS_Seek (cl_capturevideo_soundfile, 0, SEEK_SET);
1111 FS_Write (cl_capturevideo_soundfile, out, 44);
1112 FS_Close (cl_capturevideo_soundfile);
1113 cl_capturevideo_soundfile = NULL;
1116 if (cl_capturevideo_buffer)
1118 Mem_Free (cl_capturevideo_buffer);
1119 cl_capturevideo_buffer = NULL;
1122 cl_capturevideo_starttime = 0;
1123 cl_capturevideo_framerate = 0;
1124 cl_capturevideo_frame = 0;
1127 qboolean SCR_CaptureVideo_VideoFrame(int newframenum)
1129 int x = 0, y = 0, width = vid.width, height = vid.height;
1130 unsigned char *b, *out;
1132 int outoffset = (width/2)*(height/2);
1133 //return SCR_ScreenShot(filename, cl_capturevideo_buffer, cl_capturevideo_buffer + vid.width * vid.height * 3, cl_capturevideo_buffer + vid.width * vid.height * 6, 0, 0, vid.width, vid.height, false, false, false, jpeg, true);
1134 // speed is critical here, so do saving as directly as possible
1135 switch (cl_capturevideo_format)
1137 case CAPTUREVIDEOFORMAT_RAWYV12:
1138 // FIXME: width/height must be multiple of 2, enforce this?
1139 qglReadPixels (x, y, width, height, GL_RGB, GL_UNSIGNED_BYTE, cl_capturevideo_buffer);
1141 // process one line at a time, and CbCr every other line at 2 pixel intervals
1142 for (y = 0;y < height;y++)
1145 for (b = cl_capturevideo_buffer + (height-1-y)*width*3, out = cl_capturevideo_buffer + width*height*3 + y*width, x = 0;x < width;x++, b += 3, out++)
1146 *out = cl_capturevideo_yuvnormalizetable[0][cl_capturevideo_rgbtoyuvscaletable[0][0][b[0]] + cl_capturevideo_rgbtoyuvscaletable[0][1][b[1]] + cl_capturevideo_rgbtoyuvscaletable[0][2][b[2]]];
1149 // 2x2 Cb and Cr planes
1151 // low quality, no averaging
1152 for (b = cl_capturevideo_buffer + (height-2-y)*width*3, out = cl_capturevideo_buffer + width*height*3 + width*height + (y/2)*(width/2), x = 0;x < width/2;x++, b += 6, out++)
1155 out[0 ] = cl_capturevideo_yuvnormalizetable[2][cl_capturevideo_rgbtoyuvscaletable[2][0][b[0]] + cl_capturevideo_rgbtoyuvscaletable[2][1][b[1]] + cl_capturevideo_rgbtoyuvscaletable[2][2][b[2]] + 128];
1157 out[outoffset] = cl_capturevideo_yuvnormalizetable[1][cl_capturevideo_rgbtoyuvscaletable[1][0][b[0]] + cl_capturevideo_rgbtoyuvscaletable[1][1][b[1]] + cl_capturevideo_rgbtoyuvscaletable[1][2][b[2]] + 128];
1160 // high quality, averaging
1161 int inpitch = width*3;
1162 for (b = cl_capturevideo_buffer + (height-2-y)*width*3, out = cl_capturevideo_buffer + width*height*3 + width*height + (y/2)*(width/2), x = 0;x < width/2;x++, b += 6, out++)
1164 int blockr, blockg, blockb;
1165 blockr = (b[0] + b[3] + b[inpitch+0] + b[inpitch+3]) >> 2;
1166 blockg = (b[1] + b[4] + b[inpitch+1] + b[inpitch+4]) >> 2;
1167 blockb = (b[2] + b[5] + b[inpitch+2] + b[inpitch+5]) >> 2;
1169 out[0 ] = cl_capturevideo_yuvnormalizetable[2][cl_capturevideo_rgbtoyuvscaletable[2][0][blockr] + cl_capturevideo_rgbtoyuvscaletable[2][1][blockg] + cl_capturevideo_rgbtoyuvscaletable[2][2][blockb] + 128];
1171 out[outoffset] = cl_capturevideo_yuvnormalizetable[1][cl_capturevideo_rgbtoyuvscaletable[1][0][blockr] + cl_capturevideo_rgbtoyuvscaletable[1][1][blockg] + cl_capturevideo_rgbtoyuvscaletable[1][2][blockb] + 128];
1176 for (;cl_capturevideo_frame < newframenum;cl_capturevideo_frame++)
1177 if (!FS_Write (cl_capturevideo_videofile, cl_capturevideo_buffer + width*height*3, width*height+(width/2)*(height/2)*2))
1180 case CAPTUREVIDEOFORMAT_RAWRGB:
1181 qglReadPixels (x, y, width, height, GL_RGB, GL_UNSIGNED_BYTE, cl_capturevideo_buffer);
1183 for (;cl_capturevideo_frame < newframenum;cl_capturevideo_frame++)
1184 if (!FS_Write (cl_capturevideo_videofile, cl_capturevideo_buffer, width*height*3))
1187 case CAPTUREVIDEOFORMAT_JPEG:
1188 qglReadPixels (x, y, width, height, GL_RGB, GL_UNSIGNED_BYTE, cl_capturevideo_buffer);
1190 for (;cl_capturevideo_frame < newframenum;cl_capturevideo_frame++)
1192 sprintf(filename, "video/dp%06d.jpg", cl_capturevideo_frame);
1193 if (!JPEG_SaveImage_preflipped (filename, width, height, cl_capturevideo_buffer))
1197 case CAPTUREVIDEOFORMAT_TARGA:
1198 //return Image_WriteTGARGB_preflipped (filename, width, height, cl_capturevideo_buffer, cl_capturevideo_buffer + vid.width * vid.height * 3, );
1199 memset (cl_capturevideo_buffer, 0, 18);
1200 cl_capturevideo_buffer[2] = 2; // uncompressed type
1201 cl_capturevideo_buffer[12] = (width >> 0) & 0xFF;
1202 cl_capturevideo_buffer[13] = (width >> 8) & 0xFF;
1203 cl_capturevideo_buffer[14] = (height >> 0) & 0xFF;
1204 cl_capturevideo_buffer[15] = (height >> 8) & 0xFF;
1205 cl_capturevideo_buffer[16] = 24; // pixel size
1206 qglReadPixels (x, y, width, height, GL_BGR, GL_UNSIGNED_BYTE, cl_capturevideo_buffer + 18);
1208 for (;cl_capturevideo_frame < newframenum;cl_capturevideo_frame++)
1210 sprintf(filename, "video/dp%06d.tga", cl_capturevideo_frame);
1211 if (!FS_WriteFile (filename, cl_capturevideo_buffer, width*height*3 + 18))
1220 void SCR_CaptureVideo_SoundFrame(unsigned char *bufstereo16le, size_t length, int rate)
1222 if (!cl_capturevideo_soundfile)
1224 cl_capturevideo_soundrate = rate;
1225 if (FS_Write (cl_capturevideo_soundfile, bufstereo16le, 4 * length) < (fs_offset_t)(4 * length))
1227 Cvar_SetValueQuick(&cl_capturevideo, 0);
1228 Con_Printf("video sound saving failed on frame %i, out of disk space? stopping video capture.\n", cl_capturevideo_frame);
1229 SCR_CaptureVideo_EndVideo();
1233 void SCR_CaptureVideo(void)
1236 if (cl_capturevideo.integer && r_render.integer)
1238 if (!cl_capturevideo_active)
1239 SCR_CaptureVideo_BeginVideo();
1240 if (cl_capturevideo_framerate != cl_capturevideo_fps.value)
1242 Con_Printf("You can not change the video framerate while recording a video.\n");
1243 Cvar_SetValueQuick(&cl_capturevideo_fps, cl_capturevideo_framerate);
1245 if (cl_capturevideo_soundfile)
1247 // preserve sound sync by duplicating frames when running slow
1248 newframenum = (Sys_DoubleTime() - cl_capturevideo_starttime) * cl_capturevideo_framerate;
1251 newframenum = cl_capturevideo_frame + 1;
1252 // if falling behind more than one second, stop
1253 if (newframenum - cl_capturevideo_frame > (int)ceil(cl_capturevideo_framerate))
1255 Cvar_SetValueQuick(&cl_capturevideo, 0);
1256 Con_Printf("video saving failed on frame %i, your machine is too slow for this capture speed.\n", cl_capturevideo_frame);
1257 SCR_CaptureVideo_EndVideo();
1261 if (!SCR_CaptureVideo_VideoFrame(newframenum))
1263 Cvar_SetValueQuick(&cl_capturevideo, 0);
1264 Con_Printf("video saving failed on frame %i, out of disk space? stopping video capture.\n", cl_capturevideo_frame);
1265 SCR_CaptureVideo_EndVideo();
1268 else if (cl_capturevideo_active)
1269 SCR_CaptureVideo_EndVideo();
1276 Grab six views for environment mapping tests
1283 qboolean flipx, flipy, flipdiagonaly;
1287 {{ 0, 0, 0}, "rt", false, false, false},
1288 {{ 0, 270, 0}, "ft", false, false, false},
1289 {{ 0, 180, 0}, "lf", false, false, false},
1290 {{ 0, 90, 0}, "bk", false, false, false},
1291 {{-90, 180, 0}, "up", true, true, false},
1292 {{ 90, 180, 0}, "dn", true, true, false},
1294 {{ 0, 0, 0}, "px", true, true, true},
1295 {{ 0, 90, 0}, "py", false, true, false},
1296 {{ 0, 180, 0}, "nx", false, false, true},
1297 {{ 0, 270, 0}, "ny", true, false, false},
1298 {{-90, 180, 0}, "pz", false, false, true},
1299 {{ 90, 180, 0}, "nz", false, false, true}
1302 static void R_Envmap_f (void)
1305 char filename[MAX_QPATH], basename[MAX_QPATH];
1306 unsigned char *buffer1;
1307 unsigned char *buffer2;
1308 unsigned char *buffer3;
1310 if (Cmd_Argc() != 3)
1312 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");
1316 strlcpy (basename, Cmd_Argv(1), sizeof (basename));
1317 size = atoi(Cmd_Argv(2));
1318 if (size != 128 && size != 256 && size != 512 && size != 1024)
1320 Con_Print("envmap: size must be one of 128, 256, 512, or 1024\n");
1323 if (size > vid.width || size > vid.height)
1325 Con_Print("envmap: your resolution is not big enough to render that size\n");
1333 r_refdef.width = size;
1334 r_refdef.height = size;
1336 r_refdef.frustum_x = tan(90 * M_PI / 360.0);
1337 r_refdef.frustum_y = tan(90 * M_PI / 360.0);
1339 buffer1 = (unsigned char *)Mem_Alloc(tempmempool, size * size * 3);
1340 buffer2 = (unsigned char *)Mem_Alloc(tempmempool, size * size * 3);
1341 buffer3 = (unsigned char *)Mem_Alloc(tempmempool, size * size * 3 + 18);
1343 for (j = 0;j < 12;j++)
1345 sprintf(filename, "env/%s%s.tga", basename, envmapinfo[j].name);
1346 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);
1351 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);
1361 //=============================================================================
1363 // LordHavoc: SHOWLMP stuff
1364 #define SHOWLMP_MAXLABELS 256
1365 typedef struct showlmp_s
1375 showlmp_t showlmp[SHOWLMP_MAXLABELS];
1377 void SHOWLMP_decodehide(void)
1381 lmplabel = MSG_ReadString();
1382 for (i = 0;i < SHOWLMP_MAXLABELS;i++)
1383 if (showlmp[i].isactive && strcmp(showlmp[i].label, lmplabel) == 0)
1385 showlmp[i].isactive = false;
1390 void SHOWLMP_decodeshow(void)
1393 char lmplabel[256], picname[256];
1395 strlcpy (lmplabel,MSG_ReadString(), sizeof (lmplabel));
1396 strlcpy (picname, MSG_ReadString(), sizeof (picname));
1397 if (gamemode == GAME_NEHAHRA) // LordHavoc: nasty old legacy junk
1404 x = MSG_ReadShort();
1405 y = MSG_ReadShort();
1408 for (i = 0;i < SHOWLMP_MAXLABELS;i++)
1409 if (showlmp[i].isactive)
1411 if (strcmp(showlmp[i].label, lmplabel) == 0)
1414 break; // drop out to replace it
1417 else if (k < 0) // find first empty one to replace
1420 return; // none found to replace
1421 // change existing one
1422 showlmp[k].isactive = true;
1423 strlcpy (showlmp[k].label, lmplabel, sizeof (showlmp[k].label));
1424 strlcpy (showlmp[k].pic, picname, sizeof (showlmp[k].pic));
1429 void SHOWLMP_drawall(void)
1432 for (i = 0;i < SHOWLMP_MAXLABELS;i++)
1433 if (showlmp[i].isactive)
1434 DrawQ_Pic(showlmp[i].x, showlmp[i].y, Draw_CachePic(showlmp[i].pic, false), 0, 0, 1, 1, 1, 1, 0);
1437 void SHOWLMP_clear(void)
1440 for (i = 0;i < SHOWLMP_MAXLABELS;i++)
1441 showlmp[i].isactive = false;
1444 void CL_SetupScreenSize(void)
1446 float conwidth, conheight;
1448 VID_UpdateGamma(false);
1450 conwidth = bound(320, vid_conwidth.value, 2048);
1451 conheight = bound(200, vid_conheight.value, 1536);
1452 if (vid_conwidth.value != conwidth)
1453 Cvar_SetValue("vid_conwidth", conwidth);
1454 if (vid_conheight.value != conheight)
1455 Cvar_SetValue("vid_conheight", conheight);
1457 vid_conwidth.integer = vid_conwidth.integer;
1458 vid_conheight.integer = vid_conheight.integer;
1460 SCR_SetUpToDrawConsole();
1463 extern void R_Shadow_EditLights_DrawSelectedLightProperties(void);
1464 void CL_UpdateScreen(void)
1466 if (!scr_initialized || !con_initialized || vid_hidden)
1467 return; // not initialized yet
1469 // don't allow cheats in multiplayer
1470 if (!cl.islocalgame && cl.worldmodel)
1472 if (r_fullbright.integer != 0)
1473 Cvar_Set ("r_fullbright", "0");
1474 if (r_ambient.value != 0)
1475 Cvar_Set ("r_ambient", "0");
1479 if (scr_viewsize.value < 30)
1480 Cvar_Set ("viewsize","30");
1481 if (scr_viewsize.value > 120)
1482 Cvar_Set ("viewsize","120");
1484 // bound field of view
1485 if (scr_fov.value < 1)
1486 Cvar_Set ("fov","1");
1487 if (scr_fov.value > 170)
1488 Cvar_Set ("fov","170");
1490 // intermission is always full screen
1491 if (cl.intermission)
1495 if (scr_viewsize.value >= 120)
1496 sb_lines = 0; // no status bar at all
1497 else if (scr_viewsize.value >= 110)
1498 sb_lines = 24; // no inventory
1503 r_refdef.colormask[0] = 1;
1504 r_refdef.colormask[1] = 1;
1505 r_refdef.colormask[2] = 1;
1509 if (r_timereport_active)
1510 R_TimeReport("other");
1512 CL_SetupScreenSize();
1516 if (r_timereport_active)
1517 R_TimeReport("setup");
1519 //FIXME: force menu if nothing else to look at?
1520 //if (key_dest == key_game && cls.signon != SIGNONS && cls.state == ca_disconnected)
1522 if (cls.signon == SIGNONS)
1527 if (!r_letterbox.value)
1530 SCR_CheckDrawCenterString();
1536 if (cls.signon == SIGNONS)
1538 if (r_timereport_active)
1540 R_TimeReport_Frame();
1542 R_Shadow_EditLights_DrawSelectedLightProperties();
1554 void CL_Screen_NewMap(void)