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 %-11s", t, desc);
517 length = (int)strlen(tempbuf);
518 if (speedstringcount + length > (vid_conwidth.integer / 8))
520 strlcat(r_speeds_string, "\n", sizeof(r_speeds_string));
521 speedstringcount = 0;
523 // skip the space at the beginning if it's the first on the line
524 if (speedstringcount == 0)
526 strlcat(r_speeds_string, tempbuf + 1, sizeof(r_speeds_string));
527 speedstringcount = length - 1;
531 strlcat(r_speeds_string, tempbuf, sizeof(r_speeds_string));
532 speedstringcount += length;
536 void R_TimeReport_Frame(void)
540 if (r_speeds_string[0])
542 if (r_timereport_active)
543 R_TimeReport("total");
545 r_timereport_current = r_timereport_start;
546 if (r_speeds_string[strlen(r_speeds_string)-1] == '\n')
547 r_speeds_string[strlen(r_speeds_string)-1] = 0;
549 for (i = 0;r_speeds_string[i];i++)
550 if (r_speeds_string[i] == '\n')
552 y = vid_conheight.integer - sb_lines - lines * 8;
554 DrawQ_Pic(0, y, NULL, vid_conwidth.integer, lines * 8, 0, 0, 0, 0.5, 0);
555 while (r_speeds_string[i])
558 while (r_speeds_string[i] && r_speeds_string[i] != '\n')
561 DrawQ_String(0, y, r_speeds_string + j, i - j, 8, 8, 1, 1, 1, 1, 0);
562 if (r_speeds_string[i] == '\n')
566 r_speeds_string[0] = 0;
567 r_timereport_active = false;
569 if (r_speeds.integer && cls.signon == SIGNONS && cls.state == ca_connected)
571 speedstringcount = 0;
572 r_speeds_string[0] = 0;
573 r_timereport_active = false;
574 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]);
575 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);
576 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);
577 if (renderstats.bloom)
578 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);
580 sprintf(r_speeds_string + strlen(r_speeds_string), "rendered%6i meshes%8i triangles\n", renderstats.meshes, renderstats.meshes_elements / 3);
582 memset(&renderstats, 0, sizeof(renderstats));
584 if (r_speeds.integer >= 2)
586 r_timereport_active = true;
587 r_timereport_start = Sys_DoubleTime();
599 void SCR_SizeUp_f (void)
601 Cvar_SetValue ("viewsize",scr_viewsize.value+10);
612 void SCR_SizeDown_f (void)
614 Cvar_SetValue ("viewsize",scr_viewsize.value-10);
617 void CL_Screen_Init(void)
619 Cvar_RegisterVariable (&scr_fov);
620 Cvar_RegisterVariable (&scr_viewsize);
621 Cvar_RegisterVariable (&scr_conspeed);
622 Cvar_RegisterVariable (&scr_conalpha);
623 Cvar_RegisterVariable (&scr_conbrightness);
624 Cvar_RegisterVariable (&scr_conforcewhiledisconnected);
625 Cvar_RegisterVariable (&scr_showram);
626 Cvar_RegisterVariable (&scr_showturtle);
627 Cvar_RegisterVariable (&scr_showpause);
628 Cvar_RegisterVariable (&scr_showbrand);
629 Cvar_RegisterVariable (&scr_centertime);
630 Cvar_RegisterVariable (&scr_printspeed);
631 Cvar_RegisterVariable (&vid_conwidth);
632 Cvar_RegisterVariable (&vid_conheight);
633 Cvar_RegisterVariable (&vid_pixelheight);
634 Cvar_RegisterVariable (&scr_screenshot_jpeg);
635 Cvar_RegisterVariable (&scr_screenshot_jpeg_quality);
636 Cvar_RegisterVariable (&scr_screenshot_gamma);
637 Cvar_RegisterVariable (&cl_capturevideo);
638 Cvar_RegisterVariable (&cl_capturevideo_sound);
639 Cvar_RegisterVariable (&cl_capturevideo_fps);
640 Cvar_RegisterVariable (&cl_capturevideo_rawrgb);
641 Cvar_RegisterVariable (&cl_capturevideo_rawyv12);
642 Cvar_RegisterVariable (&r_textshadow);
643 Cvar_RegisterVariable (&r_letterbox);
645 Cmd_AddCommand ("sizeup",SCR_SizeUp_f, "increase view size (increases viewsize cvar)");
646 Cmd_AddCommand ("sizedown",SCR_SizeDown_f, "decrease view size (decreases viewsize cvar)");
647 Cmd_AddCommand ("screenshot",SCR_ScreenShot_f, "takes a screenshot of the next rendered frame");
648 Cmd_AddCommand ("envmap", R_Envmap_f, "render a cubemap (skybox) of the current scene");
650 scr_initialized = true;
653 void DrawQ_Clear(void)
655 r_refdef.drawqueuesize = 0;
658 static int picelements[6] = {0, 1, 2, 0, 2, 3};
659 void DrawQ_Pic(float x, float y, cachepic_t *pic, float width, float height, float red, float green, float blue, float alpha, int flags)
661 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);
664 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)
669 if (alpha < (1.0f / 255.0f))
672 len = (int)strlen(string);
674 for (len = 0;len < maxlen && string[len];len++);
675 for (;len > 0 && string[0] == ' ';string++, x += scalex, len--);
676 for (;len > 0 && string[len - 1] == ' ';len--);
679 if (x >= vid_conwidth.integer || y >= vid_conheight.integer || x < (-scalex * len) || y < (-scaley))
681 size = sizeof(*dq) + ((len + 1 + 3) & ~3);
682 if (r_refdef.drawqueuesize + size > r_refdef.maxdrawqueuesize)
684 red = bound(0, red, 1);
685 green = bound(0, green, 1);
686 blue = bound(0, blue, 1);
687 alpha = bound(0, alpha, 1);
688 dq = (drawqueue_t *)(r_refdef.drawqueue + r_refdef.drawqueuesize);
690 dq->command = DRAWQUEUE_STRING;
692 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));
697 out = (char *)(dq + 1);
698 memcpy(out, string, len);
700 r_refdef.drawqueuesize += dq->size;
703 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)
705 if (r_textshadow.integer)
706 DrawQ_String_Real(x+scalex*0.25,y+scaley*0.25,string,maxlen,scalex,scaley,0,0,0,alpha*0.8,flags);
708 DrawQ_String_Real(x,y,string,maxlen,scalex,scaley,red,green,blue,alpha,flags);
711 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)
714 drawqueuemesh_t mesh;
715 memset(&mesh, 0, sizeof(mesh));
721 height = pic->height;
722 mesh.texture = pic->tex;
724 mesh.num_triangles = 2;
725 mesh.num_vertices = 4;
726 mesh.data_element3i = picelements;
727 mesh.data_vertex3f = floats;
728 mesh.data_texcoord2f = floats + 12;
729 mesh.data_color4f = floats + 20;
730 memset(floats, 0, sizeof(floats));
731 mesh.data_vertex3f[0] = mesh.data_vertex3f[9] = x;
732 mesh.data_vertex3f[1] = mesh.data_vertex3f[4] = y;
733 mesh.data_vertex3f[3] = mesh.data_vertex3f[6] = x + width;
734 mesh.data_vertex3f[7] = mesh.data_vertex3f[10] = y + height;
735 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;
736 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;
737 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;
738 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;
739 DrawQ_Mesh (&mesh, flags);
742 void DrawQ_Mesh (drawqueuemesh_t *mesh, int flags)
749 size += sizeof(drawqueuemesh_t);
750 size += sizeof(int[3]) * mesh->num_triangles;
751 size += sizeof(float[3]) * mesh->num_vertices;
752 size += sizeof(float[2]) * mesh->num_vertices;
753 size += sizeof(float[4]) * mesh->num_vertices;
754 if (r_refdef.drawqueuesize + size > r_refdef.maxdrawqueuesize)
756 dq = (drawqueue_t *)(r_refdef.drawqueue + r_refdef.drawqueuesize);
758 dq->command = DRAWQUEUE_MESH;
765 p = (void *)(dq + 1);
766 m = (drawqueuemesh_t *)p;p = (unsigned char*)p + sizeof(drawqueuemesh_t);
767 m->num_triangles = mesh->num_triangles;
768 m->num_vertices = mesh->num_vertices;
769 m->texture = mesh->texture;
770 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]);
771 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]);
772 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]);
773 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]);
774 r_refdef.drawqueuesize += dq->size;
777 void DrawQ_LineLoop (drawqueuemesh_t *mesh, int flags)
784 size += sizeof(drawqueuemesh_t);
785 size += sizeof(int[3]) * mesh->num_triangles;
786 size += sizeof(float[3]) * mesh->num_vertices;
787 size += sizeof(float[2]) * mesh->num_vertices;
788 size += sizeof(float[4]) * mesh->num_vertices;
789 if (r_refdef.drawqueuesize + size > r_refdef.maxdrawqueuesize)
791 dq = (void *)(r_refdef.drawqueue + r_refdef.drawqueuesize);
793 dq->command = DRAWQUEUE_LINES;
800 p = (void *)(dq + 1);
801 m = p;p = (unsigned char*)p + sizeof(drawqueuemesh_t);
802 m->num_triangles = mesh->num_triangles;
803 m->num_vertices = mesh->num_vertices;
804 m->texture = mesh->texture;
805 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]);
806 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]);
807 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]);
808 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]);
809 r_refdef.drawqueuesize += dq->size;
812 //LordHavoc: FIXME: this is nasty!
813 void DrawQ_LineWidth (float width)
816 static int linewidth = 1;
817 if(width == linewidth)
820 if(r_refdef.drawqueuesize + (int)sizeof(*dq) > r_refdef.maxdrawqueuesize)
822 Con_DPrint("DrawQueue full !\n");
825 dq = (void*) (r_refdef.drawqueue + r_refdef.drawqueuesize);
826 dq->size = sizeof(*dq);
827 dq->command = DRAWQUEUE_LINEWIDTH;
830 r_refdef.drawqueuesize += dq->size;
833 //[515]: this is old, delete
834 void DrawQ_Line (float width, float x1, float y1, float x2, float y2, float r, float g, float b, float alpha, int flags)
838 DrawQ_LineWidth(width);
839 if(r_refdef.drawqueuesize + (int)sizeof(*dq) > r_refdef.maxdrawqueuesize)
841 Con_DPrint("DrawQueue full !\n");
844 dq = (void*) (r_refdef.drawqueue + r_refdef.drawqueuesize);
845 dq->size = sizeof(*dq);
846 dq->command = DRAWQUEUE_LINES;
852 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));
854 r_refdef.drawqueuesize += dq->size;
857 void DrawQ_SetClipArea(float x, float y, float width, float height)
860 if(r_refdef.drawqueuesize + (int)sizeof(*dq) > r_refdef.maxdrawqueuesize)
862 Con_DPrint("DrawQueue full !\n");
865 dq = (drawqueue_t *) (r_refdef.drawqueue + r_refdef.drawqueuesize);
866 dq->size = sizeof(*dq);
867 dq->command = DRAWQUEUE_SETCLIP;
875 r_refdef.drawqueuesize += dq->size;
878 void DrawQ_ResetClipArea(void)
881 if(r_refdef.drawqueuesize + (int)sizeof(*dq) > r_refdef.maxdrawqueuesize)
883 Con_DPrint("DrawQueue full !\n");
886 dq = (drawqueue_t *) (r_refdef.drawqueue + r_refdef.drawqueuesize);
887 dq->size = sizeof(*dq);
888 dq->command = DRAWQUEUE_RESETCLIP;
896 r_refdef.drawqueuesize += dq->size;
904 void SCR_ScreenShot_f (void)
906 static int shotnumber;
907 static char oldname[MAX_QPATH];
908 char base[MAX_QPATH];
909 char filename[MAX_QPATH];
910 unsigned char *buffer1;
911 unsigned char *buffer2;
912 unsigned char *buffer3;
913 qboolean jpeg = (scr_screenshot_jpeg.integer != 0);
915 sprintf (base, "screenshots/%s", scr_screenshot_name.string);
917 if (strcmp (oldname, scr_screenshot_name.string))
919 sprintf(oldname, "%s", scr_screenshot_name.string);
923 // find a file name to save it to
924 for (;shotnumber < 1000000;shotnumber++)
925 if (!FS_SysFileExists(va("%s/%s%06d.tga", fs_gamedir, base, shotnumber)) && !FS_SysFileExists(va("%s/%s%06d.jpg", fs_gamedir, base, shotnumber)))
927 if (shotnumber >= 1000000)
929 Con_Print("SCR_ScreenShot_f: Couldn't create the image file\n");
933 sprintf(filename, "%s%06d.%s", base, shotnumber, jpeg ? "jpg" : "tga");
935 buffer1 = (unsigned char *)Mem_Alloc(tempmempool, vid.width * vid.height * 3);
936 buffer2 = (unsigned char *)Mem_Alloc(tempmempool, vid.width * vid.height * 3);
937 buffer3 = (unsigned char *)Mem_Alloc(tempmempool, vid.width * vid.height * 3 + 18);
939 if (SCR_ScreenShot (filename, buffer1, buffer2, buffer3, 0, 0, vid.width, vid.height, false, false, false, jpeg, true))
940 Con_Printf("Wrote %s\n", filename);
942 Con_Printf("unable to write %s\n", filename);
951 typedef enum capturevideoformat_e
953 CAPTUREVIDEOFORMAT_TARGA,
954 CAPTUREVIDEOFORMAT_JPEG,
955 CAPTUREVIDEOFORMAT_RAWRGB,
956 CAPTUREVIDEOFORMAT_RAWYV12
958 capturevideoformat_t;
960 qboolean cl_capturevideo_active = false;
961 capturevideoformat_t cl_capturevideo_format;
962 static double cl_capturevideo_starttime = 0;
963 double cl_capturevideo_framerate = 0;
964 static int cl_capturevideo_soundrate = 0;
965 static int cl_capturevideo_frame = 0;
966 static unsigned char *cl_capturevideo_buffer = NULL;
967 static qfile_t *cl_capturevideo_videofile = NULL;
968 qfile_t *cl_capturevideo_soundfile = NULL;
969 static short cl_capturevideo_rgbtoyuvscaletable[3][3][256];
970 static unsigned char cl_capturevideo_yuvnormalizetable[3][256];
971 //static unsigned char cl_capturevideo_rgbgammatable[3][256];
973 void SCR_CaptureVideo_BeginVideo(void)
977 unsigned char out[44];
978 if (cl_capturevideo_active)
980 // soundrate is figured out on the first SoundFrame
981 cl_capturevideo_active = true;
982 cl_capturevideo_starttime = Sys_DoubleTime();
983 cl_capturevideo_framerate = bound(1, cl_capturevideo_fps.value, 1000);
984 cl_capturevideo_soundrate = 0;
985 cl_capturevideo_frame = 0;
986 cl_capturevideo_buffer = (unsigned char *)Mem_Alloc(tempmempool, vid.width * vid.height * (3+3+3) + 18);
987 gamma = 1.0/scr_screenshot_gamma.value;
990 for (i = 0;i < 256;i++)
992 unsigned char j = (unsigned char)bound(0, 255*pow(i/255.0, gamma), 255);
993 cl_capturevideo_rgbgammatable[0][i] = j;
994 cl_capturevideo_rgbgammatable[1][i] = j;
995 cl_capturevideo_rgbgammatable[2][i] = j;
999 R = Y + 1.4075 * (Cr - 128);
1000 G = Y + -0.3455 * (Cb - 128) + -0.7169 * (Cr - 128);
1001 B = Y + 1.7790 * (Cb - 128);
1002 Y = R * .299 + G * .587 + B * .114;
1003 Cb = R * -.169 + G * -.332 + B * .500 + 128.;
1004 Cr = R * .500 + G * -.419 + B * -.0813 + 128.;
1006 for (i = 0;i < 256;i++)
1008 g = 255*pow(i/255.0, gamma);
1009 // Y weights from RGB
1010 cl_capturevideo_rgbtoyuvscaletable[0][0][i] = (short)(g * 0.299);
1011 cl_capturevideo_rgbtoyuvscaletable[0][1][i] = (short)(g * 0.587);
1012 cl_capturevideo_rgbtoyuvscaletable[0][2][i] = (short)(g * 0.114);
1013 // Cb weights from RGB
1014 cl_capturevideo_rgbtoyuvscaletable[1][0][i] = (short)(g * -0.169);
1015 cl_capturevideo_rgbtoyuvscaletable[1][1][i] = (short)(g * -0.332);
1016 cl_capturevideo_rgbtoyuvscaletable[1][2][i] = (short)(g * 0.500);
1017 // Cr weights from RGB
1018 cl_capturevideo_rgbtoyuvscaletable[2][0][i] = (short)(g * 0.500);
1019 cl_capturevideo_rgbtoyuvscaletable[2][1][i] = (short)(g * -0.419);
1020 cl_capturevideo_rgbtoyuvscaletable[2][2][i] = (short)(g * -0.0813);
1021 // range reduction of YCbCr to valid signal range
1022 cl_capturevideo_yuvnormalizetable[0][i] = 16 + i * (236-16) / 256;
1023 cl_capturevideo_yuvnormalizetable[1][i] = 16 + i * (240-16) / 256;
1024 cl_capturevideo_yuvnormalizetable[2][i] = 16 + i * (240-16) / 256;
1027 if (cl_capturevideo_rawrgb.integer)
1029 cl_capturevideo_format = CAPTUREVIDEOFORMAT_RAWRGB;
1030 cl_capturevideo_videofile = FS_Open ("video/dpvideo.rgb", "wb", false, true);
1032 else if (cl_capturevideo_rawyv12.integer)
1034 cl_capturevideo_format = CAPTUREVIDEOFORMAT_RAWYV12;
1035 cl_capturevideo_videofile = FS_Open ("video/dpvideo.yv12", "wb", false, true);
1037 else if (scr_screenshot_jpeg.integer)
1039 cl_capturevideo_format = CAPTUREVIDEOFORMAT_JPEG;
1040 cl_capturevideo_videofile = NULL;
1044 cl_capturevideo_format = CAPTUREVIDEOFORMAT_TARGA;
1045 cl_capturevideo_videofile = NULL;
1048 if (cl_capturevideo_sound.integer)
1050 cl_capturevideo_soundfile = FS_Open ("video/dpvideo.wav", "wb", false, true);
1051 // wave header will be filled out when video ends
1053 FS_Write (cl_capturevideo_soundfile, out, 44);
1056 cl_capturevideo_soundfile = NULL;
1059 void SCR_CaptureVideo_EndVideo(void)
1062 unsigned char out[44];
1063 if (!cl_capturevideo_active)
1065 cl_capturevideo_active = false;
1067 if (cl_capturevideo_videofile)
1069 FS_Close(cl_capturevideo_videofile);
1070 cl_capturevideo_videofile = NULL;
1073 // finish the wave file
1074 if (cl_capturevideo_soundfile)
1076 i = (int)FS_Tell (cl_capturevideo_soundfile);
1077 //"RIFF", (int) unknown (chunk size), "WAVE",
1078 //"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
1079 //"data", (int) unknown (chunk size)
1080 memcpy (out, "RIFF****WAVEfmt \x10\x00\x00\x00\x01\x00\x02\x00********\x04\x00\x10\0data****", 44);
1081 // the length of the whole RIFF chunk
1083 out[4] = (n) & 0xFF;
1084 out[5] = (n >> 8) & 0xFF;
1085 out[6] = (n >> 16) & 0xFF;
1086 out[7] = (n >> 24) & 0xFF;
1088 n = cl_capturevideo_soundrate;
1089 out[24] = (n) & 0xFF;
1090 out[25] = (n >> 8) & 0xFF;
1091 out[26] = (n >> 16) & 0xFF;
1092 out[27] = (n >> 24) & 0xFF;
1093 // bytes per second (rate * channels * bytes per channel)
1094 n = cl_capturevideo_soundrate * 2 * 2;
1095 out[28] = (n) & 0xFF;
1096 out[29] = (n >> 8) & 0xFF;
1097 out[30] = (n >> 16) & 0xFF;
1098 out[31] = (n >> 24) & 0xFF;
1099 // the length of the data chunk
1101 out[40] = (n) & 0xFF;
1102 out[41] = (n >> 8) & 0xFF;
1103 out[42] = (n >> 16) & 0xFF;
1104 out[43] = (n >> 24) & 0xFF;
1105 FS_Seek (cl_capturevideo_soundfile, 0, SEEK_SET);
1106 FS_Write (cl_capturevideo_soundfile, out, 44);
1107 FS_Close (cl_capturevideo_soundfile);
1108 cl_capturevideo_soundfile = NULL;
1111 if (cl_capturevideo_buffer)
1113 Mem_Free (cl_capturevideo_buffer);
1114 cl_capturevideo_buffer = NULL;
1117 cl_capturevideo_starttime = 0;
1118 cl_capturevideo_framerate = 0;
1119 cl_capturevideo_frame = 0;
1122 qboolean SCR_CaptureVideo_VideoFrame(int newframenum)
1124 int x = 0, y = 0, width = vid.width, height = vid.height;
1125 unsigned char *b, *out;
1127 int outoffset = (width/2)*(height/2);
1128 //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);
1129 // speed is critical here, so do saving as directly as possible
1130 switch (cl_capturevideo_format)
1132 case CAPTUREVIDEOFORMAT_RAWYV12:
1133 // FIXME: width/height must be multiple of 2, enforce this?
1134 qglReadPixels (x, y, width, height, GL_RGB, GL_UNSIGNED_BYTE, cl_capturevideo_buffer);
1136 // process one line at a time, and CbCr every other line at 2 pixel intervals
1137 for (y = 0;y < height;y++)
1140 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++)
1141 *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]]];
1144 // 2x2 Cb and Cr planes
1146 // low quality, no averaging
1147 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++)
1150 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];
1152 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];
1155 // high quality, averaging
1156 int inpitch = width*3;
1157 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++)
1159 int blockr, blockg, blockb;
1160 blockr = (b[0] + b[3] + b[inpitch+0] + b[inpitch+3]) >> 2;
1161 blockg = (b[1] + b[4] + b[inpitch+1] + b[inpitch+4]) >> 2;
1162 blockb = (b[2] + b[5] + b[inpitch+2] + b[inpitch+5]) >> 2;
1164 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];
1166 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];
1171 for (;cl_capturevideo_frame < newframenum;cl_capturevideo_frame++)
1172 if (!FS_Write (cl_capturevideo_videofile, cl_capturevideo_buffer + width*height*3, width*height+(width/2)*(height/2)*2))
1175 case CAPTUREVIDEOFORMAT_RAWRGB:
1176 qglReadPixels (x, y, width, height, GL_RGB, GL_UNSIGNED_BYTE, cl_capturevideo_buffer);
1178 for (;cl_capturevideo_frame < newframenum;cl_capturevideo_frame++)
1179 if (!FS_Write (cl_capturevideo_videofile, cl_capturevideo_buffer, width*height*3))
1182 case CAPTUREVIDEOFORMAT_JPEG:
1183 qglReadPixels (x, y, width, height, GL_RGB, GL_UNSIGNED_BYTE, cl_capturevideo_buffer);
1185 for (;cl_capturevideo_frame < newframenum;cl_capturevideo_frame++)
1187 sprintf(filename, "video/dp%06d.jpg", cl_capturevideo_frame);
1188 if (!JPEG_SaveImage_preflipped (filename, width, height, cl_capturevideo_buffer))
1192 case CAPTUREVIDEOFORMAT_TARGA:
1193 //return Image_WriteTGARGB_preflipped (filename, width, height, cl_capturevideo_buffer, cl_capturevideo_buffer + vid.width * vid.height * 3, );
1194 memset (cl_capturevideo_buffer, 0, 18);
1195 cl_capturevideo_buffer[2] = 2; // uncompressed type
1196 cl_capturevideo_buffer[12] = (width >> 0) & 0xFF;
1197 cl_capturevideo_buffer[13] = (width >> 8) & 0xFF;
1198 cl_capturevideo_buffer[14] = (height >> 0) & 0xFF;
1199 cl_capturevideo_buffer[15] = (height >> 8) & 0xFF;
1200 cl_capturevideo_buffer[16] = 24; // pixel size
1201 qglReadPixels (x, y, width, height, GL_BGR, GL_UNSIGNED_BYTE, cl_capturevideo_buffer + 18);
1203 for (;cl_capturevideo_frame < newframenum;cl_capturevideo_frame++)
1205 sprintf(filename, "video/dp%06d.tga", cl_capturevideo_frame);
1206 if (!FS_WriteFile (filename, cl_capturevideo_buffer, width*height*3 + 18))
1215 void SCR_CaptureVideo_SoundFrame(unsigned char *bufstereo16le, size_t length, int rate)
1217 if (!cl_capturevideo_soundfile)
1219 cl_capturevideo_soundrate = rate;
1220 if (FS_Write (cl_capturevideo_soundfile, bufstereo16le, 4 * length) < (fs_offset_t)(4 * length))
1222 Cvar_SetValueQuick(&cl_capturevideo, 0);
1223 Con_Printf("video sound saving failed on frame %i, out of disk space? stopping video capture.\n", cl_capturevideo_frame);
1224 SCR_CaptureVideo_EndVideo();
1228 void SCR_CaptureVideo(void)
1231 if (cl_capturevideo.integer && r_render.integer)
1233 if (!cl_capturevideo_active)
1234 SCR_CaptureVideo_BeginVideo();
1235 if (cl_capturevideo_framerate != cl_capturevideo_fps.value)
1237 Con_Printf("You can not change the video framerate while recording a video.\n");
1238 Cvar_SetValueQuick(&cl_capturevideo_fps, cl_capturevideo_framerate);
1240 if (cl_capturevideo_soundfile)
1242 // preserve sound sync by duplicating frames when running slow
1243 newframenum = (Sys_DoubleTime() - cl_capturevideo_starttime) * cl_capturevideo_framerate;
1246 newframenum = cl_capturevideo_frame + 1;
1247 // if falling behind more than one second, stop
1248 if (newframenum - cl_capturevideo_frame > (int)ceil(cl_capturevideo_framerate))
1250 Cvar_SetValueQuick(&cl_capturevideo, 0);
1251 Con_Printf("video saving failed on frame %i, your machine is too slow for this capture speed.\n", cl_capturevideo_frame);
1252 SCR_CaptureVideo_EndVideo();
1256 if (!SCR_CaptureVideo_VideoFrame(newframenum))
1258 Cvar_SetValueQuick(&cl_capturevideo, 0);
1259 Con_Printf("video saving failed on frame %i, out of disk space? stopping video capture.\n", cl_capturevideo_frame);
1260 SCR_CaptureVideo_EndVideo();
1263 else if (cl_capturevideo_active)
1264 SCR_CaptureVideo_EndVideo();
1271 Grab six views for environment mapping tests
1278 qboolean flipx, flipy, flipdiagonaly;
1282 {{ 0, 0, 0}, "rt", false, false, false},
1283 {{ 0, 270, 0}, "ft", false, false, false},
1284 {{ 0, 180, 0}, "lf", false, false, false},
1285 {{ 0, 90, 0}, "bk", false, false, false},
1286 {{-90, 180, 0}, "up", true, true, false},
1287 {{ 90, 180, 0}, "dn", true, true, false},
1289 {{ 0, 0, 0}, "px", true, true, true},
1290 {{ 0, 90, 0}, "py", false, true, false},
1291 {{ 0, 180, 0}, "nx", false, false, true},
1292 {{ 0, 270, 0}, "ny", true, false, false},
1293 {{-90, 180, 0}, "pz", false, false, true},
1294 {{ 90, 180, 0}, "nz", false, false, true}
1297 static void R_Envmap_f (void)
1300 char filename[MAX_QPATH], basename[MAX_QPATH];
1301 unsigned char *buffer1;
1302 unsigned char *buffer2;
1303 unsigned char *buffer3;
1305 if (Cmd_Argc() != 3)
1307 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");
1311 strlcpy (basename, Cmd_Argv(1), sizeof (basename));
1312 size = atoi(Cmd_Argv(2));
1313 if (size != 128 && size != 256 && size != 512 && size != 1024)
1315 Con_Print("envmap: size must be one of 128, 256, 512, or 1024\n");
1318 if (size > vid.width || size > vid.height)
1320 Con_Print("envmap: your resolution is not big enough to render that size\n");
1328 r_refdef.width = size;
1329 r_refdef.height = size;
1331 r_refdef.frustum_x = tan(90 * M_PI / 360.0);
1332 r_refdef.frustum_y = tan(90 * M_PI / 360.0);
1334 buffer1 = (unsigned char *)Mem_Alloc(tempmempool, size * size * 3);
1335 buffer2 = (unsigned char *)Mem_Alloc(tempmempool, size * size * 3);
1336 buffer3 = (unsigned char *)Mem_Alloc(tempmempool, size * size * 3 + 18);
1338 for (j = 0;j < 12;j++)
1340 sprintf(filename, "env/%s%s.tga", basename, envmapinfo[j].name);
1341 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);
1346 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);
1356 //=============================================================================
1358 // LordHavoc: SHOWLMP stuff
1359 #define SHOWLMP_MAXLABELS 256
1360 typedef struct showlmp_s
1370 showlmp_t showlmp[SHOWLMP_MAXLABELS];
1372 void SHOWLMP_decodehide(void)
1376 lmplabel = MSG_ReadString();
1377 for (i = 0;i < SHOWLMP_MAXLABELS;i++)
1378 if (showlmp[i].isactive && strcmp(showlmp[i].label, lmplabel) == 0)
1380 showlmp[i].isactive = false;
1385 void SHOWLMP_decodeshow(void)
1388 char lmplabel[256], picname[256];
1390 strlcpy (lmplabel,MSG_ReadString(), sizeof (lmplabel));
1391 strlcpy (picname, MSG_ReadString(), sizeof (picname));
1392 if (gamemode == GAME_NEHAHRA) // LordHavoc: nasty old legacy junk
1399 x = MSG_ReadShort();
1400 y = MSG_ReadShort();
1403 for (i = 0;i < SHOWLMP_MAXLABELS;i++)
1404 if (showlmp[i].isactive)
1406 if (strcmp(showlmp[i].label, lmplabel) == 0)
1409 break; // drop out to replace it
1412 else if (k < 0) // find first empty one to replace
1415 return; // none found to replace
1416 // change existing one
1417 showlmp[k].isactive = true;
1418 strlcpy (showlmp[k].label, lmplabel, sizeof (showlmp[k].label));
1419 strlcpy (showlmp[k].pic, picname, sizeof (showlmp[k].pic));
1424 void SHOWLMP_drawall(void)
1427 for (i = 0;i < SHOWLMP_MAXLABELS;i++)
1428 if (showlmp[i].isactive)
1429 DrawQ_Pic(showlmp[i].x, showlmp[i].y, Draw_CachePic(showlmp[i].pic, false), 0, 0, 1, 1, 1, 1, 0);
1432 void SHOWLMP_clear(void)
1435 for (i = 0;i < SHOWLMP_MAXLABELS;i++)
1436 showlmp[i].isactive = false;
1439 void CL_SetupScreenSize(void)
1441 float conwidth, conheight;
1443 VID_UpdateGamma(false);
1445 conwidth = bound(320, vid_conwidth.value, 2048);
1446 conheight = bound(200, vid_conheight.value, 1536);
1447 if (vid_conwidth.value != conwidth)
1448 Cvar_SetValue("vid_conwidth", conwidth);
1449 if (vid_conheight.value != conheight)
1450 Cvar_SetValue("vid_conheight", conheight);
1452 vid_conwidth.integer = vid_conwidth.integer;
1453 vid_conheight.integer = vid_conheight.integer;
1455 SCR_SetUpToDrawConsole();
1458 extern void R_Shadow_EditLights_DrawSelectedLightProperties(void);
1459 void CL_UpdateScreen(void)
1461 if (!scr_initialized || !con_initialized || vid_hidden)
1462 return; // not initialized yet
1464 // don't allow cheats in multiplayer
1465 if (!cl.islocalgame && cl.worldmodel)
1467 if (r_fullbright.integer != 0)
1468 Cvar_Set ("r_fullbright", "0");
1469 if (r_ambient.value != 0)
1470 Cvar_Set ("r_ambient", "0");
1474 if (scr_viewsize.value < 30)
1475 Cvar_Set ("viewsize","30");
1476 if (scr_viewsize.value > 120)
1477 Cvar_Set ("viewsize","120");
1479 // bound field of view
1480 if (scr_fov.value < 1)
1481 Cvar_Set ("fov","1");
1482 if (scr_fov.value > 170)
1483 Cvar_Set ("fov","170");
1485 // intermission is always full screen
1486 if (cl.intermission)
1490 if (scr_viewsize.value >= 120)
1491 sb_lines = 0; // no status bar at all
1492 else if (scr_viewsize.value >= 110)
1493 sb_lines = 24; // no inventory
1498 r_refdef.colormask[0] = 1;
1499 r_refdef.colormask[1] = 1;
1500 r_refdef.colormask[2] = 1;
1504 if (r_timereport_active)
1505 R_TimeReport("other");
1507 CL_SetupScreenSize();
1511 if (r_timereport_active)
1512 R_TimeReport("setup");
1514 //FIXME: force menu if nothing else to look at?
1515 //if (key_dest == key_game && cls.signon != SIGNONS && cls.state == ca_disconnected)
1517 if (cls.signon == SIGNONS)
1522 if (!r_letterbox.value)
1525 SCR_CheckDrawCenterString();
1531 if (cls.signon == SIGNONS)
1533 if (r_timereport_active)
1535 R_TimeReport_Frame();
1537 R_Shadow_EditLights_DrawSelectedLightProperties();
1549 void CL_Screen_NewMap(void)