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);
394 //=============================================================================
399 SCR_SetUpToDrawConsole
402 void SCR_SetUpToDrawConsole (void)
404 // lines of console to display
409 if (key_dest == key_game && cls.signon != SIGNONS && scr_conforcewhiledisconnected.integer)
410 key_consoleactive |= KEY_CONSOLEACTIVE_FORCED;
412 key_consoleactive &= ~KEY_CONSOLEACTIVE_FORCED;
414 // decide on the height of the console
415 if (key_consoleactive & KEY_CONSOLEACTIVE_USER)
416 conlines = vid_conheight.integer/2; // half screen
418 conlines = 0; // none visible
420 if (scr_conspeed.value)
422 if (scr_con_current > conlines)
424 scr_con_current -= scr_conspeed.value*host_realframetime;
425 if (scr_con_current < conlines)
426 scr_con_current = conlines;
429 else if (scr_con_current < conlines)
431 scr_con_current += scr_conspeed.value*host_realframetime;
432 if (scr_con_current > conlines)
433 scr_con_current = conlines;
437 scr_con_current = conlines;
445 void SCR_DrawConsole (void)
447 if (key_consoleactive & KEY_CONSOLEACTIVE_FORCED)
450 Con_DrawConsole (vid_conheight.integer);
452 else if (scr_con_current)
453 Con_DrawConsole (scr_con_current);
457 if (key_dest == key_game || key_dest == key_message)
458 Con_DrawNotify (); // only draw notify in game
464 SCR_BeginLoadingPlaque
468 void SCR_BeginLoadingPlaque (void)
472 SCR_UpdateLoadingScreen();
475 //=============================================================================
477 char r_speeds_string[1024];
478 int speedstringcount, r_timereport_active;
479 double r_timereport_temp = 0, r_timereport_current = 0, r_timereport_start = 0;
481 void R_TimeReport(char *desc)
487 if (!r_timereport_active || r_showtrispass)
491 r_timereport_temp = r_timereport_current;
492 r_timereport_current = Sys_DoubleTime();
493 t = (int) ((r_timereport_current - r_timereport_temp) * 1000000.0);
495 dpsnprintf(tempbuf, sizeof(tempbuf), "%8i %s", t, desc);
496 length = (int)strlen(tempbuf);
498 tempbuf[length++] = ' ';
500 if (speedstringcount + length > (vid_conwidth.integer / 8))
502 strlcat(r_speeds_string, "\n", sizeof(r_speeds_string));
503 speedstringcount = 0;
505 // skip the space at the beginning if it's the first on the line
506 if (speedstringcount == 0)
508 strlcat(r_speeds_string, tempbuf + 1, sizeof(r_speeds_string));
509 speedstringcount = length - 1;
513 strlcat(r_speeds_string, tempbuf, sizeof(r_speeds_string));
514 speedstringcount += length;
518 void R_TimeReport_Start(void)
520 r_timereport_active = r_speeds.integer && cls.signon == SIGNONS && cls.state == ca_connected;
521 r_speeds_string[0] = 0;
522 if (r_timereport_active)
524 speedstringcount = 0;
525 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]);
526 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);
527 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);
528 if (renderstats.bloom)
529 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);
531 sprintf(r_speeds_string + strlen(r_speeds_string), "rendered%6i meshes%8i triangles\n", renderstats.meshes, renderstats.meshes_elements / 3);
533 r_timereport_start = Sys_DoubleTime();
536 memset(&renderstats, 0, sizeof(renderstats));
539 void R_TimeReport_End(void)
541 r_timereport_current = r_timereport_start;
542 R_TimeReport("total");
544 if (r_timereport_active)
548 for (i = 0;r_speeds_string[i];i++)
549 if (r_speeds_string[i] == '\n')
551 y = vid_conheight.integer - sb_lines - lines * 8;
553 DrawQ_Fill(0, y, vid_conwidth.integer, lines * 8, 0, 0, 0, 0.5, 0);
554 while (r_speeds_string[i])
557 while (r_speeds_string[i] && r_speeds_string[i] != '\n')
560 DrawQ_String(0, y, r_speeds_string + j, i - j, 8, 8, 1, 1, 1, 1, 0);
561 if (r_speeds_string[i] == '\n')
575 void SCR_SizeUp_f (void)
577 Cvar_SetValue ("viewsize",scr_viewsize.value+10);
588 void SCR_SizeDown_f (void)
590 Cvar_SetValue ("viewsize",scr_viewsize.value-10);
593 void CL_Screen_Init(void)
595 Cvar_RegisterVariable (&scr_fov);
596 Cvar_RegisterVariable (&scr_viewsize);
597 Cvar_RegisterVariable (&scr_conspeed);
598 Cvar_RegisterVariable (&scr_conalpha);
599 Cvar_RegisterVariable (&scr_conbrightness);
600 Cvar_RegisterVariable (&scr_conforcewhiledisconnected);
601 Cvar_RegisterVariable (&scr_showram);
602 Cvar_RegisterVariable (&scr_showturtle);
603 Cvar_RegisterVariable (&scr_showpause);
604 Cvar_RegisterVariable (&scr_showbrand);
605 Cvar_RegisterVariable (&scr_centertime);
606 Cvar_RegisterVariable (&scr_printspeed);
607 Cvar_RegisterVariable (&vid_conwidth);
608 Cvar_RegisterVariable (&vid_conheight);
609 Cvar_RegisterVariable (&vid_pixelheight);
610 Cvar_RegisterVariable (&scr_screenshot_jpeg);
611 Cvar_RegisterVariable (&scr_screenshot_jpeg_quality);
612 Cvar_RegisterVariable (&scr_screenshot_gamma);
613 Cvar_RegisterVariable (&cl_capturevideo);
614 Cvar_RegisterVariable (&cl_capturevideo_sound);
615 Cvar_RegisterVariable (&cl_capturevideo_fps);
616 Cvar_RegisterVariable (&cl_capturevideo_rawrgb);
617 Cvar_RegisterVariable (&cl_capturevideo_rawyv12);
618 Cvar_RegisterVariable (&r_textshadow);
619 Cvar_RegisterVariable (&r_letterbox);
621 Cmd_AddCommand ("sizeup",SCR_SizeUp_f, "increase view size (increases viewsize cvar)");
622 Cmd_AddCommand ("sizedown",SCR_SizeDown_f, "decrease view size (decreases viewsize cvar)");
623 Cmd_AddCommand ("screenshot",SCR_ScreenShot_f, "takes a screenshot of the next rendered frame");
624 Cmd_AddCommand ("envmap", R_Envmap_f, "render a cubemap (skybox) of the current scene");
626 scr_initialized = true;
629 void DrawQ_Clear(void)
631 r_refdef.drawqueuesize = 0;
634 static int picelements[6] = {0, 1, 2, 0, 2, 3};
635 void DrawQ_Pic(float x, float y, const char *picname, float width, float height, float red, float green, float blue, float alpha, int flags)
637 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);
640 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)
645 if (alpha < (1.0f / 255.0f))
648 len = (int)strlen(string);
650 for (len = 0;len < maxlen && string[len];len++);
651 for (;len > 0 && string[0] == ' ';string++, x += scalex, len--);
652 for (;len > 0 && string[len - 1] == ' ';len--);
655 if (x >= vid_conwidth.integer || y >= vid_conheight.integer || x < (-scalex * len) || y < (-scaley))
657 size = sizeof(*dq) + ((len + 1 + 3) & ~3);
658 if (r_refdef.drawqueuesize + size > r_refdef.maxdrawqueuesize)
660 red = bound(0, red, 1);
661 green = bound(0, green, 1);
662 blue = bound(0, blue, 1);
663 alpha = bound(0, alpha, 1);
664 dq = (drawqueue_t *)(r_refdef.drawqueue + r_refdef.drawqueuesize);
666 dq->command = DRAWQUEUE_STRING;
668 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));
673 out = (char *)(dq + 1);
674 memcpy(out, string, len);
676 r_refdef.drawqueuesize += dq->size;
679 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)
681 if (r_textshadow.integer)
682 DrawQ_String_Real(x+scalex*0.25,y+scaley*0.25,string,maxlen,scalex,scaley,0,0,0,alpha*0.8,flags);
684 DrawQ_String_Real(x,y,string,maxlen,scalex,scaley,red,green,blue,alpha,flags);
689 void DrawQ_Fill (float x, float y, float w, float h, float red, float green, float blue, float alpha, int flags)
691 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);
694 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)
698 drawqueuemesh_t mesh;
699 memset(&mesh, 0, sizeof(mesh));
700 if (picname && picname[0])
702 pic = Draw_CachePic(picname, false);
706 height = pic->height;
707 mesh.texture = pic->tex;
709 mesh.num_triangles = 2;
710 mesh.num_vertices = 4;
711 mesh.data_element3i = picelements;
712 mesh.data_vertex3f = floats;
713 mesh.data_texcoord2f = floats + 12;
714 mesh.data_color4f = floats + 20;
715 memset(floats, 0, sizeof(floats));
716 mesh.data_vertex3f[0] = mesh.data_vertex3f[9] = x;
717 mesh.data_vertex3f[1] = mesh.data_vertex3f[4] = y;
718 mesh.data_vertex3f[3] = mesh.data_vertex3f[6] = x + width;
719 mesh.data_vertex3f[7] = mesh.data_vertex3f[10] = y + height;
720 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;
721 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;
722 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;
723 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;
724 DrawQ_Mesh (&mesh, flags);
727 void DrawQ_Mesh (drawqueuemesh_t *mesh, int flags)
734 size += sizeof(drawqueuemesh_t);
735 size += sizeof(int[3]) * mesh->num_triangles;
736 size += sizeof(float[3]) * mesh->num_vertices;
737 size += sizeof(float[2]) * mesh->num_vertices;
738 size += sizeof(float[4]) * mesh->num_vertices;
739 if (r_refdef.drawqueuesize + size > r_refdef.maxdrawqueuesize)
741 dq = (drawqueue_t *)(r_refdef.drawqueue + r_refdef.drawqueuesize);
743 dq->command = DRAWQUEUE_MESH;
750 p = (void *)(dq + 1);
751 m = (drawqueuemesh_t *)p;p = (unsigned char*)p + sizeof(drawqueuemesh_t);
752 m->num_triangles = mesh->num_triangles;
753 m->num_vertices = mesh->num_vertices;
754 m->texture = mesh->texture;
755 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]);
756 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]);
757 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]);
758 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]);
759 r_refdef.drawqueuesize += dq->size;
762 void DrawQ_LineLoop (drawqueuemesh_t *mesh, int flags)
769 size += sizeof(drawqueuemesh_t);
770 size += sizeof(int[3]) * mesh->num_triangles;
771 size += sizeof(float[3]) * mesh->num_vertices;
772 size += sizeof(float[2]) * mesh->num_vertices;
773 size += sizeof(float[4]) * mesh->num_vertices;
774 if (r_refdef.drawqueuesize + size > r_refdef.maxdrawqueuesize)
776 dq = (void *)(r_refdef.drawqueue + r_refdef.drawqueuesize);
778 dq->command = DRAWQUEUE_LINES;
785 p = (void *)(dq + 1);
786 m = p;p = (unsigned char*)p + sizeof(drawqueuemesh_t);
787 m->num_triangles = mesh->num_triangles;
788 m->num_vertices = mesh->num_vertices;
789 m->texture = mesh->texture;
790 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]);
791 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]);
792 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]);
793 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]);
794 r_refdef.drawqueuesize += dq->size;
797 //LordHavoc: FIXME: this is nasty!
798 void DrawQ_LineWidth (float width)
801 static int linewidth = 1;
802 if(width == linewidth)
805 if(r_refdef.drawqueuesize + (int)sizeof(*dq) > r_refdef.maxdrawqueuesize)
807 Con_DPrint("DrawQueue full !\n");
810 dq = (void*) (r_refdef.drawqueue + r_refdef.drawqueuesize);
811 dq->size = sizeof(*dq);
812 dq->command = DRAWQUEUE_LINEWIDTH;
815 r_refdef.drawqueuesize += dq->size;
818 //[515]: this is old, delete
819 void DrawQ_Line (float width, float x1, float y1, float x2, float y2, float r, float g, float b, float alpha, int flags)
823 DrawQ_LineWidth(width);
824 if(r_refdef.drawqueuesize + (int)sizeof(*dq) > r_refdef.maxdrawqueuesize)
826 Con_DPrint("DrawQueue full !\n");
829 dq = (void*) (r_refdef.drawqueue + r_refdef.drawqueuesize);
830 dq->size = sizeof(*dq);
831 dq->command = DRAWQUEUE_LINES;
837 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));
839 r_refdef.drawqueuesize += dq->size;
842 void DrawQ_SetClipArea(float x, float y, float width, float height)
845 if(r_refdef.drawqueuesize + (int)sizeof(*dq) > r_refdef.maxdrawqueuesize)
847 Con_DPrint("DrawQueue full !\n");
850 dq = (drawqueue_t *) (r_refdef.drawqueue + r_refdef.drawqueuesize);
851 dq->size = sizeof(*dq);
852 dq->command = DRAWQUEUE_SETCLIP;
860 r_refdef.drawqueuesize += dq->size;
863 void DrawQ_ResetClipArea(void)
866 if(r_refdef.drawqueuesize + (int)sizeof(*dq) > r_refdef.maxdrawqueuesize)
868 Con_DPrint("DrawQueue full !\n");
871 dq = (drawqueue_t *) (r_refdef.drawqueue + r_refdef.drawqueuesize);
872 dq->size = sizeof(*dq);
873 dq->command = DRAWQUEUE_RESETCLIP;
881 r_refdef.drawqueuesize += dq->size;
889 void SCR_ScreenShot_f (void)
891 static int shotnumber;
892 static char oldname[MAX_QPATH];
893 char base[MAX_QPATH];
894 char filename[MAX_QPATH];
895 unsigned char *buffer1;
896 unsigned char *buffer2;
897 unsigned char *buffer3;
898 qboolean jpeg = (scr_screenshot_jpeg.integer != 0);
900 sprintf (base, "screenshots/%s", scr_screenshot_name.string);
902 if (strcmp (oldname, scr_screenshot_name.string))
904 sprintf(oldname, "%s", scr_screenshot_name.string);
908 // find a file name to save it to
909 for (;shotnumber < 1000000;shotnumber++)
910 if (!FS_SysFileExists(va("%s/%s%06d.tga", fs_gamedir, base, shotnumber)) && !FS_SysFileExists(va("%s/%s%06d.jpg", fs_gamedir, base, shotnumber)))
912 if (shotnumber >= 1000000)
914 Con_Print("SCR_ScreenShot_f: Couldn't create the image file\n");
918 sprintf(filename, "%s%06d.%s", base, shotnumber, jpeg ? "jpg" : "tga");
920 buffer1 = (unsigned char *)Mem_Alloc(tempmempool, vid.width * vid.height * 3);
921 buffer2 = (unsigned char *)Mem_Alloc(tempmempool, vid.width * vid.height * 3);
922 buffer3 = (unsigned char *)Mem_Alloc(tempmempool, vid.width * vid.height * 3 + 18);
924 if (SCR_ScreenShot (filename, buffer1, buffer2, buffer3, 0, 0, vid.width, vid.height, false, false, false, jpeg, true))
925 Con_Printf("Wrote %s\n", filename);
927 Con_Printf("unable to write %s\n", filename);
936 typedef enum capturevideoformat_e
938 CAPTUREVIDEOFORMAT_TARGA,
939 CAPTUREVIDEOFORMAT_JPEG,
940 CAPTUREVIDEOFORMAT_RAWRGB,
941 CAPTUREVIDEOFORMAT_RAWYV12
943 capturevideoformat_t;
945 qboolean cl_capturevideo_active = false;
946 capturevideoformat_t cl_capturevideo_format;
947 static double cl_capturevideo_starttime = 0;
948 double cl_capturevideo_framerate = 0;
949 static int cl_capturevideo_soundrate = 0;
950 static int cl_capturevideo_frame = 0;
951 static unsigned char *cl_capturevideo_buffer = NULL;
952 static qfile_t *cl_capturevideo_videofile = NULL;
953 qfile_t *cl_capturevideo_soundfile = NULL;
954 static short cl_capturevideo_rgbtoyuvscaletable[3][3][256];
955 static unsigned char cl_capturevideo_yuvnormalizetable[3][256];
956 //static unsigned char cl_capturevideo_rgbgammatable[3][256];
958 void SCR_CaptureVideo_BeginVideo(void)
962 unsigned char out[44];
963 if (cl_capturevideo_active)
965 // soundrate is figured out on the first SoundFrame
966 cl_capturevideo_active = true;
967 cl_capturevideo_starttime = Sys_DoubleTime();
968 cl_capturevideo_framerate = bound(1, cl_capturevideo_fps.value, 1000);
969 cl_capturevideo_soundrate = 0;
970 cl_capturevideo_frame = 0;
971 cl_capturevideo_buffer = (unsigned char *)Mem_Alloc(tempmempool, vid.width * vid.height * (3+3+3) + 18);
972 gamma = 1.0/scr_screenshot_gamma.value;
975 for (i = 0;i < 256;i++)
977 unsigned char j = (unsigned char)bound(0, 255*pow(i/255.0, gamma), 255);
978 cl_capturevideo_rgbgammatable[0][i] = j;
979 cl_capturevideo_rgbgammatable[1][i] = j;
980 cl_capturevideo_rgbgammatable[2][i] = j;
984 R = Y + 1.4075 * (Cr - 128);
985 G = Y + -0.3455 * (Cb - 128) + -0.7169 * (Cr - 128);
986 B = Y + 1.7790 * (Cb - 128);
987 Y = R * .299 + G * .587 + B * .114;
988 Cb = R * -.169 + G * -.332 + B * .500 + 128.;
989 Cr = R * .500 + G * -.419 + B * -.0813 + 128.;
991 for (i = 0;i < 256;i++)
993 g = 255*pow(i/255.0, gamma);
994 // Y weights from RGB
995 cl_capturevideo_rgbtoyuvscaletable[0][0][i] = (short)(g * 0.299);
996 cl_capturevideo_rgbtoyuvscaletable[0][1][i] = (short)(g * 0.587);
997 cl_capturevideo_rgbtoyuvscaletable[0][2][i] = (short)(g * 0.114);
998 // Cb weights from RGB
999 cl_capturevideo_rgbtoyuvscaletable[1][0][i] = (short)(g * -0.169);
1000 cl_capturevideo_rgbtoyuvscaletable[1][1][i] = (short)(g * -0.332);
1001 cl_capturevideo_rgbtoyuvscaletable[1][2][i] = (short)(g * 0.500);
1002 // Cr weights from RGB
1003 cl_capturevideo_rgbtoyuvscaletable[2][0][i] = (short)(g * 0.500);
1004 cl_capturevideo_rgbtoyuvscaletable[2][1][i] = (short)(g * -0.419);
1005 cl_capturevideo_rgbtoyuvscaletable[2][2][i] = (short)(g * -0.0813);
1006 // range reduction of YCbCr to valid signal range
1007 cl_capturevideo_yuvnormalizetable[0][i] = 16 + i * (236-16) / 256;
1008 cl_capturevideo_yuvnormalizetable[1][i] = 16 + i * (240-16) / 256;
1009 cl_capturevideo_yuvnormalizetable[2][i] = 16 + i * (240-16) / 256;
1012 if (cl_capturevideo_rawrgb.integer)
1014 cl_capturevideo_format = CAPTUREVIDEOFORMAT_RAWRGB;
1015 cl_capturevideo_videofile = FS_Open ("video/dpvideo.rgb", "wb", false, true);
1017 else if (cl_capturevideo_rawyv12.integer)
1019 cl_capturevideo_format = CAPTUREVIDEOFORMAT_RAWYV12;
1020 cl_capturevideo_videofile = FS_Open ("video/dpvideo.yv12", "wb", false, true);
1022 else if (scr_screenshot_jpeg.integer)
1024 cl_capturevideo_format = CAPTUREVIDEOFORMAT_JPEG;
1025 cl_capturevideo_videofile = NULL;
1029 cl_capturevideo_format = CAPTUREVIDEOFORMAT_TARGA;
1030 cl_capturevideo_videofile = NULL;
1033 if (cl_capturevideo_sound.integer)
1035 cl_capturevideo_soundfile = FS_Open ("video/dpvideo.wav", "wb", false, true);
1036 // wave header will be filled out when video ends
1038 FS_Write (cl_capturevideo_soundfile, out, 44);
1041 cl_capturevideo_soundfile = NULL;
1044 void SCR_CaptureVideo_EndVideo(void)
1047 unsigned char out[44];
1048 if (!cl_capturevideo_active)
1050 cl_capturevideo_active = false;
1052 if (cl_capturevideo_videofile)
1054 FS_Close(cl_capturevideo_videofile);
1055 cl_capturevideo_videofile = NULL;
1058 // finish the wave file
1059 if (cl_capturevideo_soundfile)
1061 i = (int)FS_Tell (cl_capturevideo_soundfile);
1062 //"RIFF", (int) unknown (chunk size), "WAVE",
1063 //"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
1064 //"data", (int) unknown (chunk size)
1065 memcpy (out, "RIFF****WAVEfmt \x10\x00\x00\x00\x01\x00\x02\x00********\x04\x00\x10\0data****", 44);
1066 // the length of the whole RIFF chunk
1068 out[4] = (n) & 0xFF;
1069 out[5] = (n >> 8) & 0xFF;
1070 out[6] = (n >> 16) & 0xFF;
1071 out[7] = (n >> 24) & 0xFF;
1073 n = cl_capturevideo_soundrate;
1074 out[24] = (n) & 0xFF;
1075 out[25] = (n >> 8) & 0xFF;
1076 out[26] = (n >> 16) & 0xFF;
1077 out[27] = (n >> 24) & 0xFF;
1078 // bytes per second (rate * channels * bytes per channel)
1079 n = cl_capturevideo_soundrate * 2 * 2;
1080 out[28] = (n) & 0xFF;
1081 out[29] = (n >> 8) & 0xFF;
1082 out[30] = (n >> 16) & 0xFF;
1083 out[31] = (n >> 24) & 0xFF;
1084 // the length of the data chunk
1086 out[40] = (n) & 0xFF;
1087 out[41] = (n >> 8) & 0xFF;
1088 out[42] = (n >> 16) & 0xFF;
1089 out[43] = (n >> 24) & 0xFF;
1090 FS_Seek (cl_capturevideo_soundfile, 0, SEEK_SET);
1091 FS_Write (cl_capturevideo_soundfile, out, 44);
1092 FS_Close (cl_capturevideo_soundfile);
1093 cl_capturevideo_soundfile = NULL;
1096 if (cl_capturevideo_buffer)
1098 Mem_Free (cl_capturevideo_buffer);
1099 cl_capturevideo_buffer = NULL;
1102 cl_capturevideo_starttime = 0;
1103 cl_capturevideo_framerate = 0;
1104 cl_capturevideo_frame = 0;
1107 qboolean SCR_CaptureVideo_VideoFrame(int newframenum)
1109 int x = 0, y = 0, width = vid.width, height = vid.height;
1110 unsigned char *b, *out;
1112 int outoffset = (width/2)*(height/2);
1113 //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);
1114 // speed is critical here, so do saving as directly as possible
1115 switch (cl_capturevideo_format)
1117 case CAPTUREVIDEOFORMAT_RAWYV12:
1118 // FIXME: width/height must be multiple of 2, enforce this?
1119 qglReadPixels (x, y, width, height, GL_RGB, GL_UNSIGNED_BYTE, cl_capturevideo_buffer);
1121 // process one line at a time, and CbCr every other line at 2 pixel intervals
1122 for (y = 0;y < height;y++)
1125 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++)
1126 *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]]];
1129 // 2x2 Cb and Cr planes
1131 // low quality, no averaging
1132 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++)
1135 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];
1137 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];
1140 // high quality, averaging
1141 int inpitch = width*3;
1142 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++)
1144 int blockr, blockg, blockb;
1145 blockr = (b[0] + b[3] + b[inpitch+0] + b[inpitch+3]) >> 2;
1146 blockg = (b[1] + b[4] + b[inpitch+1] + b[inpitch+4]) >> 2;
1147 blockb = (b[2] + b[5] + b[inpitch+2] + b[inpitch+5]) >> 2;
1149 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];
1151 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];
1156 for (;cl_capturevideo_frame < newframenum;cl_capturevideo_frame++)
1157 if (!FS_Write (cl_capturevideo_videofile, cl_capturevideo_buffer + width*height*3, width*height+(width/2)*(height/2)*2))
1160 case CAPTUREVIDEOFORMAT_RAWRGB:
1161 qglReadPixels (x, y, width, height, GL_RGB, GL_UNSIGNED_BYTE, cl_capturevideo_buffer);
1163 for (;cl_capturevideo_frame < newframenum;cl_capturevideo_frame++)
1164 if (!FS_Write (cl_capturevideo_videofile, cl_capturevideo_buffer, width*height*3))
1167 case CAPTUREVIDEOFORMAT_JPEG:
1168 qglReadPixels (x, y, width, height, GL_RGB, GL_UNSIGNED_BYTE, cl_capturevideo_buffer);
1170 for (;cl_capturevideo_frame < newframenum;cl_capturevideo_frame++)
1172 sprintf(filename, "video/dp%06d.jpg", cl_capturevideo_frame);
1173 if (!JPEG_SaveImage_preflipped (filename, width, height, cl_capturevideo_buffer))
1177 case CAPTUREVIDEOFORMAT_TARGA:
1178 //return Image_WriteTGARGB_preflipped (filename, width, height, cl_capturevideo_buffer, cl_capturevideo_buffer + vid.width * vid.height * 3, );
1179 memset (cl_capturevideo_buffer, 0, 18);
1180 cl_capturevideo_buffer[2] = 2; // uncompressed type
1181 cl_capturevideo_buffer[12] = (width >> 0) & 0xFF;
1182 cl_capturevideo_buffer[13] = (width >> 8) & 0xFF;
1183 cl_capturevideo_buffer[14] = (height >> 0) & 0xFF;
1184 cl_capturevideo_buffer[15] = (height >> 8) & 0xFF;
1185 cl_capturevideo_buffer[16] = 24; // pixel size
1186 qglReadPixels (x, y, width, height, GL_BGR, GL_UNSIGNED_BYTE, cl_capturevideo_buffer + 18);
1188 for (;cl_capturevideo_frame < newframenum;cl_capturevideo_frame++)
1190 sprintf(filename, "video/dp%06d.tga", cl_capturevideo_frame);
1191 if (!FS_WriteFile (filename, cl_capturevideo_buffer, width*height*3 + 18))
1200 void SCR_CaptureVideo_SoundFrame(unsigned char *bufstereo16le, size_t length, int rate)
1202 if (!cl_capturevideo_soundfile)
1204 cl_capturevideo_soundrate = rate;
1205 if (FS_Write (cl_capturevideo_soundfile, bufstereo16le, 4 * length) < (fs_offset_t)(4 * length))
1207 Cvar_SetValueQuick(&cl_capturevideo, 0);
1208 Con_Printf("video sound saving failed on frame %i, out of disk space? stopping video capture.\n", cl_capturevideo_frame);
1209 SCR_CaptureVideo_EndVideo();
1213 void SCR_CaptureVideo(void)
1216 if (cl_capturevideo.integer && r_render.integer)
1218 if (!cl_capturevideo_active)
1219 SCR_CaptureVideo_BeginVideo();
1220 if (cl_capturevideo_framerate != cl_capturevideo_fps.value)
1222 Con_Printf("You can not change the video framerate while recording a video.\n");
1223 Cvar_SetValueQuick(&cl_capturevideo_fps, cl_capturevideo_framerate);
1225 if (cl_capturevideo_soundfile)
1227 // preserve sound sync by duplicating frames when running slow
1228 newframenum = (Sys_DoubleTime() - cl_capturevideo_starttime) * cl_capturevideo_framerate;
1231 newframenum = cl_capturevideo_frame + 1;
1232 // if falling behind more than one second, stop
1233 if (newframenum - cl_capturevideo_frame > (int)ceil(cl_capturevideo_framerate))
1235 Cvar_SetValueQuick(&cl_capturevideo, 0);
1236 Con_Printf("video saving failed on frame %i, your machine is too slow for this capture speed.\n", cl_capturevideo_frame);
1237 SCR_CaptureVideo_EndVideo();
1241 if (!SCR_CaptureVideo_VideoFrame(newframenum))
1243 Cvar_SetValueQuick(&cl_capturevideo, 0);
1244 Con_Printf("video saving failed on frame %i, out of disk space? stopping video capture.\n", cl_capturevideo_frame);
1245 SCR_CaptureVideo_EndVideo();
1248 else if (cl_capturevideo_active)
1249 SCR_CaptureVideo_EndVideo();
1256 Grab six views for environment mapping tests
1263 qboolean flipx, flipy, flipdiagonaly;
1267 {{ 0, 0, 0}, "rt", false, false, false},
1268 {{ 0, 270, 0}, "ft", false, false, false},
1269 {{ 0, 180, 0}, "lf", false, false, false},
1270 {{ 0, 90, 0}, "bk", false, false, false},
1271 {{-90, 180, 0}, "up", true, true, false},
1272 {{ 90, 180, 0}, "dn", true, true, false},
1274 {{ 0, 0, 0}, "px", true, true, true},
1275 {{ 0, 90, 0}, "py", false, true, false},
1276 {{ 0, 180, 0}, "nx", false, false, true},
1277 {{ 0, 270, 0}, "ny", true, false, false},
1278 {{-90, 180, 0}, "pz", false, false, true},
1279 {{ 90, 180, 0}, "nz", false, false, true}
1282 static void R_Envmap_f (void)
1285 char filename[MAX_QPATH], basename[MAX_QPATH];
1286 unsigned char *buffer1;
1287 unsigned char *buffer2;
1288 unsigned char *buffer3;
1290 if (Cmd_Argc() != 3)
1292 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");
1296 strlcpy (basename, Cmd_Argv(1), sizeof (basename));
1297 size = atoi(Cmd_Argv(2));
1298 if (size != 128 && size != 256 && size != 512 && size != 1024)
1300 Con_Print("envmap: size must be one of 128, 256, 512, or 1024\n");
1303 if (size > vid.width || size > vid.height)
1305 Con_Print("envmap: your resolution is not big enough to render that size\n");
1313 r_refdef.width = size;
1314 r_refdef.height = size;
1316 r_refdef.frustum_x = tan(90 * M_PI / 360.0);
1317 r_refdef.frustum_y = tan(90 * M_PI / 360.0);
1319 buffer1 = (unsigned char *)Mem_Alloc(tempmempool, size * size * 3);
1320 buffer2 = (unsigned char *)Mem_Alloc(tempmempool, size * size * 3);
1321 buffer3 = (unsigned char *)Mem_Alloc(tempmempool, size * size * 3 + 18);
1323 for (j = 0;j < 12;j++)
1325 sprintf(filename, "env/%s%s.tga", basename, envmapinfo[j].name);
1326 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);
1331 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);
1341 //=============================================================================
1343 // LordHavoc: SHOWLMP stuff
1344 #define SHOWLMP_MAXLABELS 256
1345 typedef struct showlmp_s
1355 showlmp_t showlmp[SHOWLMP_MAXLABELS];
1357 void SHOWLMP_decodehide(void)
1361 lmplabel = MSG_ReadString();
1362 for (i = 0;i < SHOWLMP_MAXLABELS;i++)
1363 if (showlmp[i].isactive && strcmp(showlmp[i].label, lmplabel) == 0)
1365 showlmp[i].isactive = false;
1370 void SHOWLMP_decodeshow(void)
1373 char lmplabel[256], picname[256];
1375 strlcpy (lmplabel,MSG_ReadString(), sizeof (lmplabel));
1376 strlcpy (picname, MSG_ReadString(), sizeof (picname));
1377 if (gamemode == GAME_NEHAHRA) // LordHavoc: nasty old legacy junk
1384 x = MSG_ReadShort();
1385 y = MSG_ReadShort();
1388 for (i = 0;i < SHOWLMP_MAXLABELS;i++)
1389 if (showlmp[i].isactive)
1391 if (strcmp(showlmp[i].label, lmplabel) == 0)
1394 break; // drop out to replace it
1397 else if (k < 0) // find first empty one to replace
1400 return; // none found to replace
1401 // change existing one
1402 showlmp[k].isactive = true;
1403 strlcpy (showlmp[k].label, lmplabel, sizeof (showlmp[k].label));
1404 strlcpy (showlmp[k].pic, picname, sizeof (showlmp[k].pic));
1409 void SHOWLMP_drawall(void)
1412 for (i = 0;i < SHOWLMP_MAXLABELS;i++)
1413 if (showlmp[i].isactive)
1414 DrawQ_Pic(showlmp[i].x, showlmp[i].y, showlmp[i].pic, 0, 0, 1, 1, 1, 1, 0);
1417 void SHOWLMP_clear(void)
1420 for (i = 0;i < SHOWLMP_MAXLABELS;i++)
1421 showlmp[i].isactive = false;
1424 void CL_SetupScreenSize(void)
1426 float conwidth, conheight;
1428 VID_UpdateGamma(false);
1430 conwidth = bound(320, vid_conwidth.value, 2048);
1431 conheight = bound(200, vid_conheight.value, 1536);
1432 if (vid_conwidth.value != conwidth)
1433 Cvar_SetValue("vid_conwidth", conwidth);
1434 if (vid_conheight.value != conheight)
1435 Cvar_SetValue("vid_conheight", conheight);
1437 vid_conwidth.integer = vid_conwidth.integer;
1438 vid_conheight.integer = vid_conheight.integer;
1440 SCR_SetUpToDrawConsole();
1443 extern void R_Shadow_EditLights_DrawSelectedLightProperties(void);
1444 void CL_UpdateScreen(void)
1446 if (!scr_initialized || !con_initialized || vid_hidden)
1447 return; // not initialized yet
1449 // don't allow cheats in multiplayer
1450 if (!cl.islocalgame && cl.worldmodel)
1452 if (r_fullbright.integer != 0)
1453 Cvar_Set ("r_fullbright", "0");
1454 if (r_ambient.value != 0)
1455 Cvar_Set ("r_ambient", "0");
1459 if (scr_viewsize.value < 30)
1460 Cvar_Set ("viewsize","30");
1461 if (scr_viewsize.value > 120)
1462 Cvar_Set ("viewsize","120");
1464 // bound field of view
1465 if (scr_fov.value < 1)
1466 Cvar_Set ("fov","1");
1467 if (scr_fov.value > 170)
1468 Cvar_Set ("fov","170");
1470 // intermission is always full screen
1471 if (cl.intermission)
1475 if (scr_viewsize.value >= 120)
1476 sb_lines = 0; // no status bar at all
1477 else if (scr_viewsize.value >= 110)
1478 sb_lines = 24; // no inventory
1483 r_refdef.colormask[0] = 1;
1484 r_refdef.colormask[1] = 1;
1485 r_refdef.colormask[2] = 1;
1489 if (cls.signon == SIGNONS)
1490 R_TimeReport("other");
1492 CL_SetupScreenSize();
1496 if (cls.signon == SIGNONS)
1497 R_TimeReport("setup");
1499 //FIXME: force menu if nothing else to look at?
1500 //if (key_dest == key_game && cls.signon != SIGNONS && cls.state == ca_disconnected)
1502 if (cls.signon == SIGNONS)
1507 if (!r_letterbox.value)
1510 SCR_CheckDrawCenterString();
1516 if (cls.signon == SIGNONS)
1520 R_TimeReport_Start();
1522 R_Shadow_EditLights_DrawSelectedLightProperties();
1532 void CL_Screen_NewMap(void)