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);
408 len = (int)strlen(temp);
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_Frame(void)
543 if (r_speeds_string[0])
545 if (r_timereport_active)
546 R_TimeReport("total");
548 r_timereport_current = r_timereport_start;
549 j = (int)strlen(r_speeds_string);
550 if (r_timereport_active && j > 0)
552 if (r_speeds_string[j-1] == '\n')
553 r_speeds_string[j-1] = 0;
555 for (i = 0;r_speeds_string[i];i++)
556 if (r_speeds_string[i] == '\n')
558 y = vid_conheight.integer - sb_lines - lines * 8;
560 DrawQ_Fill(0, y, vid_conwidth.integer, lines * 8, 0, 0, 0, 0.5, 0);
561 while (r_speeds_string[i])
564 while (r_speeds_string[i] && r_speeds_string[i] != '\n')
567 DrawQ_String(0, y, r_speeds_string + j, i - j, 8, 8, 1, 1, 1, 1, 0);
568 if (r_speeds_string[i] == '\n')
573 r_speeds_string[0] = 0;
574 r_timereport_active = false;
576 if (r_speeds.integer && cls.signon == SIGNONS && cls.state == ca_connected)
578 speedstringcount = 0;
579 sprintf(r_speeds_string + strlen(r_speeds_string), "org:'%+8.2f %+8.2f %+8.2f' dir:'%+2.3f %+2.3f %+2.3f'\n", r_vieworigin[0], r_vieworigin[1], r_vieworigin[2], r_viewforward[0], r_viewforward[1], r_viewforward[2]);
580 sprintf(r_speeds_string + strlen(r_speeds_string), "%5i entities%6i surfaces%6i triangles%5i leafs%5i portals%6i particles\n", renderstats.entities, renderstats.entities_surfaces, renderstats.entities_triangles, renderstats.world_leafs, renderstats.world_portals, renderstats.particles);
581 sprintf(r_speeds_string + strlen(r_speeds_string), "%4i lights%4i clears%4i scissored%7i light%7i shadow%7i dynamic\n", renderstats.lights, renderstats.lights_clears, renderstats.lights_scissored, renderstats.lights_lighttriangles, renderstats.lights_shadowtriangles, renderstats.lights_dynamicshadowtriangles);
582 if (renderstats.bloom)
583 sprintf(r_speeds_string + strlen(r_speeds_string), "rendered%6i meshes%8i triangles bloompixels%8i copied%8i drawn\n", renderstats.meshes, renderstats.meshes_elements / 3, renderstats.bloom_copypixels, renderstats.bloom_drawpixels);
585 sprintf(r_speeds_string + strlen(r_speeds_string), "rendered%6i meshes%8i triangles\n", renderstats.meshes, renderstats.meshes_elements / 3);
587 memset(&renderstats, 0, sizeof(renderstats));
589 if (r_speeds.integer >= 2)
591 r_timereport_active = true;
592 r_timereport_start = Sys_DoubleTime();
604 void SCR_SizeUp_f (void)
606 Cvar_SetValue ("viewsize",scr_viewsize.value+10);
617 void SCR_SizeDown_f (void)
619 Cvar_SetValue ("viewsize",scr_viewsize.value-10);
622 void CL_Screen_Init(void)
624 Cvar_RegisterVariable (&scr_fov);
625 Cvar_RegisterVariable (&scr_viewsize);
626 Cvar_RegisterVariable (&scr_conspeed);
627 Cvar_RegisterVariable (&scr_conalpha);
628 Cvar_RegisterVariable (&scr_conbrightness);
629 Cvar_RegisterVariable (&scr_conforcewhiledisconnected);
630 Cvar_RegisterVariable (&scr_showram);
631 Cvar_RegisterVariable (&scr_showturtle);
632 Cvar_RegisterVariable (&scr_showpause);
633 Cvar_RegisterVariable (&scr_showbrand);
634 Cvar_RegisterVariable (&scr_centertime);
635 Cvar_RegisterVariable (&scr_printspeed);
636 Cvar_RegisterVariable (&vid_conwidth);
637 Cvar_RegisterVariable (&vid_conheight);
638 Cvar_RegisterVariable (&vid_pixelheight);
639 Cvar_RegisterVariable (&scr_screenshot_jpeg);
640 Cvar_RegisterVariable (&scr_screenshot_jpeg_quality);
641 Cvar_RegisterVariable (&scr_screenshot_gamma);
642 Cvar_RegisterVariable (&cl_capturevideo);
643 Cvar_RegisterVariable (&cl_capturevideo_sound);
644 Cvar_RegisterVariable (&cl_capturevideo_fps);
645 Cvar_RegisterVariable (&cl_capturevideo_rawrgb);
646 Cvar_RegisterVariable (&cl_capturevideo_rawyv12);
647 Cvar_RegisterVariable (&r_textshadow);
648 Cvar_RegisterVariable (&r_letterbox);
650 Cmd_AddCommand ("sizeup",SCR_SizeUp_f, "increase view size (increases viewsize cvar)");
651 Cmd_AddCommand ("sizedown",SCR_SizeDown_f, "decrease view size (decreases viewsize cvar)");
652 Cmd_AddCommand ("screenshot",SCR_ScreenShot_f, "takes a screenshot of the next rendered frame");
653 Cmd_AddCommand ("envmap", R_Envmap_f, "render a cubemap (skybox) of the current scene");
655 scr_initialized = true;
658 void DrawQ_Clear(void)
660 r_refdef.drawqueuesize = 0;
663 static int picelements[6] = {0, 1, 2, 0, 2, 3};
664 void DrawQ_Pic(float x, float y, const char *picname, float width, float height, float red, float green, float blue, float alpha, int flags)
666 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);
669 void DrawQ_String_Real(float x, float y, const char *string, int maxlen, float scalex, float scaley, float red, float green, float blue, float alpha, int flags)
674 if (alpha < (1.0f / 255.0f))
677 len = (int)strlen(string);
679 for (len = 0;len < maxlen && string[len];len++);
680 for (;len > 0 && string[0] == ' ';string++, x += scalex, len--);
681 for (;len > 0 && string[len - 1] == ' ';len--);
684 if (x >= vid_conwidth.integer || y >= vid_conheight.integer || x < (-scalex * len) || y < (-scaley))
686 size = sizeof(*dq) + ((len + 1 + 3) & ~3);
687 if (r_refdef.drawqueuesize + size > r_refdef.maxdrawqueuesize)
689 red = bound(0, red, 1);
690 green = bound(0, green, 1);
691 blue = bound(0, blue, 1);
692 alpha = bound(0, alpha, 1);
693 dq = (drawqueue_t *)(r_refdef.drawqueue + r_refdef.drawqueuesize);
695 dq->command = DRAWQUEUE_STRING;
697 dq->color = ((unsigned int) (red * 255.0f) << 24) | ((unsigned int) (green * 255.0f) << 16) | ((unsigned int) (blue * 255.0f) << 8) | ((unsigned int) (alpha * 255.0f));
702 out = (char *)(dq + 1);
703 memcpy(out, string, len);
705 r_refdef.drawqueuesize += dq->size;
708 void DrawQ_String(float x, float y, const char *string, int maxlen, float scalex, float scaley, float red, float green, float blue, float alpha, int flags)
710 if (r_textshadow.integer)
711 DrawQ_String_Real(x+scalex*0.25,y+scaley*0.25,string,maxlen,scalex,scaley,0,0,0,alpha*0.8,flags);
713 DrawQ_String_Real(x,y,string,maxlen,scalex,scaley,red,green,blue,alpha,flags);
718 void DrawQ_Fill (float x, float y, float w, float h, float red, float green, float blue, float alpha, int flags)
720 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);
723 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)
727 drawqueuemesh_t mesh;
728 memset(&mesh, 0, sizeof(mesh));
729 if (picname && picname[0])
731 pic = Draw_CachePic(picname, false);
735 height = pic->height;
736 mesh.texture = pic->tex;
738 mesh.num_triangles = 2;
739 mesh.num_vertices = 4;
740 mesh.data_element3i = picelements;
741 mesh.data_vertex3f = floats;
742 mesh.data_texcoord2f = floats + 12;
743 mesh.data_color4f = floats + 20;
744 memset(floats, 0, sizeof(floats));
745 mesh.data_vertex3f[0] = mesh.data_vertex3f[9] = x;
746 mesh.data_vertex3f[1] = mesh.data_vertex3f[4] = y;
747 mesh.data_vertex3f[3] = mesh.data_vertex3f[6] = x + width;
748 mesh.data_vertex3f[7] = mesh.data_vertex3f[10] = y + height;
749 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;
750 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;
751 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;
752 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;
753 DrawQ_Mesh (&mesh, flags);
756 void DrawQ_Mesh (drawqueuemesh_t *mesh, int flags)
763 size += sizeof(drawqueuemesh_t);
764 size += sizeof(int[3]) * mesh->num_triangles;
765 size += sizeof(float[3]) * mesh->num_vertices;
766 size += sizeof(float[2]) * mesh->num_vertices;
767 size += sizeof(float[4]) * mesh->num_vertices;
768 if (r_refdef.drawqueuesize + size > r_refdef.maxdrawqueuesize)
770 dq = (drawqueue_t *)(r_refdef.drawqueue + r_refdef.drawqueuesize);
772 dq->command = DRAWQUEUE_MESH;
779 p = (void *)(dq + 1);
780 m = (drawqueuemesh_t *)p;p = (unsigned char*)p + sizeof(drawqueuemesh_t);
781 m->num_triangles = mesh->num_triangles;
782 m->num_vertices = mesh->num_vertices;
783 m->texture = mesh->texture;
784 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]);
785 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]);
786 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]);
787 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]);
788 r_refdef.drawqueuesize += dq->size;
791 void DrawQ_LineLoop (drawqueuemesh_t *mesh, int flags)
798 size += sizeof(drawqueuemesh_t);
799 size += sizeof(int[3]) * mesh->num_triangles;
800 size += sizeof(float[3]) * mesh->num_vertices;
801 size += sizeof(float[2]) * mesh->num_vertices;
802 size += sizeof(float[4]) * mesh->num_vertices;
803 if (r_refdef.drawqueuesize + size > r_refdef.maxdrawqueuesize)
805 dq = (void *)(r_refdef.drawqueue + r_refdef.drawqueuesize);
807 dq->command = DRAWQUEUE_LINES;
814 p = (void *)(dq + 1);
815 m = p;p = (unsigned char*)p + sizeof(drawqueuemesh_t);
816 m->num_triangles = mesh->num_triangles;
817 m->num_vertices = mesh->num_vertices;
818 m->texture = mesh->texture;
819 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]);
820 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]);
821 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]);
822 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]);
823 r_refdef.drawqueuesize += dq->size;
826 //LordHavoc: FIXME: this is nasty!
827 void DrawQ_LineWidth (float width)
830 static int linewidth = 1;
831 if(width == linewidth)
834 if(r_refdef.drawqueuesize + (int)sizeof(*dq) > r_refdef.maxdrawqueuesize)
836 Con_DPrint("DrawQueue full !\n");
839 dq = (void*) (r_refdef.drawqueue + r_refdef.drawqueuesize);
840 dq->size = sizeof(*dq);
841 dq->command = DRAWQUEUE_LINEWIDTH;
844 r_refdef.drawqueuesize += dq->size;
847 //[515]: this is old, delete
848 void DrawQ_Line (float width, float x1, float y1, float x2, float y2, float r, float g, float b, float alpha, int flags)
852 DrawQ_LineWidth(width);
853 if(r_refdef.drawqueuesize + (int)sizeof(*dq) > r_refdef.maxdrawqueuesize)
855 Con_DPrint("DrawQueue full !\n");
858 dq = (void*) (r_refdef.drawqueue + r_refdef.drawqueuesize);
859 dq->size = sizeof(*dq);
860 dq->command = DRAWQUEUE_LINES;
866 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));
868 r_refdef.drawqueuesize += dq->size;
871 void DrawQ_SetClipArea(float x, float y, float width, float height)
874 if(r_refdef.drawqueuesize + (int)sizeof(*dq) > r_refdef.maxdrawqueuesize)
876 Con_DPrint("DrawQueue full !\n");
879 dq = (drawqueue_t *) (r_refdef.drawqueue + r_refdef.drawqueuesize);
880 dq->size = sizeof(*dq);
881 dq->command = DRAWQUEUE_SETCLIP;
889 r_refdef.drawqueuesize += dq->size;
892 void DrawQ_ResetClipArea(void)
895 if(r_refdef.drawqueuesize + (int)sizeof(*dq) > r_refdef.maxdrawqueuesize)
897 Con_DPrint("DrawQueue full !\n");
900 dq = (drawqueue_t *) (r_refdef.drawqueue + r_refdef.drawqueuesize);
901 dq->size = sizeof(*dq);
902 dq->command = DRAWQUEUE_RESETCLIP;
910 r_refdef.drawqueuesize += dq->size;
918 void SCR_ScreenShot_f (void)
920 static int shotnumber;
921 static char oldname[MAX_QPATH];
922 char base[MAX_QPATH];
923 char filename[MAX_QPATH];
924 unsigned char *buffer1;
925 unsigned char *buffer2;
926 unsigned char *buffer3;
927 qboolean jpeg = (scr_screenshot_jpeg.integer != 0);
929 sprintf (base, "screenshots/%s", scr_screenshot_name.string);
931 if (strcmp (oldname, scr_screenshot_name.string))
933 sprintf(oldname, "%s", scr_screenshot_name.string);
937 // find a file name to save it to
938 for (;shotnumber < 1000000;shotnumber++)
939 if (!FS_SysFileExists(va("%s/%s%06d.tga", fs_gamedir, base, shotnumber)) && !FS_SysFileExists(va("%s/%s%06d.jpg", fs_gamedir, base, shotnumber)))
941 if (shotnumber >= 1000000)
943 Con_Print("SCR_ScreenShot_f: Couldn't create the image file\n");
947 sprintf(filename, "%s%06d.%s", base, shotnumber, jpeg ? "jpg" : "tga");
949 buffer1 = (unsigned char *)Mem_Alloc(tempmempool, vid.width * vid.height * 3);
950 buffer2 = (unsigned char *)Mem_Alloc(tempmempool, vid.width * vid.height * 3);
951 buffer3 = (unsigned char *)Mem_Alloc(tempmempool, vid.width * vid.height * 3 + 18);
953 if (SCR_ScreenShot (filename, buffer1, buffer2, buffer3, 0, 0, vid.width, vid.height, false, false, false, jpeg, true))
954 Con_Printf("Wrote %s\n", filename);
956 Con_Printf("unable to write %s\n", filename);
965 typedef enum capturevideoformat_e
967 CAPTUREVIDEOFORMAT_TARGA,
968 CAPTUREVIDEOFORMAT_JPEG,
969 CAPTUREVIDEOFORMAT_RAWRGB,
970 CAPTUREVIDEOFORMAT_RAWYV12
972 capturevideoformat_t;
974 qboolean cl_capturevideo_active = false;
975 capturevideoformat_t cl_capturevideo_format;
976 static double cl_capturevideo_starttime = 0;
977 double cl_capturevideo_framerate = 0;
978 static int cl_capturevideo_soundrate = 0;
979 static int cl_capturevideo_frame = 0;
980 static unsigned char *cl_capturevideo_buffer = NULL;
981 static qfile_t *cl_capturevideo_videofile = NULL;
982 qfile_t *cl_capturevideo_soundfile = NULL;
983 static short cl_capturevideo_rgbtoyuvscaletable[3][3][256];
984 static unsigned char cl_capturevideo_yuvnormalizetable[3][256];
985 //static unsigned char cl_capturevideo_rgbgammatable[3][256];
987 void SCR_CaptureVideo_BeginVideo(void)
991 unsigned char out[44];
992 if (cl_capturevideo_active)
994 // soundrate is figured out on the first SoundFrame
995 cl_capturevideo_active = true;
996 cl_capturevideo_starttime = Sys_DoubleTime();
997 cl_capturevideo_framerate = bound(1, cl_capturevideo_fps.value, 1000);
998 cl_capturevideo_soundrate = 0;
999 cl_capturevideo_frame = 0;
1000 cl_capturevideo_buffer = (unsigned char *)Mem_Alloc(tempmempool, vid.width * vid.height * (3+3+3) + 18);
1001 gamma = 1.0/scr_screenshot_gamma.value;
1004 for (i = 0;i < 256;i++)
1006 unsigned char j = (unsigned char)bound(0, 255*pow(i/255.0, gamma), 255);
1007 cl_capturevideo_rgbgammatable[0][i] = j;
1008 cl_capturevideo_rgbgammatable[1][i] = j;
1009 cl_capturevideo_rgbgammatable[2][i] = j;
1013 R = Y + 1.4075 * (Cr - 128);
1014 G = Y + -0.3455 * (Cb - 128) + -0.7169 * (Cr - 128);
1015 B = Y + 1.7790 * (Cb - 128);
1016 Y = R * .299 + G * .587 + B * .114;
1017 Cb = R * -.169 + G * -.332 + B * .500 + 128.;
1018 Cr = R * .500 + G * -.419 + B * -.0813 + 128.;
1020 for (i = 0;i < 256;i++)
1022 g = 255*pow(i/255.0, gamma);
1023 // Y weights from RGB
1024 cl_capturevideo_rgbtoyuvscaletable[0][0][i] = (short)(g * 0.299);
1025 cl_capturevideo_rgbtoyuvscaletable[0][1][i] = (short)(g * 0.587);
1026 cl_capturevideo_rgbtoyuvscaletable[0][2][i] = (short)(g * 0.114);
1027 // Cb weights from RGB
1028 cl_capturevideo_rgbtoyuvscaletable[1][0][i] = (short)(g * -0.169);
1029 cl_capturevideo_rgbtoyuvscaletable[1][1][i] = (short)(g * -0.332);
1030 cl_capturevideo_rgbtoyuvscaletable[1][2][i] = (short)(g * 0.500);
1031 // Cr weights from RGB
1032 cl_capturevideo_rgbtoyuvscaletable[2][0][i] = (short)(g * 0.500);
1033 cl_capturevideo_rgbtoyuvscaletable[2][1][i] = (short)(g * -0.419);
1034 cl_capturevideo_rgbtoyuvscaletable[2][2][i] = (short)(g * -0.0813);
1035 // range reduction of YCbCr to valid signal range
1036 cl_capturevideo_yuvnormalizetable[0][i] = 16 + i * (236-16) / 256;
1037 cl_capturevideo_yuvnormalizetable[1][i] = 16 + i * (240-16) / 256;
1038 cl_capturevideo_yuvnormalizetable[2][i] = 16 + i * (240-16) / 256;
1041 if (cl_capturevideo_rawrgb.integer)
1043 cl_capturevideo_format = CAPTUREVIDEOFORMAT_RAWRGB;
1044 cl_capturevideo_videofile = FS_Open ("video/dpvideo.rgb", "wb", false, true);
1046 else if (cl_capturevideo_rawyv12.integer)
1048 cl_capturevideo_format = CAPTUREVIDEOFORMAT_RAWYV12;
1049 cl_capturevideo_videofile = FS_Open ("video/dpvideo.yv12", "wb", false, true);
1051 else if (scr_screenshot_jpeg.integer)
1053 cl_capturevideo_format = CAPTUREVIDEOFORMAT_JPEG;
1054 cl_capturevideo_videofile = NULL;
1058 cl_capturevideo_format = CAPTUREVIDEOFORMAT_TARGA;
1059 cl_capturevideo_videofile = NULL;
1062 if (cl_capturevideo_sound.integer)
1064 cl_capturevideo_soundfile = FS_Open ("video/dpvideo.wav", "wb", false, true);
1065 // wave header will be filled out when video ends
1067 FS_Write (cl_capturevideo_soundfile, out, 44);
1070 cl_capturevideo_soundfile = NULL;
1073 void SCR_CaptureVideo_EndVideo(void)
1076 unsigned char out[44];
1077 if (!cl_capturevideo_active)
1079 cl_capturevideo_active = false;
1081 if (cl_capturevideo_videofile)
1083 FS_Close(cl_capturevideo_videofile);
1084 cl_capturevideo_videofile = NULL;
1087 // finish the wave file
1088 if (cl_capturevideo_soundfile)
1090 i = (int)FS_Tell (cl_capturevideo_soundfile);
1091 //"RIFF", (int) unknown (chunk size), "WAVE",
1092 //"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
1093 //"data", (int) unknown (chunk size)
1094 memcpy (out, "RIFF****WAVEfmt \x10\x00\x00\x00\x01\x00\x02\x00********\x04\x00\x10\0data****", 44);
1095 // the length of the whole RIFF chunk
1097 out[4] = (n) & 0xFF;
1098 out[5] = (n >> 8) & 0xFF;
1099 out[6] = (n >> 16) & 0xFF;
1100 out[7] = (n >> 24) & 0xFF;
1102 n = cl_capturevideo_soundrate;
1103 out[24] = (n) & 0xFF;
1104 out[25] = (n >> 8) & 0xFF;
1105 out[26] = (n >> 16) & 0xFF;
1106 out[27] = (n >> 24) & 0xFF;
1107 // bytes per second (rate * channels * bytes per channel)
1108 n = cl_capturevideo_soundrate * 2 * 2;
1109 out[28] = (n) & 0xFF;
1110 out[29] = (n >> 8) & 0xFF;
1111 out[30] = (n >> 16) & 0xFF;
1112 out[31] = (n >> 24) & 0xFF;
1113 // the length of the data chunk
1115 out[40] = (n) & 0xFF;
1116 out[41] = (n >> 8) & 0xFF;
1117 out[42] = (n >> 16) & 0xFF;
1118 out[43] = (n >> 24) & 0xFF;
1119 FS_Seek (cl_capturevideo_soundfile, 0, SEEK_SET);
1120 FS_Write (cl_capturevideo_soundfile, out, 44);
1121 FS_Close (cl_capturevideo_soundfile);
1122 cl_capturevideo_soundfile = NULL;
1125 if (cl_capturevideo_buffer)
1127 Mem_Free (cl_capturevideo_buffer);
1128 cl_capturevideo_buffer = NULL;
1131 cl_capturevideo_starttime = 0;
1132 cl_capturevideo_framerate = 0;
1133 cl_capturevideo_frame = 0;
1136 qboolean SCR_CaptureVideo_VideoFrame(int newframenum)
1138 int x = 0, y = 0, width = vid.width, height = vid.height;
1139 unsigned char *b, *out;
1141 int outoffset = (width/2)*(height/2);
1142 //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);
1143 // speed is critical here, so do saving as directly as possible
1144 switch (cl_capturevideo_format)
1146 case CAPTUREVIDEOFORMAT_RAWYV12:
1147 // FIXME: width/height must be multiple of 2, enforce this?
1148 qglReadPixels (x, y, width, height, GL_RGB, GL_UNSIGNED_BYTE, cl_capturevideo_buffer);
1150 // process one line at a time, and CbCr every other line at 2 pixel intervals
1151 for (y = 0;y < height;y++)
1154 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++)
1155 *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]]];
1158 // 2x2 Cb and Cr planes
1160 // low quality, no averaging
1161 for (b = cl_capturevideo_buffer + (height-2-y)*width*3, out = cl_capturevideo_buffer + width*height*3 + width*height + (y/2)*(width/2), x = 0;x < width/2;x++, b += 6, out++)
1164 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];
1166 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];
1169 // high quality, averaging
1170 int inpitch = width*3;
1171 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++)
1173 int blockr, blockg, blockb;
1174 blockr = (b[0] + b[3] + b[inpitch+0] + b[inpitch+3]) >> 2;
1175 blockg = (b[1] + b[4] + b[inpitch+1] + b[inpitch+4]) >> 2;
1176 blockb = (b[2] + b[5] + b[inpitch+2] + b[inpitch+5]) >> 2;
1178 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];
1180 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];
1185 for (;cl_capturevideo_frame < newframenum;cl_capturevideo_frame++)
1186 if (!FS_Write (cl_capturevideo_videofile, cl_capturevideo_buffer + width*height*3, width*height+(width/2)*(height/2)*2))
1189 case CAPTUREVIDEOFORMAT_RAWRGB:
1190 qglReadPixels (x, y, width, height, GL_RGB, GL_UNSIGNED_BYTE, cl_capturevideo_buffer);
1192 for (;cl_capturevideo_frame < newframenum;cl_capturevideo_frame++)
1193 if (!FS_Write (cl_capturevideo_videofile, cl_capturevideo_buffer, width*height*3))
1196 case CAPTUREVIDEOFORMAT_JPEG:
1197 qglReadPixels (x, y, width, height, GL_RGB, GL_UNSIGNED_BYTE, cl_capturevideo_buffer);
1199 for (;cl_capturevideo_frame < newframenum;cl_capturevideo_frame++)
1201 sprintf(filename, "video/dp%06d.jpg", cl_capturevideo_frame);
1202 if (!JPEG_SaveImage_preflipped (filename, width, height, cl_capturevideo_buffer))
1206 case CAPTUREVIDEOFORMAT_TARGA:
1207 //return Image_WriteTGARGB_preflipped (filename, width, height, cl_capturevideo_buffer, cl_capturevideo_buffer + vid.width * vid.height * 3, );
1208 memset (cl_capturevideo_buffer, 0, 18);
1209 cl_capturevideo_buffer[2] = 2; // uncompressed type
1210 cl_capturevideo_buffer[12] = (width >> 0) & 0xFF;
1211 cl_capturevideo_buffer[13] = (width >> 8) & 0xFF;
1212 cl_capturevideo_buffer[14] = (height >> 0) & 0xFF;
1213 cl_capturevideo_buffer[15] = (height >> 8) & 0xFF;
1214 cl_capturevideo_buffer[16] = 24; // pixel size
1215 qglReadPixels (x, y, width, height, GL_BGR, GL_UNSIGNED_BYTE, cl_capturevideo_buffer + 18);
1217 for (;cl_capturevideo_frame < newframenum;cl_capturevideo_frame++)
1219 sprintf(filename, "video/dp%06d.tga", cl_capturevideo_frame);
1220 if (!FS_WriteFile (filename, cl_capturevideo_buffer, width*height*3 + 18))
1229 void SCR_CaptureVideo_SoundFrame(unsigned char *bufstereo16le, size_t length, int rate)
1231 if (!cl_capturevideo_soundfile)
1233 cl_capturevideo_soundrate = rate;
1234 if (FS_Write (cl_capturevideo_soundfile, bufstereo16le, 4 * length) < (fs_offset_t)(4 * length))
1236 Cvar_SetValueQuick(&cl_capturevideo, 0);
1237 Con_Printf("video sound saving failed on frame %i, out of disk space? stopping video capture.\n", cl_capturevideo_frame);
1238 SCR_CaptureVideo_EndVideo();
1242 void SCR_CaptureVideo(void)
1245 if (cl_capturevideo.integer && r_render.integer)
1247 if (!cl_capturevideo_active)
1248 SCR_CaptureVideo_BeginVideo();
1249 if (cl_capturevideo_framerate != cl_capturevideo_fps.value)
1251 Con_Printf("You can not change the video framerate while recording a video.\n");
1252 Cvar_SetValueQuick(&cl_capturevideo_fps, cl_capturevideo_framerate);
1254 if (cl_capturevideo_soundfile)
1256 // preserve sound sync by duplicating frames when running slow
1257 newframenum = (Sys_DoubleTime() - cl_capturevideo_starttime) * cl_capturevideo_framerate;
1260 newframenum = cl_capturevideo_frame + 1;
1261 // if falling behind more than one second, stop
1262 if (newframenum - cl_capturevideo_frame > (int)ceil(cl_capturevideo_framerate))
1264 Cvar_SetValueQuick(&cl_capturevideo, 0);
1265 Con_Printf("video saving failed on frame %i, your machine is too slow for this capture speed.\n", cl_capturevideo_frame);
1266 SCR_CaptureVideo_EndVideo();
1270 if (!SCR_CaptureVideo_VideoFrame(newframenum))
1272 Cvar_SetValueQuick(&cl_capturevideo, 0);
1273 Con_Printf("video saving failed on frame %i, out of disk space? stopping video capture.\n", cl_capturevideo_frame);
1274 SCR_CaptureVideo_EndVideo();
1277 else if (cl_capturevideo_active)
1278 SCR_CaptureVideo_EndVideo();
1285 Grab six views for environment mapping tests
1292 qboolean flipx, flipy, flipdiagonaly;
1296 {{ 0, 0, 0}, "rt", false, false, false},
1297 {{ 0, 270, 0}, "ft", false, false, false},
1298 {{ 0, 180, 0}, "lf", false, false, false},
1299 {{ 0, 90, 0}, "bk", false, false, false},
1300 {{-90, 180, 0}, "up", true, true, false},
1301 {{ 90, 180, 0}, "dn", true, true, false},
1303 {{ 0, 0, 0}, "px", true, true, true},
1304 {{ 0, 90, 0}, "py", false, true, false},
1305 {{ 0, 180, 0}, "nx", false, false, true},
1306 {{ 0, 270, 0}, "ny", true, false, false},
1307 {{-90, 180, 0}, "pz", false, false, true},
1308 {{ 90, 180, 0}, "nz", false, false, true}
1311 static void R_Envmap_f (void)
1314 char filename[MAX_QPATH], basename[MAX_QPATH];
1315 unsigned char *buffer1;
1316 unsigned char *buffer2;
1317 unsigned char *buffer3;
1319 if (Cmd_Argc() != 3)
1321 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");
1325 strlcpy (basename, Cmd_Argv(1), sizeof (basename));
1326 size = atoi(Cmd_Argv(2));
1327 if (size != 128 && size != 256 && size != 512 && size != 1024)
1329 Con_Print("envmap: size must be one of 128, 256, 512, or 1024\n");
1332 if (size > vid.width || size > vid.height)
1334 Con_Print("envmap: your resolution is not big enough to render that size\n");
1342 r_refdef.width = size;
1343 r_refdef.height = size;
1345 r_refdef.frustum_x = tan(90 * M_PI / 360.0);
1346 r_refdef.frustum_y = tan(90 * M_PI / 360.0);
1348 buffer1 = (unsigned char *)Mem_Alloc(tempmempool, size * size * 3);
1349 buffer2 = (unsigned char *)Mem_Alloc(tempmempool, size * size * 3);
1350 buffer3 = (unsigned char *)Mem_Alloc(tempmempool, size * size * 3 + 18);
1352 for (j = 0;j < 12;j++)
1354 sprintf(filename, "env/%s%s.tga", basename, envmapinfo[j].name);
1355 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);
1360 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);
1370 //=============================================================================
1372 // LordHavoc: SHOWLMP stuff
1373 #define SHOWLMP_MAXLABELS 256
1374 typedef struct showlmp_s
1384 showlmp_t showlmp[SHOWLMP_MAXLABELS];
1386 void SHOWLMP_decodehide(void)
1390 lmplabel = MSG_ReadString();
1391 for (i = 0;i < SHOWLMP_MAXLABELS;i++)
1392 if (showlmp[i].isactive && strcmp(showlmp[i].label, lmplabel) == 0)
1394 showlmp[i].isactive = false;
1399 void SHOWLMP_decodeshow(void)
1402 char lmplabel[256], picname[256];
1404 strlcpy (lmplabel,MSG_ReadString(), sizeof (lmplabel));
1405 strlcpy (picname, MSG_ReadString(), sizeof (picname));
1406 if (gamemode == GAME_NEHAHRA) // LordHavoc: nasty old legacy junk
1413 x = MSG_ReadShort();
1414 y = MSG_ReadShort();
1417 for (i = 0;i < SHOWLMP_MAXLABELS;i++)
1418 if (showlmp[i].isactive)
1420 if (strcmp(showlmp[i].label, lmplabel) == 0)
1423 break; // drop out to replace it
1426 else if (k < 0) // find first empty one to replace
1429 return; // none found to replace
1430 // change existing one
1431 showlmp[k].isactive = true;
1432 strlcpy (showlmp[k].label, lmplabel, sizeof (showlmp[k].label));
1433 strlcpy (showlmp[k].pic, picname, sizeof (showlmp[k].pic));
1438 void SHOWLMP_drawall(void)
1441 for (i = 0;i < SHOWLMP_MAXLABELS;i++)
1442 if (showlmp[i].isactive)
1443 DrawQ_Pic(showlmp[i].x, showlmp[i].y, showlmp[i].pic, 0, 0, 1, 1, 1, 1, 0);
1446 void SHOWLMP_clear(void)
1449 for (i = 0;i < SHOWLMP_MAXLABELS;i++)
1450 showlmp[i].isactive = false;
1453 void CL_SetupScreenSize(void)
1455 float conwidth, conheight;
1457 VID_UpdateGamma(false);
1459 conwidth = bound(320, vid_conwidth.value, 2048);
1460 conheight = bound(200, vid_conheight.value, 1536);
1461 if (vid_conwidth.value != conwidth)
1462 Cvar_SetValue("vid_conwidth", conwidth);
1463 if (vid_conheight.value != conheight)
1464 Cvar_SetValue("vid_conheight", conheight);
1466 vid_conwidth.integer = vid_conwidth.integer;
1467 vid_conheight.integer = vid_conheight.integer;
1469 SCR_SetUpToDrawConsole();
1472 extern void R_Shadow_EditLights_DrawSelectedLightProperties(void);
1473 void CL_UpdateScreen(void)
1475 if (!scr_initialized || !con_initialized || vid_hidden)
1476 return; // not initialized yet
1478 // don't allow cheats in multiplayer
1479 if (!cl.islocalgame && cl.worldmodel)
1481 if (r_fullbright.integer != 0)
1482 Cvar_Set ("r_fullbright", "0");
1483 if (r_ambient.value != 0)
1484 Cvar_Set ("r_ambient", "0");
1488 if (scr_viewsize.value < 30)
1489 Cvar_Set ("viewsize","30");
1490 if (scr_viewsize.value > 120)
1491 Cvar_Set ("viewsize","120");
1493 // bound field of view
1494 if (scr_fov.value < 1)
1495 Cvar_Set ("fov","1");
1496 if (scr_fov.value > 170)
1497 Cvar_Set ("fov","170");
1499 // intermission is always full screen
1500 if (cl.intermission)
1504 if (scr_viewsize.value >= 120)
1505 sb_lines = 0; // no status bar at all
1506 else if (scr_viewsize.value >= 110)
1507 sb_lines = 24; // no inventory
1512 r_refdef.colormask[0] = 1;
1513 r_refdef.colormask[1] = 1;
1514 r_refdef.colormask[2] = 1;
1518 if (r_timereport_active)
1519 R_TimeReport("other");
1521 CL_SetupScreenSize();
1525 if (r_timereport_active)
1526 R_TimeReport("setup");
1528 //FIXME: force menu if nothing else to look at?
1529 //if (key_dest == key_game && cls.signon != SIGNONS && cls.state == ca_disconnected)
1531 if (cls.signon == SIGNONS)
1536 if (!r_letterbox.value)
1539 SCR_CheckDrawCenterString();
1545 if (cls.signon == SIGNONS)
1547 if (r_timereport_active)
1549 R_TimeReport_Frame();
1551 R_Shadow_EditLights_DrawSelectedLightProperties();
1563 void CL_Screen_NewMap(void)