6 #include "cl_collision.h"
9 cvar_t scr_viewsize = {CVAR_SAVE, "viewsize","100", "how large the view should be, 110 disables inventory bar, 120 disables status bar"};
10 cvar_t scr_fov = {CVAR_SAVE, "fov","90", "field of vision, 1-170 degrees, default 90, some players use 110-130"}; // 1 - 170
11 cvar_t scr_conalpha = {CVAR_SAVE, "scr_conalpha", "1", "opacity of console background"};
12 cvar_t scr_conbrightness = {CVAR_SAVE, "scr_conbrightness", "1", "brightness of console background (0 = black, 1 = image)"};
13 cvar_t scr_conforcewhiledisconnected = {0, "scr_conforcewhiledisconnected", "1", "forces fullscreen console while disconnected"};
14 cvar_t scr_menuforcewhiledisconnected = {0, "scr_menuforcewhiledisconnected", "0", "forces menu while disconnected"};
15 cvar_t scr_centertime = {0, "scr_centertime","2", "how long centerprint messages show"};
16 cvar_t scr_showram = {CVAR_SAVE, "showram","1", "show ram icon if low on surface cache memory (not used)"};
17 cvar_t scr_showturtle = {CVAR_SAVE, "showturtle","0", "show turtle icon when framerate is too low (not used)"};
18 cvar_t scr_showpause = {CVAR_SAVE, "showpause","1", "show pause icon when game is paused"};
19 cvar_t scr_showbrand = {0, "showbrand","0", "shows gfx/brand.tga in a corner of the screen (different values select different positions, including centered)"};
20 cvar_t scr_printspeed = {0, "scr_printspeed","8", "speed of intermission printing (episode end texts)"};
21 cvar_t vid_conwidth = {CVAR_SAVE, "vid_conwidth", "640", "virtual width of 2D graphics system"};
22 cvar_t vid_conheight = {CVAR_SAVE, "vid_conheight", "480", "virtual height of 2D graphics system"};
23 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)"};
24 cvar_t scr_screenshot_jpeg = {CVAR_SAVE, "scr_screenshot_jpeg","1", "save jpeg instead of targa"};
25 cvar_t scr_screenshot_jpeg_quality = {CVAR_SAVE, "scr_screenshot_jpeg_quality","0.9", "image quality of saved jpeg"};
26 cvar_t scr_screenshot_gammaboost = {CVAR_SAVE, "scr_screenshot_gammaboost","1", "gamma correction on saved screenshots and videos, 1.0 saves unmodified images"};
27 // scr_screenshot_name is defined in fs.c
28 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_gammaboost affects the brightness of the output)"};
29 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)"};
30 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)"};
31 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)"};
32 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)"};
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)"};
34 cvar_t r_stereo_separation = {0, "r_stereo_separation", "4", "separation of eyes in the world (try negative values too)"};
35 cvar_t r_stereo_sidebyside = {0, "r_stereo_sidebyside", "0", "side by side views (for those who can't afford glasses but can afford eye strain)"};
36 cvar_t r_stereo_redblue = {0, "r_stereo_redblue", "0", "red/blue anaglyph stereo glasses (note: most of these glasses are actually red/cyan, try that one too)"};
37 cvar_t r_stereo_redcyan = {0, "r_stereo_redcyan", "0", "red/cyan anaglyph stereo glasses, the kind given away at drive-in movies like Creature From The Black Lagoon In 3D"};
38 cvar_t r_stereo_redgreen = {0, "r_stereo_redgreen", "0", "red/green anaglyph stereo glasses (for those who don't mind yellow)"};
39 cvar_t scr_zoomwindow = {CVAR_SAVE, "scr_zoomwindow", "0", "displays a zoomed in overlay window"};
40 cvar_t scr_zoomwindow_viewsizex = {CVAR_SAVE, "scr_zoomwindow_viewsizex", "20", "horizontal viewsize of zoom window"};
41 cvar_t scr_zoomwindow_viewsizey = {CVAR_SAVE, "scr_zoomwindow_viewsizey", "20", "vertical viewsize of zoom window"};
42 cvar_t scr_zoomwindow_fov = {CVAR_SAVE, "scr_zoomwindow_fov", "20", "fov of zoom window"};
45 int jpeg_supported = false;
47 qboolean scr_initialized; // ready to draw
49 float scr_con_current;
51 extern int con_vislines;
53 void DrawCrosshair(int num);
54 static void SCR_ScreenShot_f (void);
55 static void R_Envmap_f (void);
58 void R_ClearScreen(void);
61 ===============================================================================
65 ===============================================================================
68 char scr_centerstring[MAX_INPUTLINE];
69 float scr_centertime_start; // for slow victory printing
70 float scr_centertime_off;
79 Called for important messages that should stay in the center of the screen
83 void SCR_CenterPrint(char *str)
85 strlcpy (scr_centerstring, str, sizeof (scr_centerstring));
86 scr_centertime_off = scr_centertime.value;
87 scr_centertime_start = cl.time;
89 // count the number of lines for centering
100 void SCR_DrawCenterString (void)
108 // the finale prints the characters one at a time
110 remaining = (int)(scr_printspeed.value * (cl.time - scr_centertime_start));
114 scr_erase_center = 0;
115 start = scr_centerstring;
120 if (scr_center_lines <= 4)
121 y = (int)(vid_conheight.integer*0.35);
128 // scan the width of the line
129 for (l=0 ; l<vid_conwidth.integer/8 ; l++)
130 if (start[l] == '\n' || !start[l])
132 x = (vid_conwidth.integer - l*8)/2;
137 DrawQ_ColoredString(x, y, start, l, 8, 8, 1, 1, 1, 1, 0, &color);
145 while (*start && *start != '\n')
150 start++; // skip the \n
154 void SCR_CheckDrawCenterString (void)
156 if (scr_center_lines > scr_erase_lines)
157 scr_erase_lines = scr_center_lines;
159 scr_centertime_off -= cl.realframetime;
161 // don't draw if this is a normal stats-screen intermission,
162 // only if it is not an intermission, or a finale intermission
163 if (cl.intermission == 1)
165 if (scr_centertime_off <= 0 && !cl.intermission)
167 if (key_dest != key_game)
170 SCR_DrawCenterString ();
178 void SCR_DrawTurtle (void)
182 if (cls.state != ca_connected)
185 if (!scr_showturtle.integer)
188 if (cl.realframetime < 0.1)
198 DrawQ_Pic (0, 0, Draw_CachePic("gfx/turtle", true), 0, 0, 1, 1, 1, 1, 0);
206 void SCR_DrawNet (void)
208 if (cls.state != ca_connected)
210 if (realtime - cl.last_received_message < 0.3)
212 if (cls.demoplayback)
215 DrawQ_Pic (64, 0, Draw_CachePic("gfx/net", true), 0, 0, 1, 1, 1, 1, 0);
223 void SCR_DrawPause (void)
227 if (cls.state != ca_connected)
230 if (!scr_showpause.integer) // turn off for screenshots
236 pic = Draw_CachePic ("gfx/pause", true);
237 DrawQ_Pic ((vid_conwidth.integer - pic->width)/2, (vid_conheight.integer - pic->height)/2, pic, 0, 0, 1, 1, 1, 1, 0);
245 void SCR_DrawBrand (void)
250 if (!scr_showbrand.value)
253 pic = Draw_CachePic ("gfx/brand", true);
255 switch ((int)scr_showbrand.value)
257 case 1: // bottom left
259 y = vid_conheight.integer - pic->height;
261 case 2: // bottom centre
262 x = (vid_conwidth.integer - pic->width) / 2;
263 y = vid_conheight.integer - pic->height;
265 case 3: // bottom right
266 x = vid_conwidth.integer - pic->width;
267 y = vid_conheight.integer - pic->height;
269 case 4: // centre right
270 x = vid_conwidth.integer - pic->width;
271 y = (vid_conheight.integer - pic->height) / 2;
274 x = vid_conwidth.integer - pic->width;
277 case 6: // top centre
278 x = (vid_conwidth.integer - pic->width) / 2;
285 case 8: // centre left
287 y = (vid_conheight.integer - pic->height) / 2;
293 DrawQ_Pic (x, y, pic, 0, 0, 1, 1, 1, 1, 0);
301 static void SCR_DrawDownload(void)
307 if (!cls.qw_downloadname[0])
309 dpsnprintf(temp, sizeof(temp), "Downloading %s ... %3i%%\n", cls.qw_downloadname, cls.qw_downloadpercent);
310 len = (int)strlen(temp);
311 x = (vid_conwidth.integer - len*size) / 2;
312 y = vid_conheight.integer - size;
313 DrawQ_Pic(0, y, NULL, vid_conwidth.integer, size, 0, 0, 0, 0.5, 0);
314 DrawQ_String(x, y, temp, len, size, size, 1, 1, 1, 1, 0);
317 //=============================================================================
322 SCR_SetUpToDrawConsole
325 void SCR_SetUpToDrawConsole (void)
327 // lines of console to display
329 static int framecounter = 0;
333 if (scr_menuforcewhiledisconnected.integer && key_dest == key_game && cls.state == ca_disconnected)
335 if (framecounter >= 2)
343 if (scr_conforcewhiledisconnected.integer && key_dest == key_game && cls.signon != SIGNONS)
344 key_consoleactive |= KEY_CONSOLEACTIVE_FORCED;
346 key_consoleactive &= ~KEY_CONSOLEACTIVE_FORCED;
348 // decide on the height of the console
349 if (key_consoleactive & KEY_CONSOLEACTIVE_USER)
350 conlines = vid_conheight.integer/2; // half screen
352 conlines = 0; // none visible
354 scr_con_current = conlines;
362 void SCR_DrawConsole (void)
364 if (key_consoleactive & KEY_CONSOLEACTIVE_FORCED)
367 Con_DrawConsole (vid_conheight.integer);
369 else if (scr_con_current)
370 Con_DrawConsole ((int)scr_con_current);
374 if (key_dest == key_game || key_dest == key_message)
375 Con_DrawNotify (); // only draw notify in game
381 SCR_BeginLoadingPlaque
385 void SCR_BeginLoadingPlaque (void)
387 // save console log up to this point to log_file if it was set by configs
392 SCR_UpdateLoadingScreen();
395 //=============================================================================
397 char r_speeds_string[1024];
398 int speedstringcount, r_timereport_active;
399 double r_timereport_temp = 0, r_timereport_current = 0, r_timereport_start = 0;
401 void R_TimeReport(char *desc)
407 if (r_speeds.integer < 2 || !r_timereport_active)
411 qglFinish();CHECKGLERROR
412 r_timereport_temp = r_timereport_current;
413 r_timereport_current = Sys_DoubleTime();
414 t = (int) ((r_timereport_current - r_timereport_temp) * 1000000.0 + 0.5);
416 dpsnprintf(tempbuf, sizeof(tempbuf), "%8i %-11s", t, desc);
417 length = (int)strlen(tempbuf);
418 if (speedstringcount + length > (vid_conwidth.integer / 8))
420 strlcat(r_speeds_string, "\n", sizeof(r_speeds_string));
421 speedstringcount = 0;
423 strlcat(r_speeds_string, tempbuf, sizeof(r_speeds_string));
424 speedstringcount += length;
427 void R_TimeReport_Frame(void)
431 if (r_speeds_string[0])
433 if (r_timereport_active)
435 r_timereport_current = r_timereport_start;
436 R_TimeReport("total");
439 if (r_speeds_string[strlen(r_speeds_string)-1] == '\n')
440 r_speeds_string[strlen(r_speeds_string)-1] = 0;
442 for (i = 0;r_speeds_string[i];i++)
443 if (r_speeds_string[i] == '\n')
445 y = vid_conheight.integer - sb_lines - lines * 8;
447 DrawQ_Pic(0, y, NULL, vid_conwidth.integer, lines * 8, 0, 0, 0, 0.5, 0);
448 while (r_speeds_string[i])
451 while (r_speeds_string[i] && r_speeds_string[i] != '\n')
454 DrawQ_String(0, y, r_speeds_string + j, i - j, 8, 8, 1, 1, 1, 1, 0);
455 if (r_speeds_string[i] == '\n')
459 r_speeds_string[0] = 0;
460 r_timereport_active = false;
462 if (r_speeds.integer && cls.signon == SIGNONS && cls.state == ca_connected)
464 speedstringcount = 0;
465 r_speeds_string[0] = 0;
466 r_timereport_active = false;
467 sprintf(r_speeds_string + strlen(r_speeds_string), "org:'%+8.2f %+8.2f %+8.2f' dir:'%+2.3f %+2.3f %+2.3f'\n", r_view.origin[0], r_view.origin[1], r_view.origin[2], r_view.forward[0], r_view.forward[1], r_view.forward[2]);
468 sprintf(r_speeds_string + strlen(r_speeds_string), "%5i entities%6i surfaces%6i triangles%5i leafs%5i portals%6i particles\n", r_refdef.stats.entities, r_refdef.stats.entities_surfaces, r_refdef.stats.entities_triangles, r_refdef.stats.world_leafs, r_refdef.stats.world_portals, r_refdef.stats.particles);
469 sprintf(r_speeds_string + strlen(r_speeds_string), "%4i lights%4i clears%4i scissored%7i light%7i shadow%7i dynamic\n", r_refdef.stats.lights, r_refdef.stats.lights_clears, r_refdef.stats.lights_scissored, r_refdef.stats.lights_lighttriangles, r_refdef.stats.lights_shadowtriangles, r_refdef.stats.lights_dynamicshadowtriangles);
470 if (r_refdef.stats.bloom)
471 sprintf(r_speeds_string + strlen(r_speeds_string), "rendered%6i meshes%8i triangles bloompixels%8i copied%8i drawn\n", r_refdef.stats.meshes, r_refdef.stats.meshes_elements / 3, r_refdef.stats.bloom_copypixels, r_refdef.stats.bloom_drawpixels);
473 sprintf(r_speeds_string + strlen(r_speeds_string), "rendered%6i meshes%8i triangles\n", r_refdef.stats.meshes, r_refdef.stats.meshes_elements / 3);
475 memset(&r_refdef.stats, 0, sizeof(r_refdef.stats));
477 if (r_speeds.integer >= 2)
479 r_timereport_active = true;
480 r_timereport_start = r_timereport_current = Sys_DoubleTime();
492 void SCR_SizeUp_f (void)
494 Cvar_SetValue ("viewsize",scr_viewsize.value+10);
505 void SCR_SizeDown_f (void)
507 Cvar_SetValue ("viewsize",scr_viewsize.value-10);
510 void CL_Screen_Init(void)
512 Cvar_RegisterVariable (&scr_fov);
513 Cvar_RegisterVariable (&scr_viewsize);
514 Cvar_RegisterVariable (&scr_conalpha);
515 Cvar_RegisterVariable (&scr_conbrightness);
516 Cvar_RegisterVariable (&scr_conforcewhiledisconnected);
517 Cvar_RegisterVariable (&scr_menuforcewhiledisconnected);
518 Cvar_RegisterVariable (&scr_showram);
519 Cvar_RegisterVariable (&scr_showturtle);
520 Cvar_RegisterVariable (&scr_showpause);
521 Cvar_RegisterVariable (&scr_showbrand);
522 Cvar_RegisterVariable (&scr_centertime);
523 Cvar_RegisterVariable (&scr_printspeed);
524 Cvar_RegisterVariable (&vid_conwidth);
525 Cvar_RegisterVariable (&vid_conheight);
526 Cvar_RegisterVariable (&vid_pixelheight);
527 Cvar_RegisterVariable (&scr_screenshot_jpeg);
528 Cvar_RegisterVariable (&scr_screenshot_jpeg_quality);
529 Cvar_RegisterVariable (&scr_screenshot_gammaboost);
530 Cvar_RegisterVariable (&cl_capturevideo);
531 Cvar_RegisterVariable (&cl_capturevideo_sound);
532 Cvar_RegisterVariable (&cl_capturevideo_fps);
533 Cvar_RegisterVariable (&cl_capturevideo_rawrgb);
534 Cvar_RegisterVariable (&cl_capturevideo_rawyv12);
535 Cvar_RegisterVariable (&r_letterbox);
536 Cvar_RegisterVariable(&r_stereo_separation);
537 Cvar_RegisterVariable(&r_stereo_sidebyside);
538 Cvar_RegisterVariable(&r_stereo_redblue);
539 Cvar_RegisterVariable(&r_stereo_redcyan);
540 Cvar_RegisterVariable(&r_stereo_redgreen);
541 Cvar_RegisterVariable(&scr_zoomwindow);
542 Cvar_RegisterVariable(&scr_zoomwindow_viewsizex);
543 Cvar_RegisterVariable(&scr_zoomwindow_viewsizey);
544 Cvar_RegisterVariable(&scr_zoomwindow_fov);
546 Cmd_AddCommand ("sizeup",SCR_SizeUp_f, "increase view size (increases viewsize cvar)");
547 Cmd_AddCommand ("sizedown",SCR_SizeDown_f, "decrease view size (decreases viewsize cvar)");
548 Cmd_AddCommand ("screenshot",SCR_ScreenShot_f, "takes a screenshot of the next rendered frame");
549 Cmd_AddCommand ("envmap", R_Envmap_f, "render a cubemap (skybox) of the current scene");
551 scr_initialized = true;
559 void SCR_ScreenShot_f (void)
561 static int shotnumber;
562 static char oldname[MAX_QPATH];
563 char base[MAX_QPATH];
564 char filename[MAX_QPATH];
565 unsigned char *buffer1;
566 unsigned char *buffer2;
567 unsigned char *buffer3;
568 qboolean jpeg = (scr_screenshot_jpeg.integer != 0);
570 sprintf (base, "screenshots/%s", scr_screenshot_name.string);
572 if (strcmp (oldname, scr_screenshot_name.string))
574 sprintf(oldname, "%s", scr_screenshot_name.string);
578 // find a file name to save it to
579 for (;shotnumber < 1000000;shotnumber++)
580 if (!FS_SysFileExists(va("%s/%s%06d.tga", fs_gamedir, base, shotnumber)) && !FS_SysFileExists(va("%s/%s%06d.jpg", fs_gamedir, base, shotnumber)))
582 if (shotnumber >= 1000000)
584 Con_Print("SCR_ScreenShot_f: Couldn't create the image file\n");
588 sprintf(filename, "%s%06d.%s", base, shotnumber, jpeg ? "jpg" : "tga");
590 buffer1 = (unsigned char *)Mem_Alloc(tempmempool, vid.width * vid.height * 3);
591 buffer2 = (unsigned char *)Mem_Alloc(tempmempool, vid.width * vid.height * 3);
592 buffer3 = (unsigned char *)Mem_Alloc(tempmempool, vid.width * vid.height * 3 + 18);
594 if (SCR_ScreenShot (filename, buffer1, buffer2, buffer3, 0, 0, vid.width, vid.height, false, false, false, jpeg, true))
595 Con_Printf("Wrote %s\n", filename);
597 Con_Printf("unable to write %s\n", filename);
606 void SCR_CaptureVideo_BeginVideo(void)
610 unsigned char out[44];
611 if (cls.capturevideo_active)
613 // soundrate is figured out on the first SoundFrame
614 cls.capturevideo_active = true;
615 cls.capturevideo_starttime = Sys_DoubleTime();
616 cls.capturevideo_framerate = bound(1, cl_capturevideo_fps.value, 1000);
617 cls.capturevideo_soundrate = 0;
618 cls.capturevideo_frame = 0;
619 cls.capturevideo_buffer = (unsigned char *)Mem_Alloc(tempmempool, vid.width * vid.height * (3+3+3) + 18);
620 gamma = 1.0/scr_screenshot_gammaboost.value;
623 for (i = 0;i < 256;i++)
625 unsigned char j = (unsigned char)bound(0, 255*pow(i/255.0, gamma), 255);
626 cls.capturevideo_rgbgammatable[0][i] = j;
627 cls.capturevideo_rgbgammatable[1][i] = j;
628 cls.capturevideo_rgbgammatable[2][i] = j;
632 R = Y + 1.4075 * (Cr - 128);
633 G = Y + -0.3455 * (Cb - 128) + -0.7169 * (Cr - 128);
634 B = Y + 1.7790 * (Cb - 128);
635 Y = R * .299 + G * .587 + B * .114;
636 Cb = R * -.169 + G * -.332 + B * .500 + 128.;
637 Cr = R * .500 + G * -.419 + B * -.0813 + 128.;
639 for (i = 0;i < 256;i++)
641 g = 255*pow(i/255.0, gamma);
642 // Y weights from RGB
643 cls.capturevideo_rgbtoyuvscaletable[0][0][i] = (short)(g * 0.299);
644 cls.capturevideo_rgbtoyuvscaletable[0][1][i] = (short)(g * 0.587);
645 cls.capturevideo_rgbtoyuvscaletable[0][2][i] = (short)(g * 0.114);
646 // Cb weights from RGB
647 cls.capturevideo_rgbtoyuvscaletable[1][0][i] = (short)(g * -0.169);
648 cls.capturevideo_rgbtoyuvscaletable[1][1][i] = (short)(g * -0.332);
649 cls.capturevideo_rgbtoyuvscaletable[1][2][i] = (short)(g * 0.500);
650 // Cr weights from RGB
651 cls.capturevideo_rgbtoyuvscaletable[2][0][i] = (short)(g * 0.500);
652 cls.capturevideo_rgbtoyuvscaletable[2][1][i] = (short)(g * -0.419);
653 cls.capturevideo_rgbtoyuvscaletable[2][2][i] = (short)(g * -0.0813);
654 // range reduction of YCbCr to valid signal range
655 cls.capturevideo_yuvnormalizetable[0][i] = 16 + i * (236-16) / 256;
656 cls.capturevideo_yuvnormalizetable[1][i] = 16 + i * (240-16) / 256;
657 cls.capturevideo_yuvnormalizetable[2][i] = 16 + i * (240-16) / 256;
660 if (cl_capturevideo_rawrgb.integer)
662 cls.capturevideo_format = CAPTUREVIDEOFORMAT_RAWRGB;
663 cls.capturevideo_videofile = FS_Open ("video/dpvideo.rgb", "wb", false, true);
665 else if (cl_capturevideo_rawyv12.integer)
667 cls.capturevideo_format = CAPTUREVIDEOFORMAT_RAWYV12;
668 cls.capturevideo_videofile = FS_Open ("video/dpvideo.yv12", "wb", false, true);
670 else if (scr_screenshot_jpeg.integer)
672 cls.capturevideo_format = CAPTUREVIDEOFORMAT_JPEG;
673 cls.capturevideo_videofile = NULL;
677 cls.capturevideo_format = CAPTUREVIDEOFORMAT_TARGA;
678 cls.capturevideo_videofile = NULL;
681 if (cl_capturevideo_sound.integer)
683 cls.capturevideo_soundfile = FS_Open ("video/dpvideo.wav", "wb", false, true);
684 // wave header will be filled out when video ends
686 FS_Write (cls.capturevideo_soundfile, out, 44);
689 cls.capturevideo_soundfile = NULL;
692 void SCR_CaptureVideo_EndVideo(void)
695 unsigned char out[44];
696 if (!cls.capturevideo_active)
698 cls.capturevideo_active = false;
700 if (cls.capturevideo_videofile)
702 FS_Close(cls.capturevideo_videofile);
703 cls.capturevideo_videofile = NULL;
706 // finish the wave file
707 if (cls.capturevideo_soundfile)
709 i = (int)FS_Tell (cls.capturevideo_soundfile);
710 //"RIFF", (int) unknown (chunk size), "WAVE",
711 //"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
712 //"data", (int) unknown (chunk size)
713 memcpy (out, "RIFF****WAVEfmt \x10\x00\x00\x00\x01\x00\x02\x00********\x04\x00\x10\0data****", 44);
714 // the length of the whole RIFF chunk
717 out[5] = (n >> 8) & 0xFF;
718 out[6] = (n >> 16) & 0xFF;
719 out[7] = (n >> 24) & 0xFF;
721 n = cls.capturevideo_soundrate;
722 out[24] = (n) & 0xFF;
723 out[25] = (n >> 8) & 0xFF;
724 out[26] = (n >> 16) & 0xFF;
725 out[27] = (n >> 24) & 0xFF;
726 // bytes per second (rate * channels * bytes per channel)
727 n = cls.capturevideo_soundrate * 2 * 2;
728 out[28] = (n) & 0xFF;
729 out[29] = (n >> 8) & 0xFF;
730 out[30] = (n >> 16) & 0xFF;
731 out[31] = (n >> 24) & 0xFF;
732 // the length of the data chunk
734 out[40] = (n) & 0xFF;
735 out[41] = (n >> 8) & 0xFF;
736 out[42] = (n >> 16) & 0xFF;
737 out[43] = (n >> 24) & 0xFF;
738 FS_Seek (cls.capturevideo_soundfile, 0, SEEK_SET);
739 FS_Write (cls.capturevideo_soundfile, out, 44);
740 FS_Close (cls.capturevideo_soundfile);
741 cls.capturevideo_soundfile = NULL;
744 if (cls.capturevideo_buffer)
746 Mem_Free (cls.capturevideo_buffer);
747 cls.capturevideo_buffer = NULL;
750 cls.capturevideo_starttime = 0;
751 cls.capturevideo_framerate = 0;
752 cls.capturevideo_frame = 0;
755 qboolean SCR_CaptureVideo_VideoFrame(int newframenum)
757 int x = 0, y = 0, width = vid.width, height = vid.height;
758 unsigned char *b, *out;
760 int outoffset = (width/2)*(height/2);
762 //return SCR_ScreenShot(filename, cls.capturevideo_buffer, cls.capturevideo_buffer + vid.width * vid.height * 3, cls.capturevideo_buffer + vid.width * vid.height * 6, 0, 0, vid.width, vid.height, false, false, false, jpeg, true);
763 // speed is critical here, so do saving as directly as possible
764 switch (cls.capturevideo_format)
766 case CAPTUREVIDEOFORMAT_RAWYV12:
767 // FIXME: width/height must be multiple of 2, enforce this?
768 qglReadPixels (x, y, width, height, GL_RGB, GL_UNSIGNED_BYTE, cls.capturevideo_buffer);CHECKGLERROR
769 // process one line at a time, and CbCr every other line at 2 pixel intervals
770 for (y = 0;y < height;y++)
773 for (b = cls.capturevideo_buffer + (height-1-y)*width*3, out = cls.capturevideo_buffer + width*height*3 + y*width, x = 0;x < width;x++, b += 3, out++)
774 *out = cls.capturevideo_yuvnormalizetable[0][cls.capturevideo_rgbtoyuvscaletable[0][0][b[0]] + cls.capturevideo_rgbtoyuvscaletable[0][1][b[1]] + cls.capturevideo_rgbtoyuvscaletable[0][2][b[2]]];
777 // 2x2 Cb and Cr planes
779 // low quality, no averaging
780 for (b = cls.capturevideo_buffer + (height-2-y)*width*3, out = cls.capturevideo_buffer + width*height*3 + width*height + (y/2)*(width/2), x = 0;x < width/2;x++, b += 6, out++)
783 out[0 ] = cls.capturevideo_yuvnormalizetable[2][cls.capturevideo_rgbtoyuvscaletable[2][0][b[0]] + cls.capturevideo_rgbtoyuvscaletable[2][1][b[1]] + cls.capturevideo_rgbtoyuvscaletable[2][2][b[2]] + 128];
785 out[outoffset] = cls.capturevideo_yuvnormalizetable[1][cls.capturevideo_rgbtoyuvscaletable[1][0][b[0]] + cls.capturevideo_rgbtoyuvscaletable[1][1][b[1]] + cls.capturevideo_rgbtoyuvscaletable[1][2][b[2]] + 128];
788 // high quality, averaging
789 int inpitch = width*3;
790 for (b = cls.capturevideo_buffer + (height-2-y)*width*3, out = cls.capturevideo_buffer + width*height*3 + width*height + (y/2)*(width/2), x = 0;x < width/2;x++, b += 6, out++)
792 int blockr, blockg, blockb;
793 blockr = (b[0] + b[3] + b[inpitch+0] + b[inpitch+3]) >> 2;
794 blockg = (b[1] + b[4] + b[inpitch+1] + b[inpitch+4]) >> 2;
795 blockb = (b[2] + b[5] + b[inpitch+2] + b[inpitch+5]) >> 2;
797 out[0 ] = cls.capturevideo_yuvnormalizetable[2][cls.capturevideo_rgbtoyuvscaletable[2][0][blockr] + cls.capturevideo_rgbtoyuvscaletable[2][1][blockg] + cls.capturevideo_rgbtoyuvscaletable[2][2][blockb] + 128];
799 out[outoffset] = cls.capturevideo_yuvnormalizetable[1][cls.capturevideo_rgbtoyuvscaletable[1][0][blockr] + cls.capturevideo_rgbtoyuvscaletable[1][1][blockg] + cls.capturevideo_rgbtoyuvscaletable[1][2][blockb] + 128];
804 for (;cls.capturevideo_frame < newframenum;cls.capturevideo_frame++)
805 if (!FS_Write (cls.capturevideo_videofile, cls.capturevideo_buffer + width*height*3, width*height+(width/2)*(height/2)*2))
808 case CAPTUREVIDEOFORMAT_RAWRGB:
809 qglReadPixels (x, y, width, height, GL_RGB, GL_UNSIGNED_BYTE, cls.capturevideo_buffer);CHECKGLERROR
810 for (;cls.capturevideo_frame < newframenum;cls.capturevideo_frame++)
811 if (!FS_Write (cls.capturevideo_videofile, cls.capturevideo_buffer, width*height*3))
814 case CAPTUREVIDEOFORMAT_JPEG:
815 qglReadPixels (x, y, width, height, GL_RGB, GL_UNSIGNED_BYTE, cls.capturevideo_buffer);CHECKGLERROR
816 for (;cls.capturevideo_frame < newframenum;cls.capturevideo_frame++)
818 sprintf(filename, "video/dp%06d.jpg", cls.capturevideo_frame);
819 if (!JPEG_SaveImage_preflipped (filename, width, height, cls.capturevideo_buffer))
823 case CAPTUREVIDEOFORMAT_TARGA:
824 //return Image_WriteTGARGB_preflipped (filename, width, height, cls.capturevideo_buffer, cls.capturevideo_buffer + vid.width * vid.height * 3, );
825 memset (cls.capturevideo_buffer, 0, 18);
826 cls.capturevideo_buffer[2] = 2; // uncompressed type
827 cls.capturevideo_buffer[12] = (width >> 0) & 0xFF;
828 cls.capturevideo_buffer[13] = (width >> 8) & 0xFF;
829 cls.capturevideo_buffer[14] = (height >> 0) & 0xFF;
830 cls.capturevideo_buffer[15] = (height >> 8) & 0xFF;
831 cls.capturevideo_buffer[16] = 24; // pixel size
832 qglReadPixels (x, y, width, height, GL_BGR, GL_UNSIGNED_BYTE, cls.capturevideo_buffer + 18);CHECKGLERROR
833 for (;cls.capturevideo_frame < newframenum;cls.capturevideo_frame++)
835 sprintf(filename, "video/dp%06d.tga", cls.capturevideo_frame);
836 if (!FS_WriteFile (filename, cls.capturevideo_buffer, width*height*3 + 18))
845 void SCR_CaptureVideo_SoundFrame(unsigned char *bufstereo16le, size_t length, int rate)
847 if (!cls.capturevideo_soundfile)
849 cls.capturevideo_soundrate = rate;
850 if (FS_Write (cls.capturevideo_soundfile, bufstereo16le, 4 * length) < (fs_offset_t)(4 * length))
852 Cvar_SetValueQuick(&cl_capturevideo, 0);
853 Con_Printf("video sound saving failed on frame %i, out of disk space? stopping video capture.\n", cls.capturevideo_frame);
854 SCR_CaptureVideo_EndVideo();
858 void SCR_CaptureVideo(void)
861 if (cl_capturevideo.integer && r_render.integer)
863 if (!cls.capturevideo_active)
864 SCR_CaptureVideo_BeginVideo();
865 if (cls.capturevideo_framerate != cl_capturevideo_fps.value)
867 Con_Printf("You can not change the video framerate while recording a video.\n");
868 Cvar_SetValueQuick(&cl_capturevideo_fps, cls.capturevideo_framerate);
870 if (cls.capturevideo_soundfile)
872 // preserve sound sync by duplicating frames when running slow
873 newframenum = (int)((Sys_DoubleTime() - cls.capturevideo_starttime) * cls.capturevideo_framerate);
876 newframenum = cls.capturevideo_frame + 1;
877 // if falling behind more than one second, stop
878 if (newframenum - cls.capturevideo_frame > (int)ceil(cls.capturevideo_framerate))
880 Cvar_SetValueQuick(&cl_capturevideo, 0);
881 Con_Printf("video saving failed on frame %i, your machine is too slow for this capture speed.\n", cls.capturevideo_frame);
882 SCR_CaptureVideo_EndVideo();
886 if (!SCR_CaptureVideo_VideoFrame(newframenum))
888 Cvar_SetValueQuick(&cl_capturevideo, 0);
889 Con_Printf("video saving failed on frame %i, out of disk space? stopping video capture.\n", cls.capturevideo_frame);
890 SCR_CaptureVideo_EndVideo();
893 else if (cls.capturevideo_active)
894 SCR_CaptureVideo_EndVideo();
901 Grab six views for environment mapping tests
908 qboolean flipx, flipy, flipdiagonaly;
912 {{ 0, 0, 0}, "rt", false, false, false},
913 {{ 0, 270, 0}, "ft", false, false, false},
914 {{ 0, 180, 0}, "lf", false, false, false},
915 {{ 0, 90, 0}, "bk", false, false, false},
916 {{-90, 180, 0}, "up", true, true, false},
917 {{ 90, 180, 0}, "dn", true, true, false},
919 {{ 0, 0, 0}, "px", true, true, true},
920 {{ 0, 90, 0}, "py", false, true, false},
921 {{ 0, 180, 0}, "nx", false, false, true},
922 {{ 0, 270, 0}, "ny", true, false, false},
923 {{-90, 180, 0}, "pz", false, false, true},
924 {{ 90, 180, 0}, "nz", false, false, true}
927 static void R_Envmap_f (void)
930 char filename[MAX_QPATH], basename[MAX_QPATH];
931 unsigned char *buffer1;
932 unsigned char *buffer2;
933 unsigned char *buffer3;
937 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");
941 strlcpy (basename, Cmd_Argv(1), sizeof (basename));
942 size = atoi(Cmd_Argv(2));
943 if (size != 128 && size != 256 && size != 512 && size != 1024)
945 Con_Print("envmap: size must be one of 128, 256, 512, or 1024\n");
948 if (size > vid.width || size > vid.height)
950 Con_Print("envmap: your resolution is not big enough to render that size\n");
954 r_refdef.envmap = true;
962 r_view.height = size;
965 r_view.frustum_x = tan(90 * M_PI / 360.0);
966 r_view.frustum_y = tan(90 * M_PI / 360.0);
968 buffer1 = (unsigned char *)Mem_Alloc(tempmempool, size * size * 3);
969 buffer2 = (unsigned char *)Mem_Alloc(tempmempool, size * size * 3);
970 buffer3 = (unsigned char *)Mem_Alloc(tempmempool, size * size * 3 + 18);
972 for (j = 0;j < 12;j++)
974 sprintf(filename, "env/%s%s.tga", basename, envmapinfo[j].name);
975 Matrix4x4_CreateFromQuakeEntity(&r_view.matrix, r_view.origin[0], r_view.origin[1], r_view.origin[2], envmapinfo[j].angles[0], envmapinfo[j].angles[1], envmapinfo[j].angles[2], 1);
980 SCR_ScreenShot(filename, buffer1, buffer2, buffer3, 0, vid.height - (r_view.y + r_view.height), size, size, envmapinfo[j].flipx, envmapinfo[j].flipy, envmapinfo[j].flipdiagonaly, false, false);
987 r_refdef.envmap = false;
990 //=============================================================================
992 // LordHavoc: SHOWLMP stuff
993 #define SHOWLMP_MAXLABELS 256
994 typedef struct showlmp_s
1004 showlmp_t showlmp[SHOWLMP_MAXLABELS];
1006 void SHOWLMP_decodehide(void)
1010 lmplabel = MSG_ReadString();
1011 for (i = 0;i < SHOWLMP_MAXLABELS;i++)
1012 if (showlmp[i].isactive && strcmp(showlmp[i].label, lmplabel) == 0)
1014 showlmp[i].isactive = false;
1019 void SHOWLMP_decodeshow(void)
1022 char lmplabel[256], picname[256];
1024 strlcpy (lmplabel,MSG_ReadString(), sizeof (lmplabel));
1025 strlcpy (picname, MSG_ReadString(), sizeof (picname));
1026 if (gamemode == GAME_NEHAHRA) // LordHavoc: nasty old legacy junk
1033 x = MSG_ReadShort();
1034 y = MSG_ReadShort();
1037 for (i = 0;i < SHOWLMP_MAXLABELS;i++)
1038 if (showlmp[i].isactive)
1040 if (strcmp(showlmp[i].label, lmplabel) == 0)
1043 break; // drop out to replace it
1046 else if (k < 0) // find first empty one to replace
1049 return; // none found to replace
1050 // change existing one
1051 showlmp[k].isactive = true;
1052 strlcpy (showlmp[k].label, lmplabel, sizeof (showlmp[k].label));
1053 strlcpy (showlmp[k].pic, picname, sizeof (showlmp[k].pic));
1058 void SHOWLMP_drawall(void)
1061 for (i = 0;i < SHOWLMP_MAXLABELS;i++)
1062 if (showlmp[i].isactive)
1063 DrawQ_Pic(showlmp[i].x, showlmp[i].y, Draw_CachePic(showlmp[i].pic, true), 0, 0, 1, 1, 1, 1, 0);
1066 void SHOWLMP_clear(void)
1069 for (i = 0;i < SHOWLMP_MAXLABELS;i++)
1070 showlmp[i].isactive = false;
1074 ==============================================================================
1078 ==============================================================================
1081 qboolean SCR_ScreenShot(char *filename, unsigned char *buffer1, unsigned char *buffer2, unsigned char *buffer3, int x, int y, int width, int height, qboolean flipx, qboolean flipy, qboolean flipdiagonal, qboolean jpeg, qboolean gammacorrect)
1083 int indices[3] = {0,1,2};
1086 if (!r_render.integer)
1090 qglReadPixels (x, y, width, height, GL_RGB, GL_UNSIGNED_BYTE, buffer1);CHECKGLERROR
1092 if (scr_screenshot_gammaboost.value != 1 && gammacorrect)
1095 double igamma = 1.0 / scr_screenshot_gammaboost.value;
1096 unsigned char ramp[256];
1097 for (i = 0;i < 256;i++)
1098 ramp[i] = (unsigned char) (pow(i * (1.0 / 255.0), igamma) * 255.0);
1099 for (i = 0;i < width*height*3;i++)
1100 buffer1[i] = ramp[buffer1[i]];
1103 Image_CopyMux (buffer2, buffer1, width, height, flipx, flipy, flipdiagonal, 3, 3, indices);
1106 ret = JPEG_SaveImage_preflipped (filename, width, height, buffer2);
1108 ret = Image_WriteTGARGB_preflipped (filename, width, height, buffer2, buffer3);
1113 //=============================================================================
1115 void R_ClearScreen(void)
1117 if (r_render.integer)
1121 if (r_refdef.fogenabled)
1123 qglClearColor(r_refdef.fogcolor[0],r_refdef.fogcolor[1],r_refdef.fogcolor[2],0);CHECKGLERROR
1127 qglClearColor(0,0,0,0);CHECKGLERROR
1129 qglClearDepth(1);CHECKGLERROR
1132 // LordHavoc: we use a stencil centered around 128 instead of 0,
1133 // to avoid clamping interfering with strange shadow volume
1135 qglClearStencil(128);CHECKGLERROR
1138 GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | (gl_stencil ? GL_STENCIL_BUFFER_BIT : 0));
1139 // set dithering mode
1140 if (gl_dither.integer)
1142 qglEnable(GL_DITHER);CHECKGLERROR
1146 qglDisable(GL_DITHER);CHECKGLERROR
1151 qboolean CL_VM_UpdateView (void);
1152 void SCR_DrawConsole (void);
1153 void R_Shadow_EditLights_DrawSelectedLightProperties(void);
1157 void SCR_DrawScreen (void)
1161 if (r_timereport_active)
1162 R_TimeReport("setup");
1164 R_UpdateVariables();
1166 if (cls.signon == SIGNONS)
1170 size = scr_viewsize.value * (1.0 / 100.0);
1171 size = min(size, 1);
1173 if (r_stereo_sidebyside.integer)
1175 r_view.width = (int)(vid.width * size / 2.5);
1176 r_view.height = (int)(vid.height * size / 2.5 * (1 - bound(0, r_letterbox.value, 100) / 100));
1178 r_view.x = (int)((vid.width - r_view.width * 2.5) * 0.5);
1179 r_view.y = (int)((vid.height - r_view.height)/2);
1182 r_view.x += (int)(r_view.width * 1.5);
1186 r_view.width = (int)(vid.width * size);
1187 r_view.height = (int)(vid.height * size * (1 - bound(0, r_letterbox.value, 100) / 100));
1189 r_view.x = (int)((vid.width - r_view.width)/2);
1190 r_view.y = (int)((vid.height - r_view.height)/2);
1194 // LordHavoc: viewzoom (zoom in for sniper rifles, etc)
1195 // LordHavoc: this is designed to produce widescreen fov values
1196 // when the screen is wider than 4/3 width/height aspect, to do
1197 // this it simply assumes the requested fov is the vertical fov
1198 // for a 4x3 display, if the ratio is not 4x3 this makes the fov
1199 // higher/lower according to the ratio
1200 r_view.frustum_y = tan(scr_fov.value * cl.viewzoom * M_PI / 360.0) * (3.0/4.0);
1201 r_view.frustum_x = r_view.frustum_y * (float)r_view.width / (float)r_view.height / vid_pixelheight.value;
1203 r_view.frustum_x *= r_refdef.frustumscale_x;
1204 r_view.frustum_y *= r_refdef.frustumscale_y;
1206 if(!CL_VM_UpdateView())
1211 if (scr_zoomwindow.integer)
1213 float sizex = bound(10, scr_zoomwindow_viewsizex.value, 100) / 100.0;
1214 float sizey = bound(10, scr_zoomwindow_viewsizey.value, 100) / 100.0;
1215 r_view.width = (int)(vid.width * sizex);
1216 r_view.height = (int)(vid.height * sizey);
1218 r_view.x = (int)((vid.width - r_view.width)/2);
1222 r_view.frustum_y = tan(scr_zoomwindow_fov.value * cl.viewzoom * M_PI / 360.0) * (3.0/4.0);
1223 r_view.frustum_x = r_view.frustum_y * vid_pixelheight.value * (float)r_view.width / (float)r_view.height;
1225 r_view.frustum_x *= r_refdef.frustumscale_x;
1226 r_view.frustum_y *= r_refdef.frustumscale_y;
1228 if(!CL_VM_UpdateView())
1233 if (!r_stereo_sidebyside.integer)
1235 r_view.width = vid.width;
1236 r_view.height = vid.height;
1246 //FIXME: force menu if nothing else to look at?
1247 //if (key_dest == key_game && cls.signon != SIGNONS && cls.state == ca_disconnected)
1249 if (cls.signon == SIGNONS)
1254 if (!r_letterbox.value)
1257 SCR_CheckDrawCenterString();
1261 R_Shadow_EditLights_DrawSelectedLightProperties();
1270 if (r_timereport_active)
1273 if (cls.signon == SIGNONS)
1274 R_TimeReport_Frame();
1282 if (r_timereport_active)
1283 R_TimeReport("meshfinish");
1286 void SCR_UpdateLoadingScreen (void)
1291 float texcoord2f[8];
1292 // don't do anything if not initialized yet
1296 qglViewport(0, 0, vid.width, vid.height);CHECKGLERROR
1297 //qglDisable(GL_SCISSOR_TEST);CHECKGLERROR
1298 //qglDepthMask(1);CHECKGLERROR
1299 qglColorMask(1,1,1,1);CHECKGLERROR
1300 //qglClearColor(0,0,0,0);CHECKGLERROR
1301 //qglClear(GL_COLOR_BUFFER_BIT);CHECKGLERROR
1302 //qglCullFace(GL_FRONT);CHECKGLERROR
1303 //qglDisable(GL_CULL_FACE);CHECKGLERROR
1306 GL_SetupView_Mode_Ortho(0, 0, vid_conwidth.integer, vid_conheight.integer, -10, 100);
1308 R_Mesh_Matrix(&identitymatrix);
1309 // draw the loading plaque
1310 pic = Draw_CachePic("gfx/loading", true);
1311 x = (vid_conwidth.integer - pic->width)/2;
1312 y = (vid_conheight.integer - pic->height)/2;
1314 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1315 GL_DepthTest(false);
1316 R_Mesh_VertexPointer(vertex3f);
1317 R_Mesh_ColorPointer(NULL);
1318 R_Mesh_ResetTextureState();
1319 R_Mesh_TexBind(0, R_GetTexture(pic->tex));
1320 R_Mesh_TexCoordPointer(0, 2, texcoord2f);
1321 vertex3f[2] = vertex3f[5] = vertex3f[8] = vertex3f[11] = 0;
1322 vertex3f[0] = vertex3f[9] = x;
1323 vertex3f[1] = vertex3f[4] = y;
1324 vertex3f[3] = vertex3f[6] = x + pic->width;
1325 vertex3f[7] = vertex3f[10] = y + pic->height;
1326 texcoord2f[0] = 0;texcoord2f[1] = 0;
1327 texcoord2f[2] = 1;texcoord2f[3] = 0;
1328 texcoord2f[4] = 1;texcoord2f[5] = 1;
1329 texcoord2f[6] = 0;texcoord2f[7] = 1;
1330 R_Mesh_Draw(0, 4, 2, polygonelements);
1336 void CL_UpdateScreen(void)
1338 float conwidth, conheight;
1343 if (!scr_initialized || !con_initialized || vid_hidden)
1344 return; // not initialized yet
1346 // don't allow cheats in multiplayer
1347 if (!cl.islocalgame && cl.worldmodel)
1349 if (r_fullbright.integer != 0)
1350 Cvar_Set ("r_fullbright", "0");
1351 if (r_ambient.value != 0)
1352 Cvar_Set ("r_ambient", "0");
1355 conwidth = bound(320, vid_conwidth.value, 2048);
1356 conheight = bound(200, vid_conheight.value, 1536);
1357 if (vid_conwidth.value != conwidth)
1358 Cvar_SetValue("vid_conwidth", conwidth);
1359 if (vid_conheight.value != conheight)
1360 Cvar_SetValue("vid_conheight", conheight);
1363 if (scr_viewsize.value < 30)
1364 Cvar_Set ("viewsize","30");
1365 if (scr_viewsize.value > 120)
1366 Cvar_Set ("viewsize","120");
1368 // bound field of view
1369 if (scr_fov.value < 1)
1370 Cvar_Set ("fov","1");
1371 if (scr_fov.value > 170)
1372 Cvar_Set ("fov","170");
1374 // validate r_textureunits cvar
1375 if (r_textureunits.integer > gl_textureunits)
1376 Cvar_SetValueQuick(&r_textureunits, gl_textureunits);
1377 if (r_textureunits.integer < 1)
1378 Cvar_SetValueQuick(&r_textureunits, 1);
1380 // validate gl_combine cvar
1381 if (gl_combine.integer && !gl_combine_extension)
1382 Cvar_SetValueQuick(&gl_combine, 0);
1384 // intermission is always full screen
1385 if (cl.intermission)
1389 if (scr_viewsize.value >= 120)
1390 sb_lines = 0; // no status bar at all
1391 else if (scr_viewsize.value >= 110)
1392 sb_lines = 24; // no inventory
1397 r_view.colormask[0] = 1;
1398 r_view.colormask[1] = 1;
1399 r_view.colormask[2] = 1;
1401 if (r_timereport_active)
1402 R_TimeReport("other");
1404 SCR_SetUpToDrawConsole();
1406 if (r_timereport_active)
1407 R_TimeReport("start");
1410 qglViewport(0, 0, vid.width, vid.height);CHECKGLERROR
1411 qglDisable(GL_SCISSOR_TEST);CHECKGLERROR
1412 qglDepthMask(1);CHECKGLERROR
1413 qglColorMask(1,1,1,1);CHECKGLERROR
1414 qglClearColor(0,0,0,0);CHECKGLERROR
1415 qglClear(GL_COLOR_BUFFER_BIT);CHECKGLERROR
1417 if (r_timereport_active)
1418 R_TimeReport("clear");
1420 if (r_stereo_redblue.integer || r_stereo_redgreen.integer || r_stereo_redcyan.integer || r_stereo_sidebyside.integer)
1422 matrix4x4_t originalmatrix = r_view.matrix;
1423 r_view.matrix.m[0][3] = originalmatrix.m[0][3] + r_stereo_separation.value * -0.5f * r_view.matrix.m[0][1];
1424 r_view.matrix.m[1][3] = originalmatrix.m[1][3] + r_stereo_separation.value * -0.5f * r_view.matrix.m[1][1];
1425 r_view.matrix.m[2][3] = originalmatrix.m[2][3] + r_stereo_separation.value * -0.5f * r_view.matrix.m[2][1];
1427 if (r_stereo_sidebyside.integer)
1430 if (r_stereo_redblue.integer || r_stereo_redgreen.integer || r_stereo_redcyan.integer)
1432 r_view.colormask[0] = 1;
1433 r_view.colormask[1] = 0;
1434 r_view.colormask[2] = 0;
1439 r_view.matrix.m[0][3] = originalmatrix.m[0][3] + r_stereo_separation.value * 0.5f * r_view.matrix.m[0][1];
1440 r_view.matrix.m[1][3] = originalmatrix.m[1][3] + r_stereo_separation.value * 0.5f * r_view.matrix.m[1][1];
1441 r_view.matrix.m[2][3] = originalmatrix.m[2][3] + r_stereo_separation.value * 0.5f * r_view.matrix.m[2][1];
1443 if (r_stereo_sidebyside.integer)
1446 if (r_stereo_redblue.integer || r_stereo_redgreen.integer || r_stereo_redcyan.integer)
1448 r_view.colormask[0] = 0;
1449 r_view.colormask[1] = r_stereo_redcyan.integer || r_stereo_redgreen.integer;
1450 r_view.colormask[2] = r_stereo_redcyan.integer || r_stereo_redblue.integer;
1455 r_view.matrix = originalmatrix;
1463 if (r_timereport_active)
1464 R_TimeReport("finish");
1467 void CL_Screen_NewMap(void)