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_speeds.integer < 2 || !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)
543 r_timereport_current = r_timereport_start;
544 R_TimeReport("total");
546 j = (int)strlen(r_speeds_string);
547 if (r_timereport_active && j > 0)
549 if (r_speeds_string[j-1] == '\n')
550 r_speeds_string[j-1] = 0;
552 for (i = 0;r_speeds_string[i];i++)
553 if (r_speeds_string[i] == '\n')
555 y = vid_conheight.integer - sb_lines - lines * 8;
557 DrawQ_Fill(0, y, vid_conwidth.integer, lines * 8, 0, 0, 0, 0.5, 0);
558 while (r_speeds_string[i])
561 while (r_speeds_string[i] && r_speeds_string[i] != '\n')
564 DrawQ_String(0, y, r_speeds_string + j, i - j, 8, 8, 1, 1, 1, 1, 0);
565 if (r_speeds_string[i] == '\n')
579 void SCR_SizeUp_f (void)
581 Cvar_SetValue ("viewsize",scr_viewsize.value+10);
592 void SCR_SizeDown_f (void)
594 Cvar_SetValue ("viewsize",scr_viewsize.value-10);
597 void CL_Screen_Init(void)
599 Cvar_RegisterVariable (&scr_fov);
600 Cvar_RegisterVariable (&scr_viewsize);
601 Cvar_RegisterVariable (&scr_conspeed);
602 Cvar_RegisterVariable (&scr_conalpha);
603 Cvar_RegisterVariable (&scr_conbrightness);
604 Cvar_RegisterVariable (&scr_conforcewhiledisconnected);
605 Cvar_RegisterVariable (&scr_showram);
606 Cvar_RegisterVariable (&scr_showturtle);
607 Cvar_RegisterVariable (&scr_showpause);
608 Cvar_RegisterVariable (&scr_showbrand);
609 Cvar_RegisterVariable (&scr_centertime);
610 Cvar_RegisterVariable (&scr_printspeed);
611 Cvar_RegisterVariable (&vid_conwidth);
612 Cvar_RegisterVariable (&vid_conheight);
613 Cvar_RegisterVariable (&vid_pixelheight);
614 Cvar_RegisterVariable (&scr_screenshot_jpeg);
615 Cvar_RegisterVariable (&scr_screenshot_jpeg_quality);
616 Cvar_RegisterVariable (&scr_screenshot_gamma);
617 Cvar_RegisterVariable (&cl_capturevideo);
618 Cvar_RegisterVariable (&cl_capturevideo_sound);
619 Cvar_RegisterVariable (&cl_capturevideo_fps);
620 Cvar_RegisterVariable (&cl_capturevideo_rawrgb);
621 Cvar_RegisterVariable (&cl_capturevideo_rawyv12);
622 Cvar_RegisterVariable (&r_textshadow);
623 Cvar_RegisterVariable (&r_letterbox);
625 Cmd_AddCommand ("sizeup",SCR_SizeUp_f, "increase view size (increases viewsize cvar)");
626 Cmd_AddCommand ("sizedown",SCR_SizeDown_f, "decrease view size (decreases viewsize cvar)");
627 Cmd_AddCommand ("screenshot",SCR_ScreenShot_f, "takes a screenshot of the next rendered frame");
628 Cmd_AddCommand ("envmap", R_Envmap_f, "render a cubemap (skybox) of the current scene");
630 scr_initialized = true;
633 void DrawQ_Clear(void)
635 r_refdef.drawqueuesize = 0;
638 static int picelements[6] = {0, 1, 2, 0, 2, 3};
639 void DrawQ_Pic(float x, float y, const char *picname, float width, float height, float red, float green, float blue, float alpha, int flags)
641 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);
644 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)
649 if (alpha < (1.0f / 255.0f))
652 len = (int)strlen(string);
654 for (len = 0;len < maxlen && string[len];len++);
655 for (;len > 0 && string[0] == ' ';string++, x += scalex, len--);
656 for (;len > 0 && string[len - 1] == ' ';len--);
659 if (x >= vid_conwidth.integer || y >= vid_conheight.integer || x < (-scalex * len) || y < (-scaley))
661 size = sizeof(*dq) + ((len + 1 + 3) & ~3);
662 if (r_refdef.drawqueuesize + size > r_refdef.maxdrawqueuesize)
664 red = bound(0, red, 1);
665 green = bound(0, green, 1);
666 blue = bound(0, blue, 1);
667 alpha = bound(0, alpha, 1);
668 dq = (drawqueue_t *)(r_refdef.drawqueue + r_refdef.drawqueuesize);
670 dq->command = DRAWQUEUE_STRING;
672 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));
677 out = (char *)(dq + 1);
678 memcpy(out, string, len);
680 r_refdef.drawqueuesize += dq->size;
683 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)
685 if (r_textshadow.integer)
686 DrawQ_String_Real(x+scalex*0.25,y+scaley*0.25,string,maxlen,scalex,scaley,0,0,0,alpha*0.8,flags);
688 DrawQ_String_Real(x,y,string,maxlen,scalex,scaley,red,green,blue,alpha,flags);
693 void DrawQ_Fill (float x, float y, float w, float h, float red, float green, float blue, float alpha, int flags)
695 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);
698 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)
702 drawqueuemesh_t mesh;
703 memset(&mesh, 0, sizeof(mesh));
704 if (picname && picname[0])
706 pic = Draw_CachePic(picname, false);
710 height = pic->height;
711 mesh.texture = pic->tex;
713 mesh.num_triangles = 2;
714 mesh.num_vertices = 4;
715 mesh.data_element3i = picelements;
716 mesh.data_vertex3f = floats;
717 mesh.data_texcoord2f = floats + 12;
718 mesh.data_color4f = floats + 20;
719 memset(floats, 0, sizeof(floats));
720 mesh.data_vertex3f[0] = mesh.data_vertex3f[9] = x;
721 mesh.data_vertex3f[1] = mesh.data_vertex3f[4] = y;
722 mesh.data_vertex3f[3] = mesh.data_vertex3f[6] = x + width;
723 mesh.data_vertex3f[7] = mesh.data_vertex3f[10] = y + height;
724 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;
725 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;
726 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;
727 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;
728 DrawQ_Mesh (&mesh, flags);
731 void DrawQ_Mesh (drawqueuemesh_t *mesh, int flags)
738 size += sizeof(drawqueuemesh_t);
739 size += sizeof(int[3]) * mesh->num_triangles;
740 size += sizeof(float[3]) * mesh->num_vertices;
741 size += sizeof(float[2]) * mesh->num_vertices;
742 size += sizeof(float[4]) * mesh->num_vertices;
743 if (r_refdef.drawqueuesize + size > r_refdef.maxdrawqueuesize)
745 dq = (drawqueue_t *)(r_refdef.drawqueue + r_refdef.drawqueuesize);
747 dq->command = DRAWQUEUE_MESH;
754 p = (void *)(dq + 1);
755 m = (drawqueuemesh_t *)p;p = (unsigned char*)p + sizeof(drawqueuemesh_t);
756 m->num_triangles = mesh->num_triangles;
757 m->num_vertices = mesh->num_vertices;
758 m->texture = mesh->texture;
759 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]);
760 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]);
761 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]);
762 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]);
763 r_refdef.drawqueuesize += dq->size;
766 void DrawQ_LineLoop (drawqueuemesh_t *mesh, int flags)
773 size += sizeof(drawqueuemesh_t);
774 size += sizeof(int[3]) * mesh->num_triangles;
775 size += sizeof(float[3]) * mesh->num_vertices;
776 size += sizeof(float[2]) * mesh->num_vertices;
777 size += sizeof(float[4]) * mesh->num_vertices;
778 if (r_refdef.drawqueuesize + size > r_refdef.maxdrawqueuesize)
780 dq = (void *)(r_refdef.drawqueue + r_refdef.drawqueuesize);
782 dq->command = DRAWQUEUE_LINES;
789 p = (void *)(dq + 1);
790 m = p;p = (unsigned char*)p + sizeof(drawqueuemesh_t);
791 m->num_triangles = mesh->num_triangles;
792 m->num_vertices = mesh->num_vertices;
793 m->texture = mesh->texture;
794 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]);
795 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]);
796 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]);
797 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]);
798 r_refdef.drawqueuesize += dq->size;
801 //LordHavoc: FIXME: this is nasty!
802 void DrawQ_LineWidth (float width)
805 static int linewidth = 1;
806 if(width == linewidth)
809 if(r_refdef.drawqueuesize + (int)sizeof(*dq) > r_refdef.maxdrawqueuesize)
811 Con_DPrint("DrawQueue full !\n");
814 dq = (void*) (r_refdef.drawqueue + r_refdef.drawqueuesize);
815 dq->size = sizeof(*dq);
816 dq->command = DRAWQUEUE_LINEWIDTH;
819 r_refdef.drawqueuesize += dq->size;
822 //[515]: this is old, delete
823 void DrawQ_Line (float width, float x1, float y1, float x2, float y2, float r, float g, float b, float alpha, int flags)
827 DrawQ_LineWidth(width);
828 if(r_refdef.drawqueuesize + (int)sizeof(*dq) > r_refdef.maxdrawqueuesize)
830 Con_DPrint("DrawQueue full !\n");
833 dq = (void*) (r_refdef.drawqueue + r_refdef.drawqueuesize);
834 dq->size = sizeof(*dq);
835 dq->command = DRAWQUEUE_LINES;
841 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));
843 r_refdef.drawqueuesize += dq->size;
846 void DrawQ_SetClipArea(float x, float y, float width, float height)
849 if(r_refdef.drawqueuesize + (int)sizeof(*dq) > r_refdef.maxdrawqueuesize)
851 Con_DPrint("DrawQueue full !\n");
854 dq = (drawqueue_t *) (r_refdef.drawqueue + r_refdef.drawqueuesize);
855 dq->size = sizeof(*dq);
856 dq->command = DRAWQUEUE_SETCLIP;
864 r_refdef.drawqueuesize += dq->size;
867 void DrawQ_ResetClipArea(void)
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_RESETCLIP;
885 r_refdef.drawqueuesize += dq->size;
893 void SCR_ScreenShot_f (void)
895 static int shotnumber;
896 static char oldname[MAX_QPATH];
897 char base[MAX_QPATH];
898 char filename[MAX_QPATH];
899 unsigned char *buffer1;
900 unsigned char *buffer2;
901 unsigned char *buffer3;
902 qboolean jpeg = (scr_screenshot_jpeg.integer != 0);
904 sprintf (base, "screenshots/%s", scr_screenshot_name.string);
906 if (strcmp (oldname, scr_screenshot_name.string))
908 sprintf(oldname, "%s", scr_screenshot_name.string);
912 // find a file name to save it to
913 for (;shotnumber < 1000000;shotnumber++)
914 if (!FS_SysFileExists(va("%s/%s%06d.tga", fs_gamedir, base, shotnumber)) && !FS_SysFileExists(va("%s/%s%06d.jpg", fs_gamedir, base, shotnumber)))
916 if (shotnumber >= 1000000)
918 Con_Print("SCR_ScreenShot_f: Couldn't create the image file\n");
922 sprintf(filename, "%s%06d.%s", base, shotnumber, jpeg ? "jpg" : "tga");
924 buffer1 = (unsigned char *)Mem_Alloc(tempmempool, vid.width * vid.height * 3);
925 buffer2 = (unsigned char *)Mem_Alloc(tempmempool, vid.width * vid.height * 3);
926 buffer3 = (unsigned char *)Mem_Alloc(tempmempool, vid.width * vid.height * 3 + 18);
928 if (SCR_ScreenShot (filename, buffer1, buffer2, buffer3, 0, 0, vid.width, vid.height, false, false, false, jpeg, true))
929 Con_Printf("Wrote %s\n", filename);
931 Con_Printf("unable to write %s\n", filename);
940 typedef enum capturevideoformat_e
942 CAPTUREVIDEOFORMAT_TARGA,
943 CAPTUREVIDEOFORMAT_JPEG,
944 CAPTUREVIDEOFORMAT_RAWRGB,
945 CAPTUREVIDEOFORMAT_RAWYV12
947 capturevideoformat_t;
949 qboolean cl_capturevideo_active = false;
950 capturevideoformat_t cl_capturevideo_format;
951 static double cl_capturevideo_starttime = 0;
952 double cl_capturevideo_framerate = 0;
953 static int cl_capturevideo_soundrate = 0;
954 static int cl_capturevideo_frame = 0;
955 static unsigned char *cl_capturevideo_buffer = NULL;
956 static qfile_t *cl_capturevideo_videofile = NULL;
957 qfile_t *cl_capturevideo_soundfile = NULL;
958 static short cl_capturevideo_rgbtoyuvscaletable[3][3][256];
959 static unsigned char cl_capturevideo_yuvnormalizetable[3][256];
960 //static unsigned char cl_capturevideo_rgbgammatable[3][256];
962 void SCR_CaptureVideo_BeginVideo(void)
966 unsigned char out[44];
967 if (cl_capturevideo_active)
969 // soundrate is figured out on the first SoundFrame
970 cl_capturevideo_active = true;
971 cl_capturevideo_starttime = Sys_DoubleTime();
972 cl_capturevideo_framerate = bound(1, cl_capturevideo_fps.value, 1000);
973 cl_capturevideo_soundrate = 0;
974 cl_capturevideo_frame = 0;
975 cl_capturevideo_buffer = (unsigned char *)Mem_Alloc(tempmempool, vid.width * vid.height * (3+3+3) + 18);
976 gamma = 1.0/scr_screenshot_gamma.value;
979 for (i = 0;i < 256;i++)
981 unsigned char j = (unsigned char)bound(0, 255*pow(i/255.0, gamma), 255);
982 cl_capturevideo_rgbgammatable[0][i] = j;
983 cl_capturevideo_rgbgammatable[1][i] = j;
984 cl_capturevideo_rgbgammatable[2][i] = j;
988 R = Y + 1.4075 * (Cr - 128);
989 G = Y + -0.3455 * (Cb - 128) + -0.7169 * (Cr - 128);
990 B = Y + 1.7790 * (Cb - 128);
991 Y = R * .299 + G * .587 + B * .114;
992 Cb = R * -.169 + G * -.332 + B * .500 + 128.;
993 Cr = R * .500 + G * -.419 + B * -.0813 + 128.;
995 for (i = 0;i < 256;i++)
997 g = 255*pow(i/255.0, gamma);
998 // Y weights from RGB
999 cl_capturevideo_rgbtoyuvscaletable[0][0][i] = (short)(g * 0.299);
1000 cl_capturevideo_rgbtoyuvscaletable[0][1][i] = (short)(g * 0.587);
1001 cl_capturevideo_rgbtoyuvscaletable[0][2][i] = (short)(g * 0.114);
1002 // Cb weights from RGB
1003 cl_capturevideo_rgbtoyuvscaletable[1][0][i] = (short)(g * -0.169);
1004 cl_capturevideo_rgbtoyuvscaletable[1][1][i] = (short)(g * -0.332);
1005 cl_capturevideo_rgbtoyuvscaletable[1][2][i] = (short)(g * 0.500);
1006 // Cr weights from RGB
1007 cl_capturevideo_rgbtoyuvscaletable[2][0][i] = (short)(g * 0.500);
1008 cl_capturevideo_rgbtoyuvscaletable[2][1][i] = (short)(g * -0.419);
1009 cl_capturevideo_rgbtoyuvscaletable[2][2][i] = (short)(g * -0.0813);
1010 // range reduction of YCbCr to valid signal range
1011 cl_capturevideo_yuvnormalizetable[0][i] = 16 + i * (236-16) / 256;
1012 cl_capturevideo_yuvnormalizetable[1][i] = 16 + i * (240-16) / 256;
1013 cl_capturevideo_yuvnormalizetable[2][i] = 16 + i * (240-16) / 256;
1016 if (cl_capturevideo_rawrgb.integer)
1018 cl_capturevideo_format = CAPTUREVIDEOFORMAT_RAWRGB;
1019 cl_capturevideo_videofile = FS_Open ("video/dpvideo.rgb", "wb", false, true);
1021 else if (cl_capturevideo_rawyv12.integer)
1023 cl_capturevideo_format = CAPTUREVIDEOFORMAT_RAWYV12;
1024 cl_capturevideo_videofile = FS_Open ("video/dpvideo.yv12", "wb", false, true);
1026 else if (scr_screenshot_jpeg.integer)
1028 cl_capturevideo_format = CAPTUREVIDEOFORMAT_JPEG;
1029 cl_capturevideo_videofile = NULL;
1033 cl_capturevideo_format = CAPTUREVIDEOFORMAT_TARGA;
1034 cl_capturevideo_videofile = NULL;
1037 if (cl_capturevideo_sound.integer)
1039 cl_capturevideo_soundfile = FS_Open ("video/dpvideo.wav", "wb", false, true);
1040 // wave header will be filled out when video ends
1042 FS_Write (cl_capturevideo_soundfile, out, 44);
1045 cl_capturevideo_soundfile = NULL;
1048 void SCR_CaptureVideo_EndVideo(void)
1051 unsigned char out[44];
1052 if (!cl_capturevideo_active)
1054 cl_capturevideo_active = false;
1056 if (cl_capturevideo_videofile)
1058 FS_Close(cl_capturevideo_videofile);
1059 cl_capturevideo_videofile = NULL;
1062 // finish the wave file
1063 if (cl_capturevideo_soundfile)
1065 i = (int)FS_Tell (cl_capturevideo_soundfile);
1066 //"RIFF", (int) unknown (chunk size), "WAVE",
1067 //"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
1068 //"data", (int) unknown (chunk size)
1069 memcpy (out, "RIFF****WAVEfmt \x10\x00\x00\x00\x01\x00\x02\x00********\x04\x00\x10\0data****", 44);
1070 // the length of the whole RIFF chunk
1072 out[4] = (n) & 0xFF;
1073 out[5] = (n >> 8) & 0xFF;
1074 out[6] = (n >> 16) & 0xFF;
1075 out[7] = (n >> 24) & 0xFF;
1077 n = cl_capturevideo_soundrate;
1078 out[24] = (n) & 0xFF;
1079 out[25] = (n >> 8) & 0xFF;
1080 out[26] = (n >> 16) & 0xFF;
1081 out[27] = (n >> 24) & 0xFF;
1082 // bytes per second (rate * channels * bytes per channel)
1083 n = cl_capturevideo_soundrate * 2 * 2;
1084 out[28] = (n) & 0xFF;
1085 out[29] = (n >> 8) & 0xFF;
1086 out[30] = (n >> 16) & 0xFF;
1087 out[31] = (n >> 24) & 0xFF;
1088 // the length of the data chunk
1090 out[40] = (n) & 0xFF;
1091 out[41] = (n >> 8) & 0xFF;
1092 out[42] = (n >> 16) & 0xFF;
1093 out[43] = (n >> 24) & 0xFF;
1094 FS_Seek (cl_capturevideo_soundfile, 0, SEEK_SET);
1095 FS_Write (cl_capturevideo_soundfile, out, 44);
1096 FS_Close (cl_capturevideo_soundfile);
1097 cl_capturevideo_soundfile = NULL;
1100 if (cl_capturevideo_buffer)
1102 Mem_Free (cl_capturevideo_buffer);
1103 cl_capturevideo_buffer = NULL;
1106 cl_capturevideo_starttime = 0;
1107 cl_capturevideo_framerate = 0;
1108 cl_capturevideo_frame = 0;
1111 qboolean SCR_CaptureVideo_VideoFrame(int newframenum)
1113 int x = 0, y = 0, width = vid.width, height = vid.height;
1114 unsigned char *b, *out;
1116 int outoffset = (width/2)*(height/2);
1117 //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);
1118 // speed is critical here, so do saving as directly as possible
1119 switch (cl_capturevideo_format)
1121 case CAPTUREVIDEOFORMAT_RAWYV12:
1122 // FIXME: width/height must be multiple of 2, enforce this?
1123 qglReadPixels (x, y, width, height, GL_RGB, GL_UNSIGNED_BYTE, cl_capturevideo_buffer);
1125 // process one line at a time, and CbCr every other line at 2 pixel intervals
1126 for (y = 0;y < height;y++)
1129 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++)
1130 *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]]];
1133 // 2x2 Cb and Cr planes
1135 // low quality, no averaging
1136 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++)
1139 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];
1141 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];
1144 // high quality, averaging
1145 int inpitch = width*3;
1146 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++)
1148 int blockr, blockg, blockb;
1149 blockr = (b[0] + b[3] + b[inpitch+0] + b[inpitch+3]) >> 2;
1150 blockg = (b[1] + b[4] + b[inpitch+1] + b[inpitch+4]) >> 2;
1151 blockb = (b[2] + b[5] + b[inpitch+2] + b[inpitch+5]) >> 2;
1153 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];
1155 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];
1160 for (;cl_capturevideo_frame < newframenum;cl_capturevideo_frame++)
1161 if (!FS_Write (cl_capturevideo_videofile, cl_capturevideo_buffer + width*height*3, width*height+(width/2)*(height/2)*2))
1164 case CAPTUREVIDEOFORMAT_RAWRGB:
1165 qglReadPixels (x, y, width, height, GL_RGB, GL_UNSIGNED_BYTE, cl_capturevideo_buffer);
1167 for (;cl_capturevideo_frame < newframenum;cl_capturevideo_frame++)
1168 if (!FS_Write (cl_capturevideo_videofile, cl_capturevideo_buffer, width*height*3))
1171 case CAPTUREVIDEOFORMAT_JPEG:
1172 qglReadPixels (x, y, width, height, GL_RGB, GL_UNSIGNED_BYTE, cl_capturevideo_buffer);
1174 for (;cl_capturevideo_frame < newframenum;cl_capturevideo_frame++)
1176 sprintf(filename, "video/dp%06d.jpg", cl_capturevideo_frame);
1177 if (!JPEG_SaveImage_preflipped (filename, width, height, cl_capturevideo_buffer))
1181 case CAPTUREVIDEOFORMAT_TARGA:
1182 //return Image_WriteTGARGB_preflipped (filename, width, height, cl_capturevideo_buffer, cl_capturevideo_buffer + vid.width * vid.height * 3, );
1183 memset (cl_capturevideo_buffer, 0, 18);
1184 cl_capturevideo_buffer[2] = 2; // uncompressed type
1185 cl_capturevideo_buffer[12] = (width >> 0) & 0xFF;
1186 cl_capturevideo_buffer[13] = (width >> 8) & 0xFF;
1187 cl_capturevideo_buffer[14] = (height >> 0) & 0xFF;
1188 cl_capturevideo_buffer[15] = (height >> 8) & 0xFF;
1189 cl_capturevideo_buffer[16] = 24; // pixel size
1190 qglReadPixels (x, y, width, height, GL_BGR, GL_UNSIGNED_BYTE, cl_capturevideo_buffer + 18);
1192 for (;cl_capturevideo_frame < newframenum;cl_capturevideo_frame++)
1194 sprintf(filename, "video/dp%06d.tga", cl_capturevideo_frame);
1195 if (!FS_WriteFile (filename, cl_capturevideo_buffer, width*height*3 + 18))
1204 void SCR_CaptureVideo_SoundFrame(unsigned char *bufstereo16le, size_t length, int rate)
1206 if (!cl_capturevideo_soundfile)
1208 cl_capturevideo_soundrate = rate;
1209 if (FS_Write (cl_capturevideo_soundfile, bufstereo16le, 4 * length) < (fs_offset_t)(4 * length))
1211 Cvar_SetValueQuick(&cl_capturevideo, 0);
1212 Con_Printf("video sound saving failed on frame %i, out of disk space? stopping video capture.\n", cl_capturevideo_frame);
1213 SCR_CaptureVideo_EndVideo();
1217 void SCR_CaptureVideo(void)
1220 if (cl_capturevideo.integer && r_render.integer)
1222 if (!cl_capturevideo_active)
1223 SCR_CaptureVideo_BeginVideo();
1224 if (cl_capturevideo_framerate != cl_capturevideo_fps.value)
1226 Con_Printf("You can not change the video framerate while recording a video.\n");
1227 Cvar_SetValueQuick(&cl_capturevideo_fps, cl_capturevideo_framerate);
1229 if (cl_capturevideo_soundfile)
1231 // preserve sound sync by duplicating frames when running slow
1232 newframenum = (Sys_DoubleTime() - cl_capturevideo_starttime) * cl_capturevideo_framerate;
1235 newframenum = cl_capturevideo_frame + 1;
1236 // if falling behind more than one second, stop
1237 if (newframenum - cl_capturevideo_frame > (int)ceil(cl_capturevideo_framerate))
1239 Cvar_SetValueQuick(&cl_capturevideo, 0);
1240 Con_Printf("video saving failed on frame %i, your machine is too slow for this capture speed.\n", cl_capturevideo_frame);
1241 SCR_CaptureVideo_EndVideo();
1245 if (!SCR_CaptureVideo_VideoFrame(newframenum))
1247 Cvar_SetValueQuick(&cl_capturevideo, 0);
1248 Con_Printf("video saving failed on frame %i, out of disk space? stopping video capture.\n", cl_capturevideo_frame);
1249 SCR_CaptureVideo_EndVideo();
1252 else if (cl_capturevideo_active)
1253 SCR_CaptureVideo_EndVideo();
1260 Grab six views for environment mapping tests
1267 qboolean flipx, flipy, flipdiagonaly;
1271 {{ 0, 0, 0}, "rt", false, false, false},
1272 {{ 0, 270, 0}, "ft", false, false, false},
1273 {{ 0, 180, 0}, "lf", false, false, false},
1274 {{ 0, 90, 0}, "bk", false, false, false},
1275 {{-90, 180, 0}, "up", true, true, false},
1276 {{ 90, 180, 0}, "dn", true, true, false},
1278 {{ 0, 0, 0}, "px", true, true, true},
1279 {{ 0, 90, 0}, "py", false, true, false},
1280 {{ 0, 180, 0}, "nx", false, false, true},
1281 {{ 0, 270, 0}, "ny", true, false, false},
1282 {{-90, 180, 0}, "pz", false, false, true},
1283 {{ 90, 180, 0}, "nz", false, false, true}
1286 static void R_Envmap_f (void)
1289 char filename[MAX_QPATH], basename[MAX_QPATH];
1290 unsigned char *buffer1;
1291 unsigned char *buffer2;
1292 unsigned char *buffer3;
1294 if (Cmd_Argc() != 3)
1296 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");
1300 strlcpy (basename, Cmd_Argv(1), sizeof (basename));
1301 size = atoi(Cmd_Argv(2));
1302 if (size != 128 && size != 256 && size != 512 && size != 1024)
1304 Con_Print("envmap: size must be one of 128, 256, 512, or 1024\n");
1307 if (size > vid.width || size > vid.height)
1309 Con_Print("envmap: your resolution is not big enough to render that size\n");
1317 r_refdef.width = size;
1318 r_refdef.height = size;
1320 r_refdef.frustum_x = tan(90 * M_PI / 360.0);
1321 r_refdef.frustum_y = tan(90 * M_PI / 360.0);
1323 buffer1 = (unsigned char *)Mem_Alloc(tempmempool, size * size * 3);
1324 buffer2 = (unsigned char *)Mem_Alloc(tempmempool, size * size * 3);
1325 buffer3 = (unsigned char *)Mem_Alloc(tempmempool, size * size * 3 + 18);
1327 for (j = 0;j < 12;j++)
1329 sprintf(filename, "env/%s%s.tga", basename, envmapinfo[j].name);
1330 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);
1335 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);
1345 //=============================================================================
1347 // LordHavoc: SHOWLMP stuff
1348 #define SHOWLMP_MAXLABELS 256
1349 typedef struct showlmp_s
1359 showlmp_t showlmp[SHOWLMP_MAXLABELS];
1361 void SHOWLMP_decodehide(void)
1365 lmplabel = MSG_ReadString();
1366 for (i = 0;i < SHOWLMP_MAXLABELS;i++)
1367 if (showlmp[i].isactive && strcmp(showlmp[i].label, lmplabel) == 0)
1369 showlmp[i].isactive = false;
1374 void SHOWLMP_decodeshow(void)
1377 char lmplabel[256], picname[256];
1379 strlcpy (lmplabel,MSG_ReadString(), sizeof (lmplabel));
1380 strlcpy (picname, MSG_ReadString(), sizeof (picname));
1381 if (gamemode == GAME_NEHAHRA) // LordHavoc: nasty old legacy junk
1388 x = MSG_ReadShort();
1389 y = MSG_ReadShort();
1392 for (i = 0;i < SHOWLMP_MAXLABELS;i++)
1393 if (showlmp[i].isactive)
1395 if (strcmp(showlmp[i].label, lmplabel) == 0)
1398 break; // drop out to replace it
1401 else if (k < 0) // find first empty one to replace
1404 return; // none found to replace
1405 // change existing one
1406 showlmp[k].isactive = true;
1407 strlcpy (showlmp[k].label, lmplabel, sizeof (showlmp[k].label));
1408 strlcpy (showlmp[k].pic, picname, sizeof (showlmp[k].pic));
1413 void SHOWLMP_drawall(void)
1416 for (i = 0;i < SHOWLMP_MAXLABELS;i++)
1417 if (showlmp[i].isactive)
1418 DrawQ_Pic(showlmp[i].x, showlmp[i].y, showlmp[i].pic, 0, 0, 1, 1, 1, 1, 0);
1421 void SHOWLMP_clear(void)
1424 for (i = 0;i < SHOWLMP_MAXLABELS;i++)
1425 showlmp[i].isactive = false;
1428 void CL_SetupScreenSize(void)
1430 float conwidth, conheight;
1432 VID_UpdateGamma(false);
1434 conwidth = bound(320, vid_conwidth.value, 2048);
1435 conheight = bound(200, vid_conheight.value, 1536);
1436 if (vid_conwidth.value != conwidth)
1437 Cvar_SetValue("vid_conwidth", conwidth);
1438 if (vid_conheight.value != conheight)
1439 Cvar_SetValue("vid_conheight", conheight);
1441 vid_conwidth.integer = vid_conwidth.integer;
1442 vid_conheight.integer = vid_conheight.integer;
1444 SCR_SetUpToDrawConsole();
1447 extern void R_Shadow_EditLights_DrawSelectedLightProperties(void);
1448 void CL_UpdateScreen(void)
1450 if (!scr_initialized || !con_initialized || vid_hidden)
1451 return; // not initialized yet
1453 // don't allow cheats in multiplayer
1454 if (!cl.islocalgame && cl.worldmodel)
1456 if (r_fullbright.integer != 0)
1457 Cvar_Set ("r_fullbright", "0");
1458 if (r_ambient.value != 0)
1459 Cvar_Set ("r_ambient", "0");
1463 if (scr_viewsize.value < 30)
1464 Cvar_Set ("viewsize","30");
1465 if (scr_viewsize.value > 120)
1466 Cvar_Set ("viewsize","120");
1468 // bound field of view
1469 if (scr_fov.value < 1)
1470 Cvar_Set ("fov","1");
1471 if (scr_fov.value > 170)
1472 Cvar_Set ("fov","170");
1474 // intermission is always full screen
1475 if (cl.intermission)
1479 if (scr_viewsize.value >= 120)
1480 sb_lines = 0; // no status bar at all
1481 else if (scr_viewsize.value >= 110)
1482 sb_lines = 24; // no inventory
1487 r_refdef.colormask[0] = 1;
1488 r_refdef.colormask[1] = 1;
1489 r_refdef.colormask[2] = 1;
1493 if (cls.signon == SIGNONS)
1494 R_TimeReport("other");
1496 CL_SetupScreenSize();
1500 if (cls.signon == SIGNONS)
1501 R_TimeReport("setup");
1503 //FIXME: force menu if nothing else to look at?
1504 //if (key_dest == key_game && cls.signon != SIGNONS && cls.state == ca_disconnected)
1506 if (cls.signon == SIGNONS)
1511 if (!r_letterbox.value)
1514 SCR_CheckDrawCenterString();
1520 if (cls.signon == SIGNONS)
1524 R_TimeReport_Start();
1526 R_Shadow_EditLights_DrawSelectedLightProperties();
1536 void CL_Screen_NewMap(void)