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, "gfx/turtle", 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, "gfx/net", 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, "gfx/pause", 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, "gfx/brand", 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);
409 x = (vid_conwidth.integer - len*size) / 2;
410 y = vid_conheight.integer - size;
411 DrawQ_Fill(0, y, 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_Start(void)
541 r_timereport_active = r_speeds.integer && cls.signon == SIGNONS && cls.state == ca_connected;
542 r_speeds_string[0] = 0;
543 if (r_timereport_active)
545 speedstringcount = 0;
546 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]);
547 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);
548 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);
549 if (renderstats.bloom)
550 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);
552 sprintf(r_speeds_string + strlen(r_speeds_string), "rendered%6i meshes%8i triangles\n", renderstats.meshes, renderstats.meshes_elements / 3);
554 r_timereport_start = Sys_DoubleTime();
557 memset(&renderstats, 0, sizeof(renderstats));
560 void R_TimeReport_End(void)
564 r_timereport_current = r_timereport_start;
565 R_TimeReport("total");
567 j = (int)strlen(r_speeds_string);
568 if (r_timereport_active && j > 0)
570 if (r_speeds_string[j-1] == '\n')
571 r_speeds_string[j-1] = 0;
573 for (i = 0;r_speeds_string[i];i++)
574 if (r_speeds_string[i] == '\n')
576 y = vid_conheight.integer - sb_lines - lines * 8;
578 DrawQ_Fill(0, y, vid_conwidth.integer, lines * 8, 0, 0, 0, 0.5, 0);
579 while (r_speeds_string[i])
582 while (r_speeds_string[i] && r_speeds_string[i] != '\n')
585 DrawQ_String(0, y, r_speeds_string + j, i - j, 8, 8, 1, 1, 1, 1, 0);
586 if (r_speeds_string[i] == '\n')
600 void SCR_SizeUp_f (void)
602 Cvar_SetValue ("viewsize",scr_viewsize.value+10);
613 void SCR_SizeDown_f (void)
615 Cvar_SetValue ("viewsize",scr_viewsize.value-10);
618 void CL_Screen_Init(void)
620 Cvar_RegisterVariable (&scr_fov);
621 Cvar_RegisterVariable (&scr_viewsize);
622 Cvar_RegisterVariable (&scr_conspeed);
623 Cvar_RegisterVariable (&scr_conalpha);
624 Cvar_RegisterVariable (&scr_conbrightness);
625 Cvar_RegisterVariable (&scr_conforcewhiledisconnected);
626 Cvar_RegisterVariable (&scr_showram);
627 Cvar_RegisterVariable (&scr_showturtle);
628 Cvar_RegisterVariable (&scr_showpause);
629 Cvar_RegisterVariable (&scr_showbrand);
630 Cvar_RegisterVariable (&scr_centertime);
631 Cvar_RegisterVariable (&scr_printspeed);
632 Cvar_RegisterVariable (&vid_conwidth);
633 Cvar_RegisterVariable (&vid_conheight);
634 Cvar_RegisterVariable (&vid_pixelheight);
635 Cvar_RegisterVariable (&scr_screenshot_jpeg);
636 Cvar_RegisterVariable (&scr_screenshot_jpeg_quality);
637 Cvar_RegisterVariable (&scr_screenshot_gamma);
638 Cvar_RegisterVariable (&cl_capturevideo);
639 Cvar_RegisterVariable (&cl_capturevideo_sound);
640 Cvar_RegisterVariable (&cl_capturevideo_fps);
641 Cvar_RegisterVariable (&cl_capturevideo_rawrgb);
642 Cvar_RegisterVariable (&cl_capturevideo_rawyv12);
643 Cvar_RegisterVariable (&r_textshadow);
644 Cvar_RegisterVariable (&r_letterbox);
646 Cmd_AddCommand ("sizeup",SCR_SizeUp_f, "increase view size (increases viewsize cvar)");
647 Cmd_AddCommand ("sizedown",SCR_SizeDown_f, "decrease view size (decreases viewsize cvar)");
648 Cmd_AddCommand ("screenshot",SCR_ScreenShot_f, "takes a screenshot of the next rendered frame");
649 Cmd_AddCommand ("envmap", R_Envmap_f, "render a cubemap (skybox) of the current scene");
651 scr_initialized = true;
654 void DrawQ_Clear(void)
656 r_refdef.drawqueuesize = 0;
659 static int picelements[6] = {0, 1, 2, 0, 2, 3};
660 void DrawQ_Pic(float x, float y, const char *picname, float width, float height, float red, float green, float blue, float alpha, int flags)
662 DrawQ_SuperPic(x,y,picname,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);
665 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)
670 if (alpha < (1.0f / 255.0f))
673 len = (int)strlen(string);
675 for (len = 0;len < maxlen && string[len];len++);
676 for (;len > 0 && string[0] == ' ';string++, x += scalex, len--);
677 for (;len > 0 && string[len - 1] == ' ';len--);
680 if (x >= vid_conwidth.integer || y >= vid_conheight.integer || x < (-scalex * len) || y < (-scaley))
682 size = sizeof(*dq) + ((len + 1 + 3) & ~3);
683 if (r_refdef.drawqueuesize + size > r_refdef.maxdrawqueuesize)
685 red = bound(0, red, 1);
686 green = bound(0, green, 1);
687 blue = bound(0, blue, 1);
688 alpha = bound(0, alpha, 1);
689 dq = (drawqueue_t *)(r_refdef.drawqueue + r_refdef.drawqueuesize);
691 dq->command = DRAWQUEUE_STRING;
693 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));
698 out = (char *)(dq + 1);
699 memcpy(out, string, len);
701 r_refdef.drawqueuesize += dq->size;
704 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)
706 if (r_textshadow.integer)
707 DrawQ_String_Real(x+scalex*0.25,y+scaley*0.25,string,maxlen,scalex,scaley,0,0,0,alpha*0.8,flags);
709 DrawQ_String_Real(x,y,string,maxlen,scalex,scaley,red,green,blue,alpha,flags);
714 void DrawQ_Fill (float x, float y, float w, float h, float red, float green, float blue, float alpha, int flags)
716 DrawQ_SuperPic(x,y,NULL,w,h,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);
719 void DrawQ_SuperPic(float x, float y, const char *picname, 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)
723 drawqueuemesh_t mesh;
724 memset(&mesh, 0, sizeof(mesh));
725 if (picname && picname[0])
727 pic = Draw_CachePic(picname, false);
731 height = pic->height;
732 mesh.texture = pic->tex;
734 mesh.num_triangles = 2;
735 mesh.num_vertices = 4;
736 mesh.data_element3i = picelements;
737 mesh.data_vertex3f = floats;
738 mesh.data_texcoord2f = floats + 12;
739 mesh.data_color4f = floats + 20;
740 memset(floats, 0, sizeof(floats));
741 mesh.data_vertex3f[0] = mesh.data_vertex3f[9] = x;
742 mesh.data_vertex3f[1] = mesh.data_vertex3f[4] = y;
743 mesh.data_vertex3f[3] = mesh.data_vertex3f[6] = x + width;
744 mesh.data_vertex3f[7] = mesh.data_vertex3f[10] = y + height;
745 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;
746 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;
747 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;
748 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;
749 DrawQ_Mesh (&mesh, flags);
752 void DrawQ_Mesh (drawqueuemesh_t *mesh, int flags)
759 size += sizeof(drawqueuemesh_t);
760 size += sizeof(int[3]) * mesh->num_triangles;
761 size += sizeof(float[3]) * mesh->num_vertices;
762 size += sizeof(float[2]) * mesh->num_vertices;
763 size += sizeof(float[4]) * mesh->num_vertices;
764 if (r_refdef.drawqueuesize + size > r_refdef.maxdrawqueuesize)
766 dq = (drawqueue_t *)(r_refdef.drawqueue + r_refdef.drawqueuesize);
768 dq->command = DRAWQUEUE_MESH;
775 p = (void *)(dq + 1);
776 m = (drawqueuemesh_t *)p;p = (unsigned char*)p + sizeof(drawqueuemesh_t);
777 m->num_triangles = mesh->num_triangles;
778 m->num_vertices = mesh->num_vertices;
779 m->texture = mesh->texture;
780 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]);
781 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]);
782 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]);
783 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]);
784 r_refdef.drawqueuesize += dq->size;
787 void DrawQ_LineLoop (drawqueuemesh_t *mesh, int flags)
794 size += sizeof(drawqueuemesh_t);
795 size += sizeof(int[3]) * mesh->num_triangles;
796 size += sizeof(float[3]) * mesh->num_vertices;
797 size += sizeof(float[2]) * mesh->num_vertices;
798 size += sizeof(float[4]) * mesh->num_vertices;
799 if (r_refdef.drawqueuesize + size > r_refdef.maxdrawqueuesize)
801 dq = (void *)(r_refdef.drawqueue + r_refdef.drawqueuesize);
803 dq->command = DRAWQUEUE_LINES;
810 p = (void *)(dq + 1);
811 m = p;p = (unsigned char*)p + sizeof(drawqueuemesh_t);
812 m->num_triangles = mesh->num_triangles;
813 m->num_vertices = mesh->num_vertices;
814 m->texture = mesh->texture;
815 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]);
816 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]);
817 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]);
818 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]);
819 r_refdef.drawqueuesize += dq->size;
822 //LordHavoc: FIXME: this is nasty!
823 void DrawQ_LineWidth (float width)
826 static int linewidth = 1;
827 if(width == linewidth)
830 if(r_refdef.drawqueuesize + (int)sizeof(*dq) > r_refdef.maxdrawqueuesize)
832 Con_DPrint("DrawQueue full !\n");
835 dq = (void*) (r_refdef.drawqueue + r_refdef.drawqueuesize);
836 dq->size = sizeof(*dq);
837 dq->command = DRAWQUEUE_LINEWIDTH;
840 r_refdef.drawqueuesize += dq->size;
843 //[515]: this is old, delete
844 void DrawQ_Line (float width, float x1, float y1, float x2, float y2, float r, float g, float b, float alpha, int flags)
848 DrawQ_LineWidth(width);
849 if(r_refdef.drawqueuesize + (int)sizeof(*dq) > r_refdef.maxdrawqueuesize)
851 Con_DPrint("DrawQueue full !\n");
854 dq = (void*) (r_refdef.drawqueue + r_refdef.drawqueuesize);
855 dq->size = sizeof(*dq);
856 dq->command = DRAWQUEUE_LINES;
862 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));
864 r_refdef.drawqueuesize += dq->size;
867 void DrawQ_SetClipArea(float x, float y, float width, float height)
870 if(r_refdef.drawqueuesize + (int)sizeof(*dq) > r_refdef.maxdrawqueuesize)
872 Con_DPrint("DrawQueue full !\n");
875 dq = (drawqueue_t *) (r_refdef.drawqueue + r_refdef.drawqueuesize);
876 dq->size = sizeof(*dq);
877 dq->command = DRAWQUEUE_SETCLIP;
885 r_refdef.drawqueuesize += dq->size;
888 void DrawQ_ResetClipArea(void)
891 if(r_refdef.drawqueuesize + (int)sizeof(*dq) > r_refdef.maxdrawqueuesize)
893 Con_DPrint("DrawQueue full !\n");
896 dq = (drawqueue_t *) (r_refdef.drawqueue + r_refdef.drawqueuesize);
897 dq->size = sizeof(*dq);
898 dq->command = DRAWQUEUE_RESETCLIP;
906 r_refdef.drawqueuesize += dq->size;
914 void SCR_ScreenShot_f (void)
916 static int shotnumber;
917 static char oldname[MAX_QPATH];
918 char base[MAX_QPATH];
919 char filename[MAX_QPATH];
920 unsigned char *buffer1;
921 unsigned char *buffer2;
922 unsigned char *buffer3;
923 qboolean jpeg = (scr_screenshot_jpeg.integer != 0);
925 sprintf (base, "screenshots/%s", scr_screenshot_name.string);
927 if (strcmp (oldname, scr_screenshot_name.string))
929 sprintf(oldname, "%s", scr_screenshot_name.string);
933 // find a file name to save it to
934 for (;shotnumber < 1000000;shotnumber++)
935 if (!FS_SysFileExists(va("%s/%s%06d.tga", fs_gamedir, base, shotnumber)) && !FS_SysFileExists(va("%s/%s%06d.jpg", fs_gamedir, base, shotnumber)))
937 if (shotnumber >= 1000000)
939 Con_Print("SCR_ScreenShot_f: Couldn't create the image file\n");
943 sprintf(filename, "%s%06d.%s", base, shotnumber, jpeg ? "jpg" : "tga");
945 buffer1 = (unsigned char *)Mem_Alloc(tempmempool, vid.width * vid.height * 3);
946 buffer2 = (unsigned char *)Mem_Alloc(tempmempool, vid.width * vid.height * 3);
947 buffer3 = (unsigned char *)Mem_Alloc(tempmempool, vid.width * vid.height * 3 + 18);
949 if (SCR_ScreenShot (filename, buffer1, buffer2, buffer3, 0, 0, vid.width, vid.height, false, false, false, jpeg, true))
950 Con_Printf("Wrote %s\n", filename);
952 Con_Printf("unable to write %s\n", filename);
961 typedef enum capturevideoformat_e
963 CAPTUREVIDEOFORMAT_TARGA,
964 CAPTUREVIDEOFORMAT_JPEG,
965 CAPTUREVIDEOFORMAT_RAWRGB,
966 CAPTUREVIDEOFORMAT_RAWYV12
968 capturevideoformat_t;
970 qboolean cl_capturevideo_active = false;
971 capturevideoformat_t cl_capturevideo_format;
972 static double cl_capturevideo_starttime = 0;
973 double cl_capturevideo_framerate = 0;
974 static int cl_capturevideo_soundrate = 0;
975 static int cl_capturevideo_frame = 0;
976 static unsigned char *cl_capturevideo_buffer = NULL;
977 static qfile_t *cl_capturevideo_videofile = NULL;
978 qfile_t *cl_capturevideo_soundfile = NULL;
979 static short cl_capturevideo_rgbtoyuvscaletable[3][3][256];
980 static unsigned char cl_capturevideo_yuvnormalizetable[3][256];
981 //static unsigned char cl_capturevideo_rgbgammatable[3][256];
983 void SCR_CaptureVideo_BeginVideo(void)
987 unsigned char out[44];
988 if (cl_capturevideo_active)
990 // soundrate is figured out on the first SoundFrame
991 cl_capturevideo_active = true;
992 cl_capturevideo_starttime = Sys_DoubleTime();
993 cl_capturevideo_framerate = bound(1, cl_capturevideo_fps.value, 1000);
994 cl_capturevideo_soundrate = 0;
995 cl_capturevideo_frame = 0;
996 cl_capturevideo_buffer = (unsigned char *)Mem_Alloc(tempmempool, vid.width * vid.height * (3+3+3) + 18);
997 gamma = 1.0/scr_screenshot_gamma.value;
1000 for (i = 0;i < 256;i++)
1002 unsigned char j = (unsigned char)bound(0, 255*pow(i/255.0, gamma), 255);
1003 cl_capturevideo_rgbgammatable[0][i] = j;
1004 cl_capturevideo_rgbgammatable[1][i] = j;
1005 cl_capturevideo_rgbgammatable[2][i] = j;
1009 R = Y + 1.4075 * (Cr - 128);
1010 G = Y + -0.3455 * (Cb - 128) + -0.7169 * (Cr - 128);
1011 B = Y + 1.7790 * (Cb - 128);
1012 Y = R * .299 + G * .587 + B * .114;
1013 Cb = R * -.169 + G * -.332 + B * .500 + 128.;
1014 Cr = R * .500 + G * -.419 + B * -.0813 + 128.;
1016 for (i = 0;i < 256;i++)
1018 g = 255*pow(i/255.0, gamma);
1019 // Y weights from RGB
1020 cl_capturevideo_rgbtoyuvscaletable[0][0][i] = (short)(g * 0.299);
1021 cl_capturevideo_rgbtoyuvscaletable[0][1][i] = (short)(g * 0.587);
1022 cl_capturevideo_rgbtoyuvscaletable[0][2][i] = (short)(g * 0.114);
1023 // Cb weights from RGB
1024 cl_capturevideo_rgbtoyuvscaletable[1][0][i] = (short)(g * -0.169);
1025 cl_capturevideo_rgbtoyuvscaletable[1][1][i] = (short)(g * -0.332);
1026 cl_capturevideo_rgbtoyuvscaletable[1][2][i] = (short)(g * 0.500);
1027 // Cr weights from RGB
1028 cl_capturevideo_rgbtoyuvscaletable[2][0][i] = (short)(g * 0.500);
1029 cl_capturevideo_rgbtoyuvscaletable[2][1][i] = (short)(g * -0.419);
1030 cl_capturevideo_rgbtoyuvscaletable[2][2][i] = (short)(g * -0.0813);
1031 // range reduction of YCbCr to valid signal range
1032 cl_capturevideo_yuvnormalizetable[0][i] = 16 + i * (236-16) / 256;
1033 cl_capturevideo_yuvnormalizetable[1][i] = 16 + i * (240-16) / 256;
1034 cl_capturevideo_yuvnormalizetable[2][i] = 16 + i * (240-16) / 256;
1037 if (cl_capturevideo_rawrgb.integer)
1039 cl_capturevideo_format = CAPTUREVIDEOFORMAT_RAWRGB;
1040 cl_capturevideo_videofile = FS_Open ("video/dpvideo.rgb", "wb", false, true);
1042 else if (cl_capturevideo_rawyv12.integer)
1044 cl_capturevideo_format = CAPTUREVIDEOFORMAT_RAWYV12;
1045 cl_capturevideo_videofile = FS_Open ("video/dpvideo.yv12", "wb", false, true);
1047 else if (scr_screenshot_jpeg.integer)
1049 cl_capturevideo_format = CAPTUREVIDEOFORMAT_JPEG;
1050 cl_capturevideo_videofile = NULL;
1054 cl_capturevideo_format = CAPTUREVIDEOFORMAT_TARGA;
1055 cl_capturevideo_videofile = NULL;
1058 if (cl_capturevideo_sound.integer)
1060 cl_capturevideo_soundfile = FS_Open ("video/dpvideo.wav", "wb", false, true);
1061 // wave header will be filled out when video ends
1063 FS_Write (cl_capturevideo_soundfile, out, 44);
1066 cl_capturevideo_soundfile = NULL;
1069 void SCR_CaptureVideo_EndVideo(void)
1072 unsigned char out[44];
1073 if (!cl_capturevideo_active)
1075 cl_capturevideo_active = false;
1077 if (cl_capturevideo_videofile)
1079 FS_Close(cl_capturevideo_videofile);
1080 cl_capturevideo_videofile = NULL;
1083 // finish the wave file
1084 if (cl_capturevideo_soundfile)
1086 i = (int)FS_Tell (cl_capturevideo_soundfile);
1087 //"RIFF", (int) unknown (chunk size), "WAVE",
1088 //"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
1089 //"data", (int) unknown (chunk size)
1090 memcpy (out, "RIFF****WAVEfmt \x10\x00\x00\x00\x01\x00\x02\x00********\x04\x00\x10\0data****", 44);
1091 // the length of the whole RIFF chunk
1093 out[4] = (n) & 0xFF;
1094 out[5] = (n >> 8) & 0xFF;
1095 out[6] = (n >> 16) & 0xFF;
1096 out[7] = (n >> 24) & 0xFF;
1098 n = cl_capturevideo_soundrate;
1099 out[24] = (n) & 0xFF;
1100 out[25] = (n >> 8) & 0xFF;
1101 out[26] = (n >> 16) & 0xFF;
1102 out[27] = (n >> 24) & 0xFF;
1103 // bytes per second (rate * channels * bytes per channel)
1104 n = cl_capturevideo_soundrate * 2 * 2;
1105 out[28] = (n) & 0xFF;
1106 out[29] = (n >> 8) & 0xFF;
1107 out[30] = (n >> 16) & 0xFF;
1108 out[31] = (n >> 24) & 0xFF;
1109 // the length of the data chunk
1111 out[40] = (n) & 0xFF;
1112 out[41] = (n >> 8) & 0xFF;
1113 out[42] = (n >> 16) & 0xFF;
1114 out[43] = (n >> 24) & 0xFF;
1115 FS_Seek (cl_capturevideo_soundfile, 0, SEEK_SET);
1116 FS_Write (cl_capturevideo_soundfile, out, 44);
1117 FS_Close (cl_capturevideo_soundfile);
1118 cl_capturevideo_soundfile = NULL;
1121 if (cl_capturevideo_buffer)
1123 Mem_Free (cl_capturevideo_buffer);
1124 cl_capturevideo_buffer = NULL;
1127 cl_capturevideo_starttime = 0;
1128 cl_capturevideo_framerate = 0;
1129 cl_capturevideo_frame = 0;
1132 qboolean SCR_CaptureVideo_VideoFrame(int newframenum)
1134 int x = 0, y = 0, width = vid.width, height = vid.height;
1135 unsigned char *b, *out;
1137 int outoffset = (width/2)*(height/2);
1138 //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);
1139 // speed is critical here, so do saving as directly as possible
1140 switch (cl_capturevideo_format)
1142 case CAPTUREVIDEOFORMAT_RAWYV12:
1143 // FIXME: width/height must be multiple of 2, enforce this?
1144 qglReadPixels (x, y, width, height, GL_RGB, GL_UNSIGNED_BYTE, cl_capturevideo_buffer);
1146 // process one line at a time, and CbCr every other line at 2 pixel intervals
1147 for (y = 0;y < height;y++)
1150 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++)
1151 *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]]];
1154 // 2x2 Cb and Cr planes
1156 // low quality, no averaging
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++)
1160 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];
1162 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];
1165 // high quality, averaging
1166 int inpitch = width*3;
1167 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++)
1169 int blockr, blockg, blockb;
1170 blockr = (b[0] + b[3] + b[inpitch+0] + b[inpitch+3]) >> 2;
1171 blockg = (b[1] + b[4] + b[inpitch+1] + b[inpitch+4]) >> 2;
1172 blockb = (b[2] + b[5] + b[inpitch+2] + b[inpitch+5]) >> 2;
1174 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];
1176 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];
1181 for (;cl_capturevideo_frame < newframenum;cl_capturevideo_frame++)
1182 if (!FS_Write (cl_capturevideo_videofile, cl_capturevideo_buffer + width*height*3, width*height+(width/2)*(height/2)*2))
1185 case CAPTUREVIDEOFORMAT_RAWRGB:
1186 qglReadPixels (x, y, width, height, GL_RGB, GL_UNSIGNED_BYTE, cl_capturevideo_buffer);
1188 for (;cl_capturevideo_frame < newframenum;cl_capturevideo_frame++)
1189 if (!FS_Write (cl_capturevideo_videofile, cl_capturevideo_buffer, width*height*3))
1192 case CAPTUREVIDEOFORMAT_JPEG:
1193 qglReadPixels (x, y, width, height, GL_RGB, GL_UNSIGNED_BYTE, cl_capturevideo_buffer);
1195 for (;cl_capturevideo_frame < newframenum;cl_capturevideo_frame++)
1197 sprintf(filename, "video/dp%06d.jpg", cl_capturevideo_frame);
1198 if (!JPEG_SaveImage_preflipped (filename, width, height, cl_capturevideo_buffer))
1202 case CAPTUREVIDEOFORMAT_TARGA:
1203 //return Image_WriteTGARGB_preflipped (filename, width, height, cl_capturevideo_buffer, cl_capturevideo_buffer + vid.width * vid.height * 3, );
1204 memset (cl_capturevideo_buffer, 0, 18);
1205 cl_capturevideo_buffer[2] = 2; // uncompressed type
1206 cl_capturevideo_buffer[12] = (width >> 0) & 0xFF;
1207 cl_capturevideo_buffer[13] = (width >> 8) & 0xFF;
1208 cl_capturevideo_buffer[14] = (height >> 0) & 0xFF;
1209 cl_capturevideo_buffer[15] = (height >> 8) & 0xFF;
1210 cl_capturevideo_buffer[16] = 24; // pixel size
1211 qglReadPixels (x, y, width, height, GL_BGR, GL_UNSIGNED_BYTE, cl_capturevideo_buffer + 18);
1213 for (;cl_capturevideo_frame < newframenum;cl_capturevideo_frame++)
1215 sprintf(filename, "video/dp%06d.tga", cl_capturevideo_frame);
1216 if (!FS_WriteFile (filename, cl_capturevideo_buffer, width*height*3 + 18))
1225 void SCR_CaptureVideo_SoundFrame(unsigned char *bufstereo16le, size_t length, int rate)
1227 if (!cl_capturevideo_soundfile)
1229 cl_capturevideo_soundrate = rate;
1230 if (FS_Write (cl_capturevideo_soundfile, bufstereo16le, 4 * length) < (fs_offset_t)(4 * length))
1232 Cvar_SetValueQuick(&cl_capturevideo, 0);
1233 Con_Printf("video sound saving failed on frame %i, out of disk space? stopping video capture.\n", cl_capturevideo_frame);
1234 SCR_CaptureVideo_EndVideo();
1238 void SCR_CaptureVideo(void)
1241 if (cl_capturevideo.integer && r_render.integer)
1243 if (!cl_capturevideo_active)
1244 SCR_CaptureVideo_BeginVideo();
1245 if (cl_capturevideo_framerate != cl_capturevideo_fps.value)
1247 Con_Printf("You can not change the video framerate while recording a video.\n");
1248 Cvar_SetValueQuick(&cl_capturevideo_fps, cl_capturevideo_framerate);
1250 if (cl_capturevideo_soundfile)
1252 // preserve sound sync by duplicating frames when running slow
1253 newframenum = (Sys_DoubleTime() - cl_capturevideo_starttime) * cl_capturevideo_framerate;
1256 newframenum = cl_capturevideo_frame + 1;
1257 // if falling behind more than one second, stop
1258 if (newframenum - cl_capturevideo_frame > (int)ceil(cl_capturevideo_framerate))
1260 Cvar_SetValueQuick(&cl_capturevideo, 0);
1261 Con_Printf("video saving failed on frame %i, your machine is too slow for this capture speed.\n", cl_capturevideo_frame);
1262 SCR_CaptureVideo_EndVideo();
1266 if (!SCR_CaptureVideo_VideoFrame(newframenum))
1268 Cvar_SetValueQuick(&cl_capturevideo, 0);
1269 Con_Printf("video saving failed on frame %i, out of disk space? stopping video capture.\n", cl_capturevideo_frame);
1270 SCR_CaptureVideo_EndVideo();
1273 else if (cl_capturevideo_active)
1274 SCR_CaptureVideo_EndVideo();
1281 Grab six views for environment mapping tests
1288 qboolean flipx, flipy, flipdiagonaly;
1292 {{ 0, 0, 0}, "rt", false, false, false},
1293 {{ 0, 270, 0}, "ft", false, false, false},
1294 {{ 0, 180, 0}, "lf", false, false, false},
1295 {{ 0, 90, 0}, "bk", false, false, false},
1296 {{-90, 180, 0}, "up", true, true, false},
1297 {{ 90, 180, 0}, "dn", true, true, false},
1299 {{ 0, 0, 0}, "px", true, true, true},
1300 {{ 0, 90, 0}, "py", false, true, false},
1301 {{ 0, 180, 0}, "nx", false, false, true},
1302 {{ 0, 270, 0}, "ny", true, false, false},
1303 {{-90, 180, 0}, "pz", false, false, true},
1304 {{ 90, 180, 0}, "nz", false, false, true}
1307 static void R_Envmap_f (void)
1310 char filename[MAX_QPATH], basename[MAX_QPATH];
1311 unsigned char *buffer1;
1312 unsigned char *buffer2;
1313 unsigned char *buffer3;
1315 if (Cmd_Argc() != 3)
1317 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");
1321 strlcpy (basename, Cmd_Argv(1), sizeof (basename));
1322 size = atoi(Cmd_Argv(2));
1323 if (size != 128 && size != 256 && size != 512 && size != 1024)
1325 Con_Print("envmap: size must be one of 128, 256, 512, or 1024\n");
1328 if (size > vid.width || size > vid.height)
1330 Con_Print("envmap: your resolution is not big enough to render that size\n");
1338 r_refdef.width = size;
1339 r_refdef.height = size;
1341 r_refdef.frustum_x = tan(90 * M_PI / 360.0);
1342 r_refdef.frustum_y = tan(90 * M_PI / 360.0);
1344 buffer1 = (unsigned char *)Mem_Alloc(tempmempool, size * size * 3);
1345 buffer2 = (unsigned char *)Mem_Alloc(tempmempool, size * size * 3);
1346 buffer3 = (unsigned char *)Mem_Alloc(tempmempool, size * size * 3 + 18);
1348 for (j = 0;j < 12;j++)
1350 sprintf(filename, "env/%s%s.tga", basename, envmapinfo[j].name);
1351 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);
1356 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);
1366 //=============================================================================
1368 // LordHavoc: SHOWLMP stuff
1369 #define SHOWLMP_MAXLABELS 256
1370 typedef struct showlmp_s
1380 showlmp_t showlmp[SHOWLMP_MAXLABELS];
1382 void SHOWLMP_decodehide(void)
1386 lmplabel = MSG_ReadString();
1387 for (i = 0;i < SHOWLMP_MAXLABELS;i++)
1388 if (showlmp[i].isactive && strcmp(showlmp[i].label, lmplabel) == 0)
1390 showlmp[i].isactive = false;
1395 void SHOWLMP_decodeshow(void)
1398 char lmplabel[256], picname[256];
1400 strlcpy (lmplabel,MSG_ReadString(), sizeof (lmplabel));
1401 strlcpy (picname, MSG_ReadString(), sizeof (picname));
1402 if (gamemode == GAME_NEHAHRA) // LordHavoc: nasty old legacy junk
1409 x = MSG_ReadShort();
1410 y = MSG_ReadShort();
1413 for (i = 0;i < SHOWLMP_MAXLABELS;i++)
1414 if (showlmp[i].isactive)
1416 if (strcmp(showlmp[i].label, lmplabel) == 0)
1419 break; // drop out to replace it
1422 else if (k < 0) // find first empty one to replace
1425 return; // none found to replace
1426 // change existing one
1427 showlmp[k].isactive = true;
1428 strlcpy (showlmp[k].label, lmplabel, sizeof (showlmp[k].label));
1429 strlcpy (showlmp[k].pic, picname, sizeof (showlmp[k].pic));
1434 void SHOWLMP_drawall(void)
1437 for (i = 0;i < SHOWLMP_MAXLABELS;i++)
1438 if (showlmp[i].isactive)
1439 DrawQ_Pic(showlmp[i].x, showlmp[i].y, showlmp[i].pic, 0, 0, 1, 1, 1, 1, 0);
1442 void SHOWLMP_clear(void)
1445 for (i = 0;i < SHOWLMP_MAXLABELS;i++)
1446 showlmp[i].isactive = false;
1449 void CL_SetupScreenSize(void)
1451 float conwidth, conheight;
1453 VID_UpdateGamma(false);
1455 conwidth = bound(320, vid_conwidth.value, 2048);
1456 conheight = bound(200, vid_conheight.value, 1536);
1457 if (vid_conwidth.value != conwidth)
1458 Cvar_SetValue("vid_conwidth", conwidth);
1459 if (vid_conheight.value != conheight)
1460 Cvar_SetValue("vid_conheight", conheight);
1462 vid_conwidth.integer = vid_conwidth.integer;
1463 vid_conheight.integer = vid_conheight.integer;
1465 SCR_SetUpToDrawConsole();
1468 extern void R_Shadow_EditLights_DrawSelectedLightProperties(void);
1469 void CL_UpdateScreen(void)
1471 if (!scr_initialized || !con_initialized || vid_hidden)
1472 return; // not initialized yet
1474 // don't allow cheats in multiplayer
1475 if (!cl.islocalgame && cl.worldmodel)
1477 if (r_fullbright.integer != 0)
1478 Cvar_Set ("r_fullbright", "0");
1479 if (r_ambient.value != 0)
1480 Cvar_Set ("r_ambient", "0");
1484 if (scr_viewsize.value < 30)
1485 Cvar_Set ("viewsize","30");
1486 if (scr_viewsize.value > 120)
1487 Cvar_Set ("viewsize","120");
1489 // bound field of view
1490 if (scr_fov.value < 1)
1491 Cvar_Set ("fov","1");
1492 if (scr_fov.value > 170)
1493 Cvar_Set ("fov","170");
1495 // intermission is always full screen
1496 if (cl.intermission)
1500 if (scr_viewsize.value >= 120)
1501 sb_lines = 0; // no status bar at all
1502 else if (scr_viewsize.value >= 110)
1503 sb_lines = 24; // no inventory
1508 r_refdef.colormask[0] = 1;
1509 r_refdef.colormask[1] = 1;
1510 r_refdef.colormask[2] = 1;
1514 if (cls.signon == SIGNONS)
1515 R_TimeReport("other");
1517 CL_SetupScreenSize();
1521 if (cls.signon == SIGNONS)
1522 R_TimeReport("setup");
1524 //FIXME: force menu if nothing else to look at?
1525 //if (key_dest == key_game && cls.signon != SIGNONS && cls.state == ca_disconnected)
1527 if (cls.signon == SIGNONS)
1532 if (!r_letterbox.value)
1535 SCR_CheckDrawCenterString();
1541 if (cls.signon == SIGNONS)
1545 R_TimeReport_Start();
1547 R_Shadow_EditLights_DrawSelectedLightProperties();
1559 void CL_Screen_NewMap(void)