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 typedef enum capturevideoformat_e
956 CAPTUREVIDEOFORMAT_TARGA,
957 CAPTUREVIDEOFORMAT_JPEG,
958 CAPTUREVIDEOFORMAT_RAWRGB,
959 CAPTUREVIDEOFORMAT_RAWYV12
961 capturevideoformat_t;
963 qboolean cl_capturevideo_active = false;
964 capturevideoformat_t cl_capturevideo_format;
965 static double cl_capturevideo_starttime = 0;
966 double cl_capturevideo_framerate = 0;
967 static int cl_capturevideo_soundrate = 0;
968 static int cl_capturevideo_frame = 0;
969 static unsigned char *cl_capturevideo_buffer = NULL;
970 static qfile_t *cl_capturevideo_videofile = NULL;
971 qfile_t *cl_capturevideo_soundfile = NULL;
972 static short cl_capturevideo_rgbtoyuvscaletable[3][3][256];
973 static unsigned char cl_capturevideo_yuvnormalizetable[3][256];
974 //static unsigned char cl_capturevideo_rgbgammatable[3][256];
976 void SCR_CaptureVideo_BeginVideo(void)
980 unsigned char out[44];
981 if (cl_capturevideo_active)
983 // soundrate is figured out on the first SoundFrame
984 cl_capturevideo_active = true;
985 cl_capturevideo_starttime = Sys_DoubleTime();
986 cl_capturevideo_framerate = bound(1, cl_capturevideo_fps.value, 1000);
987 cl_capturevideo_soundrate = 0;
988 cl_capturevideo_frame = 0;
989 cl_capturevideo_buffer = (unsigned char *)Mem_Alloc(tempmempool, vid.width * vid.height * (3+3+3) + 18);
990 gamma = 1.0/scr_screenshot_gamma.value;
993 for (i = 0;i < 256;i++)
995 unsigned char j = (unsigned char)bound(0, 255*pow(i/255.0, gamma), 255);
996 cl_capturevideo_rgbgammatable[0][i] = j;
997 cl_capturevideo_rgbgammatable[1][i] = j;
998 cl_capturevideo_rgbgammatable[2][i] = j;
1002 R = Y + 1.4075 * (Cr - 128);
1003 G = Y + -0.3455 * (Cb - 128) + -0.7169 * (Cr - 128);
1004 B = Y + 1.7790 * (Cb - 128);
1005 Y = R * .299 + G * .587 + B * .114;
1006 Cb = R * -.169 + G * -.332 + B * .500 + 128.;
1007 Cr = R * .500 + G * -.419 + B * -.0813 + 128.;
1009 for (i = 0;i < 256;i++)
1011 g = 255*pow(i/255.0, gamma);
1012 // Y weights from RGB
1013 cl_capturevideo_rgbtoyuvscaletable[0][0][i] = (short)(g * 0.299);
1014 cl_capturevideo_rgbtoyuvscaletable[0][1][i] = (short)(g * 0.587);
1015 cl_capturevideo_rgbtoyuvscaletable[0][2][i] = (short)(g * 0.114);
1016 // Cb weights from RGB
1017 cl_capturevideo_rgbtoyuvscaletable[1][0][i] = (short)(g * -0.169);
1018 cl_capturevideo_rgbtoyuvscaletable[1][1][i] = (short)(g * -0.332);
1019 cl_capturevideo_rgbtoyuvscaletable[1][2][i] = (short)(g * 0.500);
1020 // Cr weights from RGB
1021 cl_capturevideo_rgbtoyuvscaletable[2][0][i] = (short)(g * 0.500);
1022 cl_capturevideo_rgbtoyuvscaletable[2][1][i] = (short)(g * -0.419);
1023 cl_capturevideo_rgbtoyuvscaletable[2][2][i] = (short)(g * -0.0813);
1024 // range reduction of YCbCr to valid signal range
1025 cl_capturevideo_yuvnormalizetable[0][i] = 16 + i * (236-16) / 256;
1026 cl_capturevideo_yuvnormalizetable[1][i] = 16 + i * (240-16) / 256;
1027 cl_capturevideo_yuvnormalizetable[2][i] = 16 + i * (240-16) / 256;
1030 if (cl_capturevideo_rawrgb.integer)
1032 cl_capturevideo_format = CAPTUREVIDEOFORMAT_RAWRGB;
1033 cl_capturevideo_videofile = FS_Open ("video/dpvideo.rgb", "wb", false, true);
1035 else if (cl_capturevideo_rawyv12.integer)
1037 cl_capturevideo_format = CAPTUREVIDEOFORMAT_RAWYV12;
1038 cl_capturevideo_videofile = FS_Open ("video/dpvideo.yv12", "wb", false, true);
1040 else if (scr_screenshot_jpeg.integer)
1042 cl_capturevideo_format = CAPTUREVIDEOFORMAT_JPEG;
1043 cl_capturevideo_videofile = NULL;
1047 cl_capturevideo_format = CAPTUREVIDEOFORMAT_TARGA;
1048 cl_capturevideo_videofile = NULL;
1051 if (cl_capturevideo_sound.integer)
1053 cl_capturevideo_soundfile = FS_Open ("video/dpvideo.wav", "wb", false, true);
1054 // wave header will be filled out when video ends
1056 FS_Write (cl_capturevideo_soundfile, out, 44);
1059 cl_capturevideo_soundfile = NULL;
1062 void SCR_CaptureVideo_EndVideo(void)
1065 unsigned char out[44];
1066 if (!cl_capturevideo_active)
1068 cl_capturevideo_active = false;
1070 if (cl_capturevideo_videofile)
1072 FS_Close(cl_capturevideo_videofile);
1073 cl_capturevideo_videofile = NULL;
1076 // finish the wave file
1077 if (cl_capturevideo_soundfile)
1079 i = (int)FS_Tell (cl_capturevideo_soundfile);
1080 //"RIFF", (int) unknown (chunk size), "WAVE",
1081 //"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
1082 //"data", (int) unknown (chunk size)
1083 memcpy (out, "RIFF****WAVEfmt \x10\x00\x00\x00\x01\x00\x02\x00********\x04\x00\x10\0data****", 44);
1084 // the length of the whole RIFF chunk
1086 out[4] = (n) & 0xFF;
1087 out[5] = (n >> 8) & 0xFF;
1088 out[6] = (n >> 16) & 0xFF;
1089 out[7] = (n >> 24) & 0xFF;
1091 n = cl_capturevideo_soundrate;
1092 out[24] = (n) & 0xFF;
1093 out[25] = (n >> 8) & 0xFF;
1094 out[26] = (n >> 16) & 0xFF;
1095 out[27] = (n >> 24) & 0xFF;
1096 // bytes per second (rate * channels * bytes per channel)
1097 n = cl_capturevideo_soundrate * 2 * 2;
1098 out[28] = (n) & 0xFF;
1099 out[29] = (n >> 8) & 0xFF;
1100 out[30] = (n >> 16) & 0xFF;
1101 out[31] = (n >> 24) & 0xFF;
1102 // the length of the data chunk
1104 out[40] = (n) & 0xFF;
1105 out[41] = (n >> 8) & 0xFF;
1106 out[42] = (n >> 16) & 0xFF;
1107 out[43] = (n >> 24) & 0xFF;
1108 FS_Seek (cl_capturevideo_soundfile, 0, SEEK_SET);
1109 FS_Write (cl_capturevideo_soundfile, out, 44);
1110 FS_Close (cl_capturevideo_soundfile);
1111 cl_capturevideo_soundfile = NULL;
1114 if (cl_capturevideo_buffer)
1116 Mem_Free (cl_capturevideo_buffer);
1117 cl_capturevideo_buffer = NULL;
1120 cl_capturevideo_starttime = 0;
1121 cl_capturevideo_framerate = 0;
1122 cl_capturevideo_frame = 0;
1125 qboolean SCR_CaptureVideo_VideoFrame(int newframenum)
1127 int x = 0, y = 0, width = vid.width, height = vid.height;
1128 unsigned char *b, *out;
1130 int outoffset = (width/2)*(height/2);
1131 //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);
1132 // speed is critical here, so do saving as directly as possible
1133 switch (cl_capturevideo_format)
1135 case CAPTUREVIDEOFORMAT_RAWYV12:
1136 // FIXME: width/height must be multiple of 2, enforce this?
1137 qglReadPixels (x, y, width, height, GL_RGB, GL_UNSIGNED_BYTE, cl_capturevideo_buffer);
1139 // process one line at a time, and CbCr every other line at 2 pixel intervals
1140 for (y = 0;y < height;y++)
1143 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++)
1144 *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]]];
1147 // 2x2 Cb and Cr planes
1149 // low quality, no averaging
1150 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++)
1153 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];
1155 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];
1158 // high quality, averaging
1159 int inpitch = width*3;
1160 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++)
1162 int blockr, blockg, blockb;
1163 blockr = (b[0] + b[3] + b[inpitch+0] + b[inpitch+3]) >> 2;
1164 blockg = (b[1] + b[4] + b[inpitch+1] + b[inpitch+4]) >> 2;
1165 blockb = (b[2] + b[5] + b[inpitch+2] + b[inpitch+5]) >> 2;
1167 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];
1169 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];
1174 for (;cl_capturevideo_frame < newframenum;cl_capturevideo_frame++)
1175 if (!FS_Write (cl_capturevideo_videofile, cl_capturevideo_buffer + width*height*3, width*height+(width/2)*(height/2)*2))
1178 case CAPTUREVIDEOFORMAT_RAWRGB:
1179 qglReadPixels (x, y, width, height, GL_RGB, GL_UNSIGNED_BYTE, cl_capturevideo_buffer);
1181 for (;cl_capturevideo_frame < newframenum;cl_capturevideo_frame++)
1182 if (!FS_Write (cl_capturevideo_videofile, cl_capturevideo_buffer, width*height*3))
1185 case CAPTUREVIDEOFORMAT_JPEG:
1186 qglReadPixels (x, y, width, height, GL_RGB, GL_UNSIGNED_BYTE, cl_capturevideo_buffer);
1188 for (;cl_capturevideo_frame < newframenum;cl_capturevideo_frame++)
1190 sprintf(filename, "video/dp%06d.jpg", cl_capturevideo_frame);
1191 if (!JPEG_SaveImage_preflipped (filename, width, height, cl_capturevideo_buffer))
1195 case CAPTUREVIDEOFORMAT_TARGA:
1196 //return Image_WriteTGARGB_preflipped (filename, width, height, cl_capturevideo_buffer, cl_capturevideo_buffer + vid.width * vid.height * 3, );
1197 memset (cl_capturevideo_buffer, 0, 18);
1198 cl_capturevideo_buffer[2] = 2; // uncompressed type
1199 cl_capturevideo_buffer[12] = (width >> 0) & 0xFF;
1200 cl_capturevideo_buffer[13] = (width >> 8) & 0xFF;
1201 cl_capturevideo_buffer[14] = (height >> 0) & 0xFF;
1202 cl_capturevideo_buffer[15] = (height >> 8) & 0xFF;
1203 cl_capturevideo_buffer[16] = 24; // pixel size
1204 qglReadPixels (x, y, width, height, GL_BGR, GL_UNSIGNED_BYTE, cl_capturevideo_buffer + 18);
1206 for (;cl_capturevideo_frame < newframenum;cl_capturevideo_frame++)
1208 sprintf(filename, "video/dp%06d.tga", cl_capturevideo_frame);
1209 if (!FS_WriteFile (filename, cl_capturevideo_buffer, width*height*3 + 18))
1218 void SCR_CaptureVideo_SoundFrame(unsigned char *bufstereo16le, size_t length, int rate)
1220 if (!cl_capturevideo_soundfile)
1222 cl_capturevideo_soundrate = rate;
1223 if (FS_Write (cl_capturevideo_soundfile, bufstereo16le, 4 * length) < (fs_offset_t)(4 * length))
1225 Cvar_SetValueQuick(&cl_capturevideo, 0);
1226 Con_Printf("video sound saving failed on frame %i, out of disk space? stopping video capture.\n", cl_capturevideo_frame);
1227 SCR_CaptureVideo_EndVideo();
1231 void SCR_CaptureVideo(void)
1234 if (cl_capturevideo.integer && r_render.integer)
1236 if (!cl_capturevideo_active)
1237 SCR_CaptureVideo_BeginVideo();
1238 if (cl_capturevideo_framerate != cl_capturevideo_fps.value)
1240 Con_Printf("You can not change the video framerate while recording a video.\n");
1241 Cvar_SetValueQuick(&cl_capturevideo_fps, cl_capturevideo_framerate);
1243 if (cl_capturevideo_soundfile)
1245 // preserve sound sync by duplicating frames when running slow
1246 newframenum = (Sys_DoubleTime() - cl_capturevideo_starttime) * cl_capturevideo_framerate;
1249 newframenum = cl_capturevideo_frame + 1;
1250 // if falling behind more than one second, stop
1251 if (newframenum - cl_capturevideo_frame > (int)ceil(cl_capturevideo_framerate))
1253 Cvar_SetValueQuick(&cl_capturevideo, 0);
1254 Con_Printf("video saving failed on frame %i, your machine is too slow for this capture speed.\n", cl_capturevideo_frame);
1255 SCR_CaptureVideo_EndVideo();
1259 if (!SCR_CaptureVideo_VideoFrame(newframenum))
1261 Cvar_SetValueQuick(&cl_capturevideo, 0);
1262 Con_Printf("video saving failed on frame %i, out of disk space? stopping video capture.\n", cl_capturevideo_frame);
1263 SCR_CaptureVideo_EndVideo();
1266 else if (cl_capturevideo_active)
1267 SCR_CaptureVideo_EndVideo();
1274 Grab six views for environment mapping tests
1281 qboolean flipx, flipy, flipdiagonaly;
1285 {{ 0, 0, 0}, "rt", false, false, false},
1286 {{ 0, 270, 0}, "ft", false, false, false},
1287 {{ 0, 180, 0}, "lf", false, false, false},
1288 {{ 0, 90, 0}, "bk", false, false, false},
1289 {{-90, 180, 0}, "up", true, true, false},
1290 {{ 90, 180, 0}, "dn", true, true, false},
1292 {{ 0, 0, 0}, "px", true, true, true},
1293 {{ 0, 90, 0}, "py", false, true, false},
1294 {{ 0, 180, 0}, "nx", false, false, true},
1295 {{ 0, 270, 0}, "ny", true, false, false},
1296 {{-90, 180, 0}, "pz", false, false, true},
1297 {{ 90, 180, 0}, "nz", false, false, true}
1300 static void R_Envmap_f (void)
1303 char filename[MAX_QPATH], basename[MAX_QPATH];
1304 unsigned char *buffer1;
1305 unsigned char *buffer2;
1306 unsigned char *buffer3;
1308 if (Cmd_Argc() != 3)
1310 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");
1314 strlcpy (basename, Cmd_Argv(1), sizeof (basename));
1315 size = atoi(Cmd_Argv(2));
1316 if (size != 128 && size != 256 && size != 512 && size != 1024)
1318 Con_Print("envmap: size must be one of 128, 256, 512, or 1024\n");
1321 if (size > vid.width || size > vid.height)
1323 Con_Print("envmap: your resolution is not big enough to render that size\n");
1331 r_refdef.width = size;
1332 r_refdef.height = size;
1334 r_refdef.frustum_x = tan(90 * M_PI / 360.0);
1335 r_refdef.frustum_y = tan(90 * M_PI / 360.0);
1337 buffer1 = (unsigned char *)Mem_Alloc(tempmempool, size * size * 3);
1338 buffer2 = (unsigned char *)Mem_Alloc(tempmempool, size * size * 3);
1339 buffer3 = (unsigned char *)Mem_Alloc(tempmempool, size * size * 3 + 18);
1341 for (j = 0;j < 12;j++)
1343 sprintf(filename, "env/%s%s.tga", basename, envmapinfo[j].name);
1344 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);
1349 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);
1359 //=============================================================================
1361 // LordHavoc: SHOWLMP stuff
1362 #define SHOWLMP_MAXLABELS 256
1363 typedef struct showlmp_s
1373 showlmp_t showlmp[SHOWLMP_MAXLABELS];
1375 void SHOWLMP_decodehide(void)
1379 lmplabel = MSG_ReadString();
1380 for (i = 0;i < SHOWLMP_MAXLABELS;i++)
1381 if (showlmp[i].isactive && strcmp(showlmp[i].label, lmplabel) == 0)
1383 showlmp[i].isactive = false;
1388 void SHOWLMP_decodeshow(void)
1391 char lmplabel[256], picname[256];
1393 strlcpy (lmplabel,MSG_ReadString(), sizeof (lmplabel));
1394 strlcpy (picname, MSG_ReadString(), sizeof (picname));
1395 if (gamemode == GAME_NEHAHRA) // LordHavoc: nasty old legacy junk
1402 x = MSG_ReadShort();
1403 y = MSG_ReadShort();
1406 for (i = 0;i < SHOWLMP_MAXLABELS;i++)
1407 if (showlmp[i].isactive)
1409 if (strcmp(showlmp[i].label, lmplabel) == 0)
1412 break; // drop out to replace it
1415 else if (k < 0) // find first empty one to replace
1418 return; // none found to replace
1419 // change existing one
1420 showlmp[k].isactive = true;
1421 strlcpy (showlmp[k].label, lmplabel, sizeof (showlmp[k].label));
1422 strlcpy (showlmp[k].pic, picname, sizeof (showlmp[k].pic));
1427 void SHOWLMP_drawall(void)
1430 for (i = 0;i < SHOWLMP_MAXLABELS;i++)
1431 if (showlmp[i].isactive)
1432 DrawQ_Pic(showlmp[i].x, showlmp[i].y, Draw_CachePic(showlmp[i].pic, false), 0, 0, 1, 1, 1, 1, 0);
1435 void SHOWLMP_clear(void)
1438 for (i = 0;i < SHOWLMP_MAXLABELS;i++)
1439 showlmp[i].isactive = false;
1442 void CL_SetupScreenSize(void)
1444 float conwidth, conheight;
1446 VID_UpdateGamma(false);
1448 conwidth = bound(320, vid_conwidth.value, 2048);
1449 conheight = bound(200, vid_conheight.value, 1536);
1450 if (vid_conwidth.value != conwidth)
1451 Cvar_SetValue("vid_conwidth", conwidth);
1452 if (vid_conheight.value != conheight)
1453 Cvar_SetValue("vid_conheight", conheight);
1455 vid_conwidth.integer = vid_conwidth.integer;
1456 vid_conheight.integer = vid_conheight.integer;
1458 SCR_SetUpToDrawConsole();
1461 extern void R_Shadow_EditLights_DrawSelectedLightProperties(void);
1462 void CL_UpdateScreen(void)
1464 if (!scr_initialized || !con_initialized || vid_hidden)
1465 return; // not initialized yet
1467 // don't allow cheats in multiplayer
1468 if (!cl.islocalgame && cl.worldmodel)
1470 if (r_fullbright.integer != 0)
1471 Cvar_Set ("r_fullbright", "0");
1472 if (r_ambient.value != 0)
1473 Cvar_Set ("r_ambient", "0");
1477 if (scr_viewsize.value < 30)
1478 Cvar_Set ("viewsize","30");
1479 if (scr_viewsize.value > 120)
1480 Cvar_Set ("viewsize","120");
1482 // bound field of view
1483 if (scr_fov.value < 1)
1484 Cvar_Set ("fov","1");
1485 if (scr_fov.value > 170)
1486 Cvar_Set ("fov","170");
1488 // intermission is always full screen
1489 if (cl.intermission)
1493 if (scr_viewsize.value >= 120)
1494 sb_lines = 0; // no status bar at all
1495 else if (scr_viewsize.value >= 110)
1496 sb_lines = 24; // no inventory
1501 r_refdef.colormask[0] = 1;
1502 r_refdef.colormask[1] = 1;
1503 r_refdef.colormask[2] = 1;
1507 if (r_timereport_active)
1508 R_TimeReport("other");
1510 CL_SetupScreenSize();
1514 if (r_timereport_active)
1515 R_TimeReport("setup");
1517 //FIXME: force menu if nothing else to look at?
1518 //if (key_dest == key_game && cls.signon != SIGNONS && cls.state == ca_disconnected)
1520 if (cls.signon == SIGNONS)
1525 if (!r_letterbox.value)
1528 SCR_CheckDrawCenterString();
1532 if (cls.signon == SIGNONS)
1534 if (r_timereport_active)
1536 R_TimeReport_Frame();
1538 R_Shadow_EditLights_DrawSelectedLightProperties();
1550 void CL_Screen_NewMap(void)